日志是进行服务问题追踪,系统状态监控的重要方式.
日志级别分类较细,通常使用的是下面的四个级别,按优先级从高到低分别是ERROR、WARN、INFO、DEBUG
日志并不是越多越好,合理使用日志是非常必要的.
不同的日志级别处理不同的事件.
下面对上述4个日志级别与事件对应关系做一下说明:
ERROR
错误事件, 影响当前正常处理流程, 必须立即解决
1. 系统缺少必需的配置
2. 数据库, 缓存, MQ等中间件网路连线无预期中断且无法重连
3. 数据库CRUD失败, MQ发送失败等某些会影响功能的错误
4. 系统的关键业务流程异常终止
5. 空指针等非预期的异常
WARN
可能导致错误, 需要持续优化
1. 数据库等中间件的连接短暂丢失
2. 网路暂时中断
INFO
信息性消息,提供流程关键的状态,能快速快速判断系统状态
1. 服务的初始化或停止
2. 系统配置和启动参数
3. 微服务各服务节点交互
4. 核心数据表CRUD
5. 定期调度任务的执行情况
DEBUG
细粒度的信息事件,对于调试应用程序最有用
1. 用于分析执行时间
2. 通过日志可以分析出流程关键数据,尤其是if...else...分支等
日志打印
日志打印输出时,要注意以下三点
1.一定要输出方法参数,不仅有利于方便流程回放,而且在ELK集群中也方便查找分析上下文
2.日志数据内容尽量使用英文, 会减少部署主机不支持中文
3.日志输出一定要使用占位符’{}’,减少JVM运算
代码语言:javascript复制public void process(Object args) {
logger.info("start process:{}", args);
try {
// throw some exception
} catch (Exception e) {
logger.error("do process error:{}", args, e);
}
if (true) {
logger.debug("do if thing:{}", args);
// do something
} else {
logger.debug("do else thing:{}", args);
// do something
}
}
Log4j2
Log4j2是目前为止性能,扩展等各方面都非常优秀的日志框架.
Log4j2具有如下众多优点,是其备受青睐的原因:
1. Log4j 2被设计成一个具有审计功能的日志框架. 在配置更新时, Log4j 1.x and Logback对日志事件没有反应, Log4j 2则会正常工作. 另外, Logback不允许Appenders中的异常是不可见的, 而Log4j2可以配置成发送异常给应用程序.
2. Log4j2基于LMAX Disruptor library异步日志处理.
3. 基于插件的软件架构, 使得Log4j2更易于扩展, 而不需会改变Log4j2自身的功能. 也就是遵循了设计模式的一个重要原则, 对修改封闭, 对扩展开放.
4. 基于插件的配置文件更加简单, 配置文件中的实体不必指定一个类名.
5. 支持用户自定义的日志等级, 在代码或者配置文件中都可以定义.
6.支持lambda表达式.
7. 支持消息对象.
8. 比Log4j1和Logback更加全面的过滤器, Log4j2可以在Logger处理前, 处理中和到Appender后都添加过滤器.
9. Log4j2的Appenders接收Layout参数, 允许以任何预期的格式传送.
10. Log4j2用一个简单的方法, Layouts返回字节数组. 这使得Log4j2的Layouts可以用于任何Appender, 而不只是使用OutputStream写日志的Appenders.
11. Syslog Appender即支持TCP和UDP, 同时还支持BSD syslog和RFC 5424格式.
12. Log4j2使用了Java 5对并发性的支持, 而且可以在最低的等级执行枷锁操作. Log4j1中有很多死锁的问题. 其中一些在Logback中得到了解决, 但是很多Logback的类在相对高的层级, 仍然需要同步保证.
13. Log4j2是Apache的项目,按照Contributing路径下的步骤, 就可以获得修改软件的许可.
推荐配置
代码语言:javascript复制<?xml version="1.1" encoding="UTF-8"?>
<Configuration status="info">
<Properties>
<Property name="app.service.name">${bundle:application:spring.application.name}</Property>
<Property name="app.logging.basedir">${sys:app.logging.basedir:-/opt/logs}</Property>
<Property name="app.logging.info.size.total">${sys:app.logging.info.size.total:-50}</Property>
<Property name="app.logging.count.daily">${sys:app.logging.count.daily:-100}</Property>
<Property name="app.info.layout.pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} ${app.service.name} [%t] %-5p => %c{1.} - %m%n</Property>
</Properties>
<appenders>
<Console name="CONSOLE" target="SYSTEM_OUT">
<PatternLayout pattern="${app.info.layout.pattern} [%t] %highlight{%-5p} => %cyan{%c{1.}.%M(%F:%L)} - %m%n"/>
</Console>
<RollingFile name="info-log" fileName="${app.logging.basedir}/${app.service.name}-info.log"
filePattern="${app.logging.basedir}/${app.service.name}-info-%d{yyyy-MM-dd-HH}-%i.log.gz">
<Filters>
<MarkerFilter marker="ANALYTIC" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<PatternLayout pattern="${app.info.layout.pattern}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" maxRandomDelay="30"/>
<SizeBasedTriggeringPolicy size="1000 MB" />
</Policies>
<DefaultRolloverStrategy max="${app.logging.count.daily}">
<Delete basePath="${app.logging.basedir}" maxDepth="1">
<IfAccumulatedFileSize exceeds="${app.logging.info.size.total} GB">
<IfAny>
<IfFileName glob="${app.service.name}-info-*.log.gz"/>
<IfFileName glob="${app.service.name}-info-*.log"/>
</IfAny>
</IfAccumulatedFileSize>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
<Async name="async-log">
<AppenderRef ref="info-log"/>
</Async>
</appenders>
<loggers>
<root level="info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="async-log"/>
</root>
</loggers>
</Configuration>