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> |