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 <mattsic...@apache.org>
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 <vil...@sumskas.eu>
    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"
   }

Reply via email to