bizlog通用操作日志组件(使用篇)

Posted 好好生活_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bizlog通用操作日志组件(使用篇)相关的知识,希望对你有一定的参考价值。

引言


如上图所示,产品的新需求,需要将操作人在系统中具体编辑操作的变更内容记录下来。

按正常思路来说,无非就是将修改前后的对象字段逐个比较,再拼接为详细的操作描述记录到操作日志表中。如果是一个模块的需求,单独写个方法即可,但各个模块都有这部分需求,在各个模块中单独写就显得冗余了,功能代码与日志记录代码混在一起,代码可读性更差了。

因此,项目中引入了新的日志组件,统一实现团队项目中各模块记录操作日志的需求,将日志记录代码与功能代码分离,提升代码的可读性。

概述

在一个系统中,日志主要分为系统日志和操作日志。

系统日志主要是为开发排查问题提供依据。操作日志主要是对某条数据进行新增或者修改操作后进行记录,操作日志要求可读性强,因为它是给用户看的,比如订单的物流信息,用户需求知道在什么时候发生了什么事情。

本篇博客介绍的组件解决的就是该问题:「谁」在「什么时间」对「什么」做了「什么事」

快速开始

1. Maven依赖

<dependency>
   <groupId>io.github.mouzt</groupId>
   <artifactId>bizlog-sdk</artifactId>
   <version>3.0.3<version>
</dependency>

2. SpringBoot入口启用日志组件,添加@EnableLogRecord注解

tenant是代表租户的标识,一般一个服务或者一个业务下的多个服务都写死一个 tenant 就可以。示例如下:

@SpringBootApplication
@EnableTransactionManagement
@EnableLogRecord(tenant = "com.mzt.test")
public class Main 

    public static void main(String[] args) 
        SpringApplication.run(Main.class, args);
    

3. 普通日志记录

下面给一个示例,在新增方法上加上@LogRecord注解,补上对应的参数,代码如下:

@LogRecord(
		operator = "#currentUser",
        fail = "创建订单失败,失败原因:「#_errorMsg」",
        subType = "MANAGER_VIEW",
        extra = "#order.toString()",
        success = "#order.purchaseName下了一个订单,购买商品「#order.productName」,测试变量 #innerOrder.productName",
        type = LogRecordType.ORDER, bizNo = "#order.orderNo")
public boolean createOrder(Order order) 
    log.info("【创建订单】orderNo=", order.getOrderNo());
    // db insert order
    Order order1 = new Order();
    order1.setProductName("内部变量测试");
    LogRecordContext.putVariable("innerOrder", order1);
    return true;

参数说明:

  • SpEL 表达式:其中用双大括号包围起来的(例如:#order.purchaseName)#order.purchaseName 是 SpEL表达式。Spring中支持的它都支持的。比如调用静态方法,三目表达式
  • type:是拼接在 bizNo 上作为 log 的一个标识。避免 bizNo 都为整数 ID 的时候和其他的业务中的 ID 重复。比如订单 ID、用户 ID 等,type可以是订单或者用户
  • bizNo:就是业务的 ID,比如订单ID,我们查询的时候可以根据 bizNo 查询和它相关的操作日志
  • subType:日志子类型,主要是便于对日志做分类,实现不同角色的人看到不同的日志
  • operator:操作人
  • success:方法调用成功后把 success 记录在日志的内容中
  • extra:支持记录操作的详情或者额外信息
  • fail:如果抛出异常则记录fail的日志,其中的 #_errorMsg 是取的方法抛出异常后的异常的 errorMessage

此时会打印操作日志 “张三下了一个订单,购买商品「XXX」,测试变量「内部变量测试」

4. 保存日志于存储介质中

实现ILogRecordService接口即可,在record方法中保存日志记录,查询日志可根据自身业务需求实现。

@Service
public class DbLogRecordServiceImpl implements ILogRecordService 

    @Resource
    private LogRecordMapper logRecordMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void record(LogRecord logRecord) 
        log.info("【logRecord】log=", logRecord);
        LogRecordPO logRecordPO = LogRecordPO.toPo(logRecord);
        logRecordMapper.insert(logRecordPO);
    

    @Override
    public List<LogRecord> queryLog(String bizKey, Collection<String> types) 
        return Lists.newArrayList();
    

    @Override
    public PageDO<LogRecord> queryLogByBizNo(String bizNo, Collection<String> types, PageRequestDO pageRequestDO) 
        return logRecordMapper.selectByBizNoAndCategory(bizNo, types, pageRequestDO);
    

通过上面简单的几步就能实现记录新增操作的日志,不用在业务代码中写一些繁琐的日志代码。下面再简单介绍一些组件的其他使用特性和示例。

其他使用

1. 自定义函数

在日志记录中,可能会存在字段值是ID,如订单号,而看到一堆数字并不知道对应的内容(订单名等)这日志记录的可读性很差。因此可以使用自定义函数,可在函数中实现通过ID查询到对应内容显示。

使用上只需要实现框架里面的IParseFunction的接口,实现两个方法:

1)functionName() 方法就返回注解上面的函数名;

