qqxx6661 / log-record

使用注解优雅记录系统日志,操作日志,后端埋点等,支持SpEL表达式,自定义上下文,自定义函数,实体类DIFF等其他高阶处理。
Apache License 2.0
934 stars 175 forks source link

新增常用公共函数和可序列化对象注解的建议 #83

Open duanluan opened 1 year ago

duanluan commented 1 year ago

我再提些建议,你别烦我🥺

我在使用过程中自定义了一个toLogString函数,作用是传进去对象或集合,输出有@LogRecordDiffField的属性,而且还和diff-ignore-new-object-null-valuediff-msg-separator结合起来使用了。我觉得将参数属性名转为中文是很常见的需求,可以新增类似的公共函数。

我觉得@LogRecordDiffField注解可以改成@LogRecordField,然后同时适用于 Diff 和其他功能,就像 MyBatis Plus 的@TableField或 Hibernate 的@Column一样。

我很久以前写过一个基于 Hibernate 的注解日志记录,会自动将带有@Column的属性名转为这个注解的 comment 输出,或者将它的属性名、@Column 注解的 comment 属性的值、属性值传到一个集合里后续再使用。

我觉得除了新增类似的公共函数之外,也可以给@OperationLog加一个属性,为 true 就直接把属性名转成@LogRecordField的 alias 的值了。

CustomLogFn

/**
 * 日志自定义函数
 */
@Slf4j
@Component
@LogRecordFunc("custom")
public class CustomLogFn {

  private static boolean ignoreNullValues;
  private static String diffMsgSeparator;

  @Value("${log-record.diff-ignore-new-object-null-value}")
  public void setIgnoreNullValues(boolean ignoreNullValues) {
    CustomLogFn.ignoreNullValues = ignoreNullValues;
  }

  @Value("${log-record.diff-msg-separator}")
  public void setDiffMsgSeparator(String diffMsgSeparator) {
    CustomLogFn.diffMsgSeparator = diffMsgSeparator;
  }

  @LogRecordFunc("toLogString")
  public static String toLogString(Object object) {
    List<String> fields = new ArrayList<>();

    // 操作多个对象
    if (object instanceof Iterable<?>) {
      for (Object o : (Iterable<?>) object) {
        fields.add(toLogString(o));
      }
      return StringUtils.join(fields, " | ");
    } else {
      // 遍历对象的所有字段
      for (Field field : object.getClass().getDeclaredFields()) {
        // 跳过没有 @LogRecordDiffField 的字段
        if (!field.isAnnotationPresent(LogRecordDiffField.class)) {
          continue;
        }
        field.setAccessible(true);
        LogRecordDiffField annotation = field.getAnnotation(LogRecordDiffField.class);
        // 跳过忽略的字段
        if (annotation.ignored()) {
          continue;
        }
        try {
          Object value = field.get(object);
          // 是否忽略 null 值
          if (ignoreNullValues && value == null) {
            continue;
          }
          fields.add(annotation.alias() + ":" + (value != null ? value.toString() : "null"));
        } catch (IllegalAccessException e) {
          log.error("获取字段值失败", e);
        }
      }
      return StringUtils.join(fields, diffMsgSeparator);
    }
  }
}
@OperationLog(bizId = "#bizId", bizType = "'user:save'", msg = "'【保存用户】' + #custom_toLogString(#obj)")
// 结果:【保存用户】用户名:test2;昵称:test2;电话:18888888888;角色:3

@OperationLog(bizId = "#ids", bizType = "'user:remove'", msg = "'【删除用户】' + #custom_toLogString(#removedList)")
// 结果:【删除用户】用户名:test1;电话:18888888888;昵称:test1;角色:2 | 用户名:test2;电话:18888888888;昵称:test2;角色:3
qqxx6661 commented 1 year ago

话题好大,信息有点多。@LogRecordField这个优化点我要考虑下,感觉意义也没有那么大,目前能做的也就是提供个alias。

话说你贴的代码实现的这种处理,我给的diffDTOList里应该有的。可以针对diffDTO处理的吧。

"diffDTOList":[
    {
      "diffFieldDTOList":[
        {
          "fieldName":"id",
          "newFieldAlias":"用户工号",
          "newValue":2,
          "oldFieldAlias":"用户工号",
          "oldValue":1
        },
        {
          "fieldName":"name",
          "newValue":"李四",
          "oldValue":"张三"
        }],
      "newClassAlias":"用户信息实体",
      "newClassName":"cn.monitor4all.logRecord.test.bean.TestUser",
      "oldClassAlias":"用户信息实体",
      "oldClassName":"cn.monitor4all.logRecord.test.bean.TestUser"
    },
    {
      "diffFieldDTOList":[
        {
          "fieldName":"id",
          "newFieldAlias":"用户工号",
          "newValue":2,
          "oldFieldAlias":"用户工号",
          "oldValue":1
        },
        {
          "fieldName":"name",
          "newValue":"李四",
          "oldValue":"张三"
        }],
      "newClassAlias":"用户信息实体",
      "newClassName":"cn.monitor4all.logRecord.test.bean.TestUser",
      "oldClassAlias":"用户信息实体",
      "oldClassName":"cn.monitor4all.logRecord.test.bean.TestUser"
    }]