springboot使⽤logback的MDC做⽇志规范,便于⽇志系统监控⾸先:修改NGINX的配置⽂件
#在请求端⽣成⼀个全局唯⼀的Id,根据这个id查看整个⽇志的调⽤链,注意NGINX版本要求1.11以上
proxy_set_header X-Request-Id $request_id;
#后端的Web服务器可以通过X-Forwarded-For获取⽤户真实IP
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
其次:添加spring boot aop的依赖包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
第三步:编写AOP切⾯代码,对关键信息进⾏拦截
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.MDC;
import t.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.t.request.RequestAttributes;
import org.t.request.RequestContextHolder;
import org.t.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import flect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Component
@Configuration
@Aspect
public class LogMDCAspectConfig {
@Pointcut("execution(public * usoft.ller..*.*(..))")
public void webLog(){}
@Before("webLog()")
public void before(JoinPoint joinPoint){
RequestAttributes ra = RequestAttributes();
ServletRequestAttributes sra =(ServletRequestAttributes) ra;
assert sra != null;
HttpServletRequest request = Request();
String url = RequestURL().toString();
String method = Method();
String queryName=getFieldsName(joinPoint,request);
String x_request_id = Header("X-Request-Id");
String x_real_ip =getCliectIp(request);
//nginx返回的唯⼀请求Id
MDC.put("X_REQUEST_ID", x_request_id);
//本项⽬⾃动⽣成的唯⼀请求Id
MDC.put("TRACE_ID",UUID.randomUUID().toString());
//请求的服务器的真实的IP地址
MDC.put("X_REAL_IP",x_real_ip);
//服务请求路径
MDC.put("REQUEST_URI",url);
//服务请求的⽅法,post或者get
//服务请求的⽅法,post或者get
MDC.put("REMOTE_ADDR_METHOD",method);
//服务的请求的参数
MDC.put("QUERY_NAME",queryName);
}
/**
* 对于涉及到ThreadLocal相关使⽤的接⼝,都需要去考虑在使⽤完上下⽂对象时,
* 清除掉对应的数据,以避免内存泄露问题
* @param ret
*/
@AfterReturning(pointcut ="webLog()", returning ="ret")
public void afterReturning(Object ret){
}
/**
* 获取客户段的IP
* @param request
* @return
*/
private static String getCliectIp(HttpServletRequest request)
{
String ip = Header("x-forwarded-for");
if(ip == null || ip.trim()==""||"unknown".equalsIgnoreCase(ip)){
ip = Header("Proxy-Client-IP");
}
if(ip == null || ip.trim()==""||"unknown".equalsIgnoreCase(ip)){
ip = Header("WL-Proxy-Client-IP");
}
if(ip == null || ip.trim()==""||"unknown".equalsIgnoreCase(ip)){
ip = RemoteAddr();
}
/
/ 多个路由时,取第⼀个⾮unknown的ip
final String[] arr = ip.split(",");
for(final String str : arr){
if(!"unknown".equalsIgnoreCase(str)){
ip = str;
break;
}
}
return ip;
}
/**
* 获取请求的参数
* @param joinPoint
* @return
*/
private static String getFieldsName(JoinPoint joinPoint,HttpServletRequest request){ String method = Method();
String params ="";
Object[] args = Args();
String queryString = QueryString();
if(args.length >0){
if("POST".equals(method)){
Object object = args[0];
Map map =getKeyAndValue(object);
params = JSONString(map);
;
}else if("GET".equals(method)){
params = queryString;
}
}
return params;
}
/**
* 获取post对象的参数参数值
* @param obj
* @return
*/
private static Map<String,Object>getKeyAndValue(Object obj){
Map<String, Object> map =new HashMap<>();
// 得到类对象
Class userCla =(Class();
/* 得到类中的所有属性集合 */
Field[] fs = DeclaredFields();
for(int i =0; i < fs.length; i++){
Field f = fs[i];
f.setAccessible(true);// 设置属性是可以访问的
Object val =new Object();
try{
val = f.get(obj);
// 得到此属性的值
map.Name(), val);// 设置键值
}catch(IllegalArgumentException e){
e.printStackTrace();
}catch(IllegalAccessException e){
e.printStackTrace();
}
}
return map;
}
}
第四步:编辑logback的MDC,规范⽇志格式
<?xml version="1.0" encoding="UTF-8"?>
<!--每隔⼀分钟扫描配置⽂件-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--设置上下⽂名称为 demo -->
<contextName>imagerecognition</contextName>
<!--设置系统⽇志⽬录-->
<property name="APPDIR" value="imagerecognition"/>
<!--9444_imagerecognition:端⼝号和对应的服务名称-->
<property name="SPRING_PROFILES_ACTIVE" value="9444_imagerecognition"/>
<!--定义⽇志输出格式变量:%d表⽰时间花括号内为时间格式%level表⽰⽇志级别%thread表⽰线程名%logger{0}表⽰输出⽇志的类名[%line]表⽰⾏号⽤⽅括号包裹%msg表⽰⽇志消息%n换⾏-->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS,+08:00} [%t] ${SPRING_PROFILES_ACTIVE} %p %logger [%mdc{X_REQUEST_I D},%mdc{TRACE_ID},%mdc{X_REAL_IP},%mdc{REQUEST_URI},%mdc{REMOTE_ADDR_METHOD},%mdc{QUERY_NAME}] ${CONTEXT_NAME} - %m %n"/>
<!--定义⽇志字符集-->
<property name="log.charset" value="UTF-8"/>
<!--定义⽇志级别-->
<property name="log.level" value="INFO"/>
<!--定义⽇志存放路径-->
<property name="log.path" value="logs"/>
<!--输出到控制台-->springboot aop
<appender name="CONSOLE"class="ch.ConsoleAppender">
<!--⽇志输出格式-->
<encoder>
<!--⽇志字符集-->
<charset>${log.charset}</charset>
<!--⽇志输出格式-->
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
</appender>
<!--时间滚动输出⽇志-->
<appender name="COMMON"class="ch.olling.RollingFileAppender">
<!--写⼊的⽂件名-->
<file>${log.path}/imagerecognition.log</file>
<!--追加到⽂件结尾-->
<append>true</append>
<!--滚动策略:按照每天⽣成⽇志⽂件-->
<rollingPolicy class="ch.olling.TimeBasedRollingPolicy">
<!--每天⽇志归档路径及⽂件名格式-->
<fileNamePattern>${log.path}/imagerecognition.%d{yyyy-MM-dd}.log</fileNamePattern>
<!--⽇志⽂件保留天数-->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<charset>${log.charset}</charset>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!--⽇志记录器,⽇期滚动记录,即系统产⽣的错误⽇志信息-->
<appender name="ERROR"class="ch.olling.RollingFileAppender">
<!--正在记录的⽇志⽂件的路径及⽂件名-->
<file>${log.path}/error.log</file>
<append>true</append>
<!--⽇志记录器的滚动策略,按照⽇期,按⼤⼩记录-->
<rollingPolicy class="ch.olling.TimeBasedRollingPolicy">
<!--归档的⽇志⽂件的路径,%d{yyyy-MM-dd}指定⽇期格式%i指定索引-->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.olling.SizeAndTimeBasedFNATP">
<!--单⽇志⽂件最⼤限制100兆超过则将⽂件内容归档到按照 fileNamePattern 命名的⽂件中源⽂件则清空--> <maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!--级别过滤器匹配 ERROR 级别⽇志-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<charset>${log.charset}</charset>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!--指定 usoft.www.imagerecognition.service 包要使⽤的 appender 且不向上级传递-->
<logger name="usoft.www.imagerecognition.service" level="DEBUG" additivity="false">
<appender-ref ref="ERROR"/>
</logger>
<!--根 logger -->
<root level="${log.level}">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="COMMON"/>
<appender-ref ref="ERROR"/>
</root>
</configuration>
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论