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 Security实现RBAC权限管理
Spring Security实现RBAC权限管理 一.简介 在企业应用中,认证和授权是非常重要的一部分内容,业界最出名的两个框架就是大名鼎鼎的 Shiro和Spring Security.由于Spr ...
- uva 1416 Warfare And Logistics
题意: 给出一个无向图,定义这个无向图的花费是 其中path(i,j),是i到j的最短路. 去掉其中一条边之后,花费为c’,问c’ – c的最大值,输出c和c’. 思路: 枚举每条边,每次把这条边去掉 ...
- kali 创建快捷方式的方法
Kali应用程序快捷方式分析 kali默认使用Gnome桌面环境,所以给kali添加应用程序快捷方式就是给Gnome添加应用快捷方式. 在/usr/share/applications目录下有很多的. ...
- Axis2之Spring装配
本章主要介绍axis2接口在spring项目中的整合配置. 使用jar包:axis2-1.6.2 spring2.5.6 目录结构: 关键代码: package com.alfred.bean; pu ...
- 设计模式之Chain of Responsibility(职责链)(转)
Chain of Responsibility定义 Chain of Responsibility(CoR) 是用一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合, ...
- golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息
golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放 ...
- 1113: No mapping for the Unicode character exists in the target multi-byte code page
windows版本nginx启动 报错. 启动方式:到nginx所在目录执行:nginx.exe -c conf\nginx.conf 原因:所在路径中含有中文字符. 解决:换个没有中文的路径.
- web前端利用leaflet生成粒子风场,类似windy
wind.js如下: $(function() { var dixing = L.tileLayer.chinaProvider('Google.Satellite.Map', { maxZoom: ...
- Python框架----cookie和session
一.cookie和session的介绍 cookie不属于http协议范围,由于http协议无法保持状态,但实际情况,我们却又需要“保持状态”,因此cookie就是在这样一个场景下诞生. cookie ...
- 【shell脚本】通过遍历文件的一种批量执行shell命令的方法。
在分析数据时,经常会有许多机械重复的命令带入,作为一个半路出家的程序猿,我曾经对这种工作束手无策.不像一个熟手那样举重若轻的分析,感觉自己的生信分析完全是个体力活.为了打开这样的局面,我开始学习如何批 ...