常规日志中看到异常堆栈信息大部分时候是类似这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at com.chineseall.user.logic.UserServiceLogic$$EnhancerBySpringCGLIB$$ad3e32b0.userInfoBatch(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:244)
at org.springframework.cloud.context.scope.GenericScope$LockedScopedProxyFactoryBean.invoke(GenericScope.java:494)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
不控制堆栈打印深度的时候,日志文件会变得非常大,这里介绍一种方法可以降低日志文件的存储空间。
解决方案
logback.xml配置文件中增加如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<!-- 日志输出格式 -->
<conversionRule conversionWord="exception" converterClass="com.au92.common.log.CustomStackTraceConverter"/>
<conversionRule conversionWord="logger" converterClass="com.au92.common.log.CustomPackageNameConverter"/>
<property name="LOG_COMMON_PATTERN" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50}#%M [%X{traceId}] - %msg%n%exception{10}%n"/>
<property name="LOG_DEV_PATTERN" value="%d{HH:mm:ss.SSS} [%thread] %-5level %boldGreen(%logger{50})#%boldYellow(%M):%line [%X{traceId}] - %msg%n%exception%n"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${LOG_DEV_PATTERN}</pattern>
</encoder>
</appender>
<appender name="FILE_WARN" class="ch.qos.logback.core.rolling.RollingFileAppender" additivity="false">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<file>${LOG_HOME}/warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/warn/warn-%d{yyyy-MM-dd}-%i.log.zip</fileNamePattern>
<maxFileSize>${LOG_MAX_SIZE}</maxFileSize>
<maxHistory>3</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<pattern>${LOG_COMMON_PATTERN}</pattern>
</encoder>
</appender>
|
java代码中增加三个类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
/**
* 自定义日志打印堆栈转换器
*
* @author p_x_c
*/
public class CustomStackTraceConverter extends ThrowableProxyConverter {
int stackDepth = -1;
@Override
public void start() {
super.start();
stackDepth = NumberUtils.toInt(getFirstOption(), -1);
}
@Override
protected String throwableProxyToString(IThrowableProxy throwableProxy) {
Throwable throwable = ((ThrowableProxy) throwableProxy).getThrowable();
StringBuilder sb = new StringBuilder();
doPrintStack(throwable, sb);
return sb.toString();
}
/**
* 打印堆栈
*
* @param t 异常
* @param sb 返回字符串
*/
public void doPrintStack(Throwable t, StringBuilder sb) {
StackTraceElement[] stackTraceElements = t.getStackTrace();
if (stackDepth < 0) {
stackDepth = stackTraceElements.length;
}
if (sb.lastIndexOf("\t") > -1) {
sb.deleteCharAt(sb.length() - 1);
sb.append("Caused: ");
}
sb.append(t.getClass()
.getName())
.append(": ")
.append(t.getMessage())
.append("\n\t");
for (int i = 0; i < stackDepth; ++i) {
if (i >= stackTraceElements.length) {
break;
}
StackTraceElement element = stackTraceElements[i];
sb.append(ShortClassNameUtil.simplifyClassName(element.getClassName()))
.append("#")
.append(element.getMethodName())
.append(":")
.append(element.getLineNumber())
.append("\n\t");
}
}
}
/**
* 自定义日志打印包名转换器,需要将越来打印logger的地方替换为该转换器
*
* @author p_x_c
*/
public class CustomPackageNameConverter extends CompositeConverter<ILoggingEvent> {
@Override
protected String transform(ILoggingEvent event, String in) {
return ShortClassNameUtil.simplifyClassName(event.getLoggerName());
}
}
/**
* 更短的类名
*
* @author p_x_c
*/
@UtilityClass
public class ShortClassNameUtil {
// 白名单,不需要简化的类名
public static final String PACKAGE_NAME = "com.au92";
/**
* 简化类名
*
* @param fullClassName
* @return
*/
public String simplifyClassName(String fullClassName) {
if (fullClassName.contains(PACKAGE_NAME)) {
return fullClassName;
}
String[] parts = fullClassName.split("\\.");
StringBuilder simplifiedName = new StringBuilder();
for (int i = 0; i < parts.length - 1; i++) {
simplifiedName.append(parts[i].charAt(0))
.append('.');
}
simplifiedName.append(parts[parts.length - 1]);
return simplifiedName.toString();
}
}
|
效果
1
2
3
4
5
6
7
8
9
10
11
12
|
21:03:37.369 [XNIO-1 task-1] ERROR com.au92.common.web.exception.WebExceptionHandler#unknownException [42b240a7-6234-4354-a02f-42f682319db7] - 异常
com.au92.common.util.exception.WebException: ddsfsdf
com.au92.api.controller.category.CategoryCommonController#list:40
com.au92.api.controller.category.CategoryCommonController$$FastClassBySpringCGLIB$$9cea966b#invoke:-1
o.s.c.p.MethodProxy#invoke:218
o.s.a.f.CglibAopProxy$CglibMethodInvocation#invokeJoinpoint:792
o.s.a.f.ReflectiveMethodInvocation#proceed:163
o.s.a.f.CglibAopProxy$CglibMethodInvocation#proceed:762
o.s.a.a.MethodInvocationProceedingJoinPoint#proceed:89
com.au92.common.web.aop.LogAOP#doInvoke:52
s.r.NativeMethodAccessorImpl#invoke0:-2
s.r.NativeMethodAccessorImpl#invoke:62
|