Load providers registered through the ServiceLoader mechanism.
Change-Id: I392e78b34c8330e9b4c06d57b1423ca552ba6fc1
diff --git a/README.adoc b/README.adoc
index 79407cf..494f44c 100644
--- a/README.adoc
+++ b/README.adoc
@@ -144,6 +144,10 @@
provide contextual information such as tracing and request IDs stored
in thread-local storage.
+Alternatively, you can also register providers through the Java
+https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ServiceLoader.html[ServiceLoader]
+mechanism.
+
**Example:**
[source,java]
diff --git a/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/Formatter.java b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/Formatter.java
index 066f709..61a2dea 100644
--- a/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/Formatter.java
+++ b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/Formatter.java
@@ -7,6 +7,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.ServiceLoader;
import java.util.logging.Level;
import org.jboss.logmanager.ExtFormatter;
import org.jboss.logmanager.ExtLogRecord;
@@ -35,6 +36,9 @@
/**
* Constructs a {@link Formatter}.
*
+ * <p><strong>Note:</strong> This constructor does not automatically discover providers using the
+ * {@link ServiceLoader} mechanism. See {@link #load} for this case use.
+ *
* @param parameterProviders the {@link StructuredParameterProvider}s to apply to each log entry.
* @param labelProviders the {@link LabelProvider}s to apply to each log entry.
*/
@@ -45,6 +49,31 @@
this.labelProviders = List.copyOf(labelProviders);
}
+ /**
+ * Constructs a {@link Formatter} with parameter and label providers supplied by {@link
+ * ServiceLoader}.
+ *
+ * <p>In addition to the providers supplied as parameters, this factory method loads all {@link
+ * StructuredParameterProvider}s and {@link LabelProvider}s found through the {@link
+ * ServiceLoader} mechanism.
+ *
+ * @param parameterProviders the {@link StructuredParameterProvider}s to apply to each log entry.
+ * @param labelProviders the {@link LabelProvider}s to apply to each log entry.
+ */
+ public static Formatter load(
+ Collection<StructuredParameterProvider> parameterProviders,
+ Collection<LabelProvider> labelProviders) {
+ parameterProviders = new ArrayList<>(parameterProviders);
+ ServiceLoader.load(StructuredParameterProvider.class, Formatter.class.getClassLoader())
+ .forEach(parameterProviders::add);
+
+ labelProviders = new ArrayList<>(labelProviders);
+ ServiceLoader.load(LabelProvider.class, Formatter.class.getClassLoader())
+ .forEach(labelProviders::add);
+
+ return new Formatter(parameterProviders, labelProviders);
+ }
+
@Override
public String format(ExtLogRecord logRecord) {
var message = formatMessageWithStackTrace(logRecord);
diff --git a/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/package-info.java b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/package-info.java
index 2f4c7ce..3617b8c 100644
--- a/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/package-info.java
+++ b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/package-info.java
@@ -123,8 +123,14 @@
* parameters for each message that is logged. This can be used to provide contextual information
* such as tracing and request IDs stored in thread-local storage.
*
- * <p>If you are using the Quarkus extension, CDI beans that implement these interfaces are
- * automatically detected at build time and passed to the formatter on startup.
+ * <p><strong>Service provider support:</strong> Providers can be registered using the {@link
+ * java.util.ServiceLoader} mechanism, in which case {@link
+ * eu.mulk.quarkus.googlecloud.jsonlogging.Formatter#load} picks them up automatically.
+ *
+ * <p><strong>CDI support:</strong> If you are using the Quarkus extension, CDI beans that implement
+ * one of the provider interfaces are automatically detected at build time and passed to the
+ * formatter on startup. In addition, providers using the {@link java.util.ServiceLoader} mechanism
+ * are detected and passed to the formatter as well.
*
* <p><strong>Example:</strong>
*
diff --git a/example/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/example/RandomNumberParameterProvider.java b/example/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/example/RandomNumberParameterProvider.java
new file mode 100644
index 0000000..7e4158c
--- /dev/null
+++ b/example/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/example/RandomNumberParameterProvider.java
@@ -0,0 +1,14 @@
+package eu.mulk.quarkus.googlecloud.jsonlogging.example;
+
+import eu.mulk.quarkus.googlecloud.jsonlogging.KeyValueParameter;
+import eu.mulk.quarkus.googlecloud.jsonlogging.StructuredParameter;
+import eu.mulk.quarkus.googlecloud.jsonlogging.StructuredParameterProvider;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class RandomNumberParameterProvider implements StructuredParameterProvider {
+
+ @Override
+ public StructuredParameter getParameter() {
+ return KeyValueParameter.of("randomNumber", ThreadLocalRandom.current().nextInt());
+ }
+}
diff --git a/example/src/main/resources/META-INF/services/eu.mulk.quarkus.googlecloud.jsonlogging.StructuredParameterProvider b/example/src/main/resources/META-INF/services/eu.mulk.quarkus.googlecloud.jsonlogging.StructuredParameterProvider
new file mode 100644
index 0000000..c0017e6
--- /dev/null
+++ b/example/src/main/resources/META-INF/services/eu.mulk.quarkus.googlecloud.jsonlogging.StructuredParameterProvider
@@ -0,0 +1 @@
+eu.mulk.quarkus.googlecloud.jsonlogging.example.RandomNumberParameterProvider
diff --git a/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/runtime/GoogleCloudJsonLoggingRecorder.java b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/runtime/GoogleCloudJsonLoggingRecorder.java
index 661b69f..84d9112 100644
--- a/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/runtime/GoogleCloudJsonLoggingRecorder.java
+++ b/runtime/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/runtime/GoogleCloudJsonLoggingRecorder.java
@@ -31,6 +31,6 @@
var labelProviders =
Arc.container().select(LabelProvider.class).stream().collect(Collectors.toList());
- return new RuntimeValue<>(Optional.of(new Formatter(parameterProviders, labelProviders)));
+ return new RuntimeValue<>(Optional.of(Formatter.load(parameterProviders, labelProviders)));
}
}