工作中,用到了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!"; } }