diff --git a/README.md b/README.md index 6799e1d..ac1e43a 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,12 @@ To see additional configuration options take a look at [Config](https://quarkive quarkus.log.console.json.log-format=ecs ``` +## Google Cloud Platform Scheme +this follows the example of log4j2 and will duplicate the exception into the message +```properties +quarkus.log.console.json.log-format=gcp +``` + # Add additional fields to all log messages If you want to add a static field to all the log message, that is possible using the configuration. ```properties diff --git a/runtime/src/main/java/io/quarkiverse/loggingjson/Config.java b/runtime/src/main/java/io/quarkiverse/loggingjson/Config.java index ef77447..2ab51b3 100644 --- a/runtime/src/main/java/io/quarkiverse/loggingjson/Config.java +++ b/runtime/src/main/java/io/quarkiverse/loggingjson/Config.java @@ -130,6 +130,18 @@ public static class FieldsConfig { */ @ConfigItem public FieldConfig errorMessage; + + /** + * Options for wrappedErrorMessage. + */ + @ConfigItem + public FieldConfig wrappedError; + + /** + * Options for wrappedSourceLocation. + */ + @ConfigItem + public FieldConfig wrappedSourceLocation; } @ConfigGroup @@ -242,6 +254,7 @@ public enum AdditionalFieldType { public enum LogFormat { DEFAULT, - ECS + ECS, + GCP } } diff --git a/runtime/src/main/java/io/quarkiverse/loggingjson/LoggingJsonRecorder.java b/runtime/src/main/java/io/quarkiverse/loggingjson/LoggingJsonRecorder.java index bc7610c..06bf9fe 100644 --- a/runtime/src/main/java/io/quarkiverse/loggingjson/LoggingJsonRecorder.java +++ b/runtime/src/main/java/io/quarkiverse/loggingjson/LoggingJsonRecorder.java @@ -30,6 +30,9 @@ public RuntimeValue> initializeJsonLogging(Config config, bo if (config.logFormat == Config.LogFormat.ECS) { providers = ecsFormat(config); + } + if (config.logFormat == Config.LogFormat.GCP) { + providers = gcpFormat(config); } else { providers = defaultFormat(config); } @@ -105,4 +108,35 @@ private List ecsFormat(Config config) { providers.add(new StaticKeyValueProvider("ecs.version", "1.12.1")); return providers; } + + private List gcpFormat(Config config) { + List providers = new ArrayList<>(); + providers.add(new TimestampJsonProvider(config.fields.timestamp, "timestamp")); + providers.add(new LogLevelJsonProvider(config.fields.level, "severity")); + providers.add(new MessageWithErrorJsonProvider(config.fields.message)); + + providers.add(new SequenceJsonProvider(config.fields.sequence, "logging.googleapis.com/insertId")); // must be unique + + WrappedSourceLocation location = new WrappedSourceLocation(config.fields.wrappedError, + "logging.googleapis.com/sourceLocation", + new JsonProvider[] { + new LoggerNameJsonProvider(config.fields.loggerName, "function") + }); + providers.add(location); + + WrappedError error = new WrappedError(config.fields.wrappedError, "_exception", + new JsonProvider[] { + new ErrorTypeJsonProvider(config.fields.errorType, "class"), + new ErrorMessageJsonProvider(config.fields.errorMessage, "message"), + new StackTraceJsonProvider(config.fields.stackTrace, "stackTrace") + }); + providers.add(error); + + providers.add(new ThreadNameJsonProvider(config.fields.threadName, "_thread")); + providers.add(new LoggerNameJsonProvider(config.fields.loggerName, "_logger")); + + providers.add(new MDCJsonProvider(config.fields.mdc, "logging.googleapis.com/labels")); + + return providers; + } } diff --git a/runtime/src/main/java/io/quarkiverse/loggingjson/providers/MDCJsonProvider.java b/runtime/src/main/java/io/quarkiverse/loggingjson/providers/MDCJsonProvider.java index 73985d2..bd21b90 100644 --- a/runtime/src/main/java/io/quarkiverse/loggingjson/providers/MDCJsonProvider.java +++ b/runtime/src/main/java/io/quarkiverse/loggingjson/providers/MDCJsonProvider.java @@ -16,11 +16,15 @@ public class MDCJsonProvider implements JsonProvider, Enabled { private final Config.MDCConfig config; public MDCJsonProvider(Config.MDCConfig config) { + this(config, "mdc"); + } + + public MDCJsonProvider(Config.MDCConfig config, String defaultName) { this.config = config; if (config.flatFields) { this.fieldName = null; } else { - this.fieldName = config.fieldName.orElse("mdc"); + this.fieldName = config.fieldName.orElse(defaultName); } } diff --git a/runtime/src/main/java/io/quarkiverse/loggingjson/providers/MessageWithErrorJsonProvider.java b/runtime/src/main/java/io/quarkiverse/loggingjson/providers/MessageWithErrorJsonProvider.java new file mode 100644 index 0000000..a1020cb --- /dev/null +++ b/runtime/src/main/java/io/quarkiverse/loggingjson/providers/MessageWithErrorJsonProvider.java @@ -0,0 +1,46 @@ +package io.quarkiverse.loggingjson.providers; + +import java.io.IOException; +import java.io.PrintWriter; + +import org.jboss.logmanager.ExtFormatter; +import org.jboss.logmanager.ExtLogRecord; + +import io.quarkiverse.loggingjson.Config; +import io.quarkiverse.loggingjson.Enabled; +import io.quarkiverse.loggingjson.JsonGenerator; +import io.quarkiverse.loggingjson.JsonProvider; +import io.quarkiverse.loggingjson.JsonWritingUtils; +import io.quarkiverse.loggingjson.StringBuilderWriter; + +public class MessageWithErrorJsonProvider extends ExtFormatter implements JsonProvider, Enabled { + + private final String fieldName; + private final Config.FieldConfig config; + + public MessageWithErrorJsonProvider(Config.FieldConfig config) { + this.config = config; + this.fieldName = config.fieldName.orElse("message"); + } + + @Override + public void writeTo(JsonGenerator generator, ExtLogRecord event) throws IOException { + final StringBuilderWriter w = new StringBuilderWriter(); + w.append(formatMessage(event)); + if (event.getThrown() != null) { + w.append("\n"); + event.getThrown().printStackTrace(new PrintWriter(w)); + } + JsonWritingUtils.writeStringField(generator, fieldName, w.toString()); + } + + @Override + public String format(ExtLogRecord record) { + return null; + } + + @Override + public boolean isEnabled() { + return config.enabled.orElse(true); + } +} diff --git a/runtime/src/main/java/io/quarkiverse/loggingjson/providers/SequenceJsonProvider.java b/runtime/src/main/java/io/quarkiverse/loggingjson/providers/SequenceJsonProvider.java index cce465b..d4ca97c 100644 --- a/runtime/src/main/java/io/quarkiverse/loggingjson/providers/SequenceJsonProvider.java +++ b/runtime/src/main/java/io/quarkiverse/loggingjson/providers/SequenceJsonProvider.java @@ -16,8 +16,12 @@ public class SequenceJsonProvider implements JsonProvider, Enabled { private final Config.FieldConfig config; public SequenceJsonProvider(Config.FieldConfig config) { + this(config, "sequence"); + } + + public SequenceJsonProvider(Config.FieldConfig config, String defaultName) { this.config = config; - this.fieldName = config.fieldName.orElse("sequence"); + this.fieldName = config.fieldName.orElse(defaultName); } @Override diff --git a/runtime/src/main/java/io/quarkiverse/loggingjson/providers/WrappedError.java b/runtime/src/main/java/io/quarkiverse/loggingjson/providers/WrappedError.java new file mode 100644 index 0000000..c4c8fb9 --- /dev/null +++ b/runtime/src/main/java/io/quarkiverse/loggingjson/providers/WrappedError.java @@ -0,0 +1,42 @@ +package io.quarkiverse.loggingjson.providers; + +import java.io.IOException; + +import org.jboss.logmanager.ExtLogRecord; + +import io.quarkiverse.loggingjson.Config; +import io.quarkiverse.loggingjson.Enabled; +import io.quarkiverse.loggingjson.JsonGenerator; +import io.quarkiverse.loggingjson.JsonProvider; + +public class WrappedError implements JsonProvider, Enabled { + + private final String fieldName; + private final Config.FieldConfig config; + private final JsonProvider[] providers; + + public WrappedError(Config.FieldConfig config, JsonProvider[] providers) { + this(config, "error", providers); + } + + public WrappedError(Config.FieldConfig config, String defaultName, JsonProvider[] providers) { + this.config = config; + this.fieldName = config.fieldName.orElse(defaultName); + this.providers = providers; + } + + @Override + public void writeTo(JsonGenerator generator, ExtLogRecord event) throws IOException { + generator.writeObjectFieldStart(fieldName); + for (JsonProvider p : providers) { + p.writeTo(generator, event); + } + generator.writeEndObject(); + } + + @Override + public boolean isEnabled() { + return config.enabled.orElse(true); + } + +} diff --git a/runtime/src/main/java/io/quarkiverse/loggingjson/providers/WrappedSourceLocation.java b/runtime/src/main/java/io/quarkiverse/loggingjson/providers/WrappedSourceLocation.java new file mode 100644 index 0000000..3a44ec2 --- /dev/null +++ b/runtime/src/main/java/io/quarkiverse/loggingjson/providers/WrappedSourceLocation.java @@ -0,0 +1,42 @@ +package io.quarkiverse.loggingjson.providers; + +import java.io.IOException; + +import org.jboss.logmanager.ExtLogRecord; + +import io.quarkiverse.loggingjson.Config; +import io.quarkiverse.loggingjson.Enabled; +import io.quarkiverse.loggingjson.JsonGenerator; +import io.quarkiverse.loggingjson.JsonProvider; + +public class WrappedSourceLocation implements JsonProvider, Enabled { + + private final String fieldName; + private final Config.FieldConfig config; + private final JsonProvider[] providers; + + public WrappedSourceLocation(Config.FieldConfig config, JsonProvider[] providers) { + this(config, "error", providers); + } + + public WrappedSourceLocation(Config.FieldConfig config, String defaultName, JsonProvider[] providers) { + this.config = config; + this.fieldName = config.fieldName.orElse(defaultName); + this.providers = providers; + } + + @Override + public void writeTo(JsonGenerator generator, ExtLogRecord event) throws IOException { + generator.writeObjectFieldStart(fieldName); + for (JsonProvider p : providers) { + p.writeTo(generator, event); + } + generator.writeEndObject(); + } + + @Override + public boolean isEnabled() { + return config.enabled.orElse(true); + } + +}