!5 集成skywalking

Merge pull request !5 from WangLH/featskywalking
This commit is contained in:
芋道源码 2021-04-27 00:45:52 +08:00 committed by Gitee
commit 135acaf7ba
23 changed files with 1010 additions and 104 deletions

View File

@ -56,7 +56,8 @@
| | MySQL 监控 | 监视当前系统数据库连接池状态可进行分析SQL找出系统性能瓶颈 |
| | Redis 监控 |监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |
| 🚀 |Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 |
| 🚀 | 链路追踪 | 基于 SkyWalking 实现性能监控,特别是链路的追踪 |
| 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 |
| 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 |
| 🚀 | 分布式锁 | 基于 Redis 实现分布式锁,满足并发场景 |
| 🚀 | 幂等组件 | 基于 Redis 实现幂等组件,解决重复请求问题 |
| 🚀 | 服务保障 | 基于 Resilience4j 实现服务的稳定性,包括限流、熔断等功能 |

View File

@ -26,6 +26,8 @@ JAVA_OPS="-Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$HE
# SkyWalking Agent 配置
export SW_AGENT_NAME=$SERVER_NAME
export SW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.0.84:11800
export SW_GRPC_LOG_SERVER_HOST=192.168.0.84
export SW_AGENT_TRACE_IGNORE_PATH="Redisson/PING,/actuator/**,/admin/**"
export JAVA_AGENT=-javaagent:/work/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar
# 备份

13
pom.xml
View File

