如何优雅地记录操作日志?(4)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 如何优雅地记录操作日志?

4.2.3 日志持久化逻辑


同样在 LogRecordInterceptor 的代码中引用了 ILogRecordService,这个 Service 主要包含了日志记录的接口。


publicinterfaceILogRecordService {

  /**
    * 保存 log
    *
    * @param logRecord 日志实体
    */

  voidrecord(LogRecord logRecord);


}


业务可以实现这个保存接口,然后把日志保存在任何存储介质上。这里给了一个 2.2 节介绍的通过 log.info 保存在日志文件中的例子,业务可以把保存设置成异步或者同步,可以和业务放在一个事务中保证操作日志和业务的一致性,也可以新开辟一个事务,保证日志的错误不影响业务的事务。业务可以保存在 Elasticsearch、数据库或者文件中,用户可以根据日志结构和日志的存储实现相应的查询逻辑。


@Slf4j

publicclassDefaultLogRecordServiceImplimplementsILogRecordService {


  @Override

//    @Transactional(propagation = Propagation.REQUIRES_NEW)

  publicvoidrecord(LogRecord logRecord) {

       log.info("【logRecord】log={}", logRecord);

   }

}

4.2.4 Starter 逻辑封装


上面逻辑代码已经介绍完毕,那么接下来需要把这些组件组装起来,然后让用户去使用。在使用这个组件的时候只需要在 Springboot 的入口上添加一个注解 @EnableLogRecord(tenant = "com.mzt.test")。其中 tenant 代表租户,是为了多租户使用的。


@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableTransactionManagement
@EnableLogRecord(tenant
= "com.mzt.test")

publicclassMain {


  publicstaticvoidmain(String[] args) {

       SpringApplication.run(Main.class, args);

   }

}


我们再看下 EnableLogRecord 的代码,代码中 Import 了 LogRecordConfigureSelector.class,在 LogRecordConfigureSelector 类中暴露了 LogRecordProxyAutoConfiguration 类。


@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Import(LogRecordConfigureSelector.class)
public @interfaceEnableLogRecord
{


  String tenant();

 

  AdviceMode mode()default AdviceMode.PROXY;

}


LogRecordProxyAutoConfiguration 就是装配上面组件的核心类了,代码如下:


@Configuration

@Slf4j

publicclassLogRecordProxyAutoConfigurationimplementsImportAware {


private AnnotationAttributes enableLogRecord;



@Bean

@Role(BeanDefinition.ROLE_INFRASTRUCTURE)

public LogRecordOperationSource logRecordOperationSource() {

  returnnew LogRecordOperationSource();

 }


@Bean

@ConditionalOnMissingBean(IFunctionService.class)
 publicIFunctionServicefunctionService(ParseFunctionFactoryparseFunctionFactory)
{

  returnnew DefaultFunctionServiceImpl(parseFunctionFactory);

 }


@Bean

public ParseFunctionFactory parseFunctionFactory(@Autowired List<IParseFunction> parseFunctions) {

  returnnew ParseFunctionFactory(parseFunctions);

 }


@Bean

@ConditionalOnMissingBean(IParseFunction.class)
 publicDefaultParseFunctionparseFunction()
{

  returnnew DefaultParseFunction();

 }



@Bean

@Role(BeanDefinition.ROLE_INFRASTRUCTURE)

public BeanFactoryLogRecordAdvisor logRecordAdvisor(IFunctionService functionService) {

   BeanFactoryLogRecordAdvisor advisor =

          new BeanFactoryLogRecordAdvisor();

   advisor.setLogRecordOperationSource(logRecordOperationSource());

   advisor.setAdvice(logRecordInterceptor(functionService));

  return advisor;

 }


@Bean

@Role(BeanDefinition.ROLE_INFRASTRUCTURE)

public LogRecordInterceptor logRecordInterceptor(IFunctionService functionService) {

   LogRecordInterceptor interceptor = new LogRecordInterceptor();

   interceptor.setLogRecordOperationSource(logRecordOperationSource());

   interceptor.setTenant(enableLogRecord.getString("tenant"));

   interceptor.setFunctionService(functionService);

  return interceptor;

 }


@Bean

@ConditionalOnMissingBean(IOperatorGetService.class)
 @Role(BeanDefinition.ROLE_APPLICATION)
 publicIOperatorGetServiceoperatorGetService()
{

  returnnew DefaultOperatorGetServiceImpl();

 }


@Bean

@ConditionalOnMissingBean(ILogRecordService.class)
 @Role(BeanDefinition.ROLE_APPLICATION)
 publicILogRecordServicerecordService()
{

  returnnew DefaultLogRecordServiceImpl();

 }


@Override

publicvoidsetImportMetadata(AnnotationMetadata importMetadata) {

  this.enableLogRecord = AnnotationAttributes.fromMap(

           importMetadata.getAnnotationAttributes(EnableLogRecord.class.getName(), false));

  if (this.enableLogRecord == null) {

     log.info("@EnableCaching is not present on importing class");

   }

 }

}


