从零开始实现放置游戏(五)——实现后台管理系统(3)实现切面日志

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:  上一章,我们初步实现了后台管理系统的增删查改功能。然而还有很多功能不完善。这一章,我们先把系统日志搭建起来,不管是生产问题排查,还是方便开发调试,日志都是必不可少的核心功能。所谓切面日志,比如说,我们想把每个方法的入参都记录日志,那需要在每个方法里都写一行记录参数的语句,非常繁琐。所以需要提取出切面“方法执行前”,“方法执行后”等等,然后在这个切面里进行编程,记录入参的语句只需要写一次。

上一章,我们初步实现了后台管理系统的增删查改功能。然而还有很多功能不完善。这一章,我们先把系统日志搭建起来,不管是生产问题排查,还是方便开发调试,日志都是必不可少的核心功能。所谓切面日志,比如说,我们想把每个方法的入参都记录日志,那需要在每个方法里都写一行记录参数的语句,非常繁琐。所以需要提取出切面“方法执行前”,“方法执行后”等等,然后在这个切面里进行编程,记录入参的语句只需要写一次。整体的流程大致如下图:


502227-20190620170524591-709485307.png 


这里我们以rms模块为例,其他模块需要记录日志的地方参照本模块即可。


一、引入依赖


  java里,日志的实现一般是common-logging+log4j2或slf4j+logback,其中common-logging和slf4j是接口定义,log4j2和logback是具体实现。这里我们使用log4j,common-logging在其他包中已经间接引用了,无需重复添加,在pom中添加log4j的依赖即可(这里版本是2.11.2,也称log4j2,和1.x版本的区别较大,配置不通用,在网上学习时需注意):


<!-- 日志相关 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.11.2</version>
</dependency>


二、添加配置文件


  在"/resources/"资源文件目录下新建"log4j2.xml",这是log4j的默认配置路径和文件名。


 log4j2.xml


在这个配置文件中,我们定义了日志存放路径"/logs/idlewow-rms/",windows下默认D盘。控制台的日志输出格式,以及3个级别INFO, WARN, ERROR的文件输出方式。同时把spring组件的日志级别提高到info,过滤掉debug信息。


  以info级别的日志为例,我们定义了日志的输出格式"[时间] [日志级别] [线程名称][SessionId][文件名称 - 代码行数] - 日志信息。日志的滚动策略,按天滚动,每1天生成1个日志文件,或大于20MB时,生成一个日志文件。


三、日志打印SessionId


  上面的配置中,我们定义了日志需要打印Sessionid,主要是方便精准定位问题。但log4j默认不支持此功能,需要我们单独实现一个Filter,在请求进来时,获取sessionId,并存到log4j的上下文中。


 LogSessionFilter.java


  Filter是servlet相关的机制,因此需要在web.xml文件中添加以下配置:


<!-- log4j记录session -->
<filter>
    <filter-name>logSessionFilter</filter-name>
    <filter-class>com.idlewow.rms.filter.LogSessionFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>logSessionFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


四、具体使用


  配置全部完成,在我们想要使用log4j打印日志时,需要先获取一个logger,一般我们在contoller里声明一个final的成员变量,如下:


  private final Logger logger = LogManager.getLogger(this.getClass().getName());


  然后,在各个方法中,想记录日志时,只需像下面这样,即可打印对应级别的日志,


logger.info("hello world");
logger.warn("hello world");
logger.error("hello world");


 通常,在打印异常时,还会打印堆栈信息,方便定位问题,如下(在第一个参数传入异常信息,第二个参数传入异常对象):


logger.error(ex.getMessage(), ex);


五、切面日志的实现


  上面的日志功能,已经能让我们在程序中随时记录日志,下面我们实现切面日志的功能。这里需要依赖的两个包,spring-aop和aspectjweaver,前面我们已经引用过了。


  然后,我们需要一个类,定义切点、切面方法。新建一个包com.idlewow.rms.config,在此包下新建类LogAspect,代码如下:


LogAspect.java


这里我们定义了2个切点,commonPoint表示controller包下的所有public方法,returnPoint表示所有打了LogResult注解的方法(这是我们自定义的一个注解)。


  然后实现了4个切面方法,目前对应的都是commonPoint切点。


  其中,before在每次方法执行前都会执行,我们在这个方法里打印info级别的日志,记录请求URL、IP、入参等信息,同时记录请求起始时间,并分配一个trackId用来定位问题(假如同一个用户瞬间执行某个请求N次,SessionId都是相同的,我们就无法确定这N次中,每个返回数据对应的到底是哪次请求);


     after在每次方法之后后都会执行,我们在这个方法里记录每次请求耗时;


     afterThrowing在抛出异常时才会执行,我们在这个方法里打印error级别的日志;


     afterReturn是在方法正常返回时执行,我们在这个方法里打印返回结果。这里这个方法我们对应的是commonPoint切点,即所有方法都会打印返回结果,在实际应用时,可视情况改为对应returnPoint切点,这样只有加了@LogReuslt注解的方法,才会打印返回结果。


  最后,需要在spring的配置文件中,添加一行配置:


