如何让日志记录变得丝滑

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

相关文章

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

SpringBoot如何使用TraceId日志链路追踪

《SpringBoot如何使用TraceId日志链路追踪》文章介绍了如何使用TraceId进行日志链路追踪,通过在日志中添加TraceId关键字,可以将同一次业务调用链上的日志串起来,本文通过实例代码... 目录项目场景:实现步骤1、pom.XML 依赖2、整合logback,打印日志,logback-sp

Servlet中配置和使用过滤器的步骤记录

《Servlet中配置和使用过滤器的步骤记录》:本文主要介绍在Servlet中配置和使用过滤器的方法,包括创建过滤器类、配置过滤器以及在Web应用中使用过滤器等步骤,文中通过代码介绍的非常详细,需... 目录创建过滤器类配置过滤器使用过滤器总结在Servlet中配置和使用过滤器主要包括创建过滤器类、配置过滤

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

python与QT联合的详细步骤记录

《python与QT联合的详细步骤记录》:本文主要介绍python与QT联合的详细步骤,文章还展示了如何在Python中调用QT的.ui文件来实现GUI界面,并介绍了多窗口的应用,文中通过代码介绍... 目录一、文章简介二、安装pyqt5三、GUI页面设计四、python的使用python文件创建pytho

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件

flume系列之:查看flume系统日志、查看统计flume日志类型、查看flume日志

遍历指定目录下多个文件查找指定内容 服务器系统日志会记录flume相关日志 cat /var/log/messages |grep -i oom 查找系统日志中关于flume的指定日志 import osdef search_string_in_files(directory, search_string):count = 0

我在移动打工的日志

客户:给我搞一下录音 我:不会。不在服务范围。 客户:是不想吧 我:笑嘻嘻(气笑) 客户:小姑娘明明会,却欺负老人 我:笑嘻嘻 客户:那我交话费 我:手机号 客户:给我搞录音 我:不会。不懂。没搞过。 客户:那我交话费 我:手机号。这是电信的啊!!我这是中国移动!! 客户:我不管,我要充话费,充话费是你们的 我:可是这是移动!!中国移动!! 客户:我这是手机号 我:那又如何,这是移动!你是电信!!