一、日志级别
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 分别对应 监控/业务/统计日志
${fluentTag}
${fluentHost}
${fluentPort}
${logPath}
2. 控制台
监控日志还可以输出到控制台。
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
3.文件
重要的日志可以输出到文件作为备份。
可以设置保存文件个数和磁盘占用总容量限制。
${logPath}/business.log
${logPath}/business.%d{yyyy-MM-dd-HH}.log
30
3GB
%date %level [%thread] %logger{10} [%file:%line] %msg%n
五、记录日志
参考阿里巴巴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。