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日志并进行多维度分析。
相关文章
|
1月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
223 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
29天前
|
Java 中间件
SpringBoot入门(6)- 添加Logback日志
SpringBoot入门(6)- 添加Logback日志
72 5
|
21天前
|
Java 中间件
SpringBoot入门(6)- 添加Logback日志
SpringBoot入门(6)- 添加Logback日志
29 1
|
1月前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
43 1
|
2月前
|
Python
log日志学习
【10月更文挑战第9天】 python处理log打印模块log的使用和介绍
39 0
|
2月前
|
数据可视化
Tensorboard可视化学习笔记(一):如何可视化通过网页查看log日志
关于如何使用TensorBoard进行数据可视化的教程,包括TensorBoard的安装、配置环境变量、将数据写入TensorBoard、启动TensorBoard以及如何通过网页查看日志文件。
245 0
|
监控 Kubernetes Shell
使用阿里云日志服务采集查询kubernetes容器日志
使用阿里云日志收集查询kubernetes容器日志
2922 0
|
2月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
279 3
|
4月前
|
Kubernetes Ubuntu Windows
【Azure K8S | AKS】分享从AKS集群的Node中查看日志的方法(/var/log)
【Azure K8S | AKS】分享从AKS集群的Node中查看日志的方法(/var/log)
136 3
|
2月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1674 14