@ -38,7 +38,8 @@
<lock4j.version>2.2.0</lock4j.version>
<resilience4j.version>1.7.0</resilience4j.version>
<!-- 监控相关 -->
<skywalking.version>8.3.0</skywalking.version>
<skywalking.version>8.5.0</skywalking.version>
<logback.encoder.version>6.1</logback.encoder.version>
<spring-boot-admin.version>2.3.1</spring-boot-admin.version>
<!-- 工具类相关 -->
<lombok.version>1.16.14</lombok.version>
@ -190,6 +191,16 @@
<artifactId>apm-toolkit-trace</artifactId>
<version>${skywalking.version}</version>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>${skywalking.version}</version>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-opentracing</artifactId>
<version>${skywalking.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>

View File

@ -8,7 +8,7 @@ export default {
name: "SkyWalking",
data() {
return {
src: "http://skywalking.shop.iocoder.cn", // TODO
src: "http://skywalking.shop.iocoder.cn/trace", // TODO
height: document.documentElement.clientHeight - 94.5 + "px;",
loading: true
};

View File

@ -0,0 +1,26 @@
<template>
<div v-loading="loading" :style="'height:'+ height">
<iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" />
</div>
</template>
<script>
export default {
name: "SkyWalking-Log",
data() {
return {
src: "http://skywalking.shop.iocoder.cn/log", // TODO
height: document.documentElement.clientHeight - 94.5 + "px;",
loading: true
};
},
mounted: function() {
setTimeout(() => {
this.loading = false;
}, 230);
const that = this;
window.onresize = function temp() {
that.height = document.documentElement.clientHeight - 94.5 + "px;";
};
}
};
</script>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,56 @@
package cn.iocoder.dashboard.framework.tracer.config;
import cn.iocoder.dashboard.framework.tracer.core.aop.BizTraceAspect;
import cn.iocoder.dashboard.framework.tracer.core.filter.TraceFilter;
import cn.iocoder.dashboard.framework.web.core.enums.FilterOrderEnum;
import io.opentracing.Tracer;
import org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Tracer 配置类
*
* @author mashu
*/
@Configuration
@ConditionalOnClass({BizTraceAspect.class})
@EnableConfigurationProperties(TracerProperties.class)
@ConditionalOnProperty(prefix = "yudao.tracer", value = "enable", matchIfMissing = true)
public class TracerAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public TracerProperties bizTracerProperties() {
return new TracerProperties();
}
@Bean
@ConditionalOnMissingBean
public BizTraceAspect bizTracingAop() {
return new BizTraceAspect();
}
@Bean
@ConditionalOnMissingBean
public Tracer tracer() {
return new SkywalkingTracer();
}
/**
* 创建 TraceFilter 过滤器响应 header 设置 traceId
*/
@Bean
public FilterRegistrationBean<TraceFilter> traceFilter() {
FilterRegistrationBean<TraceFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new TraceFilter());
registrationBean.setOrder(FilterOrderEnum.TRACE_FILTER);
return registrationBean;
}
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.dashboard.framework.tracer.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* BizTracer配置类
*
* @author 麻薯
*/
@ConfigurationProperties("yudao.tracer")
@Data
public class TracerProperties {
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.dashboard.framework.tracer.core.annotation;
import java.lang.annotation.*;
/**
* 打印业务编号 / 业务类型注解
*
* 使用时需要设置 SkyWalking OAP Server application.yaml 配置文件修改 SW_SEARCHABLE_TAG_KEYS 配置项
* 增加 biz.type biz.id 两值然后重启 SkyWalking OAP Server 服务器
*
* @author 麻薯
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface BizTrace {
/**
* 业务编号 tag
*/
String ID_TAG = "biz.id";
/**
* 业务类型 tag
*/
String TYPE_TAG = "biz.type";
/**
* @return 操作名
*/
String operationName() default "";
/**
* @return 业务编号
*/
String id();
/**
* @return 业务类型
*/
String type();
}

View File

@ -0,0 +1,70 @@
package cn.iocoder.dashboard.framework.tracer.core.aop;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.framework.tracer.core.annotation.BizTrace;
import cn.iocoder.dashboard.util.sping.SpringExpressionUtils;
import io.opentracing.Span;
import io.opentracing.Tracer;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import javax.annotation.Resource;
import java.util.Map;
import static java.util.Arrays.asList;
/**
* {@link BizTrace} 切面记录业务链路
*
* @author mashu
*/
@Aspect
@Slf4j
public class BizTraceAspect {
private static final String BIZ_OPERATION_NAME_PREFIX = "Biz/";
@Resource
private Tracer tracer;
@Around(value = "@annotation(trace)")
public Object around(ProceedingJoinPoint joinPoint, BizTrace trace) throws Throwable {
// 创建 span
String operationName = getOperationName(joinPoint, trace);
Span span = tracer.buildSpan(operationName).startManual();
try {
// 执行原有方法
return joinPoint.proceed();
} finally {
// 设置 Span biz 属性
setBizTag(span, joinPoint, trace);
// 完成 Span
span.finish();
}
}
private String getOperationName(ProceedingJoinPoint joinPoint, BizTrace trace) {
// 自定义操作名
if (StrUtil.isNotEmpty(trace.operationName())) {
return BIZ_OPERATION_NAME_PREFIX + trace.operationName();
}
// 默认操作名使用方法名
return BIZ_OPERATION_NAME_PREFIX
+ joinPoint.getSignature().getDeclaringType().getSimpleName()
+ "/" + joinPoint.getSignature().getName();
}
private void setBizTag(Span span, ProceedingJoinPoint joinPoint, BizTrace trace) {
try {
Map<String, Object> result = SpringExpressionUtils.parseExpressions(joinPoint, asList(trace.type(), trace.id()));
span.setTag(BizTrace.TYPE_TAG, MapUtil.getStr(result, trace.type()));
span.setTag(BizTrace.ID_TAG, MapUtil.getStr(result, trace.id()));
} catch (Exception ex) {
log.error("[setBizTag][解析 bizType 与 bizId 发生异常]", ex);
}
}
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.dashboard.framework.tracer.core.filter;
import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Trace 过滤器打印 traceId header 中返回
*
* @author 芋道源码
*/
public class TraceFilter extends OncePerRequestFilter {
/**
* Header - 链路追踪编号
*/
private static final String HEADER_NAME_TRACE_ID = "trace-id";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 设置响应 traceId
response.addHeader(HEADER_NAME_TRACE_ID, TracerUtils.getTraceId());
// 继续过滤
chain.doFilter(request, response);
}
}

View File

@ -1,10 +1,7 @@
package cn.iocoder.dashboard.framework.tracer.core.util;
import cn.hutool.core.util.StrUtil;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import java.util.UUID;
/**
* 链路追踪工具类
*
@ -13,24 +10,19 @@ import java.util.UUID;
public class TracerUtils {
/**
* 获得链路追踪编号
*
* 一般来说通过链路追踪编号可以将访问日志错误日志链路追踪日志logger 打印日志等结合在一起从而进行排错
*
* 默认情况下我们使用 Apache SkyWalking traceId 作为链路追踪编号当然可能会存在并未引入 Skywalking 的情况此时使用 UUID
* 私有化构造方法
*/
private TracerUtils() {
}
/**
* 获得链路追踪编号直接返回 SkyWalking TraceId
* 如果不存在的话为空字符串
*
* @return 链路追踪编号
*/
public static String getTraceId() {
// 通过 SkyWalking 获取链路编号
try {
String traceId = TraceContext.traceId();
if (StrUtil.isNotBlank(traceId)) {
return traceId;
}
} catch (Throwable ignore) {}
// TODO 芋艿 多次调用会问题
return UUID.randomUUID().toString();
return TraceContext.traceId();
}
}

View File

@ -1,6 +1,6 @@
/**
* 链路追踪
* 使用 SkyWalking 组件作为链路追踪日志中心
*
* 主要目的是生成全局的链路追踪编号
* @author 芋道源码
*/
package cn.iocoder.dashboard.framework.tracer;

View File

@ -9,6 +9,7 @@ public interface FilterOrderEnum {
int CORS_FILTER = Integer.MIN_VALUE;
int TRACE_FILTER = CORS_FILTER + 1;
int REQUEST_BODY_CACHE_FILTER = Integer.MIN_VALUE + 500;

View File

@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.controller.auth;
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
import cn.iocoder.dashboard.framework.tracer.core.annotation.BizTrace;
import cn.iocoder.dashboard.modules.system.controller.auth.vo.auth.SysAuthLoginReqVO;
import cn.iocoder.dashboard.modules.system.controller.auth.vo.auth.SysAuthLoginRespVO;
import cn.iocoder.dashboard.modules.system.controller.auth.vo.auth.SysAuthMenuRespVO;

View File

@ -5,12 +5,11 @@ import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
import cn.iocoder.dashboard.framework.tracer.core.annotation.BizTrace;
import cn.iocoder.dashboard.modules.tool.controller.test.vo.*;
import cn.iocoder.dashboard.modules.tool.convert.test.ToolTestDemoConvert;
import cn.iocoder.dashboard.modules.tool.dal.dataobject.test.ToolTestDemoDO;
import cn.iocoder.dashboard.modules.tool.service.test.ToolTestDemoService;
import com.baomidou.lock.annotation.Lock4j;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
@ -66,7 +65,7 @@ public class ToolTestDemoController {
@ApiOperation("获得测试示例")
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
@Lock4j // 分布式锁
// @Lock4j // 分布式锁
public CommonResult<ToolTestDemoRespVO> getTestDemo(@RequestParam("id") Long id) {
if (true) { // 测试分布式锁
ThreadUtil.sleep(5, TimeUnit.SECONDS);
@ -79,7 +78,8 @@ public class ToolTestDemoController {
@ApiOperation("获得测试示例列表")
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, dataTypeClass = List.class)
@PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
@RateLimiter(name = "backendA")
// @RateLimiter(name = "backendA")
@BizTrace(id = "#ids", type = "'user'")
public CommonResult<List<ToolTestDemoRespVO>> getTestDemoList(@RequestParam("ids") Collection<Long> ids) {
List<ToolTestDemoDO> list = testDemoService.getTestDemoList(ids);
return success(ToolTestDemoConvert.INSTANCE.convertList(list));

View File

@ -1,46 +1,46 @@
package cn.iocoder.dashboard.util;
import cn.hutool.core.bean.BeanUtil;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;
/**
* Spring AOP 工具类
*
* 参考波克尔 http://www.bubuko.com/infodetail-3471885.html 实现
*/
public class AopTargetUtils {
/**
* 获取代理的目标对象
*
* @param proxy 代理对象
* @return 目标对象
*/
public static Object getTarget(Object proxy) throws Exception {
// 不是代理对象
if (!AopUtils.isAopProxy(proxy)) {
return proxy;
}
// Jdk 代理
if (AopUtils.isJdkDynamicProxy(proxy)) {
return getJdkDynamicProxyTargetObject(proxy);
}
// Cglib 代理
return getCglibProxyTargetObject(proxy);
}
private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
Object dynamicAdvisedInterceptor = BeanUtil.getFieldValue(proxy, "CGLIB$CALLBACK_0");
AdvisedSupport advisedSupport = (AdvisedSupport) BeanUtil.getFieldValue(dynamicAdvisedInterceptor, "advised");
return advisedSupport.getTargetSource().getTarget();
}
private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
AopProxy aopProxy = (AopProxy) BeanUtil.getFieldValue(proxy, "h");
AdvisedSupport advisedSupport = (AdvisedSupport) BeanUtil.getFieldValue(aopProxy, "advised");
return advisedSupport.getTargetSource().getTarget();
}
}
package cn.iocoder.dashboard.util.sping;
import cn.hutool.core.bean.BeanUtil;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;
/**
* Spring AOP 工具类
*
* 参考波克尔 http://www.bubuko.com/infodetail-3471885.html 实现
*/
public class SpringAopUtils {
/**
* 获取代理的目标对象
*
* @param proxy 代理对象
* @return 目标对象
*/
public static Object getTarget(Object proxy) throws Exception {
// 不是代理对象
if (!AopUtils.isAopProxy(proxy)) {
return proxy;
}
// Jdk 代理
if (AopUtils.isJdkDynamicProxy(proxy)) {
return getJdkDynamicProxyTargetObject(proxy);
}
// Cglib 代理
return getCglibProxyTargetObject(proxy);
}
private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
Object dynamicAdvisedInterceptor = BeanUtil.getFieldValue(proxy, "CGLIB$CALLBACK_0");
AdvisedSupport advisedSupport = (AdvisedSupport) BeanUtil.getFieldValue(dynamicAdvisedInterceptor, "advised");
return advisedSupport.getTargetSource().getTarget();
}
private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
AopProxy aopProxy = (AopProxy) BeanUtil.getFieldValue(proxy, "h");
AdvisedSupport advisedSupport = (AdvisedSupport) BeanUtil.getFieldValue(aopProxy, "advised");
return advisedSupport.getTargetSource().getTarget();
}
}

View File

@ -0,0 +1,82 @@
package cn.iocoder.dashboard.util.sping;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Spring EL 表达式的工具类
*
* @author mashu
*/
public class SpringExpressionUtils {
private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
private SpringExpressionUtils() {
}
/**
* 从切面中单个解析 EL 表达式的结果
*
* @param joinPoint 切面点
* @param expressionString EL 表达式数组
* @return 执行界面
*/
public static Object parseExpression(ProceedingJoinPoint joinPoint, String expressionString) {
Map<String, Object> result = parseExpressions(joinPoint, Collections.singletonList(expressionString));
return result.get(expressionString);
}
/**
* 从切面中批量解析 EL 表达式的结果
*
* @param joinPoint 切面点
* @param expressionStrings EL 表达式数组
* @return 结果key 为表达式value 为对应值
*/
public static Map<String, Object> parseExpressions(ProceedingJoinPoint joinPoint, List<String> expressionStrings) {
// 如果为空则不进行解析
if (CollUtil.isEmpty(expressionStrings)) {
return MapUtil.newHashMap();
}
// 第一步构建解析的上下文 EvaluationContext
// 通过 joinPoint 获取被注解方法
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
// 使用 spring ParameterNameDiscoverer 获取方法形参名数组
String[] paramNames = PARAMETER_NAME_DISCOVERER.getParameterNames(method);
// Spring 的表达式上下文对象
EvaluationContext context = new StandardEvaluationContext();
// 给上下文赋值
if (ArrayUtil.isNotEmpty(paramNames)) {
Object[] args = joinPoint.getArgs();
for (int i = 0; i < paramNames.length; i++) {
context.setVariable(paramNames[i], args[i]);
}
}
// 第二步逐个参数解析
Map<String, Object> result = MapUtil.newHashMap(expressionStrings.size(), true);
expressionStrings.forEach(key -> {
Object value = EXPRESSION_PARSER.parseExpression(key).getValue(context);
result.put(key, value);
});
return result;
}
}

View File

@ -145,7 +145,7 @@ spring:
# 日志文件配置
logging:
file:
path: ${user.home}/logs/ # 日志文件的路径
name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径
--- #################### 芋道相关配置 ####################

View File

@ -145,7 +145,7 @@ spring:
# 日志文件配置
logging:
file:
path: ${user.home}/logs/ # 日志文件的路径
name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径
--- #################### 芋道相关配置 ####################

View File

@ -0,0 +1,76 @@
<configuration>
<!-- 引用 Spring Boot 的 logback 基础配置 -->
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<!-- 变量 yudao.info.base-package基础业务包 -->
<springProperty scope="context" name="yudao.info.base-package" source="yudao.info.base-package"/>
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level级别从左显示 5 个字符宽度,%msg日志消息%n是换行符 -->
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%thread] [%tid] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<!-- 控制台 Appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">     
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<pattern>${PATTERN_DEFAULT}</pattern>
</layout>
</encoder>
</appender>
<!-- 文件 Appender -->
<!-- 参考 Spring Boot 的 file-appender.xml 编写 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<pattern>${PATTERN_DEFAULT}</pattern>
</layout>
</encoder>
<!-- 日志文件名 -->
<file>${LOG_FILE}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 滚动后的日志文件名 -->
<fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}</fileNamePattern>
<!-- 启动服务时,是否清理历史日志,一般不建议清理 -->
<cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>
<!-- 日志文件,到达多少容量,进行滚动 -->
<maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize>
<!-- 日志文件的总大小0 表示不限制 -->
<totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap>
<!-- 日志文件的保留天数 -->
<maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30}</maxHistory>
</rollingPolicy>
</appender>
<!-- 异步写入日志,提升性能 -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志。默认的,如果队列的 80% 已满,则会丢弃 TRACT、DEBUG、INFO 级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能。默认值为 256 -->
<queueSize>256</queueSize>
<appender-ref ref="FILE"/>
</appender>
<!-- SkyWalking GRPC 日志收集实现日志中心。注意SkyWalking 8.4.0 版本开始支持 -->
<appender name="GRPC" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<pattern>${PATTERN_DEFAULT}</pattern>
</layout>
</encoder>
</appender>
<!-- 本地环境 -->
<springProfile name="local">
<logger name="${yudao.info.base-package}" level="INFO" additivity="false">
<appender-ref ref="STDOUT"/>
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
</logger>
</springProfile>
<!-- 其它环境 -->
<springProfile name="default">
<logger name="${yudao.info.base-package}" level="INFO" additivity="false">
<appender-ref ref="STDOUT"/>
<appender-ref ref="ASYNC"/>
<appender-ref ref="GRPC"/>
</logger>
</springProfile>
</configuration>

