log4j是怎么来的?
没接触过log4j的Java开发者,看到log4j这个名字,估计会脑袋发蒙,这是啥玩意呢?log4j是Apache为Java开发者提供的日志工具,解释一下就是log for java,给Java程序提供日志输出的工具。
问题又来了,Apache为什么要开发log4j呢?因为Apache开发log4j是为了补Java的短板。Java在设计之初,充分借鉴了C等其它编程语言的优点,其语言的简洁性、易使用性以及跨平台性都非常不错,唯独没有设计日志系统。这可苦了早期Java开发者了,当写完的程序运行后,若发行程序的运行结果和预期的不一样,开发者要发现程序所存在的问题,只能采用调试的方式逐一排查,费时费力。若程序已提交给客户,在客户环境下出现了问题,是无法进行调试排查的,只能寄希望于问题在开发环境中重现。
难以发现程序运行中出现的问题,是早期Java的一个短板,为了解决这个短板。Apache开发了log4j,log4j可以把程序运行过程中的重要信息输出到文件中,这些重要信息的输出是由Java开发者来确定的,也就是说开发者在开发程序时,会把一些可能出现问题的变量、执行的语句状态、重要的节点信息写到文件中,当程序在运行过程中出现问题时,就可以从这些文件中跟踪程序的运行信息,及时发现程序存在的问题,写入程序运行信息的文件被称为系统日志,log4j就是用来写系统日志的程序。
从哪儿下载log4j?
log4j对程序的监控和问题排查确实很有用,对没有使用log4j的开发者来说,如何使用它呢?
等等,log4j怎么变成log4j2了呢?log4j2是log4j的升级版,功能上自然比log4j要强大了很多。再说,Apache已经停止对log4j的更新了,我们自然要用log4j2了。下载的压缩包里面有三个重要的文件,把这三个文件复制到项目WEB-INF目录下的lib目录。

万事具备,只欠东风
现在万事具备,只欠东风。东风就是log4j2.xml配置文件,log4j会读取这个配置文件。log4j为什么需要这个配置文件呢?因为log4j可以把更多的日志输出控制权交给开发者。举个例子,如果没有配置文件,log4j会把日志输出到一个固定的位置,你没有任何办法想让它把日志文件输出到你指定的位置;再来一个例子,假如你想自己定义输出的日志格式,没有配置文件,你无能为力。
下面是一个简单配置文件的内容。
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="WARN">
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{DEFAULT} [%t] %-5p %c{36} - %m%n"/>
</Console>
</appenders>
<loggers>
<root level="info">
<appender-ref ref="Console" />
</root>
</loggers>
</configuration>配置文件中的appenders标签是用来定义日志输出位置的,在这个标签下输出位置可以定义多个,每个位置由子标签来定义。如上面配置文件的Console标签定义了日志信息输出到控制台。Console标签下的PatternLayout标签定义了日志的输出格式,标签的pattern属性用来配置日志输出的格式,在这里你可以更改为自己喜欢的输出格式,至于具体怎么改,网上一大堆,这里就不细说了,不过一般来说保持默认的输出格式就可以了。
配置文件中的loggers标签用来定义日志输出范围,对日志信息进行级别限制,在log4j中根据输出日志信息的重要程度,将日志主要分为六个级别,按重要程度排序为fatal(致命)、error(错误)、warn(警告)、info(信息)、debug(调试)、trace(追踪)。其中,最常用的是error和info,当程序能够自己捕捉到错误,但错误不影响系统运行时,用error输出错误和异常信息;在程序运行过程中,特别是在客户环境下运行时,可以输出一些程序的重要信息,用于发现程序的潜在问题,这是可以用info输出信息。
loggers标签下的root标签中level属性可以限制日志的输出级别,当level属性设置为info级别时,log4j只输出info级别以上的日志,即使你在程序中输出了低于info级别的日志,log4j也不会让这些日志信息输出。
需要注意的是,log4j2.xml配置文件创建完成后,需要把log4j2.xml配置文件存储到WEB项目的WEB-INF根目录下。
使用log4j跟踪程序
前面都是铺垫,现在要开始真正干活了。还是以Mooc项目为案例,Mooc项目的工程文件和源代码可以从码云上下载。
@Controller
@RequestMapping("/user")
public class RegisterController {
/*声明log4j对象*/
Logger log = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
@Autowired
private RegisterService regService;
@RequestMapping(value = "/register.do", method = { RequestMethod.GET, RequestMethod.POST })
public ModelAndView registerUser(HttpServletRequest request) throws UnsupportedEncodingException {
/*设置前端字符编码为UTF-8*/
request.setCharacterEncoding("UTF-8");
/* 创建返回的ModelAndView实例 */
ModelAndView view = new ModelAndView();
/* 从发送请求的JSP页面获取表单数据 */
String paraLogin = request.getParameter("login");
String paraName = request.getParameter("name");
String paraPsw = request.getParameter("psw");
/*输出日志信息*/
log.info(paraLogin);
log.error(paraPsw);
/* 实例化UserInfo模型 */
UserInfo user = new UserInfo();
user.setLogin(paraLogin);
user.setName(paraName);
user.setPassword(paraPsw);
/* 调用注册用户业务 */
regService.registerUser(user);
/* 添加user模型到view */
view.addObject("user", user);
/* 设置跳转页面 */
view.setViewName("user/RegisterResult");
return view;
}
}加入log4j输出日志代码很轻松,首先在类中用LogManager类实例化Logger对象。
/*声明log4j对象*/ Logger log = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
然后就可以输出你想要输出的信息了。
/*输出日志信息*/ log.info(paraLogin); log.error(paraPsw);
日志信息会输出到控制台,paraLogin的值为xueshanfeihu,paraPsw的值为123456。
2018-11-24 21:04:24,172 [http-nio-8080-exec-4] INFO - xueshanfeihu 2018-11-24 21:04:24,227 [http-nio-8080-exec-4] ERROR - 123456
使用log4j输出log文件
输出日志信息到控制台不是我们使用log4j的目的,目的是输出日志信息到文件。这次配置文件又起到作用了,打开log4j2.xml配置文件在appenders标签下加入下面的子标签。
<File name="FileAppender" fileName="D:/logs/mooc.log">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</File>
<Async name="AsyncAppender">
<AppenderRef ref="FileAppender"/>
</Async>在root标签下面加入下面的子标签。
<appender-ref ref="AsyncAppender " />
完整的log4j2.xml配置文件内容如下。
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="WARN">
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{DEFAULT} [%t] %-5p %c{36} - %m%n"/>
</Console>
<File name="FileAppender" fileName="D:/logs/mooc.log">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</File>
<Async name="AsyncAppender">
<AppenderRef ref="FileAppender"/>
</Async>
</appenders>
<loggers>
<root level="info">
<appender-ref ref="Console" />
<appender-ref ref="AsyncAppender" />
</root>
</loggers>
</configuration>配置文件修改完成后,日志信息将同步输出到mooc.log文件。