Package eu.mulk.quarkus.googlecloud.jsonlogging


@NullMarked package eu.mulk.quarkus.googlecloud.jsonlogging
Provides structured logging to standard output according to the Google Cloud Logging specification.

Summary

This package contains a log formatter for JBoss Logging in the form of a Quarkus plugin that implements the Google Cloud Logging JSON format on standard output.

It is possible to log unstructured text, structured data, or a mixture of both depending on the situation.

Installation

Add the runtime POM to your dependency list. As long as the JAR is on the classpath at both build time and runtime, the log formatter automatically registers itself on startup.

Installation with Maven

<project>
  ...

  <dependencies>
    ...

    <dependency>
      <groupId>eu.mulk.quarkus-googlecloud-jsonlogging</groupId>
      <artifactId>quarkus-googlecloud-jsonlogging-core</artifactId>
      <version>7.0.0</version>
    </dependency>

    ...
  </dependencies>

  ...
</project>

Installation with Gradle

dependencies {
  // ...

  implementation("eu.mulk.quarkus-googlecloud-jsonlogging:quarkus-googlecloud-jsonlogging-core:7.0.0")

  // ...
}

Usage

Logging unstructured data requires no code changes. All logs are automatically converted to Google-Cloud-Logging-compatible JSON.

Structured data can be logged in one of 3 different ways: by passing Labels and StructuredParameters as parameters to individual log entries, by supplying LabelProviders and StructuredParameterProviders, or by using the Mapped Diagnostic Context.

Using Label and StructuredParameter

Instances of Label and StructuredParameter can be passed as log parameters to the *f family of logging functions on JBoss Logging's Logger.

Simple key–value pairs are represented by KeyValueParameter.

Example:

logger.logf(
  "Request rejected: unauthorized.",
  Label.of("requestId", "123"),
  KeyValueParameter.of("resource", "/users/mulk"),
  KeyValueParameter.of("method", "PATCH"),
  KeyValueParameter.of("reason", "invalid token"));

Result:

{
  "jsonPayload": {
    "message": "Request rejected: unauthorized.",
    "resource": "/users/mulk",
    "method": "PATCH",
    "reason": "invalid token"
  },
  "labels": {
    "requestId": "123"
  }
}

Using LabelProvider and StructuredParameterProvider

If you pass LabelProviders and StructuredParameterProviders to Formatter, then they are consulted to provide labels and 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.

Service provider support: Providers can be registered using the ServiceLoader mechanism, in which case Formatter.load(java.util.Collection<eu.mulk.quarkus.googlecloud.jsonlogging.StructuredParameterProvider>, java.util.Collection<eu.mulk.quarkus.googlecloud.jsonlogging.LabelProvider>) picks them up automatically.

CDI support: 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 ServiceLoader mechanism are detected and passed to the formatter as well.

Example:

@Singleton
@Unremovable
public final class TraceLogParameterProvider implements StructuredParameterProvider, LabelProvider {

  @Override
  public StructuredParameter getParameter() {
    var b = Json.createObjectBuilder();
    b.add("traceId", Span.current().getSpanContext().getTraceId());
    b.add("spanId", Span.current().getSpanContext().getSpanId());
    return () -> b;
  }

  @Override
  public Collection<Label> getLabels() {
    return List.of(Label.of("requestId", "123"));
  }
}
Result:
{
  "jsonPayload": {
    "message": "Request rejected: unauthorized.",
    "traceId": "39f9a49a9567a8bd7087b708f8932550",
    "spanId": "c7431b14630b633d"
  },
  "labels": {
    "requestId": "123"
  }
}

Using the Mapped Diagnostic Context

Any key–value pairs in JBoss Logging's thread-local MDC are added to the resulting JSON.

Example:

MDC.put("resource", "/users/mulk");
MDC.put("method", "PATCH");
logger.logf("Request rejected: unauthorized.");
Result:
{
  "jsonPayload": {
    "message": "Request rejected: unauthorized.",
    "resource": "/users/mulk",
    "method": "PATCH"
  }
}