This is an automated email from the ASF dual-hosted git repository.
mattsicker pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/main by this push:
new 6af1756063 Adjust GcpLayout JSON to latest format (#3586) (#3867)
6af1756063 is described below
commit 6af17560635ab14bb97651aaf4a7c7b17ba8c7bd
Author: Matt Sicker <[email protected]>
AuthorDate: Fri Aug 1 12:08:57 2025 -0500
Adjust GcpLayout JSON to latest format (#3586) (#3867)
* 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: Vilius Šumskas <[email protected]>
Co-authored-by: Volkan Yazıcı <[email protected]>
---
.../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"
}