1.src/resources路径下新建logback.xml

  • 控制台彩色日志打印
  • info日志和异常日志分不同文件存储
  • 每天自动生成日志
  • 结合myibatis方便日志打印(debug模式)
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false"> <!--定义日志文件的存储地址 可以在LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="logs" /> <!-- 彩色日志 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx"
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
<!-- Console 输出设置 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender> <!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/category-server-log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>DENY</onMatch>
<onMismatch>NEUTRAL</onMismatch>
</filter>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
<onMismatch>NEUTRAL</onMismatch>
</filter> </appender> <!-- 出错日志 appender -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<!-- log.dir 在maven profile里配置 -->
<FileNamePattern>${LOG_HOME}/category-server-error-log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!--myibatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
</configuration>

2.定义一个log实体 方便维护和后续的扩展

package com.wdcloud.categoryserver.log;

import com.wdcloud.categoryserver.common.entity.User;

/**
* @describe: 日志打印实体
* @author: zhuchunwang
* @date: 2018/5/29 17:40
* @version: 1.0
*/
public class LogEntity {
private long id;
/**
* 请求地址
*/
private String url;
/**
* 请求IP
*/
private String ip;
/**
* 请求方式
*/
private String httpMethod;
/**
* 请求类,方法
*/
private String classMethod;
/**
* 方法参数
*/
private String args;
/**
* 请求参数
*/
private String reqParams;
/**
* 响应参数
*/
private String respParams;
/**
* 响应时间
*/
private long spendTime;
/**
* 日志类型(web、service)
*/
private String logType;
/**
* 用户信息
*/
private User user; public long getId() {
return id;
} public void setId(long id) {
this.id = id;
} public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
} public String getIp() {
return ip;
} public void setIp(String ip) {
this.ip = ip;
} public String getHttpMethod() {
return httpMethod;
} public void setHttpMethod(String httpMethod) {
this.httpMethod = httpMethod;
} public String getClassMethod() {
return classMethod;
} public void setClassMethod(String classMethod) {
this.classMethod = classMethod;
} public String getArgs() {
return args;
} public void setArgs(String args) {
this.args = args;
} public String getReqParams() {
return reqParams;
} public void setReqParams(String reqParams) {
this.reqParams = reqParams;
} public String getRespParams() {
return respParams;
} public void setRespParams(String respParams) {
this.respParams = respParams;
} public long getSpendTime() {
return spendTime;
} public void setSpendTime(long spendTime) {
this.spendTime = spendTime;
} public String getLogType() {
return logType;
} public void setLogType(String logType) {
this.logType = logType;
} public User getUser() {
return user;
} public void setUser(User user) {
this.user = user;
}
}

3.定义一个controller 的切面

