diff --git a/core/src/main/java/io/jstach/rainbowgum/LogAppender.java b/core/src/main/java/io/jstach/rainbowgum/LogAppender.java index 38def54c..57411b85 100644 --- a/core/src/main/java/io/jstach/rainbowgum/LogAppender.java +++ b/core/src/main/java/io/jstach/rainbowgum/LogAppender.java @@ -8,6 +8,7 @@ import io.jstach.rainbowgum.LogAppender.AbstractLogAppender; import io.jstach.rainbowgum.LogAppender.ThreadSafeLogAppender; +import io.jstach.rainbowgum.LogConfig.Provider; import io.jstach.rainbowgum.LogEncoder.Buffer; /** @@ -16,7 +17,7 @@ * * The only exception is if an Appender implements {@link ThreadSafeLogAppender}. */ -public interface LogAppender extends LogLifecycle, LogEventConsumer { +public interface LogAppender extends LogLifecycle, LogEventConsumer, LogConfig.Provider { /** * Default Console appender name. @@ -53,27 +54,9 @@ default void append(LogEvent[] events, int count) { public void append(LogEvent event); - /** - * A factor of appenders. - */ - public interface AppenderProvider { - - /** - * Creates an appender from config. - * @param config config. - * @return appender. - */ - LogAppender provide(LogConfig config); - - /** - * Creates a builder to create an appender provider. - * @param name name of appender. - * @return builder. - */ - public static Builder builder(String name) { - return LogAppender.builder(name); - } - + @Override + default LogAppender provide(LogConfig config) { + return this; } /** @@ -109,9 +92,9 @@ public static LogAppender of(List appenders) { */ public static final class Builder { - protected @Nullable LogOutput output; + protected @Nullable Provider output; - protected @Nullable LogEncoder encoder; + protected @Nullable Provider encoder; private final String name; @@ -128,11 +111,11 @@ public String name() { } /** - * Sets output. If not set defaults to {@link LogOutput#ofStandardOut()}. + * Sets output. * @param output output. * @return builder. */ - public Builder output(LogOutput output) { + public Builder output(Provider output) { this.output = output; return this; } @@ -164,7 +147,7 @@ public Builder formatter(LogFormatter.EventFormatter formatter) { * @param encoder encoder not null. * @return builder. */ - public Builder encoder(LogEncoder encoder) { + public Builder encoder(Provider encoder) { this.encoder = encoder; return this; } @@ -173,12 +156,16 @@ public Builder encoder(LogEncoder encoder) { * Builds. * @return an appender factory. */ - public AppenderProvider build() { + public Provider build() { /* * We need to capture parameters since appender creation needs to be lazy. */ - AppenderConfig a = new AppenderConfig(name, output, encoder); + var _name = name; + var _output = output; + var _encoder = encoder; return config -> { + AppenderConfig a = new AppenderConfig(_name, Provider.provideOrNull(_output, config), + Provider.provideOrNull(_encoder, config)); return DefaultAppenderRegistry.appender(a, config); }; } diff --git a/core/src/main/java/io/jstach/rainbowgum/LogAppenderRegistry.java b/core/src/main/java/io/jstach/rainbowgum/LogAppenderRegistry.java index 06965240..332ab042 100644 --- a/core/src/main/java/io/jstach/rainbowgum/LogAppenderRegistry.java +++ b/core/src/main/java/io/jstach/rainbowgum/LogAppenderRegistry.java @@ -9,7 +9,7 @@ import org.eclipse.jdt.annotation.Nullable; -import io.jstach.rainbowgum.LogAppender.AppenderProvider; +import io.jstach.rainbowgum.LogConfig.Provider; import io.jstach.rainbowgum.LogProperties.Property; /** @@ -22,14 +22,14 @@ public sealed interface LogAppenderRegistry permits DefaultAppenderRegistry { * @param name name of the appender. * @return appender provider to be used for creating the appender. */ - Optional appender(String name); + Optional> appender(String name); /** * Registers an appender provider by name. * @param name of the appender. * @param appenderProvider factory to be used for creating appenders. */ - void register(String name, AppenderProvider appenderProvider); + void register(String name, Provider appenderProvider); /** * Creates a log appender registry. @@ -68,7 +68,7 @@ final class DefaultAppenderRegistry implements LogAppenderRegistry { * properties is complicated particularly because we want to support Spring Boots * configuration OOB. */ - private final Map providers = new ConcurrentHashMap<>(); + private final Map> providers = new ConcurrentHashMap<>(); static final Property fileProperty = Property.builder().toURI().build(LogProperties.FILE_PROPERTY); @@ -101,12 +101,14 @@ private static LogAppender defaultConsoleAppender(LogConfig config) { } static Optional fileAppender(LogConfig config) { - String name = LogAppender.FILE_APPENDER_NAME; - var outputProperty = outputProperty(LogAppender.APPENDER_OUTPUT_PROPERTY, name, config); + final String name = LogAppender.FILE_APPENDER_NAME; + var outputProperty = fileProperty // + .map(u -> config.outputRegistry().output(u, name, config.properties())); var encoderProperty = encoderProperty(LogAppender.APPENDER_ENCODER_PROPERTY, name, config); + return fileProperty // - .map(u -> appender(name, config, outputProperty, encoderProperty)) - .get(config.properties()) + .map(u -> appender(name, config, outputProperty, encoderProperty)) // + .get(config.properties()) // .optional(); } @@ -198,12 +200,12 @@ private static Property encoderProperty(String propertyName, String } @Override - public Optional appender(String name) { + public Optional> appender(String name) { return Optional.ofNullable(providers.get(name)); } @Override - public void register(String name, AppenderProvider appenderProvider) { + public void register(String name, Provider appenderProvider) { providers.put(name, appenderProvider); } diff --git a/core/src/main/java/io/jstach/rainbowgum/LogConfig.java b/core/src/main/java/io/jstach/rainbowgum/LogConfig.java index a09ba1d4..1bdea489 100644 --- a/core/src/main/java/io/jstach/rainbowgum/LogConfig.java +++ b/core/src/main/java/io/jstach/rainbowgum/LogConfig.java @@ -104,6 +104,40 @@ public static Builder builder() { */ public ServiceRegistry serviceRegistry(); + /** + * A factory that may need config to provide. Most components implements this + * interface so that you can use already created instances. + * + * @param component + */ + @FunctionalInterface + public interface Provider { + + /** + * Creates the component from config. The component is not always guaranteed to be + * new object. + * @param config config. + * @return component. + */ + T provide(LogConfig config); + + /** + * Convenience for flattening nullable providers. + * @param component + * @param provider nullable provider + * @param config config used to provide if not null. + * @return maybe null component. + */ + @SuppressWarnings("exports") + public static @Nullable U provideOrNull(@Nullable Provider provider, LogConfig config) { + if (provider == null) { + return null; + } + return provider.provide(config); + } + + } + /** * Config Change Publisher. */ diff --git a/core/src/main/java/io/jstach/rainbowgum/LogEncoder.java b/core/src/main/java/io/jstach/rainbowgum/LogEncoder.java index 2e14325d..8bf4c254 100644 --- a/core/src/main/java/io/jstach/rainbowgum/LogEncoder.java +++ b/core/src/main/java/io/jstach/rainbowgum/LogEncoder.java @@ -43,7 +43,7 @@ * @see LogAppender * @see StringBuilderBuffer */ -public interface LogEncoder { +public interface LogEncoder extends LogConfig.Provider { /** * Creates a new buffer. The encoder should not try to reuse buffers @@ -86,6 +86,11 @@ public interface EncoderProvider { } + @Override + default LogEncoder provide(LogConfig config) { + return this; + } + /** * Encoders buffer. */ diff --git a/core/src/main/java/io/jstach/rainbowgum/LogOutput.java b/core/src/main/java/io/jstach/rainbowgum/LogOutput.java index ff13539f..ed488b56 100644 --- a/core/src/main/java/io/jstach/rainbowgum/LogOutput.java +++ b/core/src/main/java/io/jstach/rainbowgum/LogOutput.java @@ -31,7 +31,7 @@ * @see LogOutput.OutputProvider * @see Buffer */ -public interface LogOutput extends LogLifecycle, Flushable { +public interface LogOutput extends LogLifecycle, Flushable, LogConfig.Provider { /** * {@link FileDescriptor#err} URI scheme. @@ -70,6 +70,10 @@ private static URI uri(String s) { } } + default LogOutput provide(LogConfig config) { + return this; + } + /** * Finds output based on URI. */ diff --git a/core/src/main/java/io/jstach/rainbowgum/LogProperties.java b/core/src/main/java/io/jstach/rainbowgum/LogProperties.java index 51693a6e..14f1c192 100644 --- a/core/src/main/java/io/jstach/rainbowgum/LogProperties.java +++ b/core/src/main/java/io/jstach/rainbowgum/LogProperties.java @@ -468,16 +468,6 @@ static String concatKey(String prefix, String name) { * @return interpolated property name. */ static String interpolateKey(String name, Map parameters) { - - // if (validate) { - // StringBuilder error = new StringBuilder(); - // for (Map.Entry entry : parameters.entrySet()) { - // String key = entry.getKey(); - // String p = "{" + key + "}"; - // if (! name.contains(p)) { - // } - // } - // } for (Map.Entry entry : parameters.entrySet()) { name = name.replace("{" + entry.getKey() + "}", entry.getValue()); } diff --git a/core/src/main/java/io/jstach/rainbowgum/LogRouter.java b/core/src/main/java/io/jstach/rainbowgum/LogRouter.java index de8ff387..a7967ad8 100644 --- a/core/src/main/java/io/jstach/rainbowgum/LogRouter.java +++ b/core/src/main/java/io/jstach/rainbowgum/LogRouter.java @@ -4,7 +4,6 @@ import java.lang.System.Logger; import java.lang.System.Logger.Level; -import java.net.URI; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; @@ -19,8 +18,6 @@ import org.eclipse.jdt.annotation.Nullable; -import io.jstach.rainbowgum.LogAppender.AppenderProvider; -import io.jstach.rainbowgum.LogProperties.Property; import io.jstach.rainbowgum.LogPublisher.PublisherProvider; import io.jstach.rainbowgum.LogRouter.RootRouter; import io.jstach.rainbowgum.LogRouter.Route; @@ -181,7 +178,7 @@ public final class Builder extends LevelResolver.AbstractBuilder { private final LogConfig config; - private List appenders = new ArrayList<>(); + private List> appenders = new ArrayList<>(); private Builder(LogConfig config) { this.config = config; @@ -216,7 +213,7 @@ public Builder appender(String name, Consumer consumer) { * @param appender appender provider. * @return this builder. */ - public Builder appender(AppenderProvider appender) { + public Builder appender(LogConfig.Provider appender) { this.appenders.add(appender); return self(); } @@ -238,11 +235,10 @@ public Builder publisher(PublisherProvider publisher) { Router build() { var levelResolver = buildLevelResolver(config.levelResolver()); var publisher = this.publisher; - List appenders = new ArrayList<>(this.appenders); + List> appenders = new ArrayList<>(this.appenders); if (appenders.isEmpty()) { DefaultAppenderRegistry.defaultAppenders(config) // .stream() // - .map(a -> (c -> a)) // .forEach(appenders::add); } if (publisher == null) { diff --git a/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/RabbitMQBuilder.java b/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/RabbitMQBuilder.java deleted file mode 100644 index febf106e..00000000 --- a/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/RabbitMQBuilder.java +++ /dev/null @@ -1,167 +0,0 @@ -package io.jstach.rainbowgum.rabbitmq; - -import java.net.URI; - -import com.rabbitmq.client.MessageProperties; - -class RabbitMQBuilder { - - /** - * Name of the exchange to publish log events to. - */ - private String exchangeName = "logs"; // done - - /** - * Type of the exchange to publish log events to. - */ - private String exchangeType = "topic"; - - /** - * Configuration arbitrary application ID. - */ - private String applicationId = null; // done - - /** - * A name for the connection (appears on the RabbitMQ Admin UI). - */ - private String connectionName; // done - - /** - * Additional client connection properties added to the rabbit connection, with the - * form {@code key:value[,key:value]...}. - */ - private String clientConnectionProperties; - - /** - * A comma-delimited list of broker addresses: host:port[,host:port]* - * - * @since 1.5.6 - */ - private String addresses; - - /** - * RabbitMQ host to connect to. - */ - private URI uri; - - /** - * RabbitMQ host to connect to. - */ - private String host; - - /** - * RabbitMQ virtual host to connect to. - */ - private String virtualHost; - - /** - * RabbitMQ port to connect to. - */ - private Integer port; - - /** - * RabbitMQ user to connect as. - */ - private String username; - - /** - * RabbitMQ password for this user. - */ - private String password; - - /** - * Use an SSL connection. - */ - private boolean useSsl; - - /** - * The SSL algorithm to use. - */ - private String sslAlgorithm; - - /** - * Location of resource containing keystore and truststore information. - */ - private String sslPropertiesLocation; - - /** - * Keystore location. - */ - private String keyStore; - - /** - * Keystore passphrase. - */ - private String keyStorePassphrase; - - /** - * Keystore type. - */ - private String keyStoreType = "JKS"; - - /** - * Truststore location. - */ - private String trustStore; - - /** - * Truststore passphrase. - */ - private String trustStorePassphrase; - - /** - * Truststore type. - */ - private String trustStoreType = "JKS"; - - /** - * SaslConfig. - * @see RabbitUtils#stringToSaslConfig(String, ConnectionFactory) - */ - private String saslConfig; - - private boolean verifyHostname = true; - - /** - * Default content-type of log messages. - */ - private String contentType = "text/plain"; - - /** - * Default content-encoding of log messages. - */ - private String contentEncoding = null; - - /** - * Whether or not to try and declare the configured exchange when this appender - * starts. - */ - private boolean declareExchange = false; - - /** - * charset to use when converting String to byte[], default null (system default - * charset used). If the charset is unsupported on the current platform, we fall back - * to using the system charset. - */ - private String charset; - - /** - * Whether or not add MDC properties into message headers. true by default for - * backward compatibility - */ - private boolean addMdcAsHeaders = true; - - private boolean durable = true; - - // private MessageDeliveryMode deliveryMode = MessageDeliveryMode.PERSISTENT; - - private boolean autoDelete = false; - - /** - * Used to determine whether {@link MessageProperties#setMessageId(String)} is set. - */ - private boolean generateId = false; - - private boolean includeCallerData; - -} \ No newline at end of file diff --git a/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/RabbitMQInitializer.java b/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/RabbitMQInitializer.java index 3efaed39..8a1acadb 100644 --- a/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/RabbitMQInitializer.java +++ b/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/RabbitMQInitializer.java @@ -12,7 +12,8 @@ import io.jstach.svc.ServiceProvider; /** - * RabbitMQ initializer to register output provider with scheme {@value #SCHEME}. + * RabbitMQ initializer to register output provider with scheme + * {@value RabbitMQOutput#URI_SCHEME}. */ @ServiceProvider(RainbowGumServiceProvider.class) public class RabbitMQInitializer implements RainbowGumServiceProvider.Initializer { @@ -23,11 +24,9 @@ public class RabbitMQInitializer implements RainbowGumServiceProvider.Initialize public RabbitMQInitializer() { } - final static String SCHEME = "amqp"; - @Override public void initialize(ServiceRegistry registry, LogConfig config) { - config.outputRegistry().register(SCHEME, RabbitMQOutputProvider.INSTANCE); + config.outputRegistry().register(RabbitMQOutput.URI_SCHEME, RabbitMQOutputProvider.INSTANCE); } private enum RabbitMQOutputProvider implements OutputProvider { diff --git a/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/RabbitMQOutput.java b/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/RabbitMQOutput.java index 616306e7..d5cccfe4 100644 --- a/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/RabbitMQOutput.java +++ b/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/RabbitMQOutput.java @@ -52,6 +52,11 @@ public class RabbitMQOutput implements LogOutput { private final String exchangeType; + /** + * The rabbitmq URI scheme for configuration. + */ + public final static String URI_SCHEME = "amqp"; + /** * Default exchange. */ @@ -76,6 +81,23 @@ public class RabbitMQOutput implements LogOutput { this.exchangeType = exchangeType; } + /** + * Creates a RabbitMQOutput. This method is called by the generated builder. + * @param name used to resolve config and give the output a name. + * @param uri passed to the rabbitmq connection factory. + * @param exchange exchange to send messages to. + * @param routingKey the logging event level will be used by default. + * @param declareExchange declare exchange on start. Default is false. + * @param host host. + * @param username set user name if not null outside of URI. + * @param password set password if not null outside of URI. + * @param port set port if not null. + * @param appId sets the message appId if not null. + * @param connectionName connection name if not null. + * @param exchangeType exchange type like "topic" covered in rabbitmq doc. + * @param virtualHost sets virtualhost if not null. + * @return output. + */ @LogConfigurable(prefix = LogProperties.OUTPUT_PREFIX) static RabbitMQOutput of( // @LogConfigurable.PrefixParameter String name, //