diff options
Diffstat (limited to 'core/src/main/java')
5 files changed, 153 insertions, 7 deletions
| 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 61a2dea..e759ff0 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 @@ -8,7 +8,9 @@ import java.util.HashMap;  import java.util.List;  import java.util.Map;  import java.util.ServiceLoader; +import java.util.ServiceLoader.Provider;  import java.util.logging.Level; +import java.util.stream.Collectors;  import org.jboss.logmanager.ExtFormatter;  import org.jboss.logmanager.ExtLogRecord; @@ -34,7 +36,7 @@ public class Formatter extends ExtFormatter {    private final List<LabelProvider> labelProviders;    /** -   * Constructs a {@link Formatter}. +   * Constructs a {@link Formatter} with custom configuration.     *     * <p><strong>Note:</strong> This constructor does not automatically discover providers using the     * {@link ServiceLoader} mechanism. See {@link #load} for this case use. @@ -59,21 +61,33 @@ public class Formatter extends ExtFormatter {     *     * @param parameterProviders the {@link StructuredParameterProvider}s to apply to each log entry.     * @param labelProviders the {@link LabelProvider}s to apply to each log entry. +   * @return a new formatter.     */    public static Formatter load(        Collection<StructuredParameterProvider> parameterProviders,        Collection<LabelProvider> labelProviders) {      parameterProviders = new ArrayList<>(parameterProviders); -    ServiceLoader.load(StructuredParameterProvider.class, Formatter.class.getClassLoader()) -        .forEach(parameterProviders::add); +    parameterProviders.addAll(loadStructuredParameterProviders());      labelProviders = new ArrayList<>(labelProviders); -    ServiceLoader.load(LabelProvider.class, Formatter.class.getClassLoader()) -        .forEach(labelProviders::add); +    labelProviders.addAll(loadLabelProviders());      return new Formatter(parameterProviders, labelProviders);    } +  private static List<StructuredParameterProvider> loadStructuredParameterProviders() { +    return ServiceLoader.load(StructuredParameterProvider.class, Formatter.class.getClassLoader()) +        .stream() +        .map(Provider::get) +        .collect(Collectors.toList()); +  } + +  private static List<LabelProvider> loadLabelProviders() { +    return ServiceLoader.load(LabelProvider.class, Formatter.class.getClassLoader()).stream() +        .map(Provider::get) +        .collect(Collectors.toList()); +  } +    @Override    public String format(ExtLogRecord logRecord) {      var message = formatMessageWithStackTrace(logRecord); diff --git a/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/logmanager/DefaultConsoleHandler.java b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/logmanager/DefaultConsoleHandler.java new file mode 100644 index 0000000..a1dbde7 --- /dev/null +++ b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/logmanager/DefaultConsoleHandler.java @@ -0,0 +1,68 @@ +package eu.mulk.quarkus.googlecloud.jsonlogging.logmanager; + +import eu.mulk.quarkus.googlecloud.jsonlogging.Formatter; +import java.io.InputStream; +import java.util.Collections; +import org.jboss.logmanager.handlers.ConsoleHandler; + +/** + * A {@link ConsoleHandler} preconfigured with {@link Formatter}. + * + * <p>Useful as a handler for {@link java.util.logging}. + * + * <p>If you have a {@code logging.properties} file (see {@link + * java.util.logging.LogManager#readConfiguration(InputStream)}), you can use this handler by + * setting the following properties: + * + * <pre>{@code + * handlers = eu.mulk.quarkus.googlecloud.jsonlogging.logmanager.ConsoleHandler + * }</pre> + * + * <p><strong>Note:</strong> You can use {@code org.slf4j.bridge.SLF4JBridgeHandler} from {@code + * org.slf4j:jul-to-slf4j} instead if you also have {@code org.jboss.slf4j:slf4j-jboss-logmanager} + * on the class path. In comparison to this class, which relies on the relatively efficient {@link + * org.jboss.logmanager.ExtLogRecord#wrap}, routing through SLF4J incurs additional overhead because + * of the necessary conversions between SLF4J's log entry structure and {@link + * java.util.logging.LogRecord}. + * + * <h2>Usage with Spring Boot</h2> + * + * <p>In case you are using Spring Boot, note that in addition to ensuring that {@code + * org.springframework.boot.logging.java.JavaLoggingSystem} is the logging system in use (see + * below), you need to accompany this with an entry in {@code application.properties} that points to + * your {@code logging.properties} file: + * + * <pre>{@code + * logging.config = classpath:logging.properties + * }</pre> + * + * <p>In order to ensure that Spring Boot chooses {@code JavaLoggingSystem} over other + * implementations, make sure that no other logging backends are present on the class path. A simple + * way of doing this is by relying on {@code spring-boot-starter-logging} while excluding Logback: + * + * <pre>{@code + * <dependency> + *   <groupId>org.springframework.boot</groupId> + *   <artifactId>spring-boot-starter</artifactId> + *   <exclusions> + *     <exclusion> + *       <groupId>ch.qos.logback</groupId> + *       <artifactId>logback-classic</artifactId> + *     </exclusion> + *   </exclusions> + * </dependency> + * }</pre> + * + * <p>You will probably want to include at least {@code org.jboss.slf4j:slf4j-jboss-logmanager} as + * well. In addition, {@code org.slf4j:jcl-over-slf4j}, {@code + * org.jboss.logmanager:log4j-jboss-logmanager}, and {@code + * org.jboss.logmanager:log4j2-jboss-logmanager} may be useful, but are not required. + */ +@SuppressWarnings("java:S110") +public final class DefaultConsoleHandler extends ConsoleHandler { + +  /** Constructs console handler with a formatter created by {@link Formatter#load}. */ +  public DefaultConsoleHandler() { +    super(Formatter.load(Collections.emptyList(), Collections.emptyList())); +  } +} diff --git a/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/logmanager/DefaultEmbeddedConfigurator.java b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/logmanager/DefaultEmbeddedConfigurator.java new file mode 100644 index 0000000..8d9d4d8 --- /dev/null +++ b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/logmanager/DefaultEmbeddedConfigurator.java @@ -0,0 +1,46 @@ +package eu.mulk.quarkus.googlecloud.jsonlogging.logmanager; + +import eu.mulk.quarkus.googlecloud.jsonlogging.Formatter; +import java.util.logging.Handler; +import org.jboss.logmanager.EmbeddedConfigurator; +import org.jboss.logmanager.handlers.ConsoleHandler; + +/** + * A convenient {@link EmbeddedConfigurator} for JBoss Log Manager. + * + * <p>You can register this class through the {@link java.util.ServiceLoader} mechanism as a + * provider of the {@link EmbeddedConfigurator} interface (under the name of {@code + * org.jboss.logmanager.EmbeddedConfigurator}) to automatically register a {@link ConsoleHandler} + * using {@link Formatter} as the default log output method for the application. + */ +public final class DefaultEmbeddedConfigurator implements EmbeddedConfigurator { + +  private final Handler[] rootHandlers; + +  /** +   * Constructs a JBoss Log Manager configuration that uses {@link Formatter} and {@link +   * ConsoleHandler} for log output. +   */ +  @SuppressWarnings("java:S2095") +  public DefaultEmbeddedConfigurator() { +    rootHandlers = new Handler[] {createConsoleHandler()}; +  } + +  /** +   * Creates a {@link ConsoleHandler} that uses {@link Formatter} for formatting. +   * +   * @return a preconfigured {@link ConsoleHandler}. +   */ +  public static ConsoleHandler createConsoleHandler() { +    return new DefaultConsoleHandler(); +  } + +  @Override +  public Handler[] getHandlersOf(String loggerName) { +    if (loggerName.isEmpty()) { +      return rootHandlers; +    } else { +      return EmbeddedConfigurator.NO_HANDLERS; +    } +  } +} diff --git a/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/logmanager/package-info.java b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/logmanager/package-info.java new file mode 100644 index 0000000..87eb71e --- /dev/null +++ b/core/src/main/java/eu/mulk/quarkus/googlecloud/jsonlogging/logmanager/package-info.java @@ -0,0 +1,18 @@ +/** + * Integration with JBoss Log Manager and {@link java.util.logging}. + * + * <p>Provides classes that can be used to conveniently configure the JBoss Log Manager ({@link + * org.jboss.logmanager.LogManager}) as well as {@link java.util.logging} to use the Google Cloud + * JSON Logging formatter ({@link eu.mulk.quarkus.googlecloud.jsonlogging.Formatter}). + * + * <p>{@link eu.mulk.quarkus.googlecloud.jsonlogging.logmanager.DefaultEmbeddedConfigurator} can be + * set as a provided implementation of {@link org.jboss.logmanager.EmbeddedConfigurator} via the + * standard {@link java.util.ServiceLoader} mechanism. + * + * <p>{@link eu.mulk.quarkus.googlecloud.jsonlogging.logmanager.DefaultConsoleHandler} can be used + * as the target of the {@code handlers} property key in {@link + * java.util.logging.LogManager#readConfiguration(java.io.InputStream)}. This is particularly useful + * when used in conjunction with frameworks other than Quarkus (such as Spring Boot). See the class + * documentation for details. + */ +package eu.mulk.quarkus.googlecloud.jsonlogging.logmanager; 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 3617b8c..e684bfd 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 @@ -4,7 +4,7 @@   *   * <ul>   *   <li><a href="#sect-summary">Summary</a> - *   <li><a href="#sect-activation">Activation</a> + *   <li><a href="#sect-installation">Installation</a>   *   <li><a href="#sect-usage">Usage</a>   * </ul>   * @@ -17,7 +17,7 @@   * <p>It is possible to log unstructured text, structured data, or a mixture of both depending on   * the situation.   * - * <h2 id="sect-activation">Installation</h2> + * <h2 id="sect-installation">Installation</h2>   *   * <ul>   *   <li><a href="#sect-installation-maven">Installation with Maven</a> | 