package com.wdcloud.categoryserver.log;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wdcloud.categoryserver.common.constant.AppConstants;
import com.wdcloud.categoryserver.utils.AppUtil;
import com.wdcloud.categoryserver.utils.JsonUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; /**
* @describe: 实现controller的日志切面
* @author: zhuchunwang
* @date: 2018/5/29 17:40
* @version: 1.0
*/
@Aspect
@Component
@Order(1)
public class ControllerLogAspect {
private Logger logger = LoggerFactory.getLogger(this.getClass());
ThreadLocal<Long> startTime = new ThreadLocal<>();
ThreadLocal<LogEntity> webLogThreadLocal = new ThreadLocal<>();
/**
* 定义一个切入点.
* 解释下:
* <p>
* ~ 第一个 * 代表任意修饰符及任意返回值.
* ~ 第二个 * 任意包名
* ~ 第三个 * 代表任意方法.
* ~ 第四个 * 定义在web包或者子包
* ~ 第五个 * 任意方法
* ~ .. 匹配任意数量的参数.
*/
@Pointcut("execution(* com.wdcloud.categoryserver.business.*.controller.*.*(..))")
public void serviceAspect() {
}
@Before("serviceAspect()")
public void doBefore(JoinPoint joinPoint) {
// 接收到请求,记录请求内容
startTime.set(System.currentTimeMillis());
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
webLogThreadLocal.set(new LogEntity());
webLogThreadLocal.get().setHttpMethod(request.getMethod());
webLogThreadLocal.get().setClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
webLogThreadLocal.get().setUrl(request.getRequestURL().toString());
webLogThreadLocal.get().setIp(request.getRemoteAddr());
webLogThreadLocal.get().setArgs(AppUtil.getArgs(joinPoint));
webLogThreadLocal.get().setLogType(AppConstants.LOG_TYPE_HTTP);
webLogThreadLocal.get().setReqParams(JsonUtil.objectToJson(request.getParameterMap()));
webLogThreadLocal.get().setUser(AppUtil.getUser(request));
} /**
* 异常通知 用于拦截service层记录异常日志
*
* @param
* @param
*/
@AfterReturning(returning = "result", pointcut = "serviceAspect()")
public void doAfterReturning(Object result) {
// 处理完请求,返回内容
ObjectMapper mapper = new ObjectMapper();
try {
webLogThreadLocal.get().setRespParams(mapper.writeValueAsString(result));
} catch (JsonProcessingException e) {
logger.error(AppUtil.getExceptionDetail(e));
}
webLogThreadLocal.get().setSpendTime(System.currentTimeMillis() - startTime.get());
try {
logger.info(">>>"+mapper.writeValueAsString(webLogThreadLocal.get()));
} catch (JsonProcessingException e) {
logger.error(AppUtil.getExceptionDetail(e));
}
}
}

4.定义一个供dubbo调用的service切面

package com.wdcloud.categoryserver.log;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wdcloud.categoryserver.common.constant.AppConstants;
import com.wdcloud.categoryserver.utils.AppUtil;
import com.wdcloud.categoryserver.utils.JsonUtil;
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.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; /**
* @describe: 实现controller的日志切面
* @author: zhuchunwang
* @date: 2018/5/29 17:40
* @version: 1.0
*/
@Aspect
@Component
@Order(1)
public class ServiceLogAspect {
private Logger logger = LoggerFactory.getLogger(this.getClass());
ThreadLocal<Long> startTime = new ThreadLocal<>();
ThreadLocal<LogEntity> webLogThreadLocal = new ThreadLocal<>();
/**
* 定义一个切入点.
* 解释下:
* <p>
* ~ 第一个 * 代表任意修饰符及任意返回值.
* ~ 第二个 * 任意包名
* ~ 第三个 * 代表任意方法.
* ~ 第四个 * 定义在web包或者子包
* ~ 第五个 * 任意方法
* ~ .. 匹配任意数量的参数.
*/
@Pointcut("execution(* com.wdcloud.categoryserver.front.*.service.*.*(..))")
public void serviceAspect() {
}
@Before("serviceAspect()")
public void doBefore(JoinPoint joinPoint) {
// 接收到请求,记录请求内容
startTime.set(System.currentTimeMillis());
webLogThreadLocal.set(new LogEntity());
webLogThreadLocal.get().setClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
webLogThreadLocal.get().setArgs(AppUtil.getArgs(joinPoint));
webLogThreadLocal.get().setLogType(AppConstants.LOG_TYPE_DUBBO);
} /**
* 异常通知 用于拦截service层记录异常日志
*
* @param
* @param
*/
@AfterReturning(returning = "result", pointcut = "serviceAspect()")
public void doAfterReturning(Object result) {
// 处理完请求,返回内容
ObjectMapper mapper = new ObjectMapper();
try {
webLogThreadLocal.get().setRespParams(mapper.writeValueAsString(result));
} catch (JsonProcessingException e) {
logger.error(AppUtil.getExceptionDetail(e));
}
webLogThreadLocal.get().setSpendTime(System.currentTimeMillis() - startTime.get());
try {
logger.info(">>>"+mapper.writeValueAsString(webLogThreadLocal.get()));
} catch (JsonProcessingException e) {
logger.error(AppUtil.getExceptionDetail(e));
}
}
}

5.统一异常处理

package com.wdcloud.categoryserver.common.exception;

