Skip to content

Commit cedda1b

Browse files
ppkarwaszrgoers
andcommitted
Backport ExtendedStackTraceElement improvements from 3.x
Closes #1640. Co-authored-by: Ralph Goers <[email protected]>
1 parent 1ee6f07 commit cedda1b

File tree

15 files changed

+713
-37
lines changed

15 files changed

+713
-37
lines changed

log4j-core-java9/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@
3939
<groupId>org.apache.logging.log4j</groupId>
4040
<artifactId>log4j-api</artifactId>
4141
</dependency>
42+
<dependency>
43+
<groupId>com.fasterxml.jackson.core</groupId>
44+
<artifactId>jackson-annotations</artifactId>
45+
</dependency>
46+
<dependency>
47+
<groupId>com.fasterxml.jackson.dataformat</groupId>
48+
<artifactId>jackson-dataformat-xml</artifactId>
49+
</dependency>
4250
<dependency>
4351
<groupId>org.apache.maven</groupId>
4452
<artifactId>maven-core</artifactId>

log4j-core-java9/src/assembly/java9.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@
2626
<directory>${project.build.outputDirectory}</directory>
2727
<outputDirectory>/classes/META-INF/versions/9</outputDirectory>
2828
<includes>
29+
<include>org/apache/logging/log4j/core/impl/ExtendedStackTraceElement.class</include>
30+
<include>org/apache/logging/log4j/core/jackson/ExtendedStackTraceElementMixIn.class</include>
31+
<include>org/apache/logging/log4j/core/jackson/StackTraceElementMixIn.class</include>
2932
<include>org/apache/logging/log4j/core/util/internal/UnsafeUtil*.class</include>
30-
<include>org/apache/logging/log4j/core/util/SystemClock*.class</include>
33+
<include>org/apache/logging/log4j/core/util/SystemClock.class</include>
3134
</includes>
3235
</fileSet>
3336
</fileSets>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.core.impl;
18+
19+
import java.io.Serializable;
20+
21+
import org.apache.logging.log4j.core.pattern.TextRenderer;
22+
23+
/**
24+
* Dummy class to let ExtendedStackTracElement to compile. It will not be copied
25+
* to `log4j-core`.
26+
*/
27+
public class ExtendedClassInfo implements Serializable {
28+
29+
public ExtendedClassInfo(final boolean exact, final String location, final String version) {
30+
}
31+
32+
public boolean getExact() {
33+
return false;
34+
}
35+
36+
public String getLocation() {
37+
return null;
38+
}
39+
40+
public String getVersion() {
41+
return null;
42+
}
43+
44+
public void renderOn(final StringBuilder output, final TextRenderer textRenderer) {
45+
}
46+
47+
}
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.core.impl;
18+
19+
import java.io.Serializable;
20+
import java.util.Objects;
21+
22+
import org.apache.logging.log4j.core.pattern.PlainTextRenderer;
23+
import org.apache.logging.log4j.core.pattern.TextRenderer;
24+
import org.apache.logging.log4j.util.Strings;
25+
26+
/**
27+
* Wraps and extends the concept of the JRE's final class {@link StackTraceElement} by adding more location information.
28+
* <p>
29+
* Complements a StackTraceElement with:
30+
* </p>
31+
* <ul>
32+
* <li>exact: whether the class was obtained via {@link sun.reflect.Reflection#getCallerClass(int)}</li>
33+
* <li>location: a classpath element or a jar</li>
34+
* <li>version</li>
35+
* </ul>
36+
*/
37+
public final class ExtendedStackTraceElement implements Serializable {
38+
39+
static final ExtendedStackTraceElement[] EMPTY_ARRAY = {};
40+
41+
private static final long serialVersionUID = -7522727097365696739L;
42+
43+
private final ExtendedClassInfo extraClassInfo;
44+
45+
private final StackTraceElement stackTraceElement;
46+
47+
public ExtendedStackTraceElement(final StackTraceElement stackTraceElement,
48+
final ExtendedClassInfo extraClassInfo) {
49+
this.stackTraceElement = stackTraceElement;
50+
this.extraClassInfo = extraClassInfo;
51+
}
52+
53+
/**
54+
* Called from Jackson for XML and JSON IO.
55+
*/
56+
public ExtendedStackTraceElement(final String classLoaderName, final String moduleName, final String moduleVersion,
57+
final String declaringClass, final String methodName, final String fileName, final int lineNumber,
58+
final boolean exact, final String location, final String version) {
59+
this(new StackTraceElement(classLoaderName, moduleName, moduleVersion, declaringClass, methodName, fileName,
60+
lineNumber),
61+
new ExtendedClassInfo(exact, location, version));
62+
}
63+
64+
@Override
65+
public boolean equals(final Object obj) {
66+
if (this == obj) {
67+
return true;
68+
}
69+
if (obj == null) {
70+
return false;
71+
}
72+
if (!(obj instanceof ExtendedStackTraceElement)) {
73+
return false;
74+
}
75+
final ExtendedStackTraceElement other = (ExtendedStackTraceElement) obj;
76+
if (!Objects.equals(this.extraClassInfo, other.extraClassInfo)) {
77+
return false;
78+
}
79+
if (!Objects.equals(this.stackTraceElement, other.stackTraceElement)) {
80+
return false;
81+
}
82+
return true;
83+
}
84+
85+
public String getClassLoaderName() {
86+
return this.stackTraceElement.getClassLoaderName();
87+
}
88+
89+
public String getModuleName() {
90+
return this.stackTraceElement.getModuleName();
91+
}
92+
93+
public String getModuleVersion() {
94+
return this.stackTraceElement.getModuleVersion();
95+
}
96+
97+
public String getClassName() {
98+
return this.stackTraceElement.getClassName();
99+
}
100+
101+
public boolean getExact() {
102+
return this.extraClassInfo.getExact();
103+
}
104+
105+
public ExtendedClassInfo getExtraClassInfo() {
106+
return this.extraClassInfo;
107+
}
108+
109+
public String getFileName() {
110+
return this.stackTraceElement.getFileName();
111+
}
112+
113+
public int getLineNumber() {
114+
return this.stackTraceElement.getLineNumber();
115+
}
116+
117+
public String getLocation() {
118+
return this.extraClassInfo.getLocation();
119+
}
120+
121+
public String getMethodName() {
122+
return this.stackTraceElement.getMethodName();
123+
}
124+
125+
public StackTraceElement getStackTraceElement() {
126+
return this.stackTraceElement;
127+
}
128+
129+
public String getVersion() {
130+
return this.extraClassInfo.getVersion();
131+
}
132+
133+
@Override
134+
public int hashCode() {
135+
return Objects.hash(extraClassInfo, stackTraceElement);
136+
}
137+
138+
public boolean isNativeMethod() {
139+
return this.stackTraceElement.isNativeMethod();
140+
}
141+
142+
void renderOn(final StringBuilder output, final TextRenderer textRenderer) {
143+
render(this.stackTraceElement, output, textRenderer);
144+
textRenderer.render(" ", output, "Text");
145+
this.extraClassInfo.renderOn(output, textRenderer);
146+
}
147+
148+
private void render(final StackTraceElement stElement, final StringBuilder output, final TextRenderer textRenderer) {
149+
final String classLoaderName = getClassLoaderName();
150+
if (Strings.isNotEmpty(classLoaderName)) {
151+
switch (classLoaderName) {
152+
case "app":
153+
case "boot":
154+
case "platform":
155+
break;
156+
default:
157+
textRenderer.render(classLoaderName, output, "StackTraceElement.ClassLoaderName");
158+
textRenderer.render("/", output, "StackTraceElement.ClassLoaderSeparator");
159+
}
160+
}
161+
final String fileName = stElement.getFileName();
162+
final int lineNumber = stElement.getLineNumber();
163+
final String moduleName = getModuleName();
164+
final String moduleVersion = getModuleVersion();
165+
if (Strings.isNotEmpty(moduleName)) {
166+
textRenderer.render(moduleName, output, "StackTraceElement.ModuleName");
167+
if (Strings.isNotEmpty(moduleVersion) && !moduleName.startsWith("java")) {
168+
textRenderer.render("@", output, "StackTraceElement.ModuleVersionSeparator");
169+
textRenderer.render(moduleVersion, output, "StackTraceElement.ModuleVersion");
170+
}
171+
textRenderer.render("/", output, "StackTraceElement.ModuleNameSeparator");
172+
}
173+
textRenderer.render(getClassName(), output, "StackTraceElement.ClassName");
174+
textRenderer.render(".", output, "StackTraceElement.ClassMethodSeparator");
175+
textRenderer.render(stElement.getMethodName(), output, "StackTraceElement.MethodName");
176+
if (stElement.isNativeMethod()) {
177+
textRenderer.render("(Native Method)", output, "StackTraceElement.NativeMethod");
178+
} else if (fileName != null && lineNumber >= 0) {
179+
textRenderer.render("(", output, "StackTraceElement.Container");
180+
textRenderer.render(fileName, output, "StackTraceElement.FileName");
181+
textRenderer.render(":", output, "StackTraceElement.ContainerSeparator");
182+
textRenderer.render(Integer.toString(lineNumber), output, "StackTraceElement.LineNumber");
183+
textRenderer.render(")", output, "StackTraceElement.Container");
184+
} else if (fileName != null) {
185+
textRenderer.render("(", output, "StackTraceElement.Container");
186+
textRenderer.render(fileName, output, "StackTraceElement.FileName");
187+
textRenderer.render(")", output, "StackTraceElement.Container");
188+
} else {
189+
textRenderer.render("(", output, "StackTraceElement.Container");
190+
textRenderer.render("Unknown Source", output, "StackTraceElement.UnknownSource");
191+
textRenderer.render(")", output, "StackTraceElement.Container");
192+
}
193+
}
194+
195+
@Override
196+
public String toString() {
197+
final StringBuilder sb = new StringBuilder();
198+
renderOn(sb, PlainTextRenderer.getInstance());
199+
return sb.toString();
200+
}
201+
202+
}

0 commit comments

Comments
 (0)