View File

@ -12,7 +12,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysMenuMapper;
import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum;
import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysMenuProducer;
import cn.iocoder.dashboard.modules.system.service.permission.impl.SysMenuServiceImpl;
import cn.iocoder.dashboard.util.AopTargetUtils;
import cn.iocoder.dashboard.util.sping.SpringAopUtils;
import cn.iocoder.dashboard.util.RandomUtils;
import cn.iocoder.dashboard.util.object.ObjectUtils;
import com.google.common.collect.Multimap;
@ -57,7 +57,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest {
sysMenuService.initLocalCache();
// 获取代理对象
SysMenuServiceImpl target = (SysMenuServiceImpl) AopTargetUtils.getTarget(sysMenuService);
SysMenuServiceImpl target = (SysMenuServiceImpl) SpringAopUtils.getTarget(sysMenuService);
Map<Long, SysMenuDO> menuCache =
(Map<Long, SysMenuDO>) BeanUtil.getFieldValue(target, "menuCache");
@ -227,7 +227,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest {
public void testListMenusFromCache_success() throws Exception {
Map<Long, SysMenuDO> mockCacheMap = new HashMap<>();
//获取代理对象
SysMenuServiceImpl target = (SysMenuServiceImpl) AopTargetUtils.getTarget(sysMenuService);
SysMenuServiceImpl target = (SysMenuServiceImpl) SpringAopUtils.getTarget(sysMenuService);
BeanUtil.setFieldValue(target, "menuCache", mockCacheMap);
Map<Long, SysMenuDO> idMenuMap = new HashMap<>();
@ -256,7 +256,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest {
public void testListMenusFromCache2_success() throws Exception {
Map<Long, SysMenuDO> mockCacheMap = new HashMap<>();
//获取代理对象
SysMenuServiceImpl target = (SysMenuServiceImpl) AopTargetUtils.getTarget(sysMenuService);
SysMenuServiceImpl target = (SysMenuServiceImpl) SpringAopUtils.getTarget(sysMenuService);
BeanUtil.setFieldValue(target, "menuCache", mockCacheMap);
Map<Long, SysMenuDO> idMenuMap = new HashMap<>();

View File

@ -13,14 +13,8 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysRoleMapper;
import cn.iocoder.dashboard.modules.system.enums.permission.SysRoleTypeEnum;
import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysRoleProducer;
import cn.iocoder.dashboard.modules.system.service.permission.impl.SysRoleServiceImpl;
import cn.iocoder.dashboard.util.AopTargetUtils;
import cn.iocoder.dashboard.util.AssertUtils;
import cn.iocoder.dashboard.util.RandomUtils;
import cn.iocoder.dashboard.util.object.ObjectUtils;
import com.google.common.collect.Sets;
import org.junit.jupiter.api.Assertions;
import cn.iocoder.dashboard.util.sping.SpringAopUtils;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
@ -63,7 +57,7 @@ public class SysRoleServiceTest extends BaseDbUnitTest {
//断言
//获取代理对象
SysRoleServiceImpl target = (SysRoleServiceImpl) AopTargetUtils.getTarget(sysRoleService);
SysRoleServiceImpl target = (SysRoleServiceImpl) SpringAopUtils.getTarget(sysRoleService);
Map<Long, SysRoleDO> roleCache = (Map<Long, SysRoleDO>) BeanUtil.getFieldValue(target, "roleCache");
assertPojoEquals(roleDO1, roleCache.get(roleDO1.getId()));