如何让日志记录变得丝滑

2023-11-23 12:08
文章标签 日志 记录 变得 丝滑

本文主要是介绍如何让日志记录变得丝滑,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

操作日志在每一个系统中都普遍存在,系统中都有一套自己记录日志的API与之想配套。而对于不同的系统日志又不近相同。大体可以分为两类:

  • 系统日志

    主要用于开发者问题排查和一些信息打印方便调试和问题排查的日志。打印在日志文件中

  • 业务日志

    有一定的业务规则,给业务人员进行查看的日志。这一类日志要求简单易懂(可能还设计一些日志的模板,不同类型的业务需要不同的模板)。打印在日志文件同时也需要进行数据库的持久化以便运营人员和关联人员的查看等等。

不管是系统日志还是业务日志,主要的作用就是用来记录操作的信息给需要的人进行查看。今天就来说一下在工作中如何优雅的记录日志。

Tips:主要讲解业务日志如何记录

业务日志记录流程图.png

1. 业务日志如何优雅的记录

针对不同的业务需要记录不同的内容,同时不同业务也有相同的东西。所以需要分析出共性和差异内容。基于自己的工作来看一下如何设计。

1.1 日志需要记录哪些东西

  • 操作人(操作用户一般记录ID和名称)
  • 操作人终端IP地址(可以用于风控和一些智能推荐)
  • 操作终端相关信息(可选根据不同公司和业务需求)
  • 操作时间(这个比较重要)
  • 操作类型(删除、查询、更新等等--根据需求进行个性化设计)

上面这些都是通用的,绝大多数业务都可以用的到。也基本上相同。但是对于业务操作日志最重要的是把业务的内容记录下来。这里就是我们通常说的业务模板

  • 业务模板

    业务模板需要根据不同的业务进行定制,在定制过程中可能还需要进行动态加载等等。例如:**123用户2021-09-16 10:00 订单创建,订单号:NO.88888888**在订单信息中可能还包含了用户信息时间以及订单信息等等。这种是比较复杂的业务模板

日志模板格式其实还可以自定义如下格式:文件中一行作为一条记录,用分隔符进行分割。在读取的时候回按一行进行读取然后进行分隔符分割,每一个位置固定是一个约定好的内容。(这种格式之前在做游戏服务器日志记录的时候就是采用这种)。

优点:就是格式固定解析起来方便,也便于后续的数据处理以及表格的呈现。

缺点:不能直观的表达内容。需要处理加工后才能知道表达什么。

1.2 静态实现方式

1.2.1 Canal监听数据库操作日志

Canal 是一款基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费的开源组件,通过采用监听数据库 Binlog 的方式,这样可以从底层知道是哪些数据做了修改,然后根据更改的数据记录操作日志。

优点:对代码没有侵入和业务逻辑完全分离。

缺点:只能记录操作数据库的操作,并且记录的字段只能是表中包含的字段,例如我想记录一下操作人的IP地址就没办法。

1.2.2 Java框架日志记录文件中

