java项目日志管理(Java高手如何搭建高效易用的日志系统)java基础 / Java Web应用中的日志记录...

wufei123 发布于 2024-07-01 阅读(8)

​在Java开发中,我们经常会遇到一个棘手的问题:记录用户的操作行为某些操作是相对简单的,我们可以逐条记录但是某些操作行为却很难记录,例如编辑操作在某一次操作中,用户可能编辑了对象A的几个属性,而下一次操作中用户可能编辑了对象B的几个属性。

如果我们针对对象A、对象B的属性变化分别进行记录,则整个操作十分复杂而且,会与业务操作高度耦合而今天我们介绍的是一个叫ObjectLogger的系统,它是一个强大且易用的Java对象日志记录系统,能够分析任何对象的属性变化,实现对象变化的记录与查询。

因此,它可以应用在用户操作日志记录、对象属性变更记录等诸多场景中。简单易用,实为利器。基于它,我们可以很方便地实现下面的效果。

该系统为github开源项目,地址为:https://github.com/yeecode/ObjectLogger下面我们简单介绍下该系统基于它,我们可以非常方便地搭建一套日志记录系统1 系统特点该系统具有以下特点:

一站整合:系统支持日志的记录与查询,开发者只需再开发前端界面即可使用完全独立:与业务系统无耦合,可插拔使用,不影响主业务流程应用共享:系统可以同时供多个业务系统使用,互不影响简单易用:服务端直接jar包启动;业务系统有官方Maven插件支持。

自动解析:能自动解析对象的属性变化,并支持富文本的前后对比便于扩展:支持自定义对象变动说明、属性变动说明支持更多对象属性类型的扩展2 快速上手2.1 创建数据库使用该项目的/server/database/init_data_table.sql文件初始化两个数据表。

2.2 启动Server下载该项目下最新的Server服务jar包,地址为/server/target/ObjectLogger-*.jar启动下载的jar包java -jar ObjectLogger-*.jar --spring.datasource.driver-class-name={db_driver} --spring.datasource.url=jdbc:{db}://{db_address}/{db_name} --spring.datasource.username={db_username} --spring.datasource.password={db_password} 。

上述命令中的用户配置项说明如下:db_driver:数据库驱动如果使用MySql数据库则为com.mysql.jdbc.Driver;如果使用SqlServer数据库则为com.microsoft.sqlserver.jdbc.SQLServerDriver。

db:数据库类型如果使用MySql数据库则为mysql;如果使用SqlServer数据库则为sqlserverdb_address:数据库连接地址如果数据库在本机则为127.0.0.1db_name:数据库名,该数据库中需包含上一步初始化的两个数据表。

db_username:数据库登录用户名db_password:数据库登录密码启动jar包后,系统默认的服务地址为:http://127.0.0.1:8080/ObjectLogger/ 访问上述地址可以看到下面的欢迎界面:。

至此,ObjectLogger系统已经搭建结束,可以接受业务系统的日志写入和查询操作3 业务系统接入该部分讲解如何配置业务系统来将业务系统中的对象变化记录到ObjectLogger中3.1 引入依赖包在pom中增加下面的依赖:

com.github.yeecode.objectLogger ObjectLoggerClient {最新版本}

3.2 添加对ObjectLoggerClient中bean的自动注入3.2.1 对于SpringBoot应用在SpringBoot的启动类前添加@ComponentScan注解,并在basePackages中增加ObjectLoggerClient的包地址:

