工作中,用到了log4j2,以前只接触过log4j,也没有太过深入,这次就稍微系统的学习了以下log4j2.
一.引入pom.xml
使用maven作为项目的构建环境,pom.xml使用slf4j,slf4j是一个抽象层,可以使用任意的日志记录.这里就不展开描述了,只需要知道,引入pom.xml后,配置依然和log4j2一样,但是获取到Logger对象稍有不同.只使用log4j2的话,一般是使用LogManager去获取的,但是如果使用slf4j的话,使用LoggerFactory去获取.(后面会讲解)
<properties> <!-- spring版本号 --> <spring.version>4.3.2.RELEASE</spring.version> <!-- log4j日志文件管理包版本 --> <slf4j.version>1.7.12</slf4j.version> <log4j.version>2.1</log4j.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <!-- spring核心包 --> <!-- springframe start --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <!--log4j相关配置开始--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-web</artifactId> <version>${log4j.version}</version> <scope>runtime</scope> </dependency> <!--log4j相关配置结束--> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build>
二.日志级别
log4j2也有五种日志隔离级别,分别为:
trace:追踪,是最低的日志级别,相当于追踪程序的执行,一般不怎么使用
debug:一般在开发中,都将其设置为最低的日志级别.
info:输出感兴趣的信息,我在开发中一般都会用info去输出.
warn:警告.有些时候,虽然程序不会报错,但是还是需要告诉程序员的.
error:错误,这个在开发中也挺常用的,,
fetal:极其重大的错误,这个一旦发生,程序基本上也要停止了,,目前限于开发经验,我还没有碰到要碰到它的地方.
日志通过Logger对象输出,Logger对象的获取见下文,输出的API基本如下:Logger对象.日志级别("日志内容");例如:
当日志级别设置为某个值的时候,低于它的日志信息将不会被输出到appender中(稍后会讲解),只有高于设置的级别的信息会被输出到appender中.例如上例中,如果日志级别定义为error,那么这条信息将不会输出.
三.appender和logger
log4j2是用xml去定义需要的配置的,其中涉及到两个重要的标签,appenders和loggers.appenders顾名思义,代表将其信息输出到哪里,在这个标签内部定义了输出位置的相关信息.appenders标签内部可以有多个appender,表示可以输出到多个位置.这些appender用具体的标签去标识,例如<console>表示输出到控制台的appender,<file>表示输出到文件中.appender内部可以定义输出的格式(用<pattern>标签去标识.),可以定义在达到某个日志级别的时候才给予输出,其余情况拦截(用<ThreadSholdFilter>标签去标识.).
loggers标签则是定义了一些必要的logger,logger代表用于输出日志信息的具体对象.logger内部有appender,指定这些对象输出的具体位置.可以定义多个appender,其中,logger的定义比较特殊,因为它涉及到了继承,可以结合log4j2的配置文件来看一看.注意log4j2.xml放在classpath下,不需要任何配置就可以加载.
<!-- status为不记录log4j本身的日志 --> <configuration status="OFF"> <properties> <property name="LOG_HOME">C:/logs</property> <property name="FILE_NAME">mylog</property> </properties> <appenders> <Console name="Console" target="SYSTEM_OUT"> <!-- ThresholdFilter相当于拦截器.info以上的命令不会被拦截. --> <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> </Console> <File name="Error" fileName="${LOG_HOME}/error.log"> <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/> </File> <RollingFile name="RollingFile" fileName="${LOG_HOME}/${FILE_NAME}.log" filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{MM-dd-yyyy}-%i.log.gz"> <PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/> <Policies> <TimeBasedTriggeringPolicy/> <SizeBasedTriggeringPolicy size="10 MB"/> </Policies> </RollingFile> </appenders> <loggers> <root level="info"> <appender-ref ref="RollingFile"/> <appender-ref ref="Console"/> <appender-ref ref="Error" /> </root> <Logger name="com.hlhdidi.servlet" additivity="false"> <appender-ref ref="RollingFile"/> <appender-ref ref="Console"/> </Logger> <Logger name="com.hlhdidi.service" level="error" additivity="true"> <appender-ref ref="Console"/> </Logger> </loggers> </configuration>
<properties>标签定义了在配置文件上下文可能会用到的键值对的信息(类似于maven).重点看看<loggers>标签,首先是root标签.在log4j2默认所有的日志输出对象(Loggger)都支持<root>标签的相关配置.描述起来可能有些晦涩,但是只要看看Logger对象是如何在类中获取就比较简单了.下面代码是在类中获取Logger对象的方式(如果只使用log4j2使用LoggerManager去获取,参数和返回值都是一样的,就不介绍它了):
这个参数是传入Class对象,并且返回一个Logger.实际上还可以传入一个字符串,如下:
但是实际上我们传入的参数是各种各样的,log4j2怎么知道我们需要返回什么样的Logger呢?实际上所有的Logger默认都继承一个配置,就是<root>.log4j2根据name去配置文件依次与各个logger的name互相匹配,寻找对应的logger配置信息.当我们传入的参数为Class对象的时候,实际上name为该Class对象的全类名,如果找到了,则采用该<logger>的配置信息,如果没有找到,则采用默认的配置信息,也就是<root>中定义的配置信息,可以看出,我们在<root>中可以将日志信息输出到三个位置.此外,在配置文件中定义name也是有"讲究"的,前面提到,在Logger对象没有在xml中找到匹配的name的时候,会采用<root>中定义的配置信息,实际上在我们定义<Logger>标签的配置的时候,它默认也是继承<root>中的配置信息的,也就是说,某个具体的<Logger>标签在默认情况下会继承<root>的所有配置.可以设置additivity为false,就可以不使用父类的配置信息.此外,Logger标签相互之间也是有继承的关系的.也就是一个Logger标签的配置信息可以继承另外一个<Logger>标签内部的配置信息.这个log4j2通过name去实现.当一个logger的name是另外一个logger的name的前缀的时候,则称该Logger是另外一个Logger的"父".例如:"com.hlhdidi.web"为name的<Logger>的配置可以继承"com.hlhdidi"为name的<logger>的配置信息.同样也可以使用additivity属性指定不继承.此外,也可以在<Logger>标签上指定level属性.它表示指定该Logger输出日志的最低日志级别.但是有一种特殊情况需要注意:考虑下面的情况:定义了一个<Logger>它的日志级别为info,设置输出到console,<root>的日志级别也定义为info,设置输出到console.当我们使用.info输出信息的时候,如果匹配到此<Logger>,那么根据继承的关系,此时控制台上同一个信息会被输出两遍.这时候,如果我们将<root>的日志级别改为error,继续使用.info输出信息,(使用的Logger依然能匹配到配置文件上的一个具体的<Logger>)那么信息将会输出几次呢?通过输出发现还是两次.我推测可能是log4j内部只要匹配到一个<Logger>,在继承的时候,将不会再次去判断是否符合父类的日志级别.
四.使用
说了那么多,其实使用log4j2还是很简单的.实际上遵循以下步骤即可使用:
1.写pom.xml/拷jar包
log4j的核心jar包只有两个,如下:
2.建立配置文件/书写配置文件
通常将log4j2.xml放在classpath下,这样子在项目启动的时候,就会加载.
3.在类中获取Logger对象,使用Logger对象输出信息
Logger对象将根据匹配到的<Logger>里的内容输出到指定的appender中.
@WebServlet("/MyWebServlet") public class MyWebServlet extends HttpServlet { private static final long serialVersionUID = 1L; private Logger logger=LoggerFactory.getLogger(MyWebServlet.class); public MyWebServlet() { logger.error("myservlet初始化了,请做好准备!"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { logger.error("调用了Get方法的哦"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { logger.error("调用了post方法,即将被转接到get方法中去"); } }
五.SpringBoot整合log4j2
SpringBoot也是我非常喜欢的技术,它整合log4j2非常简单:
1.书写pom.xml
需要注意在springboot-starter-web中去掉log4j2的依赖
<!--默认继承父类去实现--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.0.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.7</java.version> </properties> <!-- 添加springboot的web模板 --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions><!-- 去掉默认配置 --> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <!-- 引入log4j2依赖 --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
2.classpath下建立log4j2.xml以及application.properties文件
在application.properties中指定log4j2.xml的位置:
log4j2.xml省略,应该是和上文相似的配置
3.在Controller中去获取Logger对象,并且打印日志
@Controller public class WebController { private Logger logger = LoggerFactory.getLogger(this.getClass()); @RequestMapping("/index") @ResponseBody public String index() { logger.info("hello world!!"); return "hello world!"; } }