log.info("用户登录")
log.info("用户{},ip地址{}登出“,userId,ip)
复制代码

Tips:常用的日志Java日志工具:

  • log4j
  • log4j2
  • logback

这种记录有几个问题:

问题1: 用户ID和ip地址如何获取?

借助 SLF4J 中的 MDC 工具类,把操作人放在日志中,然后在日志中统一打印出来。首先在用户的拦截器中把用户的标识 Put 到 MDC 中:

public class UserInterceptor implements AsyncHandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {//获取到用户标识String userId = getUserId(request);//把用户 ID 放到 MDC 上下文中MDC.put("userId", userId);MDC.put("ip", request.getRemoteAddr());return AsyncHandlerInterceptor.super.preHandle(request, response, handler);}private String getUserId(HttpServletRequest request) {// 通过 SSO 或者Cookie 或者 Auth信息获取到 当前登陆的用户信息return null;}
}
复制代码

其次,把 userId,ip格式化到日志中,使用 %X{userId} ,%X{ip}可以取到 MDC 中用户标识。

<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level  %X{userId}  %X{ip} %logger{50} - %msg%n</pattern>
复制代码

问题2: 如何生成可读性的日志

针对每一个业务在代码中写成对应的日志模板。写到日志文件中。然后通过日志收集工具将日志收集到Elasticsearch或者数据库当中。

1.3 动态日志实现方式

为了解决上面的问题,一般采用AOP的方式记录操作日志和业务逻辑的解耦。下面来看一下:

@Service
public class UserServiceImpl {@Log(template = "新增用户-名称为:${#user.name}  用户地址:${#user.address}, " + "年龄:${#user.age}, 用户的信息:${@userServiceImpl.getUserInfo(#user)}")public boolean addUser(User user){StringBuilder sb = new StringBuilder();Random random = new Random();for(int i = 0; i < 30000; ++i){sb.append(random.nextInt());}return true;}public String getUserInfo(User use){return use.toString();}}
复制代码

这里记录日志实现的是一个静态,通过AOP的方式来实现的。那么如何实现动态模板,就会涉及到让变量通过占位符的方式解析模板,从而达到通过注解记录操作日志的目的。模板解析的方式有很多种。Java使用者用的最多的框架就是Spring, 这里实现我们也使用SpEL(Spring Expression Language,Spring表达式语言)来实现。

需要实现的功能设想,已最常用的用户在电商网站购买商品创建购买订单为例子:

业务日志模板: 用户[xxx]在[xxxx时间]购买了[xxxx商品],用户的所使用的终端为[xxxxx,ip地址为],操作类型:[xxxx]

1.4 模块介绍

动态日志功能模块.png

主要分为三大功能:

  1. 日志AOP拦截模块

    主要用于处理用户的日志拦截的切入点

  2. 日志解析模块

    提供了对动态模板的解析,生成最终业务需要的模板具体实例数据

  3. 日志存储模块

    存储主要是为了提供给后续使用这个查询

1.5 代码实现模块

从代码的实现上来说主要分成一下几个步骤:

  • AOP拦截逻辑
  • 日志解析逻辑
    • 模板解析
    • 日志上下文实现
    • 公共字段处理逻辑
    • 自定义函数的处理逻辑(调用某个类的方法)
  • 日志持久化逻辑
    • 默认持久化(现在是Java日志持久化到本地文件)
    • 持久化的方式(文件还是数据库),同步还是异步模式
  • 项目如何进行集成(Spring start开发)

项目实现.png

主要使用了Spring的AOP和Spel来实现动态日志记录功能。直接可以使用Spel表达式来。

项目github地址:github.com/mxsm/mxsm-l…

这篇关于如何让日志记录变得丝滑的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/417835

相关文章

Java 日志中 Marker 的使用示例详解

《Java日志中Marker的使用示例详解》Marker是SLF4J(以及Logback、Log4j2)提供的一个接口,它本质上是一个命名对象,你可以把它想象成一个可以附加到日志语句上的标签或戳... 目录什么是Marker?为什么使用Markejavascriptr?1. 精细化的过滤2. 触发特定操作3

docker编写java的jar完整步骤记录

《docker编写java的jar完整步骤记录》在平常的开发工作中,我们经常需要部署项目,开发测试完成后,最关键的一步就是部署,:本文主要介绍docker编写java的jar的相关资料,文中通过代... 目录all-docker/生成Docker打包部署文件配置服务A的Dockerfile (a/Docke

linux查找java项目日志查找报错信息方式

《linux查找java项目日志查找报错信息方式》日志查找定位步骤:进入项目,用tail-f实时跟踪日志,tail-n1000查看末尾1000行,grep搜索关键词或时间,vim内精准查找并高亮定位,... 目录日志查找定位在当前文件里找到报错消息总结日志查找定位1.cd 进入项目2.正常日志 和错误日

MySQL使用EXISTS检查记录是否存在的详细过程

《MySQL使用EXISTS检查记录是否存在的详细过程》EXISTS是SQL中用于检查子查询是否返回至少一条记录的运算符,它通常用于测试是否存在满足特定条件的记录,从而在主查询中进行相应操作,本文给大... 目录基本语法示例数据库和表结构1. 使用 EXISTS 在 SELECT 语句中2. 使用 EXIS

SpringBoot日志级别与日志分组详解

《SpringBoot日志级别与日志分组详解》文章介绍了日志级别(ALL至OFF)及其作用,说明SpringBoot默认日志级别为INFO,可通过application.properties调整全局或... 目录日志级别1、级别内容2、调整日志级别调整默认日志级别调整指定类的日志级别项目开发过程中,利用日志

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”

java -jar example.jar 产生的日志输出到指定文件的方法

《java-jarexample.jar产生的日志输出到指定文件的方法》这篇文章给大家介绍java-jarexample.jar产生的日志输出到指定文件的方法,本文给大家介绍的非常详细,对大家的... 目录怎么让 Java -jar example.jar 产生的日志输出到指定文件一、方法1:使用重定向1、

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

nginx配置错误日志的实现步骤

《nginx配置错误日志的实现步骤》配置nginx代理过程中,如果出现错误,需要看日志,可以把nginx日志配置出来,以便快速定位日志问题,下面就来介绍一下nginx配置错误日志的实现步骤,感兴趣的可... 目录前言nginx配置错误日志总结前言在配置nginx代理过程中,如果出现错误,需要看日志,可以把