<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>


 注意:这句话应该配置在spring-mvc.xml中扫描完controller包之后。因为我们这里拦截的是controller的方法,在applicationContext中,我们还没有扫描controller类。这里老手对java web, spring框架中各部分的执行顺序了解,更容易理解。新手照着配即可,做多了自然就懂了。


六、运行效果


  至此,日志功能已经实现,我们运行一下看下效果:


502227-20190620181754079-1085262034.png


注意:添加log4j2依赖后,通过maven插件启动时,会有红字提示 :严重: Unable to process Jar entry [META-INF/versions/9/module-info.class] from Jar [jar:file:/D:/apache-maven-3.6.1/package/org/apache/logging/log4j/log4j-api/2.11.2/log4j-api-2.11.2.jar!/] for annotations。这是因为maven插件内置的tomcat7.0.47版本过低,但不影响程序正常运行。


maven插件不能修改tomcat版本,而且13年后就停止更新了。目前,如果因为tomcat版本低等问题导致有错误提示,可以直接下载一个新版本的tomcat,比如前言章节中的7.0.85,使用IDE集成的tomcat启动方式启动,就不会报错了。


小结


  本章实现了系统日志的搭建,为我们以后开发调试时快速定位问题打好基础。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
19天前
|
存储 数据采集 数据处理
【Flume拓扑揭秘】掌握Flume的四大常用结构,构建强大的日志收集系统!
【8月更文挑战第24天】Apache Flume是一个强大的工具,专为大规模日志数据的收集、聚合及传输设计。其核心架构包括源(Source)、通道(Channel)与接收器(Sink)。Flume支持多样化的拓扑结构以适应不同需求,包括单层、扇入(Fan-in)、扇出(Fan-out)及复杂多层拓扑。单层拓扑简单直观,适用于单一数据流场景;扇入结构集中处理多源头数据;扇出结构则实现数据多目的地分发;复杂多层拓扑提供高度灵活性,适合多层次数据处理。通过灵活配置,Flume能够高效构建各种规模的数据收集系统。
26 0
|
20天前
|
存储 消息中间件 人工智能
AI大模型独角兽 MiniMax 基于阿里云数据库 SelectDB 版内核 Apache Doris 升级日志系统,PB 数据秒级查询响应
早期 MiniMax 基于 Grafana Loki 构建了日志系统,在资源消耗、写入性能及系统稳定性上都面临巨大的挑战。为此 MiniMax 开始寻找全新的日志系统方案,并基于阿里云数据库 SelectDB 版内核 Apache Doris 升级了日志系统,新系统已接入 MiniMax 内部所有业务线日志数据,数据规模为 PB 级, 整体可用性达到 99.9% 以上,10 亿级日志数据的检索速度可实现秒级响应。
AI大模型独角兽 MiniMax 基于阿里云数据库 SelectDB 版内核 Apache Doris 升级日志系统,PB 数据秒级查询响应
|
18天前
|
缓存 NoSQL Linux
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
|
7天前
|
JSON 缓存 fastjson
一行日志引发的系统异常
本文记录了一行日志引发的系统异常以及作者解决问题的思路。
|
21天前
|
存储 监控 数据可视化
在Linux中,如何查看系统日志?
在Linux中,如何查看系统日志?
|
19天前
|
监控 安全 Linux
在Linux中,某个账号登陆linux后,系统会在哪些日志文件中记录相关信息?
在Linux中,某个账号登陆linux后,系统会在哪些日志文件中记录相关信息?
|
20天前
|
运维 监控 Ubuntu
在Linux中,如何查看系统日志文件?
在Linux中,如何查看系统日志文件?
|
21天前
|
数据挖掘 语音技术
3D-Speaker说话人任务的开源项目问题之语义说话人信息模块在说话人日志系统中的问题如何解决
3D-Speaker说话人任务的开源项目问题之语义说话人信息模块在说话人日志系统中的问题如何解决
|
13天前
|
存储 消息中间件 监控
Java日志详解:日志级别,优先级、配置文件、常见日志管理系统ELK、日志收集分析
Java日志详解:日志级别,优先级、配置文件、常见日志管理系统、日志收集分析。日志级别从小到大的关系(优先级从低到高): ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF 低级别的会输出高级别的信息,高级别的不会输出低级别的信息
|
20天前
|
安全 Ubuntu Linux
在Linux中,有哪些系统日志文件?
在Linux中,有哪些系统日志文件?