一、日志级别
ALL、TRACE、DEBUG、INFO、WARN、ERROR、FATAL、OFF
从左至右日志输出由多到少。
生产环境使用INFO日志级别,调试时可以设置为DEBUG级别。
针对Spring Boot的程序,使用配置中的logging.level.root控制默认日志级别。
启动时可以使用logging.level.root参数做临时设置。例如:
java -jar app.jar --logging.level.root=debug
二、日志分类
- 监控日志
监控系统内关键点的动作,DEBUG级别可做打点使用,ERROR级别记录程序异常。
- 业务日志
系统内业务操作日志输出,例如:下单、支付、后台上下架商品等重要的操作。
- 统计日志
根据统计需要,对用户操作进行记录,例如:登录、注册、浏览商品等。
三、日志的触发点和级别
- 监控日志
触发点 | 日志级别 | 例子 |
---|---|---|
关键方法入口 | DEBUG | 记录参数 |
调用外部服务 | DEBUG | REST API调用返回数据 |
耗时和资源占用高的方法 | DEBUG | 记录处理时间、记录资源消耗 |
定时任务启动和结束 | DEBUG | 启动时间及状态、结束时间及状态 |
容错及恢复 | DEBUG | 用户目录不存在,重新建立用户目录 |
可处置的操作异常 | WARN | 用户登录失败 |
无法处置的程序异常 | ERROR | logger.error(各类参数或者对象 toString + "_" + e.getMessage(), e); |
主程序启动和关闭 | DEBUG | 启动时间及状态、结束时间及状态 |
重要配置或环境变量 | DEBUG | 配置,环境变量 |
- 业务日志
触发点 | 日志级别 | 例子 |
---|---|---|
业务操作执行后 | INFO | 关键业务操作记录执行结果,执行人 |
- 统计日志
触发点 | 日志级别 | 例子 |
---|---|---|
需要进行统计的操作 | INFO | 记录用户访问信息,IP、耗时、下载量;记录资源用量信息 |
四、日志收集方式
1. Fluentd
将日志发送到远程日志中心,由Fluentd进行收集,Elasticsearch存储,Kibana展示。
附logback配置文件片段。
logger monitor/business/stats 分别对应 监控/业务/统计日志
<appender name="FLUENT" class="ch.qos.logback.more.appenders.FluencyLogbackAppender">
<tag>${fluentTag}</tag>
<remoteHost>${fluentHost}</remoteHost>
<port>${fluentPort}</port>
<fileBackupDir>${logPath}</fileBackupDir>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern><![CDATA[%msg]]></pattern>
</layout>
</appender>
<logger name="monitor" class="ch.qos.logback.classic.AsyncAppender" additivity="false">
<appender-ref ref="FLUENT" />
<appender-ref ref="STDOUT" />
</logger>
<logger name="business" class="ch.qos.logback.classic.AsyncAppender" additivity="false">
<appender-ref ref="FLUENT" />
</logger>
<logger name="stats" class="ch.qos.logback.classic.AsyncAppender" additivity="false">
<appender-ref ref="FLUENT" />
</logger>
2. 控制台
监控日志还可以输出到控制台。
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
3.文件
重要的日志可以输出到文件作为备份。
可以设置保存文件个数和磁盘占用总容量限制。
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/business.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- hourly rollover -->
<fileNamePattern>${logPath}/business.%d{yyyy-MM-dd-HH}.log</fileNamePattern>
<!-- keep 30 days' worth of history capped at 3GB total size -->
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
</encoder>
</appender>
五、记录日志
参考阿里巴巴Java开发手册
应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架 SLF4J 中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger monitorLogger = LoggerFactory.getLogger("monitor");
private static final Logger businessLogger = LoggerFactory.getLogger("business");
private static final Logger statsLogger = LoggerFactory.getLogger("stats");
接下来按照 三、日志的触发点和级别 的说明,在程序中记录日志。
注意点:
- 使用占位符而不是字符串拼接
参考阿里巴巴Java开发手册
说明:logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);
如果日志级别是 warn,上述日志不会打印,但是会执行字符串拼接操作,如果 symbol 是对象, 会执行 toString()方法,浪费了系统资源,执行了上述操作,最终日志却没有打印。
正例:(条件)
if (logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);
}
正例:(占位符)
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
- 异常输出适当的日志
捕获不可控的异常,应该输出现场信息和异常堆栈信息,不要将异常再抛至上层,避免上层再次输出。
日志例:
logger.error(各类参数或者对象 toString + "_" + e.getMessage(), e);
异常堆栈信息是多行,在Kibana中会出现多条,不便于查看。建议在Fluent中添加合并插件,将异常堆栈信息合并为一行再输出到Elasticsearch。
网友评论