Restructure, rename, modularize.
Change-Id: I4aa6cfb486fe002cf65405ec9c2876e3114aaf46
diff --git a/.gitignore b/.gitignore
index 887007b..0390997 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,8 @@
build/
target/
+.envrc
+
*~
*.class
*.iml
diff --git a/deployment/pom.xml b/deployment/pom.xml
index 5d34a10..d468ada 100644
--- a/deployment/pom.xml
+++ b/deployment/pom.xml
@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
- <groupId>eu.mulk.quarkus-observability</groupId>
+ <groupId>eu.mulk.quarkus-googlecloud-jsonlogging</groupId>
<artifactId>quarkus-googlecloud-jsonlogging-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
@@ -19,14 +19,10 @@
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
- <artifactId>quarkus-jsonb-deployment</artifactId>
+ <artifactId>quarkus-jsonp-deployment</artifactId>
</dependency>
<dependency>
- <groupId>io.quarkus</groupId>
- <artifactId>quarkus-jsonb-spi</artifactId>
- </dependency>
- <dependency>
- <groupId>eu.mulk.quarkus-observability</groupId>
+ <groupId>eu.mulk.quarkus-googlecloud-jsonlogging</groupId>
<artifactId>quarkus-googlecloud-jsonlogging</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/deployment/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/GoogleCloudLoggingProcessor.java b/deployment/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/deployment/GoogleCloudLoggingProcessor.java
similarity index 72%
rename from deployment/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/GoogleCloudLoggingProcessor.java
rename to deployment/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/deployment/GoogleCloudLoggingProcessor.java
index 8ecf000..aea89b9 100644
--- a/deployment/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/GoogleCloudLoggingProcessor.java
+++ b/deployment/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/deployment/GoogleCloudLoggingProcessor.java
@@ -1,5 +1,6 @@
-package eu.mulk.quarkus.observability.googlecloud.jsonlogging;
+package eu.mulk.quarkus.googlecloud.jsonlogging.deployment;
+import eu.mulk.quarkus.googlecloud.jsonlogging.GoogleCloudJsonLoggingRecorder;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;
@@ -17,7 +18,7 @@
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
- LogConsoleFormatBuildItem setUpFormatter(GoogleCloudLoggingRecorder recorder) {
+ LogConsoleFormatBuildItem setUpFormatter(GoogleCloudJsonLoggingRecorder recorder) {
return new LogConsoleFormatBuildItem(recorder.initialize());
}
}
diff --git a/pom.xml b/pom.xml
index 0881faa..802886d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
- <groupId>eu.mulk.quarkus-observability</groupId>
+ <groupId>eu.mulk.quarkus-googlecloud-jsonlogging</groupId>
<artifactId>quarkus-googlecloud-jsonlogging-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
diff --git a/runtime/pom.xml b/runtime/pom.xml
index e8254f9..8b6616b 100644
--- a/runtime/pom.xml
+++ b/runtime/pom.xml
@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
- <groupId>eu.mulk.quarkus-observability</groupId>
+ <groupId>eu.mulk.quarkus-googlecloud-jsonlogging</groupId>
<artifactId>quarkus-googlecloud-jsonlogging-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
@@ -19,7 +19,7 @@
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
- <artifactId>quarkus-jsonb</artifactId>
+ <artifactId>quarkus-jsonp</artifactId>
</dependency>
</dependencies>
diff --git a/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/GoogleCloudLoggingFormatter.java b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/Formatter.java
similarity index 72%
rename from runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/GoogleCloudLoggingFormatter.java
rename to runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/Formatter.java
index 3ec1fcc..d6eeb0e 100644
--- a/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/GoogleCloudLoggingFormatter.java
+++ b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/Formatter.java
@@ -1,11 +1,12 @@
-package eu.mulk.quarkus.observability.googlecloud.jsonlogging;
+package eu.mulk.quarkus.googlecloud.jsonlogging;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.logging.Level;
-import javax.json.bind.Jsonb;
-import javax.json.bind.JsonbException;
import org.jboss.logmanager.ExtFormatter;
import org.jboss.logmanager.ExtLogRecord;
@@ -14,9 +15,9 @@
*
* <p>Meant to be used in containers running on Google Kubernetes Engine (GKE).
*
- * @see GoogleCloudLogEntry
+ * @see LogEntry
*/
-class GoogleCloudLoggingFormatter extends ExtFormatter {
+class Formatter extends ExtFormatter {
private static final String TRACE_LEVEL = "TRACE";
private static final String DEBUG_LEVEL = "DEBUG";
@@ -27,22 +28,16 @@
private static final String ERROR_EVENT_TYPE =
"type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent";
- private final Jsonb jsonb;
-
- GoogleCloudLoggingFormatter(Jsonb jsonb) {
- this.jsonb = jsonb;
- }
-
@Override
public String format(ExtLogRecord logRecord) {
var message = formatMessageWithStackTrace(logRecord);
- var parameters = new HashMap<String, Object>();
- var labels = new HashMap<String, String>();
+ List<StructuredParameter> parameters = new ArrayList<>();
+ Map<String, String> labels = new HashMap<>();
if (logRecord.getParameters() != null) {
for (var parameter : logRecord.getParameters()) {
- if (parameter instanceof KeyValueParameter kvparam) {
- parameters.put(kvparam.key(), kvparam.value());
+ if (parameter instanceof StructuredParameter sparam) {
+ parameters.add(sparam);
} else if (parameter instanceof Label label) {
labels.put(label.key(), label.value());
}
@@ -53,32 +48,27 @@
var ndc = logRecord.getNdc();
var sourceLocation =
- new GoogleCloudLogEntry.SourceLocation(
+ new LogEntry.SourceLocation(
logRecord.getSourceFileName(),
String.valueOf(logRecord.getSourceLineNumber()),
String.format(
"%s.%s", logRecord.getSourceClassName(), logRecord.getSourceMethodName()));
var entry =
- new GoogleCloudLogEntry(
+ new LogEntry(
message,
severityOf(logRecord.getLevel()),
- new GoogleCloudLogEntry.Timestamp(logRecord.getInstant()),
+ new LogEntry.Timestamp(logRecord.getInstant()),
null,
null,
sourceLocation,
- labels.isEmpty() ? null : labels,
- parameters.isEmpty() ? null : parameters,
- mdc.isEmpty() ? null : mdc,
- ndc.isEmpty() ? null : ndc,
+ labels,
+ parameters,
+ mdc,
+ ndc,
logRecord.getLevel().intValue() >= 1000 ? ERROR_EVENT_TYPE : null);
- try {
- return jsonb.toJson(entry) + "\n";
- } catch (JsonbException e) {
- e.printStackTrace();
- return message + "\n";
- }
+ return entry.json().build().toString() + "\n";
}
/**
diff --git a/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/GoogleCloudJsonLoggingRecorder.java b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/GoogleCloudJsonLoggingRecorder.java
new file mode 100644
index 0000000..db2c2e9
--- /dev/null
+++ b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/GoogleCloudJsonLoggingRecorder.java
@@ -0,0 +1,12 @@
+package eu.mulk.quarkus.googlecloud.jsonlogging;
+
+import io.quarkus.runtime.RuntimeValue;
+import io.quarkus.runtime.annotations.Recorder;
+import java.util.Optional;
+
+@Recorder
+public class GoogleCloudJsonLoggingRecorder {
+ public RuntimeValue<Optional<java.util.logging.Formatter>> initialize() {
+ return new RuntimeValue<>(Optional.of(new Formatter()));
+ }
+}
diff --git a/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/KeyValueParameter.java b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/KeyValueParameter.java
new file mode 100644
index 0000000..5f582c9
--- /dev/null
+++ b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/KeyValueParameter.java
@@ -0,0 +1,43 @@
+package eu.mulk.quarkus.googlecloud.jsonlogging;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import javax.json.Json;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonValue;
+
+public record KeyValueParameter(String key, JsonValue value) implements StructuredParameter {
+
+ public static KeyValueParameter of(String key, String value) {
+ return new KeyValueParameter(key, Json.createValue(value));
+ }
+
+ public static KeyValueParameter of(String key, int value) {
+ return new KeyValueParameter(key, Json.createValue(value));
+ }
+
+ public static KeyValueParameter of(String key, long value) {
+ return new KeyValueParameter(key, Json.createValue(value));
+ }
+
+ public static KeyValueParameter of(String key, double value) {
+ return new KeyValueParameter(key, Json.createValue(value));
+ }
+
+ public static KeyValueParameter of(String key, BigDecimal value) {
+ return new KeyValueParameter(key, Json.createValue(value));
+ }
+
+ public static KeyValueParameter of(String key, BigInteger value) {
+ return new KeyValueParameter(key, Json.createValue(value));
+ }
+
+ public static KeyValueParameter of(String key, boolean value) {
+ return new KeyValueParameter(key, value ? JsonValue.TRUE : JsonValue.FALSE);
+ }
+
+ @Override
+ public JsonObjectBuilder json() {
+ return Json.createObjectBuilder().add(key, value);
+ }
+}
diff --git a/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/Label.java b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/Label.java
new file mode 100644
index 0000000..02f7034
--- /dev/null
+++ b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/Label.java
@@ -0,0 +1,8 @@
+package eu.mulk.quarkus.googlecloud.jsonlogging;
+
+public record Label(String key, String value) {
+
+ public static Label of(String key, String value) {
+ return new Label(key, value);
+ }
+}
diff --git a/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/LogEntry.java b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/LogEntry.java
new file mode 100644
index 0000000..4394033
--- /dev/null
+++ b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/LogEntry.java
@@ -0,0 +1,103 @@
+package eu.mulk.quarkus.googlecloud.jsonlogging;
+
+import io.smallrye.common.constraint.Nullable;
+import java.time.Instant;
+import java.util.List;
+import java.util.Map;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+
+/**
+ * A JSON log entry compatible with Google Cloud Logging.
+ *
+ * <p>Roughly (but not quite) corresponds to Google Cloud Logging's <a
+ * href="https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry">LogEntry</a>
+ * structure.
+ *
+ * <p>A few of the fields are treated specially by the fluentd instance running in Google Kubernetes
+ * Engine. All other fields end up in the jsonPayload field on the Google Cloud Logging side.
+ */
+record LogEntry(
+ String message,
+ String severity,
+ Timestamp timestamp,
+ @Nullable String trace,
+ @Nullable String spanId,
+ SourceLocation sourceLocation,
+ Map<String, String> labels,
+ List<StructuredParameter> parameters,
+ Map<String, String> mappedDiagnosticContext,
+ @Nullable String nestedDiagnosticContext,
+ @Nullable String type) {
+
+ static record SourceLocation(
+ @Nullable String file, @Nullable String line, @Nullable String function) {
+
+ JsonObject json() {
+ return Json.createObjectBuilder()
+ .add("file", file)
+ .add("line", line)
+ .add("function", function)
+ .build();
+ }
+ }
+
+ static record Timestamp(long seconds, int nanos) {
+
+ Timestamp(Instant t) {
+ this(t.getEpochSecond(), t.getNano());
+ }
+
+ JsonObject json() {
+ return Json.createObjectBuilder().add("seconds", seconds).add("nanos", nanos).build();
+ }
+ }
+
+ JsonObjectBuilder json() {
+ var b = Json.createObjectBuilder();
+
+ if (trace != null) {
+ b.add("trace", trace);
+ }
+
+ if (spanId != null) {
+ b.add("spanId", spanId);
+ }
+
+ if (nestedDiagnosticContext != null && !nestedDiagnosticContext.isEmpty()) {
+ b.add("nestedDiagnosticContext", nestedDiagnosticContext);
+ }
+
+ if (!labels.isEmpty()) {
+ b.add("labels", jsonOfStringMap(labels));
+ }
+
+ if (type != null) {
+ b.add("@type", type);
+ }
+
+ return b.add("message", message)
+ .add("severity", severity)
+ .add("timestamp", timestamp.json())
+ .add("sourceLocation", sourceLocation.json())
+ .addAll(jsonOfStringMap(mappedDiagnosticContext))
+ .addAll(jsonOfParameterMap(parameters));
+ }
+
+ private static JsonObjectBuilder jsonOfStringMap(Map<String, String> stringMap) {
+ return stringMap.entrySet().stream()
+ .reduce(
+ Json.createObjectBuilder(),
+ (acc, x) -> acc.add(x.getKey(), x.getValue()),
+ JsonObjectBuilder::addAll);
+ }
+
+ private static JsonObjectBuilder jsonOfParameterMap(List<StructuredParameter> parameters) {
+ return parameters.stream()
+ .reduce(
+ Json.createObjectBuilder(),
+ (acc, p) -> acc.addAll(p.json()),
+ JsonObjectBuilder::addAll);
+ }
+}
diff --git a/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameter.java b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameter.java
new file mode 100644
index 0000000..0b4a36e
--- /dev/null
+++ b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameter.java
@@ -0,0 +1,7 @@
+package eu.mulk.quarkus.googlecloud.jsonlogging;
+
+import javax.json.JsonObjectBuilder;
+
+public interface StructuredParameter {
+ JsonObjectBuilder json();
+}
diff --git a/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/GoogleCloudLogEntry.java b/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/GoogleCloudLogEntry.java
deleted file mode 100644
index 0450d0c..0000000
--- a/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/GoogleCloudLogEntry.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package eu.mulk.quarkus.observability.googlecloud.jsonlogging;
-
-import io.smallrye.common.constraint.Nullable;
-import java.time.Instant;
-import java.util.Map;
-import javax.json.bind.annotation.JsonbProperty;
-
-/**
- * A JSON log entry compatible with Google Cloud Logging.
- *
- * <p>Roughly (but not quite) corresponds to Google Cloud Logging's <a
- * href="https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry">LogEntry</a>
- * structure.
- */
-public record GoogleCloudLogEntry(
- String getMessage,
- String getSeverity,
- Timestamp getTimestamp,
- @Nullable String getTrace,
- @Nullable String getSpanId,
- @Nullable SourceLocation getSourceLocation,
- @Nullable Map<String, String> getLabels,
- @Nullable Map<String, Object> getParameters,
- @Nullable Map<String, String> getMappedDiagnosticContext,
- @Nullable String getNestedDiagnosticContext,
- @Nullable @JsonbProperty("@type") String getType) {
-
- public static record SourceLocation(
- @Nullable String getFile, @Nullable String getLine, @Nullable String getFunction) {}
-
- public static record Timestamp(long getSeconds, int getNanos) {
-
- public Timestamp(Instant t) {
- this(t.getEpochSecond(), t.getNano());
- }
- }
-}
diff --git a/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/GoogleCloudLoggingRecorder.java b/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/GoogleCloudLoggingRecorder.java
deleted file mode 100644
index 9ae3ae1..0000000
--- a/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/GoogleCloudLoggingRecorder.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package eu.mulk.quarkus.observability.googlecloud.jsonlogging;
-
-import io.quarkus.runtime.RuntimeValue;
-import io.quarkus.runtime.annotations.Recorder;
-import java.util.Optional;
-import java.util.logging.Formatter;
-import javax.json.bind.spi.JsonbProvider;
-
-@Recorder
-public class GoogleCloudLoggingRecorder {
-
- public RuntimeValue<Optional<Formatter>> initialize() {
- var jsonb = JsonbProvider.provider().create().build();
- return new RuntimeValue<>(Optional.of(new GoogleCloudLoggingFormatter(jsonb)));
- }
-}
diff --git a/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/KeyValueParameter.java b/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/KeyValueParameter.java
deleted file mode 100644
index 358e470..0000000
--- a/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/KeyValueParameter.java
+++ /dev/null
@@ -1,3 +0,0 @@
-package eu.mulk.quarkus.observability.googlecloud.jsonlogging;
-
-public record KeyValueParameter(String key, Object value) {}
diff --git a/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/Label.java b/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/Label.java
deleted file mode 100644
index 0c13739..0000000
--- a/runtime/src/main/java/eu/mulk/quarkus/observability/googlecloud/jsonlogging/Label.java
+++ /dev/null
@@ -1,3 +0,0 @@
-package eu.mulk.quarkus.observability.googlecloud.jsonlogging;
-
-public record Label(String key, String value) {}
diff --git a/runtime/src/main/java/module-info.java b/runtime/src/main/java/module-info.java
new file mode 100644
index 0000000..56b44fc
--- /dev/null
+++ b/runtime/src/main/java/module-info.java
@@ -0,0 +1,9 @@
+module quarkus.googlecloud.jsonlogging {
+ requires java.logging;
+ requires java.json;
+ requires jboss.logmanager.embedded;
+ requires quarkus.core;
+ requires smallrye.common.constraint;
+
+ exports eu.mulk.quarkus.googlecloud.jsonlogging;
+}