This is an automated email from the ASF dual-hosted git repository.
mattsicker pushed a commit to branch fix/3.x/port-3586
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit c09e2f9b22fe84a4b5859c8fd33e976424233417
Author: Vilius Šumskas <vil...@sumskas.eu>
AuthorDate: Sun May 4 00:28:47 2025 +0300
Adjust GcpLayout JSON to latest format (#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ı <volkan.yaz...@oracle.com>
---
.../log4j/layout/template/json/GcpLayoutTest.java | 44 ++++------------------
.../src/main/resources/GcpLayout.json | 38 ++++++++-----------
2 files changed, 23 insertions(+), 59 deletions(-)
diff --git
a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/GcpLayoutTest.java
b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/GcpLayoutTest.java
index a617d3a2e2..080bb41f11 100644
---
a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/GcpLayoutTest.java
+++
b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/GcpLayoutTest.java
@@ -20,11 +20,6 @@ import static
org.apache.logging.log4j.layout.template.json.TestHelpers.CONFIGUR
import static
org.apache.logging.log4j.layout.template.json.TestHelpers.usingSerializedLogEventAccessor;
import static org.assertj.core.api.Assertions.assertThat;
-import java.time.Instant;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.Locale;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.impl.ContextDataFactory;
@@ -43,9 +38,6 @@ class GcpLayoutTest {
private static final int LOG_EVENT_COUNT = 1_000;
- private static final DateTimeFormatter DATE_TIME_FORMATTER =
- DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
Locale.US);
-
@Test
void test_lite_log_events() {
LogEventFixture.createLiteLogEvents(LOG_EVENT_COUNT).forEach(GcpLayoutTest::verifySerialization);
@@ -83,8 +75,9 @@ class GcpLayoutTest {
usingSerializedLogEventAccessor(LAYOUT, logEvent, accessor -> {
// Verify timestamp.
- final String expectedTimestamp = formatLogEventInstant(logEvent);
-
assertThat(accessor.getString("timestamp")).isEqualTo(expectedTimestamp);
+ final org.apache.logging.log4j.core.time.Instant instant =
logEvent.getInstant();
+
assertThat(accessor.getInteger("timestampSeconds")).isEqualTo(instant.getEpochSecond());
+
assertThat(accessor.getInteger("timestampNanos")).isEqualTo(instant.getNanoOfSecond());
// Verify severity.
final Level level = logEvent.getLevel();
@@ -147,48 +140,25 @@ class GcpLayoutTest {
.isEmpty();
}
- // Verify insert id.
-
assertThat(accessor.getString("logging.googleapis.com/insertId")).matches("[-]?[0-9]+");
-
// Verify exception.
if (exception != null) {
- // Verify exception class.
- assertThat(accessor.getString(new String[] {"_exception",
"class"}))
- .isEqualTo(exception.getClass().getCanonicalName());
-
- // Verify exception message.
- assertThat(accessor.getString(new String[] {"_exception",
"message"}))
- .isEqualTo(exception.getMessage());
-
// Verify exception stack trace.
- assertThat(accessor.getString(new String[] {"_exception",
"stackTrace"}))
+ assertThat(accessor.getString("exception"))
.contains(exception.getLocalizedMessage())
.contains("at
org.apache.logging.log4j.layout.template.json")
.contains("at java.base/java.lang.reflect.Method")
.contains("at org.junit.platform.engine");
} else {
- assertThat(accessor.getObject(new String[] {"_exception",
"class"}))
- .isNull();
- assertThat(accessor.getObject(new String[] {"_exception",
"message"}))
- .isNull();
- assertThat(accessor.getString(new String[] {"_exception",
"stackTrace"}))
- .isEmpty();
+ assertThat(accessor.getString("exception")).isNull();
}
// Verify thread name.
-
assertThat(accessor.getString("_thread")).isEqualTo(logEvent.getThreadName());
+
assertThat(accessor.getString("thread")).isEqualTo(logEvent.getThreadName());
// Verify logger name.
-
assertThat(accessor.getString("_logger")).isEqualTo(logEvent.getLoggerName());
+
assertThat(accessor.getString("logger")).isEqualTo(logEvent.getLoggerName());
});
}
-
- private static String formatLogEventInstant(final LogEvent logEvent) {
- final org.apache.logging.log4j.core.time.Instant instant =
logEvent.getInstant();
- final ZonedDateTime dateTime =
Instant.ofEpochSecond(instant.getEpochSecond(), instant.getNanoOfSecond())
- .atZone(ZoneId.of("UTC"));
- return DATE_TIME_FORMATTER.format(dateTime);
- }
}
diff --git a/log4j-layout-template-json/src/main/resources/GcpLayout.json
b/log4j-layout-template-json/src/main/resources/GcpLayout.json
index f00c84d981..75bf58a789 100644
--- a/log4j-layout-template-json/src/main/resources/GcpLayout.json
+++ b/log4j-layout-template-json/src/main/resources/GcpLayout.json
@@ -1,10 +1,15 @@
{
- "timestamp": {
+ "timestampSeconds": {
"$resolver": "timestamp",
- "pattern": {
- "format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
- "timeZone": "UTC",
- "locale": "en_US"
+ "epoch": {
+ "unit": "secs",
+ "rounded": true
+ }
+ },
+ "timestampNanos": {
+ "$resolver": "timestamp",
+ "epoch": {
+ "unit": "secs.nanos"
}
},
"severity": {
@@ -36,10 +41,6 @@
"stackTraceEnabled": false
}
},
- "logging.googleapis.com/insertId": {
- "$resolver": "counter",
- "stringified": true
- },
"logging.googleapis.com/trace": {
"$resolver": "mdc",
"key": "trace_id"
@@ -49,25 +50,18 @@
"key": "span_id"
},
"logging.googleapis.com/trace_sampled": true,
- "_exception": {
- "class": {
- "$resolver": "exception",
- "field": "className"
- },
- "message": {
- "$resolver": "exception",
- "field": "message"
- },
+ "exception": {
+ "$resolver": "exception",
+ "field": "stackTrace",
"stackTrace": {
- "$resolver": "pattern",
- "pattern": "%xEx"
+ "stringified": true
}
},
- "_thread": {
+ "thread": {
"$resolver": "thread",
"field": "name"
},
- "_logger": {
+ "logger": {
"$resolver": "logger",
"field": "name"
}