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码和许多可 ...
随机推荐
- notepad去掉空行
选择替换,把查找模式设置为正则表达式,在查找框中自己输入 ^\s+ ,替换框留空,点“全部替换”,即可(先全选).注意:不要复制我的,自己输入,且用英文格式输入.
- 软工网络15团队作业4——Alpha阶段敏捷冲刺7.0
1.每天举行站立式会议,提供当天站立式会议照片一张. 2.项目每个成员的昨天进展.存在问题.今天安排. 成员 昨天已完成 今天计划完成 郭炜埕 实现前端各界面的跳转连接 学习后端相关知识 郑晓丽 完善 ...
- Hadoop安装教程_单机/伪分布式配置_Hadoop2.6.0/Ubuntu14.04(转)
http://www.powerxing.com/install-hadoop/ http://blog.csdn.net/beginner_lee/article/details/6429146 h ...
- 正确把mysql数据库从windows迁移到linux系统上的方法
(一)用mysqldump命令导出数据库文件: 在windows下cd到Mysql的bin目录: c:/data.txt这个目录和导出的文本名可以自己随便取,-B 后面的是表名,我要导出的表明叫use ...
- python遍历目录os.walk(''d:\\test2",topdown=False)
os.walk(top, topdown=True, onerror=None, followlinks=False)遍历目录,topdown=false表示先返回目录,后返回文件 参数说明: top ...
- Class__One HomeWork 实验报告
石家庄铁道大学信息科学与技术学院 实验报告 2018年----2019年 第一学期 题目: 四则运算和验证码 课程名称: JAVA语言程序设计 班 ...
- C# 设置按钮快捷键
参考自:http://www.csharpwin.com/csharpspace/3932r8132.shtml 一.C# button快捷键之第一种:Alt + *(按钮快捷键) 在Button按钮 ...
- 囤币一族,被中国市场遗忘的价值币ADA
囤币一族,被中国市场遗忘的价值币ADA ==========================长期囤币目标:trx十万个,ada一万个,eos五千个,nas一千个,ont一千个,eth一百个,比特币十个 ...
- django -- 修改admin 密码问题
1.python manage.py shell 2.from django.contrib.auth.models import User 3.user=User.objects.get(usern ...
- [转载]asp.net中,<%#%>,<%=%>和<%%>分别是什么意思,有什么区别
在asp.net中经常出现包含这种形式<%%>的html代码,总的来说包含下面这样几种格式: 一. <%%> 这种格式实际上就是和asp的用法一样的,只是asp中里面是vbsc ...