com.github.yeecode.objectLoggerClient,如:@SpringBootApplication @ComponentScan(basePackages={"{your_beans_root}","com.github.yeecode.objectLogger"}) public class MyBootAppApplication { public static void main(String[] args) { // 省略其他代码 } }

3.2.2 对于Spring应用在applicationContext.xml增加对ObjectLoggerClient包地址的扫描:

3.3 完成配置在application.properties中增加:object.logger.add.log.api=http://{ObjectLogger_address}/ObjectLogger/log/add object.logger.appName={your_app_name} object.logger.autoLog=true

ObjectLogger_address:属性指向上一步的ObjectLogger的部署地址,例如:127.0.0.1:8080your_app_name:指当前业务系统的应用名以便于区分日志来源,实现同时支持多个业务系统。

object.logger.autoLog:是否对对象的所有属性进行变更日志记录至此,业务系统的配置完成已经实现了和ObjectLogger的Server端的对接4 日志查询系统运行后,可以通过/ObjectLogger/log/query查询系统中记录的日志,并通过传入参数对日志进行过滤。

通过这里,我们可以查询下一步中写入的日志5 日志写入业务系统在任何需要进行日志记录的类中引入LogClient例如:@Autowired private LogClient logClient; 5.1 简单使用

直接将对象的零个、一个、多个属性变化放入actionItemModelList中发出即可actionItemModelList置为null则表示此次对象无需要记录的属性变动例如,业务应用中调用:logClient.sendLogForItems("TaskModel",5,"actor name","addTask","add Task","via web page","some comments",null); 。

在ObjectLogger中使用如下查询条件:http://{your_ObjectLogger_address}/ObjectLogger/log/query?appName=myBootApp&objectName=TaskModel&objectId=5

查询到日志:{ "respMsg": "成功", "respData": [ { "id": 16, "appName": "myBootApp", "objectName": "TaskModel", "objectId": 5, "actor": "actor name", "action": "addTask", "actionName": "add Task", "extraWords": "via web page", "comment": "some comments", "actionTime": "2019-04-10T10:56:15.000+0000", "actionItemModelList": [] } ], "respCode": "1000" }

5.2 对象变动自动记录该功能可以自动完成新老对象的对比,并根据对比结果,将多个属性变动一起写入日志系统中使用时,要确保传入的新老对象属于同一个类例如,业务系统这样调用:TaskModel oldTaskModel = new TaskModel(); oldTaskModel.setId(9); oldTaskModel.setTaskName("oldName"); oldTaskModel.setUserId(3); oldTaskModel.setDescription("\t

the first line

\n" + "\t

the second line

\n" + "\t

the 3th line

"); TaskModel newTaskModel = new TaskModel(); newTaskModel.setId(9); newTaskModel.setTaskName("newName"); newTaskModel.setUserId(5); newTaskModel.setDescription("\t

the first line

\n" + "\t

the second line

\n" + "\t

the last line

"); logClient.sendLogForObject(9,"actor name","editTask","edit Task","via app", "some comments",oldTaskModel,newTaskModel); 。

则我们可以使用下面查询条件:http://{your_ObjectLogger_address}/ObjectLogger/log/query?appName=myBootApp&objectName=TaskModel&objectId=9

查询到如下结果:{ "respMsg": "成功", "respData": [ { "id": 15, "appName": "myBootApp", "objectName": "TaskModel", "objectId": 9, "actor": "actor name", "action": "editTask", "actionName": "edit Task", "extraWords": "via app", "comment": "some comments", "actionTime": "2019-04-10T10:56:17.000+0000", "actionItemModelList": [ { "id": 18, "actionId": 15, "attributeType": "NORMAL", "attribute": "taskName", "attributeName": "TASK", "oldValue": "oldName", "newValue": "newName", "diffValue": null }, { "id": 19, "actionId": 15, "attributeType": "USERID", "attribute": "userId", "attributeName": "USER", "oldValue": "USER:3", "newValue": "USER:5", "diffValue": "diffValue" }, { "id": 20, "actionId": 15, "attributeType": "TEXT", "attribute": "description", "attributeName": "DESCRIPTION", "oldValue": "\"\\t

the first line

\\n\\t

the second line

\\n\\t

the 3th line

\"", "newValue": "\"\\t

the first line

\\n\\t

the second line

\\n\\t

the last line

\"", "diffValue": "第6行变化:

-: the 3th line

+: the last line

" } ] } ], "respCode": "1000" }

6 对象属性过滤有些对象的属性的变动不需要进行日志记录,例如updateTime、hashCode等ObjectLogger支持对对象的属性进行过滤,只追踪我们感兴趣的属性并且,对于每个属性我们可以更改其记录到ObjectLogger系统中的具体方式,例如修改命名等。

要想启用这个功能,首先将配置中的object.logger.autoLog改为falseobject.logger.autoLog=false 然后在需要进行变化日志记录的属性上增加@LogTag注解凡是没有增加该注解的属性在日志记录时会被自动跳过。

例如,注解配置如下则id字段的变动将被忽略private Integer id; @LogTag(name = "TaskName") private String taskName; @LogTag(name = "UserId", extendedType = "userIdType") private int userId; @LogTag(name = "Description", builtinType = BuiltinTypeHandler.TEXT) private String description; 。

该注解属性介绍如下:name:必填,对应写入日志后的attributeName值builtinType:ObjectLogger的内置类型,为BuiltinTypeHandler的值默认为BuiltinTypeHandler.NORMAL。

BuiltinTypeHandler.NORMAL:记录属性的新值和旧值,对比值为nullBuiltinTypeHandler.TEXT: 用户富文本对比记录属性值的新值和旧值,并将新旧值转化为纯文本后逐行对比差异,对比值中记录差异。

extendedType:扩展属性类型使用ObjcetLogger时,用户可以扩展某些字段的处理方式7 属性处理扩展很多情况下,用户希望能够自主决定某些对象属性的处理方式例如,对于例子中Task对象的userId属性,用户可能想将其转化为姓名后存入日志系统,从而使得日志系统与userId完全解耦。

ObjectLogger完全支持这种情况,可以让用户自主决定某些属性的日志记录方式要想实现这种功能,首先在需要进行扩展处理的属性上为@LogTag的extendedType属性赋予一个字符串值例如:@LogTag(name = "UserId", extendedType = "userIdType") private int userId;

然后在业务系统中声明一个Bean继承BaseExtendedTypeHandler,作为自由扩展的钩子代码如下:@Service public class ExtendedTypeHandler implements BaseExtendedTypeHandler { @Override public BaseActionItemModel handleAttributeChange(String attributeName, String logTagName, Object oldValue, Object newValue) { return null; } } 。

接下来,当ObjectLogger处理到该属性时,会将该属性的相关信息传入到扩展Bean的handleAttributeChange方法中,然后用户可以自行处理传入的四个参数解释如下:extendedType:扩展类型值,即@LogTag注解的extendedType值。

本示例中为userIdTypeattributeName:属性名本示例中为userIdlogTagName:@LogTag注解的name值,可能为null本示例中为UserIdoldValue:该属性的旧值。

newValue:该属性的新值例如我们可以采用如下的方式处理userIdType属性:public BaseActionItemModel handleAttributeChange(String extendedType, String attributeName, String logTagName, Object oldValue, Object newValue) { BaseActionItemModel baseActionItemModel = new BaseActionItemModel(); if (extendedType.equals("userIdType")) { baseActionItemModel.setOldValue("USER_" + oldValue); baseActionItemModel.setNewValue("USER_" + newValue); baseActionItemModel.setDiffValue(oldValue + "->" + newValue); } return baseActionItemModel; } 。

8 总结怎么样,是不是ObjectLogger https://github.com/yeecode/ObjectLogger 的存在极大地方便了我们的日志记录操作欢迎关注我们,了解Java架构师原创干货!。

专栏java语言基础篇作者:KuangXiang98币1人已购查看--End--▼往期精彩文章▼详解Java序列化的分类与使用Java中枚举类型(Enum)使用进阶Java中的枚举类型(Enum)详解欢迎关注我们,不错过每期的原创干货!

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

河南中青旅行社综合资讯 奇遇综合资讯 盛世蓟州综合资讯 综合资讯 游戏百科综合资讯 新闻84756