Commit 947dd991 by ilal

Merge branch 'develop' of develop-gitlab.youlingrc.com:8timerv2/8timerapiv200 into lal

parents 04fae78a c2c9de53
package cn.timer.api.aspect;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.TimeZone;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import cn.timer.api.config.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
/**
* 拦截输出异常堆栈(改用fluentd方式)
*
* @author Rex.Tan
* @date 2018年12月13日 上午9:18:58
*/
@Slf4j
@Aspect
@Component
@Order(999)
public class RequestAop {
@Pointcut("execution(* cn.timer..*.*Controller.*(..))")
public void init() {
}
@Before("init()")
public void beforeAdvice(JoinPoint joinPoint) {
// 进入方法前拦截
}
@Around("init()")
public Object around(ProceedingJoinPoint pjp) {
long startTime = System.currentTimeMillis();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String url = request.getRequestURI();
/**
* 输出url
*/
Object obj = null;
String bodyArgs = this.bodyArgs2String(request, pjp.getArgs(), url);
JSONObject urlArgs = this.urlArgs2String(request, request.getParameterNames(), url);
try {
obj = pjp.proceed();
long endTime = System.currentTimeMillis();
this.logInfo2Kafka(request, url, bodyArgs, urlArgs, "success", 0, endTime - startTime, true);
} catch (Throwable e) {
e.printStackTrace();
long endTime = System.currentTimeMillis();
if (e instanceof CustomException) {
/**
* 拦截到主动抛出的异常
*/
CustomException ex = (CustomException) e;
this.logInfo2Kafka(request, url, bodyArgs, urlArgs, ex.getMessage(), 400, endTime - startTime, false);
throw ex;
} else {
/**
* 拦截到未知异常
*/
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
this.logInfo2Kafka(request, url, bodyArgs, urlArgs, "未捕获异常: " + stringWriter.toString(), 500, endTime - startTime, false);
throw new CustomException("未捕获异常," + e.getMessage());
}
} finally {
}
return obj;
}
/**
* 请录请求耗时
*
* @author Rex.Tan
* @date 2018年12月13日 下午2:51:31
* @param url 请求地址
* @param args requestBody中的参数
* @param args2 url中的参数
* @param message 消息
* @param status 接口调用返回状态
* @param executionTime 执行耗时
* @param isSuccess 是否调用成功
*/
@Async
public void logInfo2Kafka(HttpServletRequest request, String url, String bodyArgs, JSONObject urlArgs,
String message, Integer status, long executionTime, boolean isSuccess) {
JSONObject json = new JSONObject();
json.put("logType", "___rest___");
// if (UserContext.get() != null) {
// json.put("userName", UserContext.get().getUsername());
// }
json.put("url", url);
json.put("timestamp", System.currentTimeMillis());
json.put("visitTime", now2String());
json.put("message", message);
json.put("status", status);
json.put("executionTime", executionTime);
json.put("channel", request.getHeader("channel"));
json.put("projectName", "8timer");
json.put("requestType", request.getMethod());
/**
* 1.requestBody中的参数
*/
json.put("bodyArgs", bodyArgs);
/**
* 2.url中的参数
*/
json.put("urlArgs", urlArgs);
/**
* 3.如果请求状态不为0, 在控制台输入请求信息
*/
if (status != 0) {
log.error("\r\n" + json.toJSONString());
} else {
log.info("\r\n" + json.toJSONString());
}
}
/**
* 读取requestBody中的参数
*
* @author Rex.Tan
* @date 2018年12月13日 下午2:54:31
* @param bodyArgs
* @param url
* @return
*/
private String bodyArgs2String(HttpServletRequest request, Object[] bodyArgs, String url) {
if ("GET".equals(request.getMethod())) {
return "";
}
if (url != null && url.matches("upload")) {
return "";
}
if (url != null && url.matches("image")) {
return "";
}
try {
if (bodyArgs != null && bodyArgs.length > 0) {
String body = JSONArray.toJSONString(bodyArgs);
if (body.matches("image")) {
return "";
}
return body;
}
} catch (Exception e) {
log.error("=============序列化requestBody中的参数出错, " + url);
}
return "";
}
/**
* 读取url中的参数
*
* @author Rex.Tan
* @date 2019年9月12日 下午2:54:40
* @param request
* @param urlArgs
* @param url
* @return
*/
private JSONObject urlArgs2String(HttpServletRequest request, Enumeration<String> urlArgs, String url) {
JSONObject urlArgsJson = new JSONObject();
try {
if (urlArgs != null) {
while (urlArgs.hasMoreElements()) {
try {
String paraName = (String) urlArgs.nextElement();
urlArgsJson.put(paraName, request.getParameter(paraName));
} catch (Exception e) {
log.error("=============记录url中的参数出错", url);
break;
}
}
}
} catch (Exception e) {
log.error("=============记录url中的参数出错, " + url);
}
return urlArgsJson;
}
private static String now2String() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
Date now = new Date();
return sdf.format(now);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--2、设置上下文名称 每个logger都关联到logger上下文,默认上下文名称为“default”。但可以使用设置成其他名字,用于区分不同应用程序的记录。
一旦设置,不能修改,可以通过 %contextName 来打印日志上下文名称,一般来说我们不用这个属性,可有可无。 -->
<!--<contextName>cool_is_life</contextName> -->
<!--3、设置变量 用来定义变量值的标签, 有两个属性,name和value;其中name的值是变量的名称,value的值时变量定义的值。 通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
<!--<property name="log.path" value="/logs/logback.log" /> -->
<!--<property name="log.path" value="/logs/logback" /> -->
<property name="logback.logdir" value="/deploy/logs/" />
<property name="logback.appname" value="8timer-api" />
<!--4、appender用来格式化日志输出节点,有俩个属性name和class,class用来指定哪种输出策略,常用就是控制台输出策略和文件输出策略。
控制台输出 ConsoleAppender 输出到文件 RollingFileAppender -->
<!--输出到控制台 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--输出到文件 -->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,所以我们使用下面的策略,可以避免输出
Error 的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--过滤 Error -->
<level>ERROR</level>
<!--匹配到就禁止 -->
<onMatch>DENY</onMatch>
<!--没有匹配到就允许 -->
<onMismatch>ACCEPT</onMismatch>
</filter>
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则,如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
的日志改名为今天的日期。即,<File> 的日志都是当天的。 -->
<file>${logback.logdir}/${logback.appname}.info.log</file>
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间 -->
<FileNamePattern>${logback.logdir}/bak/${logback.appname}.info.%d{yyyy-MM-dd}.%i.log
</FileNamePattern>
<!--只保留最近7天的日志 -->
<maxHistory>7</maxHistory>
<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志 -->
<totalSizeCap>1GB</totalSizeCap>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger - %msg%n</pattern>
</encoder>
</appender>
<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Error 级别的日志,那么需要过滤一下,默认是 info 级别的,ThresholdFilter -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>error</level>
</filter>
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则 如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
的日志改名为今天的日期。即,<File> 的日志都是当天的。 -->
<File>${logback.logdir}/${logback.appname}.error.log</File>
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间 -->
<FileNamePattern>${logback.logdir}/bak/${logback.appname}.error.%d{yyyy-MM-dd}.%i.log
</FileNamePattern>
<!--只保留最近7天的日志 -->
<maxHistory>7</maxHistory>
<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志 -->
<!--<totalSizeCap>1GB</totalSizeCap> -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!--日志输出编码格式化 -->
<encoder>
<charset>UTF-8</charset>
<pattern>%d [%thread] %-5level %logger{36} %line - %msg%n</pattern>
</encoder>
</appender>
<!--1、root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性。 level:用来设置打印级别,大小写无关:TRACE,
DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能设置为INHERITED或者同义词NULL。 默认是DEBUG。 可以包含零个或多个元素,标识这个appender将会添加到这个loger。 -->
<root level="INFO">
<appender-ref ref="console" />
<appender-ref ref="file" />
<appender-ref ref="fileErrorLog" />
</root>
</configuration>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment