SpringBoot和@Aspect实现自建Log日志功能

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: SpringBoot和@Aspect实现自建Log日志功能

主页:写程序的小王叔叔的博客欢迎来访👀

支持:点赞收藏关注


1、技术

JDK1.8+

SpringBoot2.0+   、@Aspect注解

MySql5.6+

2、代码干货

Log实体对象类.java

package*****.***.***.modules.sys.log.entity;
importjava.io.Serializable;
importjava.util.Date;
importjavax.persistence.Column;
importjavax.persistence.Entity;
importjavax.persistence.Id;
importjavax.persistence.Table;
importorg.springframework.stereotype.Component;
importio.swagger.annotations.ApiModelProperty;
@Entity@Table(name="sys_log")
@Component@org.hibernate.annotations.Table(comment="系统日志信息", appliesTo="sys_log")
publicclassSysLogimplementsSerializable{
privatestaticfinallongserialVersionUID=42L;
@Id@ApiModelProperty("主键")
@Column(name="id",nullable=false,columnDefinition="bigint(64)  comment '主键'")
privateLongid;// 主键Id@ApiModelProperty("日志编号")
@Column(name="log_id",columnDefinition="varchar(255)  comment '日志编号'" )
privateStringlogId;//日志编号@ApiModelProperty("请求链接")
@Column(name="url",columnDefinition="text  comment '请求链接'" )
privateStringurl;//请求链接@ApiModelProperty("请求方法")
@Column(name="method",columnDefinition="text  comment '请求方法'" )
privateStringmethod;//请求方法@ApiModelProperty("请求类名")
@Column(name="class_name",columnDefinition="text  comment '请求类名'" )
privateStringclassName;//请求方法@ApiModelProperty("请求方法名")
@Column(name="method_name",columnDefinition="text  comment '请求方法名'" )
privateStringmethodName;//请求方法@ApiModelProperty("请求参数")
@Column(name="params",columnDefinition="text  comment '请求参数'" )
privateStringparams;//请求参数@ApiModelProperty("日志类型:(1:系统日志2:业务日志)")
@Column(name="lot_type",columnDefinition="varchar(255)  comment '日志类型:(1:系统日志2:业务日志)'" )
privateStringlogType;//请求方法@ApiModelProperty("请求方式:(GET/POST)")
@Column(name="type",columnDefinition="varchar(255)  comment '请求方式(GET/POST)'" )
privateStringtype;//请求方法@ApiModelProperty("请求IP")
@Column(name="IP",columnDefinition="text  comment '请求IP'" )
privateStringip;//请求方法@ApiModelProperty("操作的数据库表")
@Column(name="log_table",columnDefinition="varchar(255)  comment '操作的数据库表'" )
privateStringtable;//操作的数据库表@ApiModelProperty("请求异常")
@Column(name="log_error",columnDefinition="text  comment '请求异常'" )
privateStringlogError;//请求异常@ApiModelProperty("运行时长")
@Column(name="time",columnDefinition="varchar(255) comment '运行时长'" )
privatelongtime;//@ApiModelProperty("备注")
@Column(name="log_comment",columnDefinition="text  comment '备注'" )
privateStringlogComment;//备注@ApiModelProperty("创建人")
@Column(name="create_by" )
privateStringcreateBy;//创建人@ApiModelProperty("创建时间")
@Column(name="create_time"  )
privateDatecreateTime;//创建时间//setter()/getter();}

3、基本的CRUD

package****.****.****.modules.sys.log.controller;
importjava.util.List;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.CrossOrigin;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.ResponseBody;
importorg.springframework.web.bind.annotation.RestController;
import*****.modules.sys.log.entity.SysLog;
import*******.modules.sys.log.service.SysLogService;
importio.swagger.annotations.ApiOperation;
@CrossOrigin//跨域@RestController@RequestMapping("/SysLog")
publicclassSysLogController{
@AutowiredpublicSysLogServicesysLogService;
//  //添加AOP注解日志管理//  @SysLogAspectValue(//      describtion = "获取所有日志列表信息",//      logType = "1",//      type="POST",//      url="/SysLog/SelectAllSysLog",//      table="sys_log",//      params = "SysLog",//      method = "POST"//  )@ResponseBody@ApiOperation(value="获取所有日志列表信息", notes="/SysLog/SelectAllSysLog")
@GetMapping(value="/SelectAllSysLog")
publicList<SysLog>SelectAllSysLog(){
returnsysLogService.SelectAllSysLogList(page).getContent();
  }
}
package*******.*****.******modules.sys.log.service;
importorg.springframework.data.domain.Page;
import***.***.****t.modules.sys.log.entity.SysLog;
/**** 系统日志接口* @ClassName: SysLogService* @Description: TODO(描述)* @author author* @date 2019-12-03 10:55:22*/publicinterfaceSysLogService {
/**** 日志保存* @Title: save* @Description: TODO(描述)* @param sysLog* @author author* @date 2019-12-10 09:56:28*/voidsave(SysLogsysLog);
}
package***.****.****.modules.sys.log.service.impl;
importjava.util.ArrayList;
importjava.util.List;
importjavax.persistence.criteria.CriteriaBuilder;
importjavax.persistence.criteria.CriteriaQuery;
importjavax.persistence.criteria.Predicate;
importjavax.persistence.criteria.Root;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.data.domain.Page;
importorg.springframework.data.domain.PageRequest;
importorg.springframework.data.domain.Pageable;
importorg.springframework.data.domain.Sort;
importorg.springframework.data.jpa.domain.Specification;
importorg.springframework.stereotype.Service;
import***.***.***.***.****.modules.sys.log.entity.SysLog;
import***.*.*.*.*.*.*.*.modules.sys.log.repository.SysLogRepository;
import*.*.*.*.*.*.*.*.*.*.modules.sys.log.service.SysLogService;
/*** 系统日志实现类* @ClassName: SysLogServiceImpl* @Description: TODO(描述)* @author author* @date 2019-12-03 10:55:17*/@Service("SysLogService")
publicclassSysLogServiceImplimplementsSysLogService{
@AutowiredpublicSysLogRepositorysysLogRepository;
@OverridepublicPage<SysLog>SelectAllSysLogList(intpage) {
Sortsort=newSort(Sort.Direction.DESC, "createTime");//创建时间正序排列Pageablepageable=PageRequest.of(page, this.size, sort);
Page<SysLog>sysLog=sysLogRepository.findAll (newSpecification<SysLog>() {
@OverridepublicPredicatetoPredicate(Root<SysLog>root,
CriteriaQuery<?>query, CriteriaBuildercriteriaBuilder) {
List<Predicate>list=newArrayList<Predicate>();
//拼接 where条件-----------------//---------------------------Predicate[] p=newPredicate[list.size()];
returncriteriaBuilder.and(list.toArray(p));
      }
    }, pageable);
returnsysLog;
  }
@Overridepublicvoidsave(SysLogsysLog) {
sysLogRepository.save(sysLog);
  }
}
package*.*.*.*.*.*.*.modules.sys.log.repository;
importorg.springframework.data.jpa.domain.Specification;
importorg.springframework.data.jpa.repository.JpaRepository;
import*.*.*.*.*.*.*.*.modules.sys.log.entity.SysLog;
/*** 系统日志管理类* @ClassName: SysLogRepository* @Description: TODO(描述)* @author author* @date 2019-12-03 10:55:09*/publicinterfaceSysLogRepositoryextendsJpaRepository<SysLog, Long> {
}

已上就是基本的业务功能中的CRUD的功能,下面就是重点的log的AOP切面功能,,,

4、AOP切面功能动态获取log信息

1)、在每个需要用到的方法头上增加注释,附加案例【四中第一个截图】

package*.*.*.*.*.*.*.*.modules.sys.log.controller;
importjava.lang.annotation.Documented;
importjava.lang.annotation.ElementType;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
importjava.lang.annotation.Target;
/**** 系统日志管理表* @ClassName: SysLogController* @Description: TODO(描述)* @author author* @date 2019-12-03 10:54:52*/@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented//注释文档public@interfaceSysLogAspectValue {
Stringdescribtion() default"";//日志描述StringlogType() default"1";//日志种类-1:系统日志2:业务日志Stringtype()  default"GET";//请求方式:(GET/POST)Stringurl()  default"";//请求链接Stringtable()  default"";//操作的数据库表Stringparams()  default"";//请求参数Stringmethod()  default"";//请求方法}

制作切面内容

package*.*.*.*.*.*.*.modules.sys.log.controller;
importjava.lang.reflect.Method;
importjava.util.ArrayList;
importjava.util.Date;
importjava.util.List;
importjavax.servlet.http.HttpServletRequest;
importorg.aspectj.lang.JoinPoint;
importorg.aspectj.lang.ProceedingJoinPoint;
importorg.aspectj.lang.annotation.AfterThrowing;
importorg.aspectj.lang.annotation.Around;
importorg.aspectj.lang.annotation.Aspect;
importorg.aspectj.lang.annotation.Pointcut;
importorg.aspectj.lang.reflect.MethodSignature;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Component;
importorg.springframework.web.context.request.RequestContextHolder;
importorg.springframework.web.context.request.ServletRequestAttributes;
importcom.google.gson.Gson;
import*.*.*.*.*.*.common.utils.IdGenerate;
import*.*.*.*.*.*.modules.sys.log.entity.SysLog;
import*.*.*.*.*.*.modules.sys.log.service.SysLogService;
/****  系统日志切面* @ClassName: SysLogAspect* @Description: TODO(描述)* @author author* @date 2019-12-04 10:34:41*/@Aspect// 使用@Aspect注解声明一个切面@ComponentpublicclassSystemLogAspect{
privatefinalStringPOINT_CUT="@annotation(*.*.*.*.*.modules.sys.log.entity)";
privatestaticfinalorg.slf4j.Loggerlog=org.slf4j.LoggerFactory.getLogger(SystemLogAspect.class);
@AutowiredpublicSysLogServicesysLogService;
/*** 这里我们使用注解的形式* 当然,我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method* 切点表达式:   execution(...)*/@Pointcut(POINT_CUT)
publicvoidPointCut() {}
/*** 环绕通知 @Around  , 当然也可以使用 @Before (前置通知)  @After (后置通知)* @param point* @return* @throws Throwable*///@Around(POINT_CUT)@Around("@annotation(SysLogAspectValue)")
publicObjectaround(ProceedingJoinPointpoint) throwsThrowable {
longbeginTime=System.currentTimeMillis();
Objectresult=point.proceed();
try {
//正常保存日志saveLog(point, System.currentTimeMillis() -beginTime);
        } catch (Exceptione) {
//异常保存日志//afterReturningMethod(point, e);        }
returnresult;
    }
/**** 捕获异常* * @Title: afterReturningMethod* @Description: TODO(描述)* @param joinPoint* @param e* @author author* @throws Throwable * @date 2019-12-10 01:40:37*/@AfterThrowing(throwing="exception",value="@annotation(SysLogAspectValue)",argNames="exception")
publicvoidafterReturningMethod(JoinPointjoinPoint, Exceptione) throwsThrowable{
if(e!=null){
SysLogsysLog=newSysLog();
longbeginTime=System.currentTimeMillis();
longtime=System.currentTimeMillis() -beginTime;
MethodSignaturesignature= (MethodSignature) joinPoint.getSignature();
Methodmethod=signature.getMethod();
// 接收到请求,记录请求内容ServletRequestAttributesattributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequestrequest=attributes.getRequest();
sysLog.setId(IdGenerate.longUUIDId());//主键sysLog.setLogId(sysLog.getId().toString());//日志编号sysLog.setTime(time);//时长sysLog.setIp(request.getRemoteAddr());//请求的IPsysLog.setCreateBy(sysLog.getIp());//请求人sysLog.setCreateTime( newDate() );//创建时间SysLogAspectValuesysLogAspectValue=method.getAnnotation(SysLogAspectValue.class);
if(sysLogAspectValue!=null){
//注解上的描述sysLog.setLogComment(sysLogAspectValue.describtion());//备注sysLog.setLogType(sysLogAspectValue.logType());//日志类型sysLog.setType(sysLogAspectValue.type());//请求类型sysLog.setUrl(sysLogAspectValue.url());//请求链接sysLog.setTable(sysLogAspectValue.table());//操作的数据表sysLog.setMethod(sysLogAspectValue.method());//操作请求方法            }
//请求的 类名、方法名sysLog.setClassName(joinPoint.getTarget().getClass().getName());//类名sysLog.setMethodName(signature.getName());//方法名//请求的参数Object[] args=joinPoint.getArgs();
List<String>list=newArrayList<String>();
for (Objecto : args) {
list.add(newGson().toJson(o));
            }
sysLog.setParams("Params:[ "+list.toString()+" ]:Aspectj @AfterThrowing");
sysLog.setLogError(joinPoint.getSignature().getName()+"[ message:"+e.getMessage() +"]:Aspectj @AfterThrowing");
System.out.println("=====异常保存日志成功==============================");
sysLogService.save(sysLog);
log.trace(POINT_CUT, sysLog);
System.out.println("=====异常保存日志  结束=========================");
        }
    }
/*** 正常保存日志* @param joinPoint* @param time* @throws Throwable */publicvoidsaveLog(ProceedingJoinPointjoinPoint, longtime) {
SysLogsysLog=newSysLog();
sysLog=this.addSysLog(joinPoint,sysLog , time );
//请求的参数Object[] args=joinPoint.getArgs();
List<String>list=newArrayList<String>();
for (Objecto : args) {
list.add(newGson().toJson(o));
        }
sysLog.setParams("Params:[ "+list.toString()+" ]:Aspectj @Around");
sysLog.setLogError( "[ message: 无 ]:Aspectj @Around");
System.out.println("=====正常保存日志成功==============================");
sysLogService.save(sysLog);
log.trace(POINT_CUT, sysLog);
System.out.println("=====正常保存日志  结束=========================");
    }
/*** 组装日志model* @Title: addSysLog* @Description: TODO(描述)* @param sysLog* @return* @author author* @date 2019-12-10 02:09:04*/publicSysLogaddSysLog(ProceedingJoinPointjoinPoint, SysLogsysLog , longtime) {
MethodSignaturesignature= (MethodSignature) joinPoint.getSignature();
Methodmethod=signature.getMethod();
// 接收到请求,记录请求内容ServletRequestAttributesattributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequestrequest=attributes.getRequest();
sysLog.setId(IdGenerate.longUUIDId());//主键sysLog.setLogId(sysLog.getId().toString());//日志编号sysLog.setTime(time);//时长sysLog.setIp(request.getRemoteAddr());//请求的IPsysLog.setCreateBy(sysLog.getIp());//请求人sysLog.setCreateTime( newDate() );//创建时间SysLogAspectValuesysLogAspectValue=method.getAnnotation(SysLogAspectValue.class);
if(sysLogAspectValue!=null){
//注解上的描述sysLog.setLogComment(sysLogAspectValue.describtion());//备注sysLog.setLogType(sysLogAspectValue.logType());//日志类型sysLog.setType(sysLogAspectValue.type());//请求类型sysLog.setUrl(sysLogAspectValue.url());//请求链接sysLog.setTable(sysLogAspectValue.table());//操作的数据表sysLog.setMethod(sysLogAspectValue.method());//操作请求方法        }
//请求的 类名、方法名sysLog.setClassName(joinPoint.getTarget().getClass().getName());//类名sysLog.setMethodName(signature.getName());//方法名returnsysLog;
    }
}

生成这个Log切面日志的用法:

image.png


转载声明:本文为博主原创文章,未经博主允许不得转载

⚠️注意 ~

💯本期内容就结束了,如果内容有误,麻烦大家评论区指出!

如有疑问❓可以在评论区💬或私信💬,尽我最大能力🏃‍♀️帮大家解决👨‍🏫!

如果我的文章有帮助到您,欢迎点赞+关注✔️鼓励博主🏃,您的鼓励是我分享的动力🏃🏃🏃~

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
17天前
|
存储 缓存 关系型数据库
图解MySQL【日志】——Redo Log
Redo Log(重做日志)是数据库中用于记录数据页修改的物理日志,确保事务的持久性和一致性。其主要作用包括崩溃恢复、提高性能和保证事务一致性。Redo Log 通过先写日志的方式,在内存中缓存修改操作,并在适当时候刷入磁盘,减少随机写入带来的性能损耗。WAL(Write-Ahead Logging)技术的核心思想是先将修改操作记录到日志文件中,再择机写入磁盘,从而实现高效且安全的数据持久化。Redo Log 的持久化过程涉及 Redo Log Buffer 和不同刷盘时机的控制参数(如 `innodb_flush_log_at_trx_commit`),以平衡性能与数据安全性。
27 5
图解MySQL【日志】——Redo Log
|
19天前
|
存储 关系型数据库 MySQL
图解MySQL【日志】——Undo Log
Undo Log(回滚日志)是 MySQL 中用于实现事务原子性和一致性的关键机制。在默认的自动提交模式下,MySQL 隐式开启事务,每条增删改语句都会记录到 Undo Log 中。其主要作用包括:
32 0
|
1月前
|
存储 SQL 关系型数据库
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log、原理、写入过程;binlog与redolog区别、update语句的执行流程、两阶段提交、主从复制、三种日志的使用场景;查询日志、慢查询日志、错误日志等其他几类日志
105 35
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log
|
2月前
|
SQL 关系型数据库 MySQL
MySQL事务日志-Undo Log工作原理分析
事务的持久性是交由Redo Log来保证,原子性则是交由Undo Log来保证。如果事务中的SQL执行到一半出现错误,需要把前面已经执行过的SQL撤销以达到原子性的目的,这个过程也叫做"回滚",所以Undo Log也叫回滚日志。
118 7
MySQL事务日志-Undo Log工作原理分析
|
3月前
|
监控 安全 Apache
什么是Apache日志?为什么Apache日志分析很重要?
Apache是全球广泛使用的Web服务器软件,支持超过30%的活跃网站。它通过接收和处理HTTP请求,与后端服务器通信,返回响应并记录日志,确保网页请求的快速准确处理。Apache日志分为访问日志和错误日志,对提升用户体验、保障安全及优化性能至关重要。EventLog Analyzer等工具可有效管理和分析这些日志,增强Web服务的安全性和可靠性。
|
3月前
|
存储 监控 安全
什么是事件日志管理系统?事件日志管理系统有哪些用处?
事件日志管理系统是IT安全的重要工具,用于集中收集、分析和解释来自组织IT基础设施各组件的事件日志,如防火墙、路由器、交换机等,帮助提升网络安全、实现主动威胁检测和促进合规性。系统支持多种日志类型,包括Windows事件日志、Syslog日志和应用程序日志,通过实时监测、告警及可视化分析,为企业提供强大的安全保障。然而,实施过程中也面临数据量大、日志管理和分析复杂等挑战。EventLog Analyzer作为一款高效工具,不仅提供实时监测与告警、可视化分析和报告功能,还支持多种合规性报告,帮助企业克服挑战,提升网络安全水平。
131 2
|
4月前
|
存储 监控 安全
什么是日志管理,如何进行日志管理?
日志管理是对IT系统生成的日志数据进行收集、存储、分析和处理的实践,对维护系统健康、确保安全及获取运营智能至关重要。本文介绍了日志管理的基本概念、常见挑战、工具的主要功能及选择解决方案的方法,强调了定义管理目标、日志收集与分析、警报和报告、持续改进等关键步骤,以及如何应对数据量大、安全问题、警报疲劳等挑战,最终实现日志数据的有效管理和利用。
454 0
|
4月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
1136 31
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
5月前
|
Python
log日志学习
【10月更文挑战第9天】 python处理log打印模块log的使用和介绍
120 0
|
5月前
|
数据可视化
Tensorboard可视化学习笔记(一):如何可视化通过网页查看log日志
关于如何使用TensorBoard进行数据可视化的教程,包括TensorBoard的安装、配置环境变量、将数据写入TensorBoard、启动TensorBoard以及如何通过网页查看日志文件。
439 0