在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数据库则为sqlserver。
  • db_address:数据库连接地址。如果数据库在本机则为127.0.0.1。
  • db_name:数据库名,该数据库中需包含上一步初始化的两个数据表。
  • db_username:数据库登录用户名。
  • db_password:数据库登录密码。

启动jar包后,系统默认的服务地址为:

http://127.0.0.1:8080/ObjectLogger/

访问上述地址可以看到下面的欢迎界面:

至此,ObjectLogger系统已经搭建结束,可以接受业务系统的日志写入和查询操作。

3 业务系统接入

该部分讲解如何配置业务系统来将业务系统中的对象变化记录到ObjectLogger中。

3.1 引入依赖包

在pom中增加下面的依赖:

<dependency><groupId>com.github.yeecode.objectLogger</groupId><artifactId>ObjectLoggerClient</artifactId><version>{最新版本}</version>
</dependency>

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包地址的扫描:

<context:component-scan base-package="com.github.yeecode.objectLoggerClient">
</context:component-scan>

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:8080
  • your_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("  <p>the first line</p>
" +" <p>the second line</p>
" +" <p>the 3th line</p>");
TaskModel newTaskModel = new TaskModel();
newTaskModel.setId(9);
newTaskModel.setTaskName("newName");
newTaskModel.setUserId(5);
newTaskModel.setDescription("  <p>the first line</p>
" +" <p>the second line</p>
" +" <p>the last line</p>");
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<p>the first line</p>nt<p>the second line</p>nt<p>the 3th line</p>"","newValue": ""t<p>the first line</p>nt<p>the second line</p>nt<p>the last line</p>"","diffValue": "第6行变化:<br/> -:<del> the 3th line </del> <br/> +:<u> the last line </u> <br/>"}]}],"respCode": "1000"
}

6 对象属性过滤

有些对象的属性的变动不需要进行日志记录,例如updateTime、hashCode等。ObjectLogger支持对对象的属性进行过滤,只追踪我们感兴趣的属性。

并且,对于每个属性我们可以更改其记录到ObjectLogger系统中的具体方式,例如修改命名等。

要想启用这个功能,首先将配置中的object.logger.autoLog改为false。

