SpringBoot 全局统一记录日志
1.记录日志
使用aop来记录controller中的请求返回日志
pom.xml引入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
在完成了引入AOP依赖包后,一般来说并不需要去做其他配置。也许在Spring中使用过注解配置方式的人会问是否需要在程序主类中增加@EnableAspectJAutoProxy来启用,实际并不需要。
可以看下面关于AOP的默认配置属性,其中spring.aop.auto属性默认是开启的,也就是说只要引入了AOP依赖后,默认已经增加了@EnableAspectJAutoProxy。
# AOP
spring.aop.auto=true # Add @EnableAspectJAutoProxy.
spring.aop.proxy-target-class=false # Whether subclass-based (CGLIB) proxies are to be created (true) as opposed to standard Java interface-based proxies (false).
1.使用Around
@Aspect
@Component
public class ControllerAspect {
private Logger logger = LoggerFactory.getLogger(getClass()); /**
* Controller aspect.
*/
@Pointcut("execution(* com.shitou.huishi.service..*.*(..))")
public void controllerAspect() {
} /**
* Around 手动控制调用核心业务逻辑,以及调用前和调用后的处理,
* <p>
* 注意:当核心业务抛异常后,立即退出,转向AfterAdvice 执行完AfterAdvice,再转到ThrowingAdvice
*
* @param pjp
* the pjp
* @return object
* @throws Throwable
* the throwable
*/
@Around(value = "controllerAspect()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest(); logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
logger.info("CLASS_METHOD : " + pjp.getSignature().getDeclaringTypeName() + "." + pjp.getSignature().getName());
logger.info("REQUEST ARGS : " + JSON.toJSONString(pjp.getArgs())); long startTime = System.currentTimeMillis();
try {
Object response = pjp.proceed();
// 2.打印出参,返回结果
long endTime = System.currentTimeMillis();
// 3.出参打印
logger.info("RESPONSE:{}", response != null ? JSON.toJSONString(response) : "");
logger.info("SPEND TIME : {}ms", (endTime - startTime));
return response;
} catch (AuthException e) {
logger.info("RESPONSE ERROR:{}", e.getMsg());
throw e;
} catch (HuishiApiException e) {
logger.info("RESPONSE ERROR:{}", e.getMsg());
throw e;
} catch (MethodArgumentNotValidException e) {
logger.info("RESPONSE ERROR:{}", e.getMessage());
throw e;
} catch (Throwable e) {
logger.error("RESPONSE ERROR:{}", Arrays.toString(e.getStackTrace()));
throw e;
} finally {
long endTime = System.currentTimeMillis();
logger.error("SPEND TIME : {}ms", (endTime - startTime));
}
}
}
2.使用Before,AfterReturning处理:
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; /**
* Created by qhong on 2018/5/28 14:25
**/
@Aspect
@Component
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(getClass()); ThreadLocal<Long> startTime = new ThreadLocal<>(); @Pointcut("execution(public * com.shitou.huishi.service.*.*(..))")
public void logAspect(){} @Before("logAspect()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
startTime.set(System.currentTimeMillis()); // 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest(); // 记录下请求内容
logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs())); } @AfterReturning(returning = "ret", pointcut = "logAspect()")
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容
logger.info("RESPONSE : " + ret);
logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
}
}
两种方式计算出来的时间,参数,返回体是一样的。
完善版本:
import com.alibaba.fastjson.JSON;
import com.shitou.huishi.contract.datacontract.exception.AuthException;
import com.shitou.huishi.contract.datacontract.exception.HuishiApiException;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; /**
* 类描述: 日志拦截器,打印controller层的入参和出参<br> 创建时间: 2016/7/29 0029 <br>
*
* @author 李恒
*/
@Aspect
@Component
public class ControllerAspect { private Logger logger = LoggerFactory.getLogger(getClass()); /**
* Controller aspect.
*/
@Pointcut("execution(* com.shitou.huishi.service..*.*(..))")
public void controllerAspect() {
} /**
* Around 手动控制调用核心业务逻辑,以及调用前和调用后的处理,
* <p>
* 注意:当核心业务抛异常后,立即退出,转向AfterAdvice 执行完AfterAdvice,再转到ThrowingAdvice
*
* @param pjp the pjp
* @return object
* @throws Throwable the throwable
*/
@Around(value = "controllerAspect()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
//防止不是http请求的方法,例如:scheduled
if (ra == null || sra == null) {
return pjp.proceed();
}
HttpServletRequest request = sra.getRequest(); logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
logger.info("CLASS_METHOD : " + pjp.getSignature().getDeclaringTypeName() + "." + pjp.getSignature().getName());
logger.info("REQUEST ARGS : " + JSON.toJSONString(pjp.getArgs())); long startTime = System.currentTimeMillis();
try {
Object response = pjp.proceed();
// 3.出参打印
logger.info("RESPONSE:{}", response != null ? JSON.toJSONString(response) : "");
return response;
} catch (Throwable e) {
if (e instanceof AuthException) {
logger.info("RESPONSE ERROR:{}", ((AuthException) e).getMsg());
} else if (e instanceof HuishiApiException) {
logger.info("RESPONSE ERROR:{}", ((HuishiApiException) e).getMsg());
} else if (e instanceof MethodArgumentNotValidException) {
logger.info("RESPONSE ERROR:{}", e.getMessage());
} else {
logger.error("RESPONSE ERROR:{}", Arrays.toString(e.getStackTrace()));
}
throw e;
} finally {
long endTime = System.currentTimeMillis();
logger.info("SPEND TIME : {}ms", (endTime - startTime));
}
}
}
http://blog.didispace.com/springbootaoplog/
http://blog.didispace.com/springbootexception/
SpringBoot 全局统一记录日志的更多相关文章
- SpringBoot开发二十三-统一记录日志
统一记录日志 AlphaAspect package com.nowcoder.community.aspect; import org.aspectj.lang.ProceedingJoinPoin ...
- SpringBoot异常处理统一封装我来做-使用篇
SpringBoot异常处理统一封装我来做-使用篇 简介 重复功能我来写.在 SpringBoot 项目里都有全局异常处理以及返回包装等,返回前端是带上succ.code.msg.data等字段.单个 ...
- spring boot 2 全局统一返回RESTful风格数据、统一异常处理
全局统一返回RESTful风格数据,主要是实现ResponseBodyAdvice接口的方法,对返回值在输出之前进行修改.使用注解@RestControllerAdvice拦截异常并统一处理. 开发环 ...
- Springboot项目统一异常处理
Springboot项目统一异常处理 一.接口返回值封装 1. 定义Result对象,作为通用返回结果封装 2. 定义CodeMsg对象,作为通用状态码和消息封装 二.定义全局异常类 三.定义异常处理 ...
- SpringBoot全局异常拦截
SpringBoot全局异常捕获 使用到的技能 @RestControllerAdvice或(@ControllerAdvice+@ResponseBody) @ExceptionHandler 代码 ...
- SpringBoot全局时间转换器
SpringBoot全局时间转换器 日常开发中,接收时间类型参数处处可见,但是针对不同的接口.往往需要的时间类型不一致 @DateTimeFormat(pattern = "yyyy-MM- ...
- SpringBoot 如何统一后端返回格式?老鸟们都是这样玩的!
大家好,我是飘渺. 今天我们来聊一聊在基于SpringBoot前后端分离开发模式下,如何友好的返回统一的标准格式以及如何优雅的处理全局异常. 首先我们来看看为什么要返回统一的标准格式? 为什么要对Sp ...
- SpringBoot 如何统一后端返回格式
在前后端分离的项目中后端返回的格式一定要友好,不然会对前端的开发人员带来很多的工作量.那么SpringBoot如何做到统一的后端返回格式呢?今天我们一起来看看. 为什么要对SpringBoot返回统一 ...
- GUID 全局统一标识符的介绍
GUID(全局统一标识符)是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的.通常平台会提供生成GUID的API.生成算法很有意思,用到了以太网卡地址.纳秒级时间.芯片ID码和许多可 ...
随机推荐
- spring boot 知识点
spring boot 好处 1. 简化配置,spring boot 提供了默认配置 例如 日志 默认logback日志 info级别 2. 简化部署,内嵌容器,tomcat,jetty,直接部署j ...
- 转 VS2010 RDLC 横向合并时“未正确设置 tablix“Tablix1”的 FixedData 属性”错误解决方法 .
最近在使用Rdlc做报表打印,有些报表的表头需要合并表头.Rdlc本身提供了横向合并的工具,但是在实际合并的时候,会出现“未正确设置 tablix“Tablix1”的 FixedData 属性.除非在 ...
- python -- 判断给定的参数是否是地理位置的经度和纬度
例子: coordinates = "2.3,-8ui" 无效地理位置 coordinates = "2.3,-8i" 有效地理位置 方法一:使用try...e ...
- 如何在Sitecore CMS中创建项目
从功能区 打开Sitecore的内容编辑器,选择内容树中的项目.创建的项目将作为所选项目的子项添加. Sitecore 8显示所选的Home项目 Sitecore 6和7显示所选的Home项目 功能区 ...
- uvalive 4960 Sensor Network
题意: 给出一个无向图,求一个生成树使得这个生成树的最大边与最小边之差最小,输出这个最小的差值.n的最大值为350. 思路: 这题不看题解想破头也不知道怎么写Orz. 暴力的做法是可以从大到小枚举边作 ...
- Presto 学习和使用笔记
1.presto 表连接查询的连接条件中不支持使用函数 比如下面的脚本在presto中运行会报错 select t1.period_start_date, t2.statistic_date from ...
- Hive静态分区和动态分区
一.静态分区 1.创建分区表 hive (default)> create table order_mulit_partition( > order_number string, > ...
- STM32 一个定时器产生4路 独立调频率,占中比可调,脉冲个数可以统计。
实现这个功能,基本原理是利用STM32 的输出比较功能. 1.其它设置就是普通定时器的设置这里开启,四个输出比较中断,和一个更新中断, 更新中断这里不需要开也可以达到目的,我这里开启是做其它的用处的. ...
- byte & 0xff char 转换
https://blog.csdn.net/lixingtao0520/article/details/75450883 版权声明:本文为博主原创文章,转载请注明作者与出处,http://blog.c ...
- 系统调用号、errno
最近老需要看系统调用号,errno,所以这里记一下 CentOS Linux release 7.2.1511 (Core) 3.10.0-327.el7.x86_64 [root@localhost ...