2)apply()函数参数是 "ORDER#orderId"中SpEL解析的#orderId的值,这里是一个数字1223110,接下来只需要在实现的类中把 ID 转换为可读懂的字符串就可以了, 一般为了方便排查问题需要把名称和ID都展示出来,例如:"订单名称(ID)"的形式。

示例代码:

//使用了自定义函数,主要是在 #orderId 的大括号中间加了 functionName
@LogRecord(success = "更新了订单ORDER#orderId,更新内容为...",
        type = LogRecordType.ORDER, bizNo = "#order.orderNo",
        extra = "#order.toString()")
public boolean update(Long orderId, Order order) 
    return false;


// 还需要加上函数的实现
@Slf4j
@Component
public class OrderParseFunction implements IParseFunction 

    @Override
    public boolean executeBefore() 
        return true;
    

    @Override
    public String functionName() 
        return "ORDER";
    

    @Override
    public String apply(Object value) 
        log.info("@@@@@@@@");
        if (StringUtils.isEmpty(value)) 
            return "";
        
        log.info("###########,", value);
        Order order = new Order();
        order.setProductName("xxxx");
        return order.getProductName().concat("(").concat(value.toString()).concat(")");
    

2. 使用方法参数之外的变量

可以在方法中通过 LogRecordContext.putVariable(variableName, Object) 的方法添加变量,第一个对象为变量名称,后面为变量的对象

3. diff特性

用于快速比较并记录两个对象之间不同的字段内容。

1)使用@DiffLogField标注字段含义

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order 
    @DiffLogField(name = "订单ID", function = "ORDER")
    private Long orderId;
    @DiffLogField(name = "订单号")
    private String orderNo;
    private String purchaseName;
    private String productName;
    @DiffLogField(name = "创建时间")
    private LocalDateTime createTime;

    @DiffLogField(name = "创建人")
    private UserDO creator;
    @DiffLogField(name = "更新人")
    private UserDO updater;
    @DiffLogField(name = "列表项", function = "ORDER")
    private List<String> items;

    @DiffLogField(name = "拓展信息", function = "extInfo")
    private String[] extInfo;

    @Data
    public static class UserDO 
        @DiffLogField(name = "用户ID")
        private Long userId;
        @DiffLogField(name = "用户姓名")
        private String userName;
    

name:是生成的 DIFF 文案中 Field 的中文, function: 自定义函数,例如可以把用户ID映射成用户姓名。

2)在更新方法上,使用日志注解

@LogRecord(success = "更新订单。_DIFF#oldOrder, #newOrder",
        type = LogRecordType.ORDER, bizNo = "#newOrder.orderNo",
        extra = "#newOrder.toString()")
public boolean diff(Order oldOrder, Order newOrder) 
    //....
    return false;

4. 日志记录与业务逻辑一起回滚

默认日志记录错误不影响业务的流程,若希望日志记录过程如果出现异常,让业务逻辑也一起回滚,在 @EnableLogRecord 中 joinTransaction 属性设置为 true, 另外 @EnableTransactionManagement order 属性设置为0 (让事务的优先级在@EnableLogRecord之前)

@EnableLogRecord(tenant = "com.mzt.test", joinTransaction = true)
@EnableTransactionManagement(order = 0)
public class Main 

    public static void main(String[] args) 
        SpringApplication.run(Main.class, args);
    

总结

通过本篇博客对bizlog的简单介绍与使用教程,相信你一定感受到了该组件的魅力所在。如果你的项目中正好有同样的需求,而你还是在业务逻辑代码中实现,不妨试试该日志框架,简单好用。

以上是关于bizlog通用操作日志组件(使用篇)的主要内容,如果未能解决你的问题,请参考以下文章

bizlog通用操作日志组件(使用篇)

bizlog通用操作日志组件(使用篇)

bizlog通用操作日志组件(使用篇)

开源:如何优雅的实现一个操作日志组件

MYSQL架构篇

05_Pulsar的主要组件介绍与命令使用名称空间Pulsar的topic相关操作Pulsar Topic(主题)相关操作_高级操作