1.前言
SpringCloud日志存储,大多数采用Sleuth + Zipkin,对于小公司来说感觉有点重
本次采用Sleuth + ControllerAdvice注解 + SpringEvent注解来完成这个任务。引入Sleuth来获取traceid,存储不采用zipkin,通过 ControllerAdvice注解来实现
2.实践
通常一个项目下有多个项目,为了统一管理我们将配置文件统一抽取到common中进行配置和管理,以下是文件的目录结构
demo
├── common
├── gateway
├── model
│ ├── base-model
│ └── demo-model
├── service
│ ├── demo-service
│ └── system-service
common中包含拦截器等组件
2.1添加pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
2.2添加配置文件
配置application.yml
spring:
sleuth:
sampler: #采样器
probability: 1 #采样率,采样率是采集Trace的比率,默认0.1
rate: 10000 #每秒数据采集量,最多n条/秒Trace
针对不同版本的sleuth,可能会在引入后无法启动项目,可以选填此项
/**
* @Author By GaoXu
* @Date 2022 11 30 10 06
* @Description : 必须配置此文件,不配置会与其他组件冲突产生死锁
**/
@Configuration
public class SleuthConfiguration {
@Value("${spring.sleuth.sampler.probability:1}")
private String probability;
@Bean
public Sampler defaultSampler() throws Exception {
Float f = new Float(probability);
SamplerProperties samplerProperties = new SamplerProperties();
samplerProperties.setProbability(f);
ProbabilityBasedSampler sampler = new ProbabilityBasedSampler(samplerProperties);
return sampler;
}
}
2.3添加ControllerAdvice
import brave.Tracer;
/**
* @Author By GaoXu
* @Date 2022 11 30 10 06
* @Description : 操作日志收集器
**/
@Slf4j
@ControllerAdvice
public class RequestLogCollect implements ResponseBodyAdvice<R> {
@Autowired
private Tracer tracer;
@Resource
private ApplicationEventPublisher context;
@Value("${spring.application.name}")
private String moduleName;
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return R.class.isAssignableFrom(methodParameter.getParameterType());
}
@Override
public R beforeBodyWrite(R body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
requestLogSave(body, methodParameter, serverHttpRequest);
return body;
}
@Async
void requestLogSave(R body, MethodParameter methodParameter, ServerHttpRequest serverHttpRequest) {
try {
boolean check = checkIgnore(methodParameter);
if (check) {
return;
}
String traceId = tracer.currentSpan().context().traceIdString();
UserVo user = RedisUtils.getUser();
OperationLogVo operationLogVo = new OperationLogVo();
operationLogVo.setTraceId(traceId);
// 获取客户端IP地址
String remoteAddr = serverHttpRequest.getRemoteAddress().getAddress().getHostAddress();
// 获取请求方式
String method = serverHttpRequest.getMethod().name();
// 获取请求路径
String servletPath = serverHttpRequest.getURI().getPath();
operationLogVo.setUserAgent(HttpUtils.getDeviceInfo(serverHttpRequest));
operationLogVo.setBasePath(methodParameter.getMethod().getDeclaringClass().getName() + "." + methodParameter.getMethod().getName());
operationLogVo.setUrl(servletPath);
operationLogVo.setModuleName(moduleName + ":" + getDescription(methodParameter));
operationLogVo.setOplogType(OperationLogTypeEnum.getLogTypeEnumByKeyWord(servletPath).getCode());
operationLogVo.setOperationContent(OperationLogTypeEnum.getLogTypeEnumByKeyWord(servletPath).getDescription() + ":" + (body.getCode() == 200 ? "成功" : "失败"));
operationLogVo.setRequestType(method);
operationLogVo.setRealIp(HttpUtils.getRealIP(serverHttpRequest));
operationLogVo.setComId(user.getComId());
operationLogVo.setTenantId(user.getTenantId());
operationLogVo.setClientIp(remoteAddr);
operationLogVo.setResult(body.getCode() == 200);
context.publishEvent(operationLogVo);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 获取方法描述
*
* @param methodParameter
* @return
*/
public String getDescription(MethodParameter methodParameter) {
StringBuilder result = new StringBuilder();
try {
Class<?> declaringClass = methodParameter.getMethod().getDeclaringClass();
Api annotation = declaringClass.getAnnotation(Api.class);
if (!Objects.isNull(annotation)) {
String[] tags = annotation.tags();
result.append(tags[0]);
ApiOperation methodAnnot = methodParameter.getMethod().getAnnotation(ApiOperation.class);
if (!Objects.isNull(methodAnnot)) {
result.append("->" + methodAnnot.value());
}
}
return result.toString();
} catch (Exception e) {
return result.toString();
}
}
}
2.4过滤不需要存储的请求
创建IgnoreLog注解
import java.lang.annotation.*;
/**
* @Author By GaoXu
* @Date 2022 11 30 16 09
* @Description : 方法上添加此注解,请求后不会进行日志存储;类上添加此注解,类中所有方法日志都不会进行存储
**/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface IgnoreLog {
}
在RequestLogCollect添加注解检测方法,通过反射获取请求方法是否加了注解
/**
* 注解检测
*
* @param methodParameter
* @return
*/
private boolean checkIgnore(MethodParameter methodParameter) {
boolean result = false;
try {
Class<?> declaringClass = methodParameter.getMethod().getDeclaringClass();
IgnoreLog annotation = declaringClass.getAnnotation(IgnoreLog.class);
if (Objects.isNull(annotation)) {
IgnoreLog methodAnnot = methodParameter.getMethod().getAnnotation(IgnoreLog.class);
if (!Objects.isNull(methodAnnot)) {
result = true;
}
} else {
result = true;
}
return result;
} catch (Exception e) {
return result;
}
}
2.5优化
缓存
由于采用注解形式,在运行时会消耗大量IO来反射获取注解,这里可以采用@PostConstruct注解,在启动完成时,扫描注解后,将需要过滤的类名方法名,存储到内存,如果数据量大可以存储到redis,这里toB项目不追求性能,就不再优化这部分了
异步
虽说是toB,该优化也要优化下,我们在存储的时候采用@Async注解异步处理
2.6存储
因为我们将配置从service中抽出后统一进行配置,这里项目起步阶段还未采用MQ,那么如果我们在common中调用service中的方法,会产生循环依赖问题,这里采用SpringEvent来化解这个问题
推送:context.publishEvent(object);
public class RequestLogCollect implements ResponseBodyAdvice<R> {
@Resource
private ApplicationEventPublisher context;
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return R.class.isAssignableFrom(methodParameter.getParameterType());
}
@Override
public R beforeBodyWrite(R body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
requestLogSave(body, methodParameter, serverHttpRequest);
return body;
}
@Async
void requestLogSave(R body, MethodParameter methodParameter, ServerHttpRequest serverHttpRequest) {
try {
context.publishEvent(object);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
接收:@EventListener
@Service
public class RequestLogCollectService {
@Resource
private OperationLogClient operationLogClient;
/**
* 添加操作日志列表记录
*
* @param operationLogVo 实例对象
* @return 对象列表
*/
@EventListener(OperationLogVo.class)
public R addOperationLog(OperationLogVo operationLogVo) {
return operationLogClient.addOperationLog(operationLogVo);
}
}
这样我们就实现了请求日志的存储
{!{data:image/webp;base64,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}!}
{!{data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAABLKADAAQAAAABAAABLAAAAADYYILnAAASPklEQVR4Ae3dv8s1y10A8GuwM3+BhnRaJAjirWIEU1rdWAkKFrGwSNo0kuYJpBBsxWj1iEUgKdIY0cTiPCGFGEFMcYXEH0UgCYnCBRXFJjrf6zu8k83MOWf37O7M2fMZOOzu7M58v/PZefbZs+e87/PGGwoBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMC1Ak/pwHdevWJdIUCAwJACb6Ws/nfyijqFwJAC7xkyK0ntJfB7lUC/WKlTRYAAge4C07ur2P5696wkQKAh4A6rAfPA1S8PPHZDH1zABWvwE9Qhva92iCkkAQIEzgq8N+2tvSWMeoXAkALusIY8Lbsk9SuNKP/ZqFdNoLuAC1b3U9AtgdYFq1tCAhMgQKAl8K20o/aWsHW8egLdBY5wh/WUFH1Te/5U+k6lyb9V6lQRILCSgG9qL4es3V1FnUJgWIF7v8OqfSv7D4fVlhgBAg8t8LU0+tqdwkOjXDn4mps7rCvxHNZH4N7vsP6yD5uoBAgQmC/wZmpSu1OY39Pjtai5ucN6vHlgxDsL1H7w4kKmnBc4pd1T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ysuo27PkuNPlGjn8Vepk2m/eXqP/3Efus7Z8Mx90xfIT6ZjvpVf0886r11NaKgcTqE2Uzx5sjFsMp+YWdXuWrXI491Yw9q1Z4plVaxxR/8eNYOUF6lz7txrtVd+hQFyYaif7Doeye8o1t6jbs2yVQ6vfuOvaosSng62Yt9Y/bZGwPvsItCZDn2zuK+oIdlvkcO7iseUZOqXOW+O5pd4d1pZnbee+axPB28HrTkLNLur2LGvncO7t2dpvBWtO8favNaa59fEc66kWRN19CnwxpV2bBPc5mv2zrtlF3Z7llILV8lj6XaZaX1EX38Xaq8SD9lYe19THg/d4vqUcTKB18g82zM2GM4Jf69/lRW5zyi+kg1vjmdvXnLjnjj2lnT88k1fe5wJ1TvEg+1oTPeqV6wRaP+DXtV7vqFYeUX/ph/nShSr6UAh0FzilDGoTvXtid5RAzTDqepTauVyjbulbyx4GYh5Y4HNpbNMJ/ZUDj3eLoU398vYWsS71ee5hec5r7tI/RL6kbv9uAvFR73QC+/h3Hv/UL2/P62W9o899HSHndu3ytF5aeiKwjsBT6sY/YVhu2frhX97j7S3jQpMfRrfyu1Qfz7UUAgQOJtD6wR9hmOU/W7l0Acv7XahGOHM75OCPje6APGCIuGDVivlQU1E3jMAR/pDqMJgSIUBgWwEXrG19R+39pZJYra5ymCoC/QS8Behn3zOyt4Q99cVeLOAOazGdhgQI7C3ggrW3uHgECCwWcMFaTKchAQJ7C7hg7S0+RryXShq1usphqgj0E/DQvZ99z8geuvfUF3uxgDusxXQaEiCwt4AL1t7i4hEgsFjABWsx3V03fKlkX6urHKaKQD8Bz7D62feM7BlWT32xFwu4w1pMd9cNXyrZ1+oqh6ki0E/AHVY/+56R3WH11Bd7sYA7rMV0d93w05Xsa3WVw1QR6CfggtXPvmfkv6sEr9VVDlNFgACB/QWeUkj/zfT+7iISIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIGlAv8HDIWTsrSvBwgAAAAASUVORK5CYII=}!}