失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > SpringBoot/Cloud AOP 统一日志输出

SpringBoot/Cloud AOP 统一日志输出

时间:2023-12-03 22:16:15

相关推荐

SpringBoot/Cloud AOP 统一日志输出

文章目录

1. 导入依赖2. aop拦截器3. logback配置4. 测试类5. 关键点6. 效果图
1. 导入依赖

<!-- AOP --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- 数据序列化--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.78</version></dependency>

2. aop拦截器

package com.course.server.config;import com.alibaba.fastjson.JSONObject;import com.alibaba.fastjson.support.spring.PropertyPreFilters;import com.course.server.util.UuidUtil;import org.aspectj.lang.JoinPoint;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.Before;import org.aspectj.lang.annotation.Pointcut;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.slf4j.MDC;import org.ponent;import org.springframework.util.StringUtils;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import org.springframework.web.multipart.MultipartFile;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import java.lang.reflect.Field;@Aspect@Componentpublic class LogAspect {private final static Logger LOG = LoggerFactory.getLogger(LogAspect.class);/** 定义一个切点 */@Pointcut("execution(public * com.course.*.controller..*Controller.*(..))")public void controllerPointcut() {}@Before("controllerPointcut()")public void doBefore(JoinPoint joinPoint) throws Throwable {// 日志编号MDC.put("UUID", UuidUtil.getShortUuid());// 开始打印请求日志ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();Signature signature = joinPoint.getSignature();String name = signature.getName();// 打印业务操作String nameCn = "";if (name.contains("list") || name.contains("query")) {nameCn = "查询";} else if (name.contains("save")) {nameCn = "保存";} else if (name.contains("delete")) {nameCn = "删除";} else {nameCn = "操作";}// 使用反射,获取业务名称Class clazz = signature.getDeclaringType();Field field;String businessName = "";try {field = clazz.getField("BUSINESS_NAME");if (!StringUtils.isEmpty(field)) {businessName = (String) field.get(clazz);}} catch (NoSuchFieldException e) {LOG.error("未获取到业务名称");} catch (SecurityException e) {LOG.error("获取业务名称失败", e);}// 打印请求信息LOG.info("------------- 【{}】{}开始 -------------", businessName, nameCn);LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());LOG.info("类名方法: {}.{}", signature.getDeclaringTypeName(), name);LOG.info("远程地址: {}", request.getRemoteAddr());// 打印请求参数Object[] args = joinPoint.getArgs();Object[] arguments = new Object[args.length];for (int i = 0; i < args.length; i++) {if (args[i] instanceof ServletRequest|| args[i] instanceof ServletResponse|| args[i] instanceof MultipartFile) {continue;}arguments[i] = args[i];}// 排除字段,敏感字段或太长的字段不显示String[] excludeProperties = {"shard"};PropertyPreFilters filters = new PropertyPreFilters();PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();excludefilter.addExcludes(excludeProperties);LOG.info("请求参数: {}", JSONObject.toJSONString(arguments, excludefilter)); // 为空的会不打印,但是像图片等长字段也会打印}@Around("controllerPointcut()")public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {long startTime = System.currentTimeMillis();Object result = proceedingJoinPoint.proceed();// 排除字段,敏感字段或太长的字段不显示String[] excludeProperties = {"password", "shard"};PropertyPreFilters filters = new PropertyPreFilters();PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();excludefilter.addExcludes(excludeProperties);LOG.info("返回结果: {}", JSONObject.toJSONString(result, excludefilter));LOG.info("------------- 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);return result;}}

3. logback配置

logback.xml

<?xml version="1.0" encoding="UTF-8"?><configuration><!-- 修改一下路径--><property name="PATH" value="/log/imooc/course/business"></property><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><!-- <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %blue(%-50logger{50}:%-4line) %green(%-8X{UUID}) %msg%n</Pattern>--><Pattern>%d{ss.SSS} %highlight(%-5level) %blue(%-30logger{30}:%-4line) %green(%-8X{UUID}) %msg%n</Pattern></encoder></appender><appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${PATH}/trace.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><FileNamePattern>${PATH}/trace.%d{yyyy-MM-dd}.%i.log</FileNamePattern><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>10MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><layout><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-50logger{50}:%-4line %green(%-8X{UUID}) %msg%n</pattern></layout></appender><appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${PATH}/error.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><FileNamePattern>${PATH}/error.%d{yyyy-MM-dd}.%i.log</FileNamePattern><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>10MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><layout><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-50logger{50}:%-4line %green(%-8X{UUID}) %msg%n</pattern></layout><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter></appender><root level="ERROR"><appender-ref ref="ERROR_FILE" /></root><root level="TRACE"><appender-ref ref="TRACE_FILE" /></root><root level="INFO"><appender-ref ref="STDOUT" /></root></configuration>

4. 测试类

package com.course.business.controller.admin;import com.course.server.dto.ChapterDto;import com.course.server.dto.PageDto;import com.course.server.dto.ResponseDto;import com.course.server.service.ChapterService;import com.course.server.util.ValidatorUtil;import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;@RestController@RequestMapping("/admin/chapter")public class ChapterController {// 业务标识public static final String BUSINESS_NAME = "大章";@Resourceprivate ChapterService chapterService;//http://127.0.0.1:9002/business/admin/chapter/list@PostMapping("/list")public ResponseDto list(@RequestBody PageDto pageDto) {ResponseDto responseDto = new ResponseDto();chapterService.list(pageDto);responseDto.setContent(pageDto);return responseDto;}@PostMapping("/save")public ResponseDto save(@RequestBody ChapterDto chapterDto) {// 保存校验ValidatorUtil.require(chapterDto.getName(), "名称");ValidatorUtil.require(chapterDto.getCourseId(), "课程ID");ValidatorUtil.length(chapterDto.getCourseId(), "课程ID", 1, 8);ResponseDto responseDto = new ResponseDto();chapterService.save(chapterDto);responseDto.setContent(chapterDto);return responseDto;}@DeleteMapping("/delete/{id}")public ResponseDto delete(@PathVariable String id) {ResponseDto responseDto = new ResponseDto();chapterService.delete(id);return responseDto;}}

5. 关键点

LogAspect中日志key “UUID”要和logback.xml中的获取的keyUUID要一致,UUID生成规则自定义

6. 效果图

如果觉得《SpringBoot/Cloud AOP 统一日志输出》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。