日志分类
- 登录日志:登录轨迹,检测账号安全性,统计用户活跃度,刻画用户画像,流动情况。
- 退出日志:系统使用时长,留存期。
- 操作日志:用户旅途
- 接口日志:接口交互频率,接口性能,三方系统联调的重要定位手段
- 程序日志:重要业务,比如订单创建、MQ消费生产
- 埋点日志:用户特定行为,产品运营数据分析
日志框架
- logback
- log4j
Java市面上主流的就是这两种日志框架,引入依赖后就能结合Spring一起使用。
要使用日志门面模式的接口,而不是耦合具体的框架,Java日志的门面叫做SLF4J(Simple logging Facade for Java )。他是一个标准接口。也符合架构设计中的依赖抽象,而不是具体。
目前大部分都使用logback,log4j前段时间频频报出漏洞影响了好多关联框架~当然logback也有。
tip: 使用lombok 在类上加@Slf4j注解即可直接用log对象来打印日志
日志等级
- fatal 致命、极其严重的错误,可能会导致程序终止或崩溃
- error 错误级别最高,用于运行时异常或者自定义的业务严重异常
- warn 有点问题,但是不会影响大局
- info 业务型日志,一般用于rest请求参数和返回值、重要业务流程节点
- debug 调试过程,用于更多程序相关开发者关注的日志
- trace 很少见,用于跟踪链路
他们的级别也按照顺序排列。等级越低的日志越没那么重要。
日志归档、留存期、分文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- 配置文件修改时重新加载,默认true -->
<configuration scan="true">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="CATALINA_BASE" value="**/logs"></property>
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8">
<!-- 输出日志记录格式 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 第一个文件输出,每天产生一个文件 -->
<appender name="FILE1" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 输出文件路径+文件名 -->
<fileNamePattern>${CATALINA_BASE}/aa.%d{yyyyMMdd}.log</fileNamePattern>
<!-- 保存30天的日志 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8">
<!-- 输出日志记录格式 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="CUSTOM" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${CATALINA_BASE}/custom.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>${CATALINA_BASE}/custom.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 设置日志输出级别 -->
<root level="ERROR">
<appender-ref ref="CONSOLE" />
</root>
<logger name="file1" level="DEBUG">
<appender-ref ref="FILE1" />
</logger>
<logger name="file1" level="INFO">
<appender-ref ref="FILE2" />
</logger>
<!-- 自定义logger -->
<logger name="custom" level="INFO">
<appender-ref ref="CUSTOM" />
</logger>
</configuration>
每个xml节点的类都是可以自定义的,比如归档后的日志文件权限只能是440以下,log4j就又一个
filePermissions
的配置,而logback不支持这个属性,只能继承ch.qos.logback.core.rolling.TimeBasedRollingPolicy
类,重写内部的文件权限设置方法。
日志安全性
隐私数据脱敏
隐私数据包含了密码、token、秘钥、电话号码、手机号、邮箱等等,这些都是业务数据,IT运维时需要脱敏。一般会在这几种场景下打印
1、打印了接口的所有入参,若修改密码 这种场景很容易出现
2、远程调用三方接口打印入参
3、查询数据库是打印返回值
4、数据处理时有意打印
那怎么解决呢?
- 不打印敏感字段,若实体类用的lombok,刚好又用toString来打印这个对象,就可以在字段上加
@ToString.Exclude
,避免打印 - 脱敏,继承日志消息转换器
MessageConverter
重写convert
方法,将要打印的字符串通过正则匹配敏感信息,再替换成如138***1111
的字符串。 - 声明变量名为
transient
,让其在序列化时忽略,但是要注意使用场景。
日志注入
用户输入的参数未做任何验证直接写入日志文件,导致攻击者可以通过特殊字符(\r \n)在日志中注入新的日志条目,破坏系统日志的完整性。
审计日志
管理界面对数据的增、改、查都非常重视,因为一个小改动都有可能对系统造成深远影响,所以需要审计日志,并且根据重要程度还需要落库。一个合格的审计日志应该有以下信息
- 来源ip
- 操作资源
- 操作类型(增?改?查)
- 涉及修改和删除,要打印部分之前重要数据,用于回滚
- 时间
- 操作人,这抓到就是一顿批
一般可以用AOP来实现对应方法的日志记录,在方法上加自定义的@AuditLog注解。
日志存储
分布式日志
常见的有ELK,EFK等技术。ELK是ElasticSearch+Logstash+Kibana,而EFK是将Logstash换成了FlieBeat。更加的轻量。
分布式集群部署的场景下,日志分散在各个微服务docker中
存储性能
写日志是一个写磁盘的操作,作为日志记录应该要和业务进行解耦,这里建议使用异步的方式(线程池、内存队列、MQ)记录日志。
存储介质
一般是直接写磁盘里,但是为了数据分析,也用到了数据库,如
- MongoDB 存储报文,不规则数据
- MySQL 日志流水、订单交易需要查询排序的数据
- ES 适用所有日志
应用组件日志
mysql
数据库的日志作用就更强大了,可以用来做数据回滚,数据备份,数据同步等等操作。
- redolog 记录数据的物理变化 InnoDB引擎独有的能力
- undolog 回滚(binlog相反的SQL)和多版本控制(MVCC)
- binlog 用于复制和恢复数据,记录所有用户的增删改操作,主从同步也是依赖该日志
- 慢日志
Nginx & tomcat
- access.log 访问日志,主要用于看用户接口层面的浏览轨迹,以及响应码是否符合预期,报表统计接口、QPS、各个状态码的分布。