Skip to content

Commit 1df2559

Browse files
committed
Add includeOrigin flag
depends on elastic/ecs#563 closes elastic#3
1 parent 0455a70 commit 1df2559

File tree

14 files changed

+105
-21
lines changed

14 files changed

+105
-21
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ We recommend using this library to log into a JSON log file and let Filebeat sen
8686
|[`@timestamp`](https://www.elastic.co/guide/en/ecs/current/ecs-base.html) | [`LogEvent#getTimeMillis()`](https://logging.apache.org/log4j/log4j-2.3/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getTimeMillis()) |
8787
|[`log.level`](https://www.elastic.co/guide/en/ecs/current/ecs-log.html) | [`LogEvent#getLevel()`](https://logging.apache.org/log4j/log4j-2.3/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getLevel()) |
8888
|[`log.logger`](https://www.elastic.co/guide/en/ecs/current/ecs-log.html)|[`LogEvent#getLoggerName()`](https://logging.apache.org/log4j/log4j-2.3/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getLoggerName())|
89+
|[`log.origin.file`](https://www.elastic.co/guide/en/ecs/current/ecs-log.html)|[StackTraceElement#getFileName()](https://docs.oracle.com/javase/6/docs/api/java/lang/StackTraceElement.html#getFileName())|
90+
|[`log.origin.function`](https://www.elastic.co/guide/en/ecs/current/ecs-log.html)|[`[StackTraceElement#getMethodName()]()`](https://docs.oracle.com/javase/6/docs/api/java/lang/StackTraceElement.html#getMethodName())|
91+
|[`log.origin.line`](https://www.elastic.co/guide/en/ecs/current/ecs-log.html)|[`[StackTraceElement#getLineNumber()]()`](https://docs.oracle.com/javase/6/docs/api/java/lang/StackTraceElement.html#getLineNumber())|
8992
|[`message`](https://www.elastic.co/guide/en/ecs/current/ecs-base.html)|[`LogEvent#getMessage()`](https://logging.apache.org/log4j/log4j-2.3/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getMessage())|
9093
|[`error.code`](https://www.elastic.co/guide/en/ecs/current/ecs-error.html)|[`Throwable#getClass()`](https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#getClass())|
9194
|[`error.message`](https://www.elastic.co/guide/en/ecs/current/ecs-error.html)|[`Throwable#getStackTrace()`](https://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#getMessage())|

ecs-logging-core/src/main/java/co/elastic/logging/EcsJsonSerializer.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,25 @@ public static void serializeTagEnd(StringBuilder builder) {
115115
builder.append("],");
116116
}
117117

118+
public static void serializeOrigin(StringBuilder builder, StackTraceElement stackTraceElement) {
119+
if (stackTraceElement != null) {
120+
serializeOrigin(builder, stackTraceElement.getFileName(), stackTraceElement.getMethodName(), stackTraceElement.getLineNumber());
121+
}
122+
}
123+
124+
public static void serializeOrigin(StringBuilder builder, String fileName, String methodName, int lineNumber) {
125+
builder.append("\"log.origin\":{");
126+
builder.append("\"file\":\"");
127+
JsonUtils.quoteAsString(fileName, builder);
128+
builder.append("\",");
129+
builder.append("\"function\":\"");
130+
JsonUtils.quoteAsString(methodName, builder);
131+
builder.append("\",");
132+
builder.append("\"line\":");
133+
builder.append(lineNumber);
134+
builder.append("},");
135+
}
136+
118137
public static void serializeLabels(StringBuilder builder, Map<String, ?> labels, Set<String> topLevelLabels) {
119138
if (!labels.isEmpty()) {
120139
for (Map.Entry<String, ?> entry : labels.entrySet()) {

ecs-logging-core/src/test/java/co/elastic/logging/AbstractEcsLoggingTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ void testLogException() throws Exception {
9393
assertThat(stackTrace).contains("at co.elastic.logging.AbstractEcsLoggingTest.testLogException");
9494
}
9595

96+
@Test
97+
void testLogOrigin() throws Exception {
98+
debug("test");
99+
assertThat(getLastLogLine().get("log.origin").get("file").textValue()).endsWith(".java");
100+
assertThat(getLastLogLine().get("log.origin").get("function").textValue()).isEqualTo("debug");
101+
assertThat(getLastLogLine().get("log.origin").get("line").intValue()).isPositive();
102+
}
103+
96104
public abstract void putMdc(String key, String value);
97105

98106
public boolean putNdc(String message) {

log4j-ecs-layout/src/main/java/co/elastic/logging/log4j/EcsLayout.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import co.elastic.logging.EcsJsonSerializer;
2828
import org.apache.log4j.Layout;
29+
import org.apache.log4j.spi.LocationInfo;
2930
import org.apache.log4j.spi.LoggingEvent;
3031
import org.apache.log4j.spi.ThrowableInformation;
3132

@@ -37,6 +38,7 @@ public class EcsLayout extends Layout {
3738
private boolean stackTraceAsArray = false;
3839
private String serviceName;
3940
private Set<String> topLevelLabels = new HashSet<String>(EcsJsonSerializer.DEFAULT_TOP_LEVEL_LABELS);
41+
private boolean includeOrigin;
4042

4143
@Override
4244
public String format(LoggingEvent event) {
@@ -49,6 +51,12 @@ public String format(LoggingEvent event) {
4951
EcsJsonSerializer.serializeLoggerName(builder, event.getLoggerName());
5052
EcsJsonSerializer.serializeLabels(builder, event.getProperties(), topLevelLabels);
5153
EcsJsonSerializer.serializeTag(builder, event.getNDC());
54+
if (includeOrigin) {
55+
LocationInfo locationInformation = event.getLocationInformation();
56+
if (locationInformation != null) {
57+
EcsJsonSerializer.serializeOrigin(builder, locationInformation.getFileName(), locationInformation.getMethodName(), getLineNumber(locationInformation));
58+
}
59+
}
5260
ThrowableInformation throwableInformation = event.getThrowableInformation();
5361
if (throwableInformation != null) {
5462
EcsJsonSerializer.serializeException(builder, throwableInformation.getThrowable(), stackTraceAsArray);
@@ -57,6 +65,19 @@ public String format(LoggingEvent event) {
5765
return builder.toString();
5866
}
5967

68+
private static int getLineNumber(LocationInfo locationInformation) {
69+
int lineNumber = -1;
70+
String lineNumberString = locationInformation.getLineNumber();
71+
if (!LocationInfo.NA.equals(lineNumberString)) {
72+
try {
73+
lineNumber = Integer.parseInt(lineNumberString);
74+
} catch (NumberFormatException e) {
75+
// ignore
76+
}
77+
}
78+
return lineNumber;
79+
}
80+
6081
@Override
6182
public boolean ignoresThrowable() {
6283
return false;
@@ -71,6 +92,10 @@ public void setServiceName(String serviceName) {
7192
this.serviceName = serviceName;
7293
}
7394

95+
public void setIncludeOrigin(boolean includeOrigin) {
96+
this.includeOrigin = includeOrigin;
97+
}
98+
7499
public void setStackTraceAsArray(boolean stackTraceAsArray) {
75100
this.stackTraceAsArray = stackTraceAsArray;
76101
}

log4j-ecs-layout/src/test/java/co/elastic/logging/log4j/ListAppender.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
import java.util.List;
3232

3333
class ListAppender extends AppenderSkeleton {
34-
private List<LoggingEvent> logEvents = new ArrayList<>();
34+
private List<String> logEvents = new ArrayList<>();
3535

3636
@Override
3737
protected void append(LoggingEvent event) {
38-
logEvents.add(event);
38+
logEvents.add(layout.format(event));
3939
}
4040

4141
@Override
@@ -45,10 +45,10 @@ public void close() {
4545

4646
@Override
4747
public boolean requiresLayout() {
48-
return false;
48+
return true;
4949
}
5050

51-
public List<LoggingEvent> getLogEvents() {
51+
public List<String> getLogEvents() {
5252
return logEvents;
5353
}
5454
}

log4j-ecs-layout/src/test/java/co/elastic/logging/log4j/Log4jEcsLayoutTest.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,11 @@
3131
import org.apache.log4j.MDC;
3232
import org.apache.log4j.NDC;
3333
import org.junit.jupiter.api.AfterEach;
34-
import org.junit.jupiter.api.Assertions;
3534
import org.junit.jupiter.api.Assumptions;
3635
import org.junit.jupiter.api.BeforeEach;
3736

3837
import java.io.IOException;
3938

40-
import static org.assertj.core.api.Assertions.assertThat;
41-
4239
class Log4jEcsLayoutTest extends AbstractEcsLoggingTest {
4340

4441
private Logger logger;
@@ -54,6 +51,8 @@ void setUp() {
5451
ecsLayout = new EcsLayout();
5552
ecsLayout.setServiceName("test");
5653
ecsLayout.setStackTraceAsArray(true);
54+
ecsLayout.setIncludeOrigin(true);
55+
appender.setLayout(ecsLayout);
5756
}
5857

5958
@BeforeEach
@@ -87,7 +86,7 @@ public void error(String message, Throwable t) {
8786

8887
@Override
8988
public JsonNode getLastLogLine() throws IOException {
90-
return objectMapper.readTree(ecsLayout.format(appender.getLogEvents().get(0)));
89+
return objectMapper.readTree(appender.getLogEvents().get(0));
9190
}
9291

9392
}

log4j2-ecs-layout/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Instead of the usual `<PatternLayout/>`, use `<EcsLayout serviceName="my-app"/>`
4747
|serviceName |String | |Sets the `service.name` field so you can filter your logs by a particular service |
4848
|includeMarkers |boolean|`false`|Log [Markers](https://logging.apache.org/log4j/2.0/manual/markers.html) as `tags` |
4949
|stackTraceAsArray|boolean|`false`|Serializes the `error.stack_trace` as a JSON array where each element is in a new line to improve readability. Note that this requires a slightly more complex [Filebeat configuration](../README.md#when-stacktraceasarray-is-enabled).|
50+
|includeOrigin |boolean|`false`|If `true`, adds the `log.origin.file`, `log.origin.function` and `log.origin.line` fields. Note that you also have to set `includeLocation="true"` on your loggers and appenders if you are using the async ones. |
5051

5152
To include any custom field in the output, use following syntax:
5253

log4j2-ecs-layout/src/main/java/co/elastic/logging/log4j2/EcsLayout.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,16 @@ public void accept(final String key, final Object value, final StringBuilder str
7676
private final KeyValuePair[] additionalFields;
7777
private final Set<String> topLevelLabels;
7878
private final boolean stackTraceAsArray;
79-
private String serviceName;
80-
private boolean includeMarkers;
79+
private final String serviceName;
80+
private final boolean includeMarkers;
81+
private final boolean includeOrigin;
8182

82-
private EcsLayout(Configuration config, String serviceName, boolean includeMarkers, KeyValuePair[] additionalFields, Collection<String> topLevelLabels, boolean stackTraceAsArray) {
83+
private EcsLayout(Configuration config, String serviceName, boolean includeMarkers, KeyValuePair[] additionalFields, Collection<String> topLevelLabels, boolean includeOrigin, boolean stackTraceAsArray) {
8384
super(config, UTF_8, null, null);
8485
this.serviceName = serviceName;
8586
this.includeMarkers = includeMarkers;
8687
this.topLevelLabels = new HashSet<String>(topLevelLabels);
88+
this.includeOrigin = includeOrigin;
8789
this.stackTraceAsArray = stackTraceAsArray;
8890
this.topLevelLabels.add("trace.id");
8991
this.topLevelLabels.add("transaction.id");
@@ -121,6 +123,9 @@ private StringBuilder toText(LogEvent event, StringBuilder builder, boolean gcFr
121123
EcsJsonSerializer.serializeLoggerName(builder, event.getLoggerName());
122124
serializeLabels(event, builder);
123125
serializeTags(event, builder);
126+
if (includeOrigin) {
127+
EcsJsonSerializer.serializeOrigin(builder, event.getSource());
128+
}
124129
EcsJsonSerializer.serializeException(builder, event.getThrown(), stackTraceAsArray);
125130
EcsJsonSerializer.serializeObjectEnd(builder);
126131
return builder;
@@ -225,6 +230,8 @@ public static class Builder extends AbstractStringLayout.Builder<EcsLayout.Build
225230
private KeyValuePair[] additionalFields;
226231
@PluginElement("TopLevelLabels")
227232
private String[] topLevelLabels;
233+
@PluginBuilderAttribute("includeOrigin")
234+
private boolean includeOrigin;
228235

229236
Builder() {
230237
super();
@@ -243,6 +250,10 @@ public boolean isIncludeMarkers() {
243250
return includeMarkers;
244251
}
245252

253+
public boolean isIncludeOrigin() {
254+
return includeOrigin;
255+
}
256+
246257
public String[] getTopLevelLabels() {
247258
return topLevelLabels;
248259
}
@@ -272,14 +283,19 @@ public EcsLayout.Builder setIncludeMarkers(final boolean includeMarkers) {
272283
return asBuilder();
273284
}
274285

286+
public EcsLayout.Builder setIncludeOrigin(final boolean includeOrigin) {
287+
this.includeOrigin = includeOrigin;
288+
return asBuilder();
289+
}
290+
275291
public EcsLayout.Builder setStackTraceAsArray(boolean stackTraceAsArray) {
276292
this.stackTraceAsArray = stackTraceAsArray;
277293
return asBuilder();
278294
}
279295

280296
@Override
281297
public EcsLayout build() {
282-
return new EcsLayout(getConfiguration(), serviceName, includeMarkers, additionalFields, topLevelLabels == null ? Collections.<String>emptyList() : Arrays.<String>asList(topLevelLabels), stackTraceAsArray);
298+
return new EcsLayout(getConfiguration(), serviceName, includeMarkers, additionalFields, topLevelLabels == null ? Collections.<String>emptyList() : Arrays.<String>asList(topLevelLabels), includeOrigin, stackTraceAsArray);
283299
}
284300

285301
public boolean isStackTraceAsArray() {

log4j2-ecs-layout/src/test/java/co/elastic/logging/log4j2/Log4j2EcsLayoutTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ void setUp() {
6868
.setConfiguration(ctx.getConfiguration())
6969
.setServiceName("test")
7070
.setIncludeMarkers(true)
71+
.setIncludeOrigin(true)
7172
.setStackTraceAsArray(true)
7273
.setAdditionalFields(new KeyValuePair[]{
7374
new KeyValuePair("cluster.uuid", "9fe9134b-20b0-465e-acf9-8cc09ac9053b"),

log4j2-ecs-layout/src/test/resources/log4j2-test.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
</Properties>
66
<Appenders>
77
<List name="TestAppender">
8-
<EcsLayout serviceName="test" includeMarkers="true" stackTraceAsArray="true">
8+
<EcsLayout serviceName="test" includeMarkers="true" includeOrigin="true" stackTraceAsArray="true">
99
<KeyValuePair key="cluster.uuid" value="9fe9134b-20b0-465e-acf9-8cc09ac9053b"/>
1010
<KeyValuePair key="node.id" value="${node.id}"/>
1111
<KeyValuePair key="empty" value="${empty}"/>

0 commit comments

Comments
 (0)