object.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:记录属性的新值和旧值,对比值为null
  • BuiltinTypeHandler.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 {@Overridepublic BaseActionItemModel handleAttributeChange(String attributeName, String logTagName, Object oldValue, Object newValue) {return null;}
}

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

  • extendedType:扩展类型值,即@LogTag注解的extendedType值。本示例中为userIdType。
  • attributeName:属性名。本示例中为userId。
  • logTagName:@LogTag注解的name值,可能为null。本示例中为UserId。
  • oldValue:该属性的旧值。
  • 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 如何去掉http debug日志_Java高手如何搭建高效易用的日志系统相关推荐

  1. java 如何去掉http debug日志_你居然还去服务器上捞日志,搭个日志收集系统难道不香吗?...

    作者:MacroZheng 链接:https://juejin.im/post/5eef217d51882565d74fb4eb 来源:掘金 SpringBoot实战电商项目mall(35k+star ...

  2. java 如何去掉http debug日志_Spring Boot手把手教学(3):从零配置logback日志

    前言 使用logback我们可以自定义控制台日志输出,可以实现对不同日志不同级别打印到不同的文件中,可以对日志进行归档保存,并定时删除: 对于一个应用来讲,一个好的日志系统,对于对问题的追溯有很大的帮 ...

  3. java 如何去掉http debug日志_你居然还去服务器上捞日志,搭个日志收集系统难道不香么!...

    作者:MacroZheng 链接:https://juejin.im/post/5eef217d51882565d74fb4eb 摘要 ELK日志收集系统进阶使用,本文主要讲解如何打造一个线上环境真实 ...

  4. java配置文件放置到jar外_java相关:Spring Boot 把配置文件和日志文件放到jar外部...

    java相关:Spring Boot 把配置文件和日志文件放到jar外部 发布于 2020-3-6| 复制链接 如果不想使用默认的application.properties,而想将属性文件放到jar ...

  5. java字符串去掉最后一个逗号_java拼接字符串时去掉最后一个多余逗号的方法

    java拼接字符串时去掉最后一个多余逗号的方法 本文实例讲述了java拼接字符串时去掉最后一个多余逗号的方法.分享给大家供大家参考.具体分析如下: 先看下面这段代码: for (int t = 0; ...

  6. java双人对弈五子棋源码_JAVA高手接招————— 五子棋双人对弈程序

    展开全部 新建一个chess类,其中代码如下 package work; import java.awt.Color; public class Chess { public static final ...

  7. java二嗨租车项目_JAVA第二季项目实战———答答租车系统代码

    总共5个类: 第1个类:Car package DaDaRentCar; //父类 public class Car { String name; //车名 int money; //租金 int c ...

  8. java sl4j 日志_Java日志框架Slf4j+Log4j入门

    一.日志系统介绍 slf4j,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统.简答的讲就是slf4j是一系列的日志 ...

  9. java输出日志_java代码中如何正确使用loggger日志输出

    java代码中如何正确使用loggger日志输出 发布时间:2019-06-28作者:spider阅读(2980) 当你遇到问题的时候,只能通过debug功能来确定问题,你应该考虑打日志,良好的系统, ...

  10. 查看java web日志_java web 日志详细

    第一步:首先建立一个WEB工程,去log4j官网下log4j的JAR包导入到工程的lib目录下 第二步:在src目录下建一个log4j.properties 文件,文件命名可以由自己,只是记加载时候和 ...

最新文章

  1. ASM丢失disk header导致ORA-15032、ORA-15040、ORA-15042 Diskgroup无法mount
  2. [渝粤教育] 西南科技大学 西方经济学 在线考试复习资料(1)
  3. c语言学习-判断101-200之间有多少个素数,并输出所有素数及素数的个数
  4. 性能测试LoadRunner_Monitors
  5. 【iCore1S 双核心板_ARM】例程五:IWDG看门狗实验——复位ARM
  6. 【大规模图像检索的利器】Deep哈希算法介绍
  7. python 存储对象_Python使用redis存储对象
  8. Cannot resolve plugin org.apache.tomcat.maven:tomcat7-maven-plugin:<unknown>
  9. 实验七 数据选择器和译码器的应用
  10. 浅谈 Java 24个设计模式(23个GoF设计模式 + 简单工厂模式) 之 六个创建型模式...
  11. 最通俗易懂的讲解工厂模式
  12. 《测绘综合能力》——工程测量
  13. 2011年10月14日22:40,“你在哪(where are you)”诞生
  14. 计算机基础知识(基础入门小白专属)五
  15. Symantec赛门铁克官网下载地址
  16. 【第3版emWin教程】第53章 emWin6.x的按钮Button控件
  17. ssis的數據分流,mark一下
  18. 【Matlab学习手记】椭圆拟合
  19. Array常用方法(数组增加、数组删除、数组截取、数组查找、数组遍历)
  20. 无聊乱做的一个线连线的功能()蓝图的(_杰森大师)

热门文章

  1. 【物理应用】基于matlab双目视觉三维重建【含Matlab源码 1781期】
  2. 【短时能量】基于matlab语音信号短时能量【含Matlab源码 1719期】
  3. 【信号检测】基于matlab双稳态随机共振的参数寻优算法【含Matlab源码 1700期】
  4. 【运动学】基于matlab GUI平衡车一阶倒立摆仿真【含Matlab源码 1258期】
  5. jvm调优工具_高级程序员必会的5个JVM性能监控、调优工具使用详解
  6. ai人工智能可以干什么_人工智能可以解决我的业务问题吗?
  7. ai替代数据可视化_在药物发现中可视化AI初创公司
  8. 计算机模拟学,深度学习是让计算机模拟
  9. 计算机网络-Postman测试http的get和post方法
  10. 获取两个数组的差 php,php-获取2个数组之间的差