关键词:
一.引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency>
二.代码
AopLoggingApplication
1 package com.example; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.boot.web.servlet.ServletComponentScan; 6 7 @SpringBootApplication 8 @ServletComponentScan 9 public class AopLoggingApplication { 10 11 public static void main(String[] args) { 12 SpringApplication.run(AopLoggingApplication.class, args); 13 } 14 }
SomeFilter
1 package com.example.filter; 2 3 import lombok.extern.slf4j.Slf4j; 4 import org.springframework.web.filter.OncePerRequestFilter; 5 import org.springframework.web.util.ContentCachingRequestWrapper; 6 7 import javax.servlet.FilterChain; 8 import javax.servlet.ServletException; 9 import javax.servlet.annotation.WebFilter; 10 import javax.servlet.http.HttpServletRequest; 11 import javax.servlet.http.HttpServletResponse; 12 import java.io.IOException; 13 14 @WebFilter 15 @Slf4j 16 public class SomeFilter extends OncePerRequestFilter { 17 @Override 18 protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { 19 log.debug("进入SomeFilter"); 20 /** 21 * 因为请求体的流在进入aop时就被关闭了,从request拿到body会抛异常,stream closed.这里这样写可以在aop里面拿到请求体,具体参考org.springframework.web.filter.AbstractRequestLoggingFilter. 22 * 假如这个方法有更改request的操作 就把这段代码写在上面. 23 */ 24 if(log.isDebugEnabled()){ 25 httpServletRequest = new ContentCachingRequestWrapper(httpServletRequest, 1024); 26 } 27 28 filterChain.doFilter(httpServletRequest, httpServletResponse); 29 } 30 }
HttpLoggingAspect
1 package com.example.aspect; 2 3 import com.fasterxml.jackson.databind.ObjectMapper; 4 import lombok.extern.slf4j.Slf4j; 5 import org.aspectj.lang.JoinPoint; 6 import org.aspectj.lang.ProceedingJoinPoint; 7 import org.aspectj.lang.annotation.*; 8 import org.springframework.beans.factory.annotation.Autowired; 9 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 10 import org.springframework.stereotype.Component; 11 import org.springframework.web.context.request.RequestContextHolder; 12 import org.springframework.web.context.request.ServletRequestAttributes; 13 import org.springframework.web.util.ContentCachingRequestWrapper; 14 import org.springframework.web.util.WebUtils; 15 16 import javax.servlet.http.HttpServletRequest; 17 import java.io.UnsupportedEncodingException; 18 import java.util.Arrays; 19 @Component 20 @Aspect 21 @Slf4j 22 @ConditionalOnProperty(name = "web-logging", havingValue = "debug") 23 public class HttpLoggingAspect { 24 25 @Autowired 26 private ObjectMapper mapper; 27 28 @Pointcut("execution(public * com.example..controller.*.*(..))")//两个..代表所有子目录,最后括号里的两个..代表所有参数 29 public void logPointCut() { 30 } 31 32 @Before("logPointCut()") 33 public void doBefore(JoinPoint joinPoint) throws Throwable { 34 // 接收到请求,记录请求内容 35 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 36 HttpServletRequest request = attributes.getRequest(); 37 38 // 记录下请求内容 39 log.debug("┌──────────请求──────────────────"); 40 log.debug("┃控制器{}->方法{}-->参数{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), mapper.writeValueAsString(Arrays.toString(joinPoint.getArgs()))); 41 log.debug("┃{}-->{}-->{}", request.getRemoteAddr(), request.getMethod(), request.getRequestURL()); 42 log.debug("┃parameter{}", mapper.writeValueAsString(request.getParameterMap()));// 格式化输出的json mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj); 43 log.debug("┃body{}",getPayload(request)); 44 log.debug("└──────────────────────────────"); 45 46 } 47 48 @Around("logPointCut()") 49 public Object doAround(ProceedingJoinPoint pjp) throws Throwable { 50 long startTime = System.currentTimeMillis(); 51 Object ob = pjp.proceed();// ob 为方法的返回值 52 log.debug("┌──────────回复──────────────────"); 53 log.debug("┃耗时{}ms" ,(System.currentTimeMillis() - startTime)); 54 return ob; 55 } 56 57 @AfterReturning(returning = "ret", pointcut = "logPointCut()")// returning的值和doAfterReturning的参数名一致 58 public void doAfterReturning(Object ret) throws Throwable { 59 log.debug("┃返回" + ret); 60 log.debug("└──────────────────────────────"); 61 } 62 63 private String getPayload(HttpServletRequest request) { 64 ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class); 65 if (wrapper != null) { 66 byte[] buf = wrapper.getContentAsByteArray(); 67 if (buf.length > 0) { 68 try { 69 int length = Math.min(buf.length, 1024);//最大只打印1024字节 70 return new String(buf, 0, length, wrapper.getCharacterEncoding()); 71 } catch (UnsupportedEncodingException var6) { 72 return "[unknown]"; 73 } 74 } 75 } 76 return ""; 77 } 78 }
测试用的TestController
1 package com.example.controller; 2 3 import org.springframework.web.bind.annotation.GetMapping; 4 import org.springframework.web.bind.annotation.PostMapping; 5 import org.springframework.web.bind.annotation.RequestBody; 6 import org.springframework.web.bind.annotation.RestController; 7 8 import java.util.Map; 9 10 @RestController 11 public class TestController { 12 @GetMapping("/") 13 public String hello(String name) { 14 return "Spring boot " + name; 15 } 16 17 @PostMapping("/") 18 public Map<String, Object> hello(@RequestBody Map<String, Object> map){ 19 return map; 20 } 21 }
配置文件application.properties
web-logging=debug #作为启动web日志的配置, 方便本地开发和上线 logging.level.com.example=debug
三.效果
1.=====================================================================
请求 GET http://localhost:8080?name=abc
回复Spring boot abc
日志
1 2018-10-10 21:55:46.873 DEBUG 53764 --- [nio-8080-exec-2] com.example.filter.SomeFilter : 进入SomeFilter 2 2018-10-10 21:55:46.914 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┌──────────请求────────────────── 3 2018-10-10 21:55:46.929 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┃控制器com.example.controller.TestController->方法hello-->参数"[abc]" 4 2018-10-10 21:55:46.929 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┃127.0.0.1-->GET-->http://localhost:8080/ 5 2018-10-10 21:55:47.087 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┃parameter{"name":["abc"]} 6 2018-10-10 21:55:47.087 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┃body 7 2018-10-10 21:55:47.087 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : └────────────────────────────── 8 2018-10-10 21:55:47.095 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┌──────────回复────────────────── 9 2018-10-10 21:55:47.095 INFO 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┃耗时181ms 10 2018-10-10 21:55:47.096 INFO 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┃返回Spring boot abc 11 2018-10-10 21:55:47.096 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : └──────────────────────────────
2.=====================================================================
请求 POST http://localhost:8080
参数 json类型 {"name":"spring boot"}
回复
{"name":"spring boot"}
日志
2018-10-10 22:00:11.465 DEBUG 59444 --- [nio-8080-exec-2] com.example.filter.SomeFilter : 进入SomeFilter 2018-10-10 22:00:11.659 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┌──────────请求────────────────── 2018-10-10 22:00:11.671 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┃控制器com.example.controller.TestController->方法hello-->参数"[{name=spring boot}]" 2018-10-10 22:00:11.672 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┃127.0.0.1-->POST-->http://localhost:8080/ 2018-10-10 22:00:11.696 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┃parameter{} 2018-10-10 22:00:11.696 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┃body{"name":"spring boot"} 2018-10-10 22:00:11.696 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : └────────────────────────────── 2018-10-10 22:00:11.702 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┌──────────回复────────────────── 2018-10-10 22:00:11.703 INFO 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┃耗时44ms 2018-10-10 22:00:11.703 INFO 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : ┃返回{name=spring boot} 2018-10-10 22:00:11.703 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect : └──────────────────────────────
github: https://github.com/tungss/aop-logging.git
5-9springbootaop的使用(代码片段)
配置AOP,打印接口耗时、请求参数、返回参数。新建: @Aspect@ComponentpublicclassLogAspectprivatefinalstaticLoggerLOG=LoggerFactory.getLogger(LogAspect.class);/***定义一个切点*/@Pointcut("execution( 查看详情
springbootaop学习:springaop实现日志功能(代码片段)
...总结前言感谢阅读菜菜的文章,本篇文章是继上一篇SpringBootAOP学习(一):AOP的诞生及AOP注解介绍后对AOP注解的使用作一个具体的应用,由于本身我也是才接触不久 查看详情
springbootaop简易操作日志管理(代码片段)
AOP(AspectOrientedProgramming)面向切面编程。业务有核心业务和边缘业务。比如用户管理,菜单管理,权限管理,这些都属于核心业务。比如日志管理,操作记录管理,这些都是边缘业务,可以统一的提出来。尝试使用SpringBoot+AOP提出... 查看详情
springbootaop综合例子
完整源码:https://github.com/947133297/cgLibDemo通过AOP来便捷地输出日志,能更加方便排查系统的bug,这个例子中简单输出自定义文件和函数执行时的参数,函数要不要输出日志,可以通过注解来控制。两个服务类代码如下:@Service@Enab... 查看详情
springboot配置aop切面日志打印
一、SpringBootAop说明1.AopAOP(Aspect-OrientedProgramming,面向切面编程),它利用一种”横切”的技术,将那些多个类的共同行为封装到一个可重用的模块。便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作... 查看详情
springbootaop解析(代码片段)
SpringBootAOP面向切面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP)。OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面。AOP(AspectOrientedProgram)面向切面编程在面向切面编程的思想里面,把功能... 查看详情
WCF - 获取原始请求/回复和操作名称
】WCF-获取原始请求/回复和操作名称【英文标题】:WCF-Getbothrawrequest/replyandoperationname【发布时间】:2021-05-3109:43:56【问题描述】:我正在尝试使用来自客户端的IClientMessageInspector/IParameterInspector实现SOAP请求/回复的日志记录。问题... 查看详情
springbootaop之对请求的参数入参与返回结果进行拦截处理
对于spring框架来说,最重要的两大特性就是AOP和IOC。以前一直都知道有这两个东西,在平时做的项目中也常常会涉及到这两块,像spring的事务管理什么的,在看了些源码后,才知道原来事务管理也是用的AOP来实现的。对于IOC的话... 查看详情
如何在超测失败时打印请求日志(如请求 url、请求正文、请求 queryParam)?
】如何在超测失败时打印请求日志(如请求url、请求正文、请求queryParam)?【英文标题】:Howtoprinttherequestlogs(likerequesturl,requestbody,requestqueryParam)onsupertestfailure?【发布时间】:2021-08-1422:53:33【问题描述】:我想在Supertest预期失败... 查看详情
nginx自定义日志打印request及responselog信息(代码片段)
...到第三方网关时,因为请求出错,所以需要在nginx打印请求的信息。配置Nginx日志格式使用lua脚本需要nginx配置了lua,或者使用openresty取代nginxhttp#默认值为off,忽略变量下划线underscores_in_headerson;#设置日志格式,... 查看详情
aop统一处理请求日志
...方法: 只拦截gilrList方法: 在访问到方法之后,打印222222 防止代码重复: 使用logger代替system.out.println 记录http请求和返回值:& 查看详情
elasticsearch日志能否把全部请求打印出来?(代码片段)
...战问题请问一下球主,es怎么配置可以把请求日志都打印出来。就是不管是调用借口,还是kibana查询数据,es能打印dsl的请求日志吗??求指导。怎么配置?——问题来源:https://t.zsxq.com/09vv8rqZj2、Elastic... 查看详情
Python请求 - 打印整个http请求(原始)?
】Python请求-打印整个http请求(原始)?【英文标题】:Pythonrequests-printentirehttprequest(raw)?【发布时间】:2014-01-0615:45:25【问题描述】:在使用requestsmodule时,有没有办法打印原始HTTP请求?我不只想要标题,我想要请求行、标题和... 查看详情
打印日志查看调接口时间
要打印日志以查看调用接口的时间,可以在代码中添加时间戳,记录请求发起时间和响应返回时间,然后将这些信息写入日志文件。具体步骤如下:1.导入时间模块:在代码开头导入time模块,例如:`importtime`2.记录请求发起时间... 查看详情
如何使得http请求记录在domino的日志中
下面是开启HTTP请求日志的简要步骤,从中可以得到最基本的日志信息。如果需要开启详细的日志,请参阅文档"OverviewofHTTPRequestLogs"(#7003598)重要提示:HTTP请求日志只能用于特定问题的故障分析,通常应该在IBM技术支持工程师的指... 查看详情
nginx详解六:nginx基础篇之nginx日志
...义上面默认的日志里面是没有请求头的,这里配置让Nginx打印出请求头,比如user-agent 在main的参数里面加上‘$http_user_agent‘(全小写,且为了方便区分,在参数后面加了一个空格) 检查配置文件的正确与否:nginx-t-c/etc/ng... 查看详情
Sails.js HOWTO:实现 HTTP 请求的日志记录
】Sails.jsHOWTO:实现HTTP请求的日志记录【英文标题】:Sails.jsHOWTO:implementloggingforHTTPrequests【发布时间】:2014-03-0905:55:06【问题描述】:Sails.js的默认日志记录很差,没有显示http请求日志(即使是详细的)。将http请求记录到控制台... 查看详情
接口耗时打印并统计
1.可以利用Tomcat的access-log日志,让其打印出http请求的每次耗时。可以在config/server.xml里Host标签下配置tomcat访问日志格式<ValveclassName="org.apache.catalina.valves.AccessLogValve"directory="logs" & 查看详情