Skip to content

Commit

Permalink
feat: 修改LogRecordThreadWrapper 优化单元测试
Browse files Browse the repository at this point in the history
  • Loading branch information
qqxx6661 committed Nov 21, 2022
1 parent 631ac1e commit e8d93f7
Show file tree
Hide file tree
Showing 13 changed files with 217 additions and 148 deletions.
78 changes: 64 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ public Response<T> function(Request request) {
- [重复注解](#重复注解)
- [消息分发线程池配置](#消息分发线程池配置)
- [函数返回值记录开关](#函数返回值记录开关)
- [日志处理线程池前置处理](#日志处理线程池前置处理)
- [让注解支持IDEA自动补全](#让注解支持IDEA自动补全)

### SpEL的使用
Expand Down Expand Up @@ -494,44 +495,67 @@ public Response<T> function(Request request) {

### 自定义函数

@LogRecordFunc注解申明在需要注册到SpEL的自定义函数上。
@LogRecordFunc注解申明在需要注册到SpEL的自定义函数上,参与SpEL表达式的运算

注意,需要在类上也声明@LogRecordFunc,否则无法找到该函数。

@LogRecordFunc可以添加参数value,实现自定义方法别名,若不添加,则默认不需要写前缀
@LogRecordFunc可以添加参数value,实现自定义方法别名,若不添加,则默认不需要写前缀。

分为静态和非静态方法两种处理方式。

静态自定义方法是SpEL天生支持的,所以写法如下:

```
@LogRecordFunc("test")
public class CustomFunctionService {
@LogRecordFunc("CustomFunctionStatic")
public class CustomFunctionStatic {
@LogRecordFunc("testMethodWithCustomName")
public static String testMethodWithCustomName(){
return "testMethodWithCustomName";
@LogRecordFunc("testStaticMethodWithCustomName")
public static String testStaticMethodWithCustomName(){
return "testStaticMethodWithCustomName";
}
@LogRecordFunc
public static String testMethodWithoutCustomName(){
return "testMethodWithoutCustomName";
public static String testStaticMethodWithoutCustomName(){
return "testStaticMethodWithoutCustomName";
}
}
```

上述代码中,注册的自定义函数名为`test_testMethodWithCustomName``test_testMethodWithoutCustomName`,若类上的注解更改为`@LogRecordFunc("test")`,则注册的自定义函数名为`testMethodWithCustomName``testMethodWithoutCustomName`
上述代码中,注册的自定义函数名为`CustomFunctionStatic_testStaticMethodWithoutCustomName``CustomFunctionStatic_testStaticMethodWithoutCustomName`,若类上的注解更改为`@LogRecordFunc("test")`,则注册的自定义函数名为`testStaticMethodWithCustomName``testStaticMethodWithoutCustomName`

非静态的自定义方法(比如直接调用Spring的Service)写法如下:

```
@Service
@Slf4j
@LogRecordFunc("CustomFunctionService")
public class CustomFunctionService {
@LogRecordFunc
public TestUser testUser() {
return new TestUser(1, "asd");
}
}
```

其原理主要是依靠我们框架内部转换,将非静态方法需要包装为静态方法再传给SpEL。原理详见[#PR25](https://github.com/qqxx6661/logRecord/pull/25/)



注意:所有自定义函数可在应用启动时的日志中找到

```
2022-06-09 11:35:18.672 INFO 73757 --- [ main] c.a.i.l.f.CustomFunctionRegistrar : LogRecord register custom function [public static java.lang.String cn.monitor4all.logRecord.test.service.CustomFunctionService.testMethodWithCustomName()] as name [test_testMethodWithCustomName]
2022-06-09 11:35:18.672 INFO 73757 --- [ main] c.a.i.l.f.CustomFunctionRegistrar : LogRecord register custom function [public static java.lang.String cn.monitor4all.logRecord.test.service.CustomFunctionService.testMethodWithoutCustomName()] as name [test_testMethodWithoutCustomName]
2022-06-09 11:35:18.672 INFO 73757 --- [ main] c.a.i.l.f.CustomFunctionRegistrar : LogRecord register custom function [public static java.lang.String cn.monitor4all.logRecord.test.service.CustomFunctionStaticService.testStaticMethodWithCustomName()] as name [CustomFunctionStatic_testStaticMethodWithoutCustomName]
2022-06-09 11:35:18.672 INFO 73757 --- [ main] c.a.i.l.f.CustomFunctionRegistrar : LogRecord register custom function [public static java.lang.String cn.monitor4all.logRecord.test.service.CustomFunctionStaticService.testStaticMethodWithoutCustomName()] as name [CustomFunctionStatic_testStaticMethodWithoutCustomName]
2022-06-09 11:35:18.672 INFO 73757 --- [ main] c.a.i.l.f.CustomFunctionRegistrar : LogRecord register custom function [public static java.lang.String cn.monitor4all.logRecord.function.CustomFunctionObjectDiff.objectDiff(java.lang.Object,java.lang.Object)] as name [_DIFF]
```

注解中使用:

```
@OperationLog(bizId = "#test_testMethodWithCustomName()", bizType = "'testMethodWithCustomName'")
@OperationLog(bizId = "#test_testMethodWithoutCustomName()", bizType = "'testMethodWithoutCustomName'")
@OperationLog(bizId = "#CustomFunctionStatic_testStaticMethodWithCustomName()", bizType = "'testStaticMethodWithCustomName'")
@OperationLog(bizId = "#CustomFunctionStatic_testStaticMethodWithoutCustomName()", bizType = "'testStaticMethodWithoutCustomName'")
public void testCustomFunc() {
}
```
Expand Down Expand Up @@ -778,6 +802,32 @@ log-record.thread-pool.enabled=true(线程池开关 默认为开启 若关闭

@OperationLog注解提供布尔值recordReturnValue() 用于是否开启记录函数返回值,默认关闭,防止返回值实体过大,造成序列化时性能消耗过多。


### 日志处理线程池前置处理

在使用线程池处理包装好的日志之前,很多人有一些特殊逻辑需要插入,比如将traceId放入上下文,这里开放接口在logDTO发送给线程池前允许加入用户自定义逻辑。

使用方式如下,添加SpringBean覆写LogRecordThreadWrapper

````
@Slf4j
@Configuration
public class LogRecordConfig {
@Bean
public LogRecordThreadWrapper logRecordThreadWrapper() {
return new LogRecordThreadWrapper() {
@Override
public Runnable createLog(Consumer<LogDTO> consumer, LogDTO logDTO) {
log.info("Before send createLog task to LogRecordThreadPool. Current thread [{}]", Thread.currentThread().getName());
return LogRecordThreadWrapper.super.createLog(consumer, logDTO);
}
};
}
}
````

### 让注解支持IDEA自动补全

在自定义注解想实现类似@Cacheable的自动补全,其实是IDEA等IDE自己的支持,可以在配置中将本二方库的注解添加上去,从而支持自动补全和SpEL表达式校验。
Expand Down
17 changes: 5 additions & 12 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<groupId>cn.monitor4all</groupId>
<artifactId>log-record-starter</artifactId>
<version>1.3.1</version>
<version>1.4.0-SNAPSHOT</version>

<dependencies>

Expand Down Expand Up @@ -86,13 +86,6 @@
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.28.0-GA</version>
<!-- <type>bundle</type>-->
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.12.6</version>
<scope>test</scope>
</dependency>
</dependencies>

Expand Down Expand Up @@ -136,17 +129,17 @@


<profiles>
<!-- idea右侧maven页签勾选自己的定制化属性,每个开发者根据本地情况可以配一套 -->
<profile>
<id>dc.mao</id>
<id>user</id>
<properties>
<doc.path>${java.home}/bin/javadoc</doc.path>
<!-- 可自行更改 -->
<doc.path>${java.home}/../bin/javadoc</doc.path>
</properties>
</profile>

<!-- 原pom参数,默认执行 -->
<profile>
<id>cloud</id>
<id>admin</id>
<activation>
<!-- 默认激活此profile -->
<activeByDefault>true</activeByDefault>
Expand Down
10 changes: 4 additions & 6 deletions src/main/java/cn/monitor4all/logRecord/aop/SystemLogAspect.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
import cn.monitor4all.logRecord.configuration.LogRecordProperties;
import cn.monitor4all.logRecord.context.LogRecordContext;
import cn.monitor4all.logRecord.function.CustomFunctionRegistrar;
import cn.monitor4all.logRecord.service.IOperationLogGetService;
import cn.monitor4all.logRecord.service.IOperatorIdGetService;
import cn.monitor4all.logRecord.service.DataPipelineService;
import cn.monitor4all.logRecord.service.LogRecordErrorHandlerService;
import cn.monitor4all.logRecord.service.*;
import cn.monitor4all.logRecord.thread.LogRecordThreadPool;
import cn.monitor4all.logRecord.thread.LogRecordThreadWrapper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -56,7 +54,7 @@ public class SystemLogAspect {
private LogRecordErrorHandlerService logRecordErrorHandlerService;

@Autowired
private SystemLogThreadWrapper systemLogThreadWrapper;
private LogRecordThreadWrapper logRecordThreadWrapper;

private final SpelExpressionParser parser = new SpelExpressionParser();

Expand Down Expand Up @@ -163,7 +161,7 @@ public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
Long finalExecutionTime = executionTime;
Consumer<LogDTO> createLogFunction = logDTO -> createLog(logDTO, finalExecutionTime);
if (logRecordThreadPool != null) {
logDTOList.forEach(logDTO -> logRecordThreadPool.getLogRecordPoolExecutor().execute(systemLogThreadWrapper.createLog(createLogFunction, logDTO)));
logDTOList.forEach(logDTO -> logRecordThreadPool.getLogRecordPoolExecutor().execute(logRecordThreadWrapper.createLog(createLogFunction, logDTO)));
} else {
logDTOList.forEach(createLogFunction);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.springframework.context.annotation.Import;

@ComponentScan("cn.monitor4all.logRecord")
@Import({RabbitMqSenderConfiguration.class, RocketMqSenderConfiguration.class})
@Import({RabbitMqSenderConfiguration.class, RocketMqSenderConfiguration.class, StreamSenderConfiguration.class})
public class LogRecordAutoConfiguration {

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cn.monitor4all.logRecord.configuration;

import cn.monitor4all.logRecord.aop.SystemLogThreadWrapper;
import cn.monitor4all.logRecord.thread.LogRecordThreadWrapper;
import cn.monitor4all.logRecord.function.CustomFunctionRegistrar;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
Expand All @@ -9,7 +9,7 @@

@Slf4j
@Configuration
public class CustomFunctionConfiguration {
public class LogRecordConfiguration {

@Bean
public CustomFunctionRegistrar registrar() {
Expand All @@ -19,7 +19,7 @@ public CustomFunctionRegistrar registrar() {

@Bean
@ConditionalOnMissingBean
public SystemLogThreadWrapper createLogConsumer() {
return new SystemLogThreadWrapper(){};
public LogRecordThreadWrapper createLogConsumer() {
return new LogRecordThreadWrapper(){};
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cn.monitor4all.logRecord.aop;
package cn.monitor4all.logRecord.thread;

import cn.monitor4all.logRecord.bean.LogDTO;

Expand All @@ -11,19 +11,18 @@
* <p>@Configuration<br>
* <p>public class LogRecordConfig<br>
* <p>&emsp;&emsp;@Bean<br>
* <p>&emsp;&emsp;public SystemLogThreadWrapper systemLogThreadWrapper() {<br>
* <p>&emsp;&emsp;&emsp;&emsp;return new SystemLogThreadWrapper() {<br>
* <p>&emsp;&emsp;public LogRecordThreadWrapper logRecordThreadWrapper() {<br>
* <p>&emsp;&emsp;&emsp;&emsp;return new LogRecordThreadWrapper() {<br>
* <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;@Override<br>
* <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;public Runnable createLog(Consumer&#60;LogDTO&#62; consumer, LogDTO logDTO) {<br>
* <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;return RunnableWrapper.of(new SystemLogThreadWrapper(){}.createLog(consumer, logDTO));<br>
* <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;return RunnableWrapper.of(new LogRecordThreadWrapper(){}.createLog(consumer, logDTO));<br>
* <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;}<br>
* <p>&emsp;&emsp;&emsp;&emsp;};<br>
* <p>&emsp;&emsp;}<br>
* <p>}<br>
* @author : dechao.mao
* @since : Created in 10:30 2022/11/10
*/
public interface SystemLogThreadWrapper {
public interface LogRecordThreadWrapper {

/**
* 暴露多线程执行任务,方便业务层对多线程任务包装
Expand All @@ -33,9 +32,7 @@ public interface SystemLogThreadWrapper {
* @return 输出日志任务
*/
default Runnable createLog(Consumer<LogDTO> consumer, LogDTO logDTO) {
return () -> {
consumer.accept(logDTO);
};
return () -> consumer.accept(logDTO);
}

}
40 changes: 4 additions & 36 deletions src/test/java/cn/monitor4all/logRecord/test/LogOperationTest.java
Original file line number Diff line number Diff line change
@@ -1,34 +1,22 @@
package cn.monitor4all.logRecord.test;

import cn.monitor4all.logRecord.aop.SystemLogAspect;
import cn.monitor4all.logRecord.aop.SystemLogThreadWrapper;
import cn.monitor4all.logRecord.bean.LogDTO;
import cn.monitor4all.logRecord.configuration.LogRecordAutoConfiguration;
import cn.monitor4all.logRecord.function.CustomFunctionRegistrar;
import cn.monitor4all.logRecord.test.bean.TestComplexUser;
import cn.monitor4all.logRecord.test.bean.TestUser;
import cn.monitor4all.logRecord.test.bean.diff.TestDiffDuty;
import cn.monitor4all.logRecord.test.bean.diff.TestDiffJob;
import cn.monitor4all.logRecord.test.bean.diff.TestDiffUserParam;
import cn.monitor4all.logRecord.test.service.OperatorIdGetService;
import cn.monitor4all.logRecord.test.service.TestService;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.TtlRunnable;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.trace.TraceContext;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.test.context.ContextConfiguration;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.function.Consumer;

/**
* 单元测试
Expand All @@ -46,11 +34,8 @@ public class LogOperationTest {
@Autowired
private TestService testService;

@Autowired
private SystemLogAspect systemLogAspect;

@Test
public void logRecordFuncTest() throws NoSuchFieldException, IllegalAccessException {
public void logRecordFuncTest() {
testService.testBizId("1");
testService.testTag("tag1");
testService.testRecordReturnValue();
Expand Down Expand Up @@ -78,26 +63,9 @@ public void logRecordFuncTest() throws NoSuchFieldException, IllegalAccessExcept
testService.testEnumAndConstantWithSpEL();
testService.testLogRecordContext();
testService.testMapUseInLogRecordContext();
testService.testSpringBeanFuncNoParam(new TestUser(2, "dsa"));
testService.testSpringBeanFuncWithParam(new TestUser(2, "dsa"));
testService.testSpringBeanFuncNoReturn(20);

TransmittableThreadLocal<String> parentThreadContext = TransmittableThreadLocal.withInitial(String::new);
parentThreadContext.set("xaazdddaq");
Field field = SystemLogAspect.class.getDeclaredField("systemLogThreadWrapper");
field.setAccessible(true);
// 模拟开启线程池后,业务和记录日志线程分离后,ThreadLocal传递情况, skywalking和transmittable原理一致
field.set(systemLogAspect, new SystemLogThreadWrapper() {
@Override
public Runnable createLog(Consumer<LogDTO> consumer, LogDTO logDTO) {
return TtlRunnable.get(
() -> {
log.info("children thread {}", parentThreadContext.get());
new SystemLogThreadWrapper(){}.createLog(consumer, logDTO);
});
}
});
testService.testSpringBeanFuncNoReturn(20);
testService.testSpringBeanCustomFuncNoParam(new TestUser(2, "dsa"));
testService.testSpringBeanCustomFuncWithParam(new TestUser(2, "dsa"));
testService.testSpringBeanCustomFuncNoReturn(20);
}

private TestDiffUserParam generateTestDiffUserParam() {
Expand Down
Loading

0 comments on commit e8d93f7

Please sign in to comment.