import com.wdcloud.categoryserver.common.constant.AppConstants;
import com.wdcloud.categoryserver.common.constant.CodeConstants;
import com.wdcloud.categoryserver.common.entity.BaseView;
import com.wdcloud.categoryserver.log.LogEntity;
import com.wdcloud.categoryserver.utils.AppUtil;
import com.wdcloud.categoryserver.utils.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.support.MissingServletRequestPartException; import javax.servlet.http.HttpServletRequest; /**
* @describe: 全局异常处理
* @author: zhuchunwang
* @date: 2018/5/29 17:40
* @version: 1.0
*/
@ControllerAdvice(annotations = {RestController.class})
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 默认未知异常
* @param request
* @param e
* @return
* @throws Exception
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public BaseView defaultErrorHandler(HttpServletRequest request, Exception e) throws Exception {
BaseView baseView = new BaseView(CodeConstants.SYSTEM_EXCEPTION,CodeConstants.SYSTEM_EXCEPTION_MSG);
printLog(request,e,baseView);
return baseView;
} /**
* 参数异常
* @param request
* @param e
* @return
* @throws Exception
*/
@ExceptionHandler(value = {HttpMessageNotReadableException.class, MissingServletRequestPartException.class ,MissingServletRequestParameterException.class, MultipartException.class})
@ResponseBody
public BaseView httpMessageNotReadableExceptionErrorHandler(HttpServletRequest request, Exception e) throws Exception {
BaseView baseView = new BaseView(CodeConstants.PARAMETER_ERROR,CodeConstants.PARAMETER_ERROR_MSG);
printLog(request,e,baseView);
return baseView;
}
/**
* contentType异常
* @param request
* @param e
* @return
* @throws Exception
*/
@ExceptionHandler(value = {HttpMediaTypeNotSupportedException.class})
@ResponseBody
public BaseView httpMediaTypeNotSupportedExceptionHandler(HttpServletRequest request, Exception e) throws Exception {
BaseView baseView = new BaseView(CodeConstants.CONTENTTYPE_ERROR,CodeConstants.CONTENTTYPE_ERROR_MSG);
printLog(request,e,baseView);
return baseView;
} /**
* 异常信息打印日志
* @param request
* @param e
* @param baseView
*/
private void printLog(HttpServletRequest request,Exception e,BaseView baseView){
logger.error(AppUtil.getExceptionDetail(e));
LogEntity logEntity = new LogEntity();
logEntity.setHttpMethod(request.getMethod());
logEntity.setUrl(request.getRequestURL().toString());
logEntity.setIp(request.getRemoteAddr());
logEntity.setArgs(AppUtil.getRequestBody(request));
logEntity.setLogType(AppConstants.LOG_TYPE_HTTP);
logEntity.setReqParams(JsonUtil.objectToJson(request.getParameterMap()));
logEntity.setRespParams(JsonUtil.objectToJson(baseView));
logger.error(">>>"+JsonUtil.objectToJson(logEntity));
} }

