本文是一個系列,歡迎關注html
查看上一篇文章能夠掃描文章下方的二維碼,點擊往期回顧-日誌系列便可查看全部相關文章java
上一篇咱們討論了爲何要使用日誌框架,此次咱們深刻問題的根源,爲何咱們須要日誌?git
大多數開發人員會糾結日誌該怎麼輸出,何時輸出,輸出了會不會有人看等問題,讓咱們跳出開發人員的侷限來考慮這個問題:誰須要日誌?日誌有幾種?日誌都須要輸出什麼?如何輸出日誌?github
System.out
來輸出,一不當心發佈到線上,會被項目經理痛批);其次線上問題很難重放,用戶的表述通常都會失真,何況不少用戶發現 bug 就刪 app 關網頁走人了注:日誌級別會在下面講解sql
throw
)了通常調試日誌由開發者自定義輸出,其餘三種應該根據實際業務需求來定製。數據庫
OK,理論就聊到這裏,接下來讓咱們回到技術層面。apache
若是要想要學會使用日誌框架,先要理解幾個簡單概念,Logger、Appenders、Layout、日誌級別與級別繼承(Level Inheritance)json
用於輸出日誌,調用一次org.slf4j.LoggerFactory#getLogger(java.lang.Class<?>)
或org.slf4j.LoggerFactory#getLogger(java.lang.String)
就會產生一個日誌實例,相同參數會共用同一個實例。安全
日誌輸出器,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 配置文件位置
lobback 支持 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更強大,更多內容請關注下一篇文章)。關於日誌如何輸出本人也是經驗之談,免不了紕漏,歡迎補充指正,另外每一個公司都有不一樣的應用場景,具體應該遵照公司統一規範。
本篇更多傾向基礎使用,接下來的文章將展開對比、原理以及擴展日誌框架,敬請各位期待。
若是以爲寫的不錯,求關注、求點贊、求轉發,若是有問題或者文中有錯誤,歡迎留言討論。
掃碼關注公衆號,第一時間得到更新
參考
https://logging.apache.org/log4j/2.x/manual/configuration.html