本文是一個系列,歡迎關注php
查看上一篇文章能夠掃描文章下方的二維碼,點擊往期回顧-日誌系列便可查看全部相關文章html
各位小夥伴你們好,我又回來更新了,上一篇咱們討論了爲何要使用日誌框架,此次咱們深刻問題的根源,爲何咱們須要日誌,日誌具體如何使用?java
大多數開發人員會糾結日誌該怎麼輸出,何時輸出,輸出了會不會有人看等問題,讓咱們跳出開發人員的侷限來考慮這個問題:誰須要日誌?日誌有幾種?日誌都須要輸出什麼?如何輸出日誌?git
System.out
來輸出,一不當心發佈到線上,會被項目經理痛批);其次線上問題很難重放,用戶的表述通常都會失真,何況不少用戶發現 bug 就刪 app 關網頁走人了注:日誌級別會在下面講解github
throw
)了通常調試日誌由開發者自定義輸出,其餘三種應該根據實際業務需求來定製。sql
OK,理論就聊到這裏,接下來讓咱們回到技術層面。數據庫
若是要想要學會使用日誌框架,先要理解幾個簡單概念,Logger、Appenders、Layout、日誌級別與級別繼承(Level Inheritance)apache
用於輸出日誌,調用一次org.slf4j.LoggerFactory#getLogger(java.lang.Class<?>)
或org.slf4j.LoggerFactory#getLogger(java.lang.String)
就會產生一個日誌實例,相同參數會共用同一個實例。json
日誌輸出器,logback 預約義了輸出到控制檯、文件、Socket 服務器、MySQL、PostgreSQL、Oracle 和其餘數據庫、JMS 和 UNIX Syslog 系統調用等實現,經過配置文件配置便可使用,固然咱們經常使用的只有控制檯和文件兩種。安全
用於控制日誌輸出格式,前文所說的」自動輸出日誌相關信息,如:日期、線程、方法名稱等等「就能夠用 Layout 來控制,實際使用很簡單,寫一個 Layout 格式定義表達式(pattern)便可,使用方法相似於Java 的SimpleDateFomat
。
RFC 5424 (page 11)規定了 8 種日誌級別,可是SLF4j 只定義了 5 種日誌級別,分別是 ERROR、WARN、INFO、DEBUG、TRACE 這五個級別從高到低,配置級別越高日誌輸出就越少,以下圖
咱們看到滑動條上五個點正好對應五個級別,滑動指示器能夠左右移動,指示器做爲分界點,指示器左側均可以輸出,右側都不能輸出,左右調整指示器就能夠調整日誌的輸出,滑倒右側就能夠所有輸出,滑倒左側就能夠減小輸出,那麼是否可以完全關閉輸出呢?答案是能夠的,配置文件中還能夠配置爲 ALL 與 OFF,分別對應全部(等價於TRACE)與關閉。
理解了日誌級別,讓咱們來考慮以下場景:
有需求就會有解決方案,其實很簡單,logback 與 log4j 都支持按照日誌實例來配置,如今問題解決了,可是新的問題又來了,若是線上全部日誌都輸出 INFO 級別,難道要一個一個配置嗎?這時候就就要請出咱們上面所提到的級別繼承,若是 Java 同樣,logback 與 log4j 中也都是單根繼承模型,Java 中是 Object,日誌中是 ROOT,以下圖:
有了繼承機制,咱們只須要將 ROOT 調整到 INFO 級別,再按照需求細化調整咱們業務對應的 logger 實例級別便可知足絕大多數場景。
問:把大象裝冰箱分幾步?分三步:一、引入依賴,二、編碼輸出日誌,三、調整配置文件。前文已經講過步驟一,若是沒有看過的讀者請移步公衆號查看往期回顧,這裏直接進入步驟二。
若是項目中使用了Lombok,那麼能夠直接在類上面加@Slf4j
註解既可得到日誌實例,不然可使用static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestLog.class);
來獲取日誌實例
具體日誌輸出方法以下:
logger.trace("A TRACE Message");
logger.debug("A DEBUG Message");
logger.info("An INFO Message");
logger.warn("A WARN Message");
logger.error("An ERROR Message");
複製代碼
這裏有個注意點,儘可能使用參數佔位而不要手動拼接字符串,以下
String level = "Trace";
// 反例
logger.trace("A " + level + " Message");
// 正確的作法
logger.trace("A {} Message", level);
複製代碼
這樣作能夠提升效率,若是不輸出日誌,第一種狀況也會拼接字符串形成性能損耗,第二種就不會有此問題(阿里巴巴Java開發手冊(華山版)這裏表述有問題,佔位符效率更高是由於儘可能延遲進行字符串處理,若是不須要輸出的日誌就不處理了,下一篇原理分析會展開),另外咱們也不須要if (logger.isTraceEnabled())
來進行判斷了(性能損耗不高,可是代碼好看多了)。
配置文件須要區分 logback 與 log4j2,兩種框架在配置文件上有差異但很類似,來看具體配置文件。
logback 配置文件位置
logback 支持 xml 與 groovy 腳本兩種配置方式,logback 查找配置文件位置規則以下(後續文章會講如何修改位置)
這段長長的文字其實不用看,咱們就把 logback.xml 放入 Classpath 根目錄就能夠了。。
logback 配置文件編寫規則
logback 配置文件主要分爲三類,一個或多個 Appender,用於定義輸出位置(不一樣文件位置,或者網絡又或者數據庫);一個或多個 Logger,用於細化配置不一樣 logger 的輸出級別以及位置;一個 ROOT,是一個特殊的logger,用於配置根 Logger。
咱們一塊兒來看下面的配置文件實例
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" debug="false">
<!-- 定義日誌文件的存儲地 -->
<property name="LOG_PATH" value="/var/log"/>
<property name="CONSOLE_LOG_PATTERN" value="%d{HH:mm:ss.SSS} %-5level [%10.10thread] %-30.30logger{29}\(%4L\\) - %msg%n"/>
<!-- 控制檯輸出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 文件日誌格式(打印日誌,不打印行號) -->
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%10.10thread] %-30.30logger{29} - %msg%n"/>
<appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在記錄的日誌文件的路徑及文件名 -->
<file>${LOG_PATH}/log.log</file>
<!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- yyyy-MM-dd 按日滾動 -->
<fileNamePattern>${LOG_PATH}/log-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 單個文件最大50M -->
<maxFileSize>50MB</maxFileSize>
<!-- 最多佔用5G磁盤空間,500個文件(總共不能超過該5G) -->
<maxHistory>500</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<!-- 追加方式記錄日誌 -->
<append>true</append>
<!-- 日誌文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 日誌輸出級別 STDOUT:控制檯;FILE_ALL:文件 -->
<root level="warn">
<appender-ref ref="STDOUT"/>
</root>
<logger name="druid.sql" level="warn" additivity="true"/>
<logger name="druid.sql.ResultSet" level="warn" additivity="true"/>
<logger name="com.alibaba.druid.pool.DruidDataSource" level="debug" additivity="true">
<appender-ref ref="FILE_ALL"/>
</logger>
</configuration>
複製代碼
上面配置文件定義了兩個 Appender,一個輸出控制檯,另外一個輸出到文件而且自動滾動。需注意的是property
標籤至關於定義一個變量,可使用${xxx}
進行引用,CONSOLE_LOG_PATTERN 與 FILE_LOG_PATTERN 定義了控制檯與文件打印格式,具體編寫方式相似於 Java 的SimpleDateFomat
就不在此展開了,具體能夠參考
log4j2 配置文件位置
log4j2 支持 XML、JSON、YAML 或者 properties 格式的配置文件,具體查找方式以下:
這段更長的文字固然也不用看,咱們就把 log4j2.xml 放入 Classpath 根目錄就能夠了
log4j2 配置文件編寫
log4j 也是 Logger 與 Appender 配置項,也有一個ROOT的特殊 Logger,Appender 比logback支持更多輸出位置,如kafka、Cassandra、Flume等。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug" strict="true">
<!-- 定義變量,能夠被${xxx}引用 -->
<Properties>
<Property name="baseDir">logs</Property>
</Properties>
<!-- 定義 Appenders 用來指定輸出位置 -->
<Appenders>
<!-- 日誌滾動 $${date:yyyy-MM}:按月滾動文件夾 按小時、文件序號滾動,每次滾動都使用gz壓縮 -->
<RollingFile name="RollingFile" fileName="${baseDir}/log.log" filePattern="${baseDir}/$${date:yyyy-MM}/log-%d{yyyy-MM-dd-HH}-%i.log.gz">
<!-- 日誌格式 -->
<PatternLayout pattern="%d %p %c{1.} [%t] %m%n"/>
<Policies>
<!-- 時間滾動(按月滾動目錄,按小時滾動文件) -->
<TimeBasedTriggeringPolicy/>
<!-- 文件大小滾動(1小時內超過250M,強制滾動一次) -->
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
<!-- 天天最多100個文件 -->
<DefaultRolloverStrategy max="100">
<!-- 刪除策略,超過三十天刪除,若是總文件小於100G,文件數量小於10個,則不會被刪除 -->
<Delete basePath="${baseDir}" maxDepth="2">
<IfFileName glob="*/app-*.log.gz">
<IfLastModified age="30d">
<IfAny>
<IfAccumulatedFileSize exceeds="100 GB"/>
<IfAccumulatedFileCount exceeds="10"/>
</IfAny>
</IfLastModified>
</IfFileName>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<!-- 多個logger -->
<Logger name="org.apache.logging.log4j.test2" level="debug" additivity="false">
<AppenderRef ref="RollingFile"/>
</Logger>
<!-- 一個ROOT -->
<Root level="trace">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
複製代碼
能夠看得出 log4j2 與 logback 配置文件書寫大同小異,甚至一樣須要注意additivity="true"
時致使的日誌重複輸出問題,畢竟 log4j1 與 logback 都是 Ceki大神都做品。
得益於 Ceki 大佬的努力,日誌使用幾乎沒有有差別(Logback 與 Log4j2,Google 於 2018年4月開源了流式(fluent)日誌框架 Flogger,Slf4j 也將在 2.0 版本支持,而 log4j2 再次落後,不過筆者認爲 log4j2 有不少優勢,更多內容請關注後續文章)。關於日誌如何輸出本人也是經驗之談,免不了紕漏,歡迎補充指正,另外每一個公司都有不一樣的應用場景,具體應該遵照公司統一規範。
本篇更多傾向基礎使用,接下來的文章將展開對比、原理以及擴展日誌框架,敬請各位小夥伴們期待。
若是以爲寫的不錯,求關注、求點贊、求轉發,若是有問題或者文中有錯誤,歡迎留言討論。
掃描關注公衆號,第一時間得到更新
參考