java 注解结合 spring aop 实现自动输出日志

tech2022-08-13  139

auto-log

auto-log 是一款为 java 设计的自动日志监控框架。

创作目的

经常会写一些工具,有时候手动加一些日志很麻烦,引入 spring 又过于大材小用。

所以希望从从简到繁实现一个工具,便于平时使用。

特性

基于注解+字节码,配置灵活

自动适配常见的日志框架

支持编程式的调用

支持注解式,完美整合 spring

支持整合 spring-boot

支持慢日志阈值指定,耗时,入参,出参,异常信息等常见属性指定

变更日志

核心原理

注解定义

import java.lang.annotation.*; /** * 自动注解 * @author binbin.hou * @since 0.0.1 */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface AutoLog { /** * 输出参数 * @return 参数 * @since 0.0.1 */ boolean param() default true; /** * 是否输出结果 * @return 结果 * @since 0.0.1 */ boolean result() default true; /** * 是否输出时间 * @return 耗时 * @since 0.0.1 */ boolean costTime() default false; /** * 是否输出异常信息 * @return 是否 * @since 0.0.6 */ boolean exception() default true; /** * 慢日志阈值 * * 当值小于 0 时,不进行慢日志统计。 * 当值大于等于0时,当前值只要大于等于这个值,就进行统计。 * @return 阈值 * @since 0.0.4 */ long slowThresholdMills() default -1; }

核心 AOP 实现

这里的 LogFactory 类是关键,可以兼容目前大部分的日志框架。

import com.github.houbb.auto.log.annotation.AutoLog; import com.github.houbb.heaven.response.exception.CommonRuntimeException; import com.github.houbb.log.integration.core.Log; import com.github.houbb.log.integration.core.LogFactory; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.stereotype.Component; import java.lang.reflect.Method; import java.util.Arrays; /** * 这是一种写法 * 自动日志输出 aop * @author binbin.hou * @since 0.0.3 */ @Aspect @Component @EnableAspectJAutoProxy public class AutoLogAop { private static final Log LOG = LogFactory.getLog(AutoLogAop.class); /** * 执行核心方法 * * 相当于 MethodInterceptor * @param point 切点 * @param autoLog 日志参数 * @return 结果 * @throws Throwable 异常信息 * @since 0.0.3 */ @Around("@annotation(autoLog)") public Object around(ProceedingJoinPoint point, AutoLog autoLog) throws Throwable { Method method = getCurrentMethod(point); String methodName = method.getName(); try { final long startMills = System.currentTimeMillis(); //1. 是否输入入参 if (autoLog.param()) { LOG.info("{} param is {}.", methodName, Arrays.toString(point.getArgs())); } //2. 执行方法 Object result = point.proceed(); //3. 结果 if (autoLog.result()) { LOG.info("{} result is {}.", methodName, result); } //3.1 耗时 final long slowThreshold = autoLog.slowThresholdMills(); if (autoLog.costTime() || slowThreshold >= 0) { final long endMills = System.currentTimeMillis(); long costTime = endMills - startMills; if (autoLog.costTime()) { LOG.info("{} cost time is {}ms.", methodName, costTime); } //3.2 慢日志 if (slowThreshold >= 0 && costTime >= slowThreshold) { LOG.warn("{} is slow log, {}ms >= {}ms.", methodName, costTime, slowThreshold); } } return result; } catch (Throwable e) { if(autoLog.exception()) { LOG.error("{} meet ex.", methodName, e); } throw e; } } /** * 获取当前方法信息 * * @param point 切点 * @return 方法 */ private Method getCurrentMethod(ProceedingJoinPoint point) { try { Signature sig = point.getSignature(); MethodSignature msig = (MethodSignature) sig; Object target = point.getTarget(); return target.getClass().getMethod(msig.getName(), msig.getParameterTypes()); } catch (NoSuchMethodException e) { throw new CommonRuntimeException(e); } } }

快速开始

maven 引入

<dependency> <group>com.github.houbb</group> <artifact>auto-log-core</artifact> <version>${最新版本}</version> </dependency>

入门案例

UserService userService = AutoLogHelper.proxy(new UserServiceImpl()); userService.queryLog("1"); 日志如下 [INFO] [2020-05-29 16:24:06.227] [main] [c.g.h.a.l.c.s.i.AutoLogMethodInterceptor.invoke] - public java.lang.String com.github.houbb.auto.log.test.service.impl.UserServiceImpl.queryLog(java.lang.String) param is [1] [INFO] [2020-05-29 16:24:06.228] [main] [c.g.h.a.l.c.s.i.AutoLogMethodInterceptor.invoke] - public java.lang.String com.github.houbb.auto.log.test.service.impl.UserServiceImpl.queryLog(java.lang.String) result is result-1

代码

其中方法实现如下:

UserService.java public interface UserService { String queryLog(final String id); } UserServiceImpl.java

直接使用注解 @AutoLog 指定需要打日志的方法即可。

public class UserServiceImpl implements UserService { @Override @AutoLog public String queryLog(String id) { return "result-"+id; } }

注解说明

核心注解 @AutoLog 的属性说明如下:

属性类型默认值说明parambooleantrue是否打印入参resultbooleantrue是否打印出参costTimebooleanfalse是否打印耗时exceptionbooleantrue是否打印异常slowThresholdMillslong-1当这个值大于等于 0 时,且耗时超过配置值,会输出慢日志

spring 整合使用

完整示例参考 SpringServiceTest

注解声明

使用 @EnableAutoLog 启用自动日志输出

@Configurable @ComponentScan(basePackages = "com.github.houbb.auto.log.test.service") @EnableAutoLog public class SpringConfig { }

测试代码

@ContextConfiguration(classes = SpringConfig.class) @RunWith(SpringJUnit4ClassRunner.class) public class SpringServiceTest { @Autowired private UserService userService; @Test public void queryLogTest() { userService.queryLog("1"); } } 输出结果 信息: public java.lang.String com.github.houbb.auto.log.test.service.impl.UserServiceImpl.queryLog(java.lang.String) param is [1] 五月 30, 2020 12:17:51 下午 com.github.houbb.auto.log.core.support.interceptor.AutoLogMethodInterceptor info 信息: public java.lang.String com.github.houbb.auto.log.test.service.impl.UserServiceImpl.queryLog(java.lang.String) result is result-1 五月 30, 2020 12:17:51 下午 org.springframework.context.support.GenericApplicationContext doClose

开源地址

Github: https://github.com/houbb/auto-log

Gitee: https://gitee.com/houbinbin/auto-log

欢迎 fork/star~

最新回复(0)