这个类继承 ImportAware 是为了拿到 EnableLogRecord 上的租户属性,这个类使用变量 logRecordAdvisor 和 logRecordInterceptor 装配了 AOP,同时把自定义函数注入到了 logRecordAdvisor 中。对外扩展类:分别是IOperatorGetServiceILogRecordServiceIParseFunction。业务可以自己实现相应的接口,因为配置了 @ConditionalOnMissingBean,所以用户的实现类会覆盖组件内的默认实现。


5. 总结


这篇文章介绍了操作日志的常见写法,以及如何让操作日志的实现更加简单、易懂,通过组件的四个模块,介绍了组件的具体实现。对于上面的组件介绍,大家如果有疑问,也欢迎在文末留言,我们会进行答疑。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
6月前
|
Java
如何实现一个高效的二叉搜索树(BST)?请给出时间复杂度分析。 要求:设计一个二叉搜索树,支持插入、删除和查找操作。要求在平均情况下,这些操作的时间复杂度为O(log n)。同时,考虑树的平衡性,使得树的高度保持在对数级别。
如何实现一个高效的二叉搜索树(BST)?请给出时间复杂度分析。 要求:设计一个二叉搜索树,支持插入、删除和查找操作。要求在平均情况下,这些操作的时间复杂度为O(log n)。同时,考虑树的平衡性,使得树的高度保持在对数级别。
65 0
|
4月前
|
SQL Java Serverless
实时计算 Flink版操作报错合集之在写入SLS(Serverless Log Service)时出现报错,该如何排查
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
5月前
|
弹性计算 Serverless 应用服务中间件
Serverless 应用引擎操作报错合集之集成sls时出现报错,是什么导致的
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
6月前
|
分布式计算 DataWorks 关系型数据库
DataWorks操作报错合集之在DataWorks中设置了一个任务节点的调度时间,并将其发布到生产环境,但到了指定时间(例如17:30)却没有产生运行实例和相关日志如何解决
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
4月前
|
Java Serverless 应用服务中间件
函数计算操作报错合集之JVM启动时找不到指定的日志目录,该如何解决
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
4月前
|
监控 数据管理 关系型数据库
数据管理DMS使用问题之是否支持将操作日志导出至阿里云日志服务(SLS)
阿里云数据管理DMS提供了全面的数据管理、数据库运维、数据安全、数据迁移与同步等功能,助力企业高效、安全地进行数据库管理和运维工作。以下是DMS产品使用合集的详细介绍。
|
5月前
|
监控 数据库
neo4j数据插入操作有日志吗
【6月更文挑战第29天】neo4j数据插入操作有日志吗
87 1
|
5月前
|
存储 运维 Java
Spring运维之boot项目开发关键之日志操作以及用文件记录日志
Spring运维之boot项目开发关键之日志操作以及用文件记录日志
63 2
|
5月前
|
Java 数据库连接 数据库
Spring日志完结篇,MyBatis操作数据库(入门)
Spring日志完结篇,MyBatis操作数据库(入门)
|
5月前
|
SQL DataWorks Oracle
DataWorks产品使用合集之datax解析oracle增量log日志该如何操作
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
59 0