Add ProviderContext.

Adds a ProviderContext type which is passed to LabelProvider#getLabels
and StructuredParameterProvider#getParameter and which carries some
information from ExtLogRecord that is not taken care of by Formatter.

ProviderContext is designed to be extended in the future.

Change-Id: Ib29b7032ae42e0f9e86c75b7404c25cd75b20011
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 f6167f6..c4e36de 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
@@ -99,15 +99,17 @@
     List<StructuredParameter> parameters = new ArrayList<>();
     Map<String, String> labels = new HashMap<>();
 
+    var providerContext = new ProviderContext(logRecord);
+
     for (var parameterProvider : parameterProviders) {
-      var parameter = parameterProvider.getParameter();
+      var parameter = parameterProvider.getParameter(providerContext);
       if (parameter != null) {
         parameters.add(parameter);
       }
     }
 
     for (var labelProvider : labelProviders) {
-      var providedLabels = labelProvider.getLabels();
+      var providedLabels = labelProvider.getLabels(providerContext);
       if (providedLabels != null) {
         for (var label : providedLabels) {
           labels.put(label.key(), label.value());
@@ -185,4 +187,37 @@
       return ERROR_LEVEL;
     }
   }
+
+  /**
+   * An implementation of {@link LabelProvider.Context} and {@link
+   * StructuredParameterProvider.Context}.
+   */
+  private static class ProviderContext
+      implements LabelProvider.Context, StructuredParameterProvider.Context {
+
+    private final String loggerName;
+    private final long sequenceNumber;
+    private final String threadName;
+
+    private ProviderContext(ExtLogRecord logRecord) {
+      loggerName = logRecord.getLoggerName();
+      sequenceNumber = logRecord.getSequenceNumber();
+      threadName = logRecord.getThreadName();
+    }
+
+    @Override
+    public String loggerName() {
+      return loggerName;
+    }
+
+    @Override
+    public long sequenceNumber() {
+      return sequenceNumber;
+    }
+
+    @Override
+    public String threadName() {
+      return threadName;
+    }
+  }
 }
diff --git a/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/LabelProvider.java b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/LabelProvider.java
index 7cca6a0..0298042 100644
--- a/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/LabelProvider.java
+++ b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/LabelProvider.java
@@ -47,7 +47,26 @@
   /**
    * Provides a collection of {@link Label}s to add to each log entry that is logged.
    *
+   * <p>If {@link #getLabels(Context)} is implemented, this method is ignored.
+   *
+   * @return a collection of {@link Label}s to add to each log entry that is logged.
+   * @see #getLabels(Context)
+   */
+  default Collection<Label> getLabels() {
+    return null;
+  }
+
+  /**
+   * Provides a collection of {@link Label}s to add to each log entry that is logged.
+   *
+   * <p>Delegates to {@link #getLabels()} by default.
+   *
    * @return a collection of {@link Label}s to add to each log entry that is logged.
    */
-  Collection<Label> getLabels();
+  default Collection<Label> getLabels(Context context) {
+    return getLabels();
+  }
+
+  /** Contextual data available to {@link #getLabels(Context)}. */
+  interface Context extends ProviderContext {}
 }
diff --git a/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/ProviderContext.java b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/ProviderContext.java
new file mode 100644
index 0000000..08b399a
--- /dev/null
+++ b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/ProviderContext.java
@@ -0,0 +1,38 @@
+// SPDX-FileCopyrightText: © 2022 Matthias Andreas Benkard <code@mail.matthias.benkard.de>
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+
+package eu.mulk.quarkus.googlecloud.jsonlogging;
+
+import org.jboss.logmanager.ExtLogRecord;
+
+/**
+ * Contextual data available to {@link StructuredParameterProvider} and {@link LabelProvider}.
+ *
+ * <p>Provides access to information carried by the {@link ExtLogRecord} that is being formatted and
+ * that is not taken care of by {@link Formatter} by default.
+ */
+public interface ProviderContext {
+
+  /**
+   * The {@link ExtLogRecord#getLoggerName()} property of the log record that is being formatted.
+   *
+   * @return {@link ExtLogRecord#getLoggerName()}.
+   */
+  String loggerName();
+
+  /**
+   * The {@link ExtLogRecord#getSequenceNumber()} property of the log record that is being
+   * formatted.
+   *
+   * @return {@link ExtLogRecord#getSequenceNumber()}.
+   */
+  long sequenceNumber();
+
+  /**
+   * The {@link ExtLogRecord#getThreadName()} property of the log record that is being formatted.
+   *
+   * @return {@link ExtLogRecord#getThreadName()}.
+   */
+  String threadName();
+}
diff --git a/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameterProvider.java b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameterProvider.java
index b8f80ce..d78f0d8 100644
--- a/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameterProvider.java
+++ b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameterProvider.java
@@ -53,7 +53,30 @@
    * KeyValueParameter} from this method. This way multiple key–value pairs can be generated by a
    * single invocation.
    *
+   * <p>If {@link #getParameter(Context)} is implemented, this method is ignored.
+   *
+   * @return a {@link StructuredParameter} to add to each log entry that is logged.
+   * @see #getParameter(Context)
+   */
+  default StructuredParameter getParameter() {
+    return null;
+  }
+
+  /**
+   * Provides a {@link StructuredParameter} to add to each log entry that is logged.
+   *
+   * <p>It is often useful to return a custom {@link StructuredParameter} rather than a {@link
+   * KeyValueParameter} from this method. This way multiple key–value pairs can be generated by a
+   * single invocation.
+   *
+   * <p>Delegates to {@link #getParameter()} by default.
+   *
    * @return a {@link StructuredParameter} to add to each log entry that is logged.
    */
-  StructuredParameter getParameter();
+  default StructuredParameter getParameter(Context context) {
+    return getParameter();
+  }
+
+  /** Contextual data available to {@link #getParameter(Context)}. */
+  interface Context extends ProviderContext {}
 }