Skip to content

Commit 9176b44

Browse files
ViliusSvy
andauthored
Adjust GcpLayout JSON to latest format (apache#3586)
* Adjust GcpLayout JSON to latest format First, it formats the log timestamp field to the correct format recognized by Fluent-Bit (component of Google Cloud Logging) and Google Ops Agent. Secondly, severity field now must be prefixed with logging.googleapis.com. Third, counter cannot be used for insertId as it is duplicated on different threads. And the last but not the least, exception, thread and logger fields are pretty standard when logging via Logback's JSON layout and Google's Spring GCP libraries. Field name changes now match these other loggers. * revert severity changes, remove insertId * Remove insertid from tests * fix spotless error * Switch exception field to use exception resolver * try to fix timestamp tests * Fix tests with empty exceptions * Add changelog * Improve changelog. --------- Co-authored-by: Volkan Yazıcı <[email protected]>
1 parent db0360d commit 9176b44

File tree

3 files changed

+33
-59
lines changed

3 files changed

+33
-59
lines changed

log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/GcpLayoutTest.java

+7-37
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@
2121
import static org.apache.logging.log4j.layout.template.json.TestHelpers.usingSerializedLogEventAccessor;
2222
import static org.assertj.core.api.Assertions.assertThat;
2323

24-
import java.time.Instant;
25-
import java.time.ZoneId;
26-
import java.time.ZonedDateTime;
27-
import java.time.format.DateTimeFormatter;
28-
import java.util.Locale;
2924
import org.apache.logging.log4j.Level;
3025
import org.apache.logging.log4j.core.LogEvent;
3126
import org.apache.logging.log4j.core.impl.ContextDataFactory;
@@ -44,9 +39,6 @@ class GcpLayoutTest {
4439

4540
private static final int LOG_EVENT_COUNT = 1_000;
4641

47-
private static final DateTimeFormatter DATE_TIME_FORMATTER =
48-
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
49-
5042
@Test
5143
void test_lite_log_events() {
5244
LogEventFixture.createLiteLogEvents(LOG_EVENT_COUNT).forEach(GcpLayoutTest::verifySerialization);
@@ -84,8 +76,9 @@ private static void verifySerialization(final LogEvent logEvent) {
8476
usingSerializedLogEventAccessor(LAYOUT, logEvent, accessor -> {
8577

8678
// Verify timestamp.
87-
final String expectedTimestamp = formatLogEventInstant(logEvent);
88-
assertThat(accessor.getString("timestamp")).isEqualTo(expectedTimestamp);
79+
final org.apache.logging.log4j.core.time.Instant instant = logEvent.getInstant();
80+
assertThat(accessor.getInteger("timestampSeconds")).isEqualTo(instant.getEpochSecond());
81+
assertThat(accessor.getInteger("timestampNanos")).isEqualTo(instant.getNanoOfSecond());
8982

9083
// Verify severity.
9184
final Level level = logEvent.getLevel();
@@ -148,48 +141,25 @@ private static void verifySerialization(final LogEvent logEvent) {
148141
.isEmpty();
149142
}
150143

151-
// Verify insert id.
152-
assertThat(accessor.getString("logging.googleapis.com/insertId")).matches("[-]?[0-9]+");
153-
154144
// Verify exception.
155145
if (exception != null) {
156146

157-
// Verify exception class.
158-
assertThat(accessor.getString(new String[] {"_exception", "class"}))
159-
.isEqualTo(exception.getClass().getCanonicalName());
160-
161-
// Verify exception message.
162-
assertThat(accessor.getString(new String[] {"_exception", "message"}))
163-
.isEqualTo(exception.getMessage());
164-
165147
// Verify exception stack trace.
166-
assertThat(accessor.getString(new String[] {"_exception", "stackTrace"}))
148+
assertThat(accessor.getString("exception"))
167149
.contains(exception.getLocalizedMessage())
168150
.contains("at org.apache.logging.log4j.layout.template.json")
169151
.contains("at " + JAVA_BASE_PREFIX + "java.lang.reflect.Method")
170152
.contains("at org.junit.platform.engine");
171153

172154
} else {
173-
assertThat(accessor.getObject(new String[] {"_exception", "class"}))
174-
.isNull();
175-
assertThat(accessor.getObject(new String[] {"_exception", "message"}))
176-
.isNull();
177-
assertThat(accessor.getString(new String[] {"_exception", "stackTrace"}))
178-
.isEmpty();
155+
assertThat(accessor.getString("exception")).isNull();
179156
}
180157

181158
// Verify thread name.
182-
assertThat(accessor.getString("_thread")).isEqualTo(logEvent.getThreadName());
159+
assertThat(accessor.getString("thread")).isEqualTo(logEvent.getThreadName());
183160

184161
// Verify logger name.
185-
assertThat(accessor.getString("_logger")).isEqualTo(logEvent.getLoggerName());
162+
assertThat(accessor.getString("logger")).isEqualTo(logEvent.getLoggerName());
186163
});
187164
}
188-
189-
private static String formatLogEventInstant(final LogEvent logEvent) {
190-
final org.apache.logging.log4j.core.time.Instant instant = logEvent.getInstant();
191-
final ZonedDateTime dateTime = Instant.ofEpochSecond(instant.getEpochSecond(), instant.getNanoOfSecond())
192-
.atZone(ZoneId.of("UTC"));
193-
return DATE_TIME_FORMATTER.format(dateTime);
194-
}
195165
}

log4j-layout-template-json/src/main/resources/GcpLayout.json

+16-22
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
{
2-
"timestamp": {
2+
"timestampSeconds": {
33
"$resolver": "timestamp",
4-
"pattern": {
5-
"format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
6-
"timeZone": "UTC",
7-
"locale": "en_US"
4+
"epoch": {
5+
"unit": "secs",
6+
"rounded": true
7+
}
8+
},
9+
"timestampNanos": {
10+
"$resolver": "timestamp",
11+
"epoch": {
12+
"unit": "secs.nanos"
813
}
914
},
1015
"severity": {
@@ -36,10 +41,6 @@
3641
"stackTraceEnabled": false
3742
}
3843
},
39-
"logging.googleapis.com/insertId": {
40-
"$resolver": "counter",
41-
"stringified": true
42-
},
4344
"logging.googleapis.com/trace": {
4445
"$resolver": "mdc",
4546
"key": "trace_id"
@@ -49,25 +50,18 @@
4950
"key": "span_id"
5051
},
5152
"logging.googleapis.com/trace_sampled": true,
52-
"_exception": {
53-
"class": {
54-
"$resolver": "exception",
55-
"field": "className"
56-
},
57-
"message": {
58-
"$resolver": "exception",
59-
"field": "message"
60-
},
53+
"exception": {
54+
"$resolver": "exception",
55+
"field": "stackTrace",
6156
"stackTrace": {
62-
"$resolver": "pattern",
63-
"pattern": "%xEx"
57+
"stringified": true
6458
}
6559
},
66-
"_thread": {
60+
"thread": {
6761
"$resolver": "thread",
6862
"field": "name"
6963
},
70-
"_logger": {
64+
"logger": {
7165
"$resolver": "logger",
7266
"field": "name"
7367
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xmlns="https://logging.apache.org/xml/ns"
4+
xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
5+
type="changed">
6+
<issue id="3586" link="https://github.com/apache/logging-log4j2/pull/3586"/>
7+
<description format="asciidoc">
8+
Update `GcpLayout.json` JSON Template Layout event template to support automatic timestamp recognition by the Google Cloud Logging. This also changes `exception`, `thread`, `logger` fields, and removes `insertId` field.
9+
</description>
10+
</entry>

0 commit comments

Comments
 (0)