springboot aop + logback + 统一异常处理 打印日志的更多相关文章

  1. SpringBoot系列——自定义统一异常处理

    前言 springboot内置的/error错误页面并不一定适用我们的项目,这时候就需要进行自定义统一异常处理,本文记录springboot进行自定义统一异常处理. 1.使用@ControllerAd ...

  2. 关于spring 事务 和 AOP 管理事务和打印日志问题

    关于spring 事务 和 AOP 管理事务和打印日志问题 1. 就是支持事务注解的(@Transactional) . ​ 可以在server层总使用@Transactional,进行方法内的事务管 ...

  3. springboot 整合logback(有全套的日志配置文件)

    logback介绍:基于Log4j基础上大量改良,不能单独使用,推荐配合日志框架SLF4J来使用,可以和springboot很好的整合,也是springboot默认推荐的. 1.在resources ...

  4. springboot整合logback集成elk实现日志的汇总、分析、统计和检索功能

    在Spring Boot当中,默认使用logback进行log操作.logback支持将日志数据通过提供IP地址.端口号,以Socket的方式远程发送.在Spring Boot中,通常使用logbac ...

  5. SpringBoot(七)_统一异常处理

    我感觉看了这节课,给我的思考还是很多的,感觉受益良多.废话不多说,一起学习. 统一的 外层结构返回 这样利于代码看着也规范,前端处理也统一 # 错误返回 { "code": 1, ...

  6. SpringBoot | 第二十四章:日志管理之AOP统一日志

    前言 上一章节,介绍了目前开发中常见的log4j2及logback日志框架的整合知识.在很多时候,我们在开发一个系统时,不管出于何种考虑,比如是审计要求,或者防抵赖,还是保留操作痕迹的角度,一般都会有 ...

  7. Spring Boot 2.0 教程 | AOP 切面统一打印请求日志

    欢迎关注微信公众号: 小哈学Java 文章首发于个人网站 https://www.exception.site/springboot/spring-boot-aop-web-request 本节中,您 ...

  8. SpringBoot整合Logback日志框架配置全解析

    目录 本篇要点 一.Logback日志框架介绍 二.SpringBoot与Logback 1.默认日志格式 2.控制台输出 3.文件输出 4.日志级别 5.日志组 6.自定义log配置 三.logba ...

  9. SpringBoot统一异常处理后TX-LCN分布式事务无法捕获异常进行回滚

    通常我们使用SpringBoot都会进行统一异常处理,例如写一个BaseController,在BaseController里进行统一异常处理,然后其他的Controller都继承BaseContro ...

随机推荐

  1. 带着萌新看springboot源码8(spring ioc源码下)

    继续接着上一节,到了第六步(温馨提醒,内容有点小多,不过看完ioc原理就差不多了) 6.注册Bean后置处理器(registerBeanPostProcessors(beanFactory)) 最后一 ...

  2. 使用mongoskin操作MongoDB

    mongoskin是一个操作MongoDB的模型工具 相当于数据库类 与之相当的还有mongoose比较出名 安装模块(特地加了版本,这里被坑过,在Ubuntu中开发的好好的,部署到线上centos中 ...

  3. kubernetes系列07—Pod控制器详解

    本文收录在容器技术学习系列文章总目录 1.Pod控制器 1.1 介绍 Pod控制器是用于实现管理pod的中间层,确保pod资源符合预期的状态,pod的资源出现故障时,会尝试 进行重启,当根据重启策略无 ...

  4. eclipse 创建maven 项目 动态web工程完整示例 maven 整合springmvc整合mybatis

    接上一篇: eclipse 创建maven 项目 动态web工程完整示例 eclipse maven工程自动添加依赖设置 maven工程可以在线搜索依赖的jar包,还是非常方便的 但是有的时候可能还需 ...

  5. 浅析java程序的执行过程

    在研究任何一门语言时,无论是面向过程的c,c++(面向过程和面向对象),还是面向对象的.net,java等,弄清语言执行过程至关重要.  何为语言执行过程? 所谓语言执行过程,指对于任何一门语言,如j ...

  6. C#简单委托示例——让你一看就会的demo

    委托 1. 什么是委托? 委托就是具有相同签名和返回值类型的有序方法列表 它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递 是一种引用类型 方法的列表称为调用列表 当委托被调用时,它调 ...

  7. C# 判断用户是否对路径拥有访问权限

    如何获取当前系统用户对文件/文件夹的操作权限? 1.获取安全信息DirectorySecurity DirectorySecurity fileAcl = Directory.GetAccessCon ...

  8. ABP大型项目实战(1) - 目录

    前面我写了<如何用ABP框架快速完成项目>系列文章,讲述了如何用ABP快速完成项目.   然后我收到很多反馈,其中一个被经常问到的问题就是,“看了你的课程,发现ABP的优势是快速开发,那么 ...

  9. Arcgis for js开发之直线、圆、箭头、多边形、集结地等绘制方法

    p{ text-align:center; } blockquote > p > span{ text-align:center; font-size: 18px; color: #ff0 ...

  10. 微信小程序(一),授权页面搭建

    wxml代码如下: <!--pages/index2/index2.wxml--> <view class="index2Container"> <i ...