大家好,我是捡田螺的小男孩.
我们日常开发中,经常需要打印日志.但是不当的日志使用可能会导致各种问题。整理了日志打印的10个坑,希望大家都能避坑~~
常见的日志级别有5种,分别是error、warn、info、debug、trace。日常开发中,我们需要选择恰当的日志级别,不要反手就是打印info哈~
比如这个例子(过度记录DEBUG级别的日志):
// 过度记录DEBUG级别的日志public void processData() { logger.debug("Entering processData method."); // 业务逻辑 logger.debug("Exiting processData method.");}
正例应该这样(仅记录必要的日志信息)
// 仅在异常和重要步骤中记录日志public void processData() { try { logger.info("Start processing data."); // 业务逻辑 logger.info("Finished processing data."); } catch (Exception e) { logger.error("Error occurred while processing data: ", e); }}
我们应当根据日志的重要性设置不同的日志级别(如ERROR、WARN、INFO、DEBUG),只记录必要的日志信息,避免日志打印处理成流水账.
有些伙伴乱用日志级别,甚至将DEBUG级别的日志用于生产环境。
反例(将DEBUG级别的日志直接用于生产环境):
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);
同步日志记录会阻塞主线程,影响系统性能。因此使用异步日志框架(比如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>
有些日志配置文件复杂,难以维护;配置文件中存在硬编码路径。如下:
// log4j.properties 示例log4j.rootLogger=INFO, filelog4j.appender.file=org.apache.log4j.RollingFileAppenderlog4j.appender.file.File=/var/log/tianluoboy.log
应当使用灵活的配置
// 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>
日志中记录了用户的敏感信息(如密码、信用卡号),存在安全风险。
logger.info("User password: {}", password);
这都把用户的密码打印出来了...解决方法就是,不能打印密码这些关键信息,如果是手机号、邮箱等敏感信息,则可以脱敏、或者掩码处理。
如果日志文件过大时未能及时轮转,就很坑.
// 简单的日志配置,没有轮转策略log4j.appender.file.File=tianluoboy.log
日志要配置合理的轮转和归档策略,避免文件过大.
// 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>
有些日志框架,在低版本,可能会存在安全漏洞问题.甚至有些可能会存在漏洞还没被发现.
我们如何做呢? 如果是低版本存在安全漏洞的日志框架,我们要尽快升级到最新版本.
比如Log4Shell 是Log4j 2.x中一个严重的远程代码执行(RCE)漏洞。攻击者可以通过特制的日志消息来触发JNDI查找请求,从而在受影响的系统上执行任意代码。
可以升级到Log4j 2.17.0或更高版本,这些版本已经修复了该漏洞。
尚未被发现的漏洞,也可能潜在地影响应用程序的安全性。我们要使用成熟的日志框架,并且要定时更新和维护.
错误配置LevelFilter可能导致日志重复记录的问题.比如你这样配置:
<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条件相同,导致每条INFO级别的日志都会同时被两个appender记录,产生了重复日志。
可以使用不同的过滤器策略来确保日志只被一个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.28at.com/showinfo-26-96759-0.html日志打印的这10个坑,你至少踩过一个...
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: 避免消息积压的终极指南:四个关键技巧
下一篇: 一文搞懂大厂商品中心设计!