大家好,我是撿田螺的小男孩.
我們?nèi)粘i_發(fā)中,經(jīng)常需要打印日志.但是不當(dāng)?shù)娜罩臼褂每赡軙?dǎo)致各種問題。整理了日志打印的10個坑,希望大家都能避坑~~
常見的日志級別有5種,分別是error、warn、info、debug、trace。日常開發(fā)中,我們需要選擇恰當(dāng)?shù)娜罩炯墑e,不要反手就是打印info哈~
比如這個例子(過度記錄DEBUG級別的日志):
// 過度記錄DEBUG級別的日志public void processData() { logger.debug("Entering processData method."); // 業(yè)務(wù)邏輯 logger.debug("Exiting processData method.");}
正例應(yīng)該這樣(僅記錄必要的日志信息)
// 僅在異常和重要步驟中記錄日志public void processData() { try { logger.info("Start processing data."); // 業(yè)務(wù)邏輯 logger.info("Finished processing data."); } catch (Exception e) { logger.error("Error occurred while processing data: ", e); }}
我們應(yīng)當(dāng)根據(jù)日志的重要性設(shè)置不同的日志級別(如ERROR、WARN、INFO、DEBUG),只記錄必要的日志信息,避免日志打印處理成流水賬.
有些伙伴亂用日志級別,甚至將DEBUG級別的日志用于生產(chǎn)環(huán)境。
反例(將DEBUG級別的日志直接用于生產(chǎn)環(huán)境):
logger.debug("This is a debug message,should not be logged in production");
正例 (debug日志級別,最好判斷一下是否開啟):
if(log.isDebugEnable()){ logger.debug("This is a debug message,should not be logged in production"); }
大家可以看下這行日志,覺得有啥問題
logger.info("User login request");
很明顯,日志缺少上下文信息,并不方便排查.比如說,你想知道是哪個用戶的登錄請求嘛? 至少把userId 打印出來吧,如下:
logger.info("User login request,userId:{}",userId);
同步日志記錄會阻塞主線程,影響系統(tǒng)性能。因此使用異步日志框架(比如Log4j 2的異步日志記錄器)來減少對性能的影響。
// 使用Log4j 2的異步日志<Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> <Async name="AsyncConsole"> <AppenderRef ref="Console"/> </Async> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="AsyncConsole"/> </Root> </Loggers></Configuration>
有些日志配置文件復(fù)雜,難以維護;配置文件中存在硬編碼路徑。如下:
// log4j.properties 示例log4j.rootLogger=INFO, filelog4j.appender.file=org.apache.log4j.RollingFileAppenderlog4j.appender.file.File=/var/log/tianluoboy.log
應(yīng)當(dāng)使用靈活的配置
// logback.xml 示例<configuration> <property name="LOG_HOME" value="${LOG_HOME:-/var/log/myapp}"/> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/tianluoboy.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_HOME}/tianluoboy.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} - %msg%n</pattern> </encoder> </appender> <root level="info"> <appender-ref ref="FILE"/> </root></configuration>
日志中記錄了用戶的敏感信息(如密碼、信用卡號),存在安全風(fēng)險。
logger.info("User password: {}", password);
這都把用戶的密碼打印出來了...解決方法就是,不能打印密碼這些關(guān)鍵信息,如果是手機號、郵箱等敏感信息,則可以脫敏、或者掩碼處理。
如果日志文件過大時未能及時輪轉(zhuǎn),就很坑.
// 簡單的日志配置,沒有輪轉(zhuǎn)策略log4j.appender.file.File=tianluoboy.log
日志要配置合理的輪轉(zhuǎn)和歸檔策略,避免文件過大.
// logback.xml 示例<configuration> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>tianluoboy.logg</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>tianluoboy.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} - %msg%n</pattern> </encoder> </appender> <root level="info"> <appender-ref ref="FILE"/> </root></configuration>
有些日志框架,在低版本,可能會存在安全漏洞問題.甚至有些可能會存在漏洞還沒被發(fā)現(xiàn).
我們?nèi)绾巫瞿? 如果是低版本存在安全漏洞的日志框架,我們要盡快升級到最新版本.
比如Log4Shell 是Log4j 2.x中一個嚴重的遠程代碼執(zhí)行(RCE)漏洞。攻擊者可以通過特制的日志消息來觸發(fā)JNDI查找請求,從而在受影響的系統(tǒng)上執(zhí)行任意代碼。
可以升級到Log4j 2.17.0或更高版本,這些版本已經(jīng)修復(fù)了該漏洞。
尚未被發(fā)現(xiàn)的漏洞,也可能潛在地影響應(yīng)用程序的安全性。我們要使用成熟的日志框架,并且要定時更新和維護.
錯誤配置LevelFilter可能導(dǎo)致日志重復(fù)記錄的問題.比如你這樣配置:
<Configuration status="WARN"> <Appenders> <Console name="ConsoleAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%d [%t] %-5level: %msg%n%throwable"/> <Filters> <LevelFilter level="INFO" notallow="ACCEPT" notallow="DENY"/> </Filters> </Console> <File name="FileAppender" fileName="app.log"> <PatternLayout pattern="%d [%t] %-5level: %msg%n%throwable"/> <Filters> <LevelFilter level="INFO" notallow="ACCEPT" notallow="DENY"/> </Filters> </File> </Appenders> <Loggers> <Root level="INFO"> <AppenderRef ref="ConsoleAppender"/> <AppenderRef ref="FileAppender"/> </Root> </Loggers></Configuration>
在上述配置中,由于兩個appender的LevelFilter條件相同,導(dǎo)致每條INFO級別的日志都會同時被兩個appender記錄,產(chǎn)生了重復(fù)日志。
可以使用不同的過濾器策略來確保日志只被一個appender記錄:
<Configuration status="WARN"> <Appenders> <Console name="ConsoleAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%d [%t] %-5level: %msg%n%throwable"/> <Filters> <LevelFilter level="INFO" notallow="ACCEPT" notallow="DENY"/> </Filters> </Console> <File name="FileAppender" fileName="app.log"> <PatternLayout pattern="%d [%t] %-5level: %msg%n%throwable"/> <Filters> <LevelFilter level="DEBUG" notallow="ACCEPT" notallow="DENY"/> <LevelFilter level="INFO" notallow="DENY" notallow="DENY"/> </Filters> </File> </Appenders> <Loggers> <Root level="DEBUG"> <AppenderRef ref="ConsoleAppender"/> <AppenderRef ref="FileAppender"/> </Root> </Loggers></Configuration>
在這個配置中,ConsoleAppender只記錄INFO級別及以上的日志,而FileAppender記錄DEBUG級別但排除INFO級別的日志。這樣可以避免INFO級別的日志被兩個appender同時記錄。
本文鏈接:http://www.www897cc.com/showinfo-26-96759-0.html日志打印的這10個坑,你至少踩過一個...
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
下一篇: 一文搞懂大廠商品中心設(shè)計!