如何让日志记录变得丝滑

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

相关文章

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

我在移动打工的日志

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

记录每次更新到仓库 —— Git 学习笔记 10

记录每次更新到仓库 文章目录 文件的状态三个区域检查当前文件状态跟踪新文件取消跟踪(un-tracking)文件重新跟踪(re-tracking)文件暂存已修改文件忽略某些文件查看已暂存和未暂存的修改提交更新跳过暂存区删除文件移动文件参考资料 咱们接着很多天以前的 取得Git仓库 这篇文章继续说。 文件的状态 不管是通过哪种方法,现在我们已经有了一个仓库,并从这个仓

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图

Detectorn2预训练模型复现:数据准备、训练命令、日志分析与输出目录

Detectorn2预训练模型复现:数据准备、训练命令、日志分析与输出目录 在深度学习项目中,目标检测是一项重要的任务。本文将详细介绍如何使用Detectron2进行目标检测模型的复现训练,涵盖训练数据准备、训练命令、训练日志分析、训练指标以及训练输出目录的各个文件及其作用。特别地,我们将演示在训练过程中出现中断后,如何使用 resume 功能继续训练,并将我们复现的模型与Model Zoo中的

perl的学习记录——仿真regression

1 记录的背景 之前只知道有这个强大语言的存在,但一直侥幸自己应该不会用到它,所以一直没有开始学习。然而人生这么长,怎就确定自己不会用到呢? 这次要搭建一个可以自动跑完所有case并且打印每个case的pass信息到指定的文件中。从而减轻手动跑仿真,手动查看log信息的重复无效低质量的操作。下面简单记录下自己的思路并贴出自己的代码,方便自己以后使用和修正。 2 思路整理 作为一个IC d

SSM项目使用AOP技术进行日志记录

本步骤只记录完成切面所需的必要代码 本人开发中遇到的问题: 切面一直切不进去,最后发现需要在springMVC的核心配置文件中中开启注解驱动才可以,只在spring的核心配置文件中开启是不会在web项目中生效的。 之后按照下面的代码进行配置,然后前端在访问controller层中的路径时即可观察到日志已经被正常记录到数据库,代码中有部分注释,看不懂的可以参照注释。接下来进入正题 1、导入m

多数据源的事务处理总是打印很多无用的log日志

之前做了一个项目,需要用到多数据源以及事务处理,在使用事务处理,服务器总是打印很多关于事务处理的log日志(com.atomikos.logging.Slf4jLogger),但是我们根本不会用到这些log日志,反而使得查询一些有用的log日志变得困难。那要如何屏蔽这些log日志呢? 之前的项目是提高项目打印log日志的级别,后来觉得这样治标不治本。 现在有一个更好的方法: 我使用的是log

flume系列之:记录一次flume agent进程被异常oom kill -9的原因定位

flume系列之:记录一次flume agent进程被异常oom kill -9的原因定位 一、背景二、定位问题三、解决方法 一、背景 flume系列之:定位flume没有关闭某个时间点生成的tmp文件的原因,并制定解决方案在博主上面这篇文章的基础上,在机器内存、cpu资源、flume agent资源都足够的情况下,flume agent又出现了tmp文件无法关闭的情况 二、