diff --git a/core/src/main/java/io/jstach/rainbowgum/ConfigObject.java b/core/src/main/java/io/jstach/rainbowgum/ConfigObject.java
index 741ce3f6..579dce98 100644
--- a/core/src/main/java/io/jstach/rainbowgum/ConfigObject.java
+++ b/core/src/main/java/io/jstach/rainbowgum/ConfigObject.java
@@ -17,9 +17,10 @@
/**
* Name of builder.
- * @return name of builder.
+ * @return name of builder by default if not set Builder will be suffixed to
+ * targetType.
*/
- String name();
+ String name() default "";
/**
* Property prefix.
@@ -43,4 +44,21 @@
}
+ /**
+ * Use to set static defaults to parameters.
+ */
+ @Retention(CLASS)
+ @Target({ ElementType.PARAMETER })
+ @Documented
+ public @interface DefaultParameter {
+
+ /**
+ * Use as parameter to prefix property names.
+ * @return by default will use the static field
+ * DEFAULT_parameterName
.
+ */
+ String value() default "";
+
+ }
+
}
diff --git a/core/src/main/java/io/jstach/rainbowgum/LogAppender.java b/core/src/main/java/io/jstach/rainbowgum/LogAppender.java
index e8cefa23..fac11c62 100644
--- a/core/src/main/java/io/jstach/rainbowgum/LogAppender.java
+++ b/core/src/main/java/io/jstach/rainbowgum/LogAppender.java
@@ -15,7 +15,7 @@
*
* The only exception is if an Appender implements {@link ThreadSafeLogAppender}.
*/
-public interface LogAppender extends AutoCloseable, LogEventConsumer {
+public interface LogAppender extends LogLifecycle, LogEventConsumer {
/**
* Batch of events. DO NOT MODIFY THE ARRAY. Do not use the
@@ -221,6 +221,11 @@ protected void append(LogEvent[] events, int count, Buffer buffer) {
protected abstract void append(LogEvent event, Buffer buffer);
+ @Override
+ public void start(LogConfig config) {
+ output.start(config);
+ }
+
@Override
public void close() {
output.close();
@@ -252,6 +257,13 @@ public void close() {
}
}
+ @Override
+ public void start(LogConfig config) {
+ for (var appender : appenders) {
+ appender.start(config);
+ }
+ }
+
}
class LockingLogAppender implements ThreadSafeLogAppender {
@@ -288,6 +300,11 @@ public void append(LogEvent event) {
}
+ @Override
+ public void start(LogConfig config) {
+ appender.start(config);
+ }
+
@Override
public void close() {
appender.close();
diff --git a/core/src/main/java/io/jstach/rainbowgum/LogConfig.java b/core/src/main/java/io/jstach/rainbowgum/LogConfig.java
index ec39d1b5..2bba9794 100644
--- a/core/src/main/java/io/jstach/rainbowgum/LogConfig.java
+++ b/core/src/main/java/io/jstach/rainbowgum/LogConfig.java
@@ -6,6 +6,8 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
+import org.eclipse.jdt.annotation.Nullable;
+
import io.jstach.rainbowgum.LevelResolver.LevelConfig;
import io.jstach.rainbowgum.LogConfig.ChangePublisher;
import io.jstach.rainbowgum.LogProperties.Property;
@@ -81,6 +83,14 @@ public static LogConfig of(ServiceRegistry registry, LogProperties properties) {
return new DefaultLogConfig(registry, properties);
}
+ /**
+ * Creates a builder for making LogConfig.
+ * @return builder.
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
/**
* An event publisher to publish configuration changes.
* @return publisher.
@@ -119,6 +129,59 @@ interface ChangePublisher {
}
+ /**
+ * Builder for LogConfig.
+ */
+ public static final class Builder {
+
+ private @Nullable ServiceRegistry serviceRegistry;
+
+ private @Nullable LogProperties logProperties;
+
+ /**
+ * Default constructor
+ */
+ private Builder() {
+ }
+
+ /**
+ * Sets log properties
+ * @param logProperties log properties.
+ * @return this.
+ */
+ public Builder logProperties(LogProperties logProperties) {
+ this.logProperties = logProperties;
+ return this;
+ }
+
+ /**
+ * Sets service registry
+ * @param serviceRegistry service registry.
+ * @return this.
+ */
+ public Builder serviceRegistry(ServiceRegistry serviceRegistry) {
+ this.serviceRegistry = serviceRegistry;
+ return this;
+ }
+
+ /**
+ * Builds LogConfig using defaults on missing properties.
+ * @return log config
+ */
+ public LogConfig build() {
+ ServiceRegistry serviceRegistry = this.serviceRegistry;
+ LogProperties logProperties = this.logProperties;
+ if (serviceRegistry == null) {
+ serviceRegistry = ServiceRegistry.of();
+ }
+ if (logProperties == null) {
+ logProperties = LogProperties.StandardProperties.SYSTEM_PROPERTIES;
+ }
+ return LogConfig.of(serviceRegistry, logProperties);
+ }
+
+ }
+
}
abstract class AbstractChangePublisher implements ChangePublisher {
diff --git a/core/src/main/java/io/jstach/rainbowgum/LogPublisher.java b/core/src/main/java/io/jstach/rainbowgum/LogPublisher.java
index 0deb63f9..8b6ce2cf 100644
--- a/core/src/main/java/io/jstach/rainbowgum/LogPublisher.java
+++ b/core/src/main/java/io/jstach/rainbowgum/LogPublisher.java
@@ -140,11 +140,6 @@ public static SyncLogPublisher.Builder builder() {
return new Builder();
}
- @Override
- default void start(LogConfig config) {
-
- }
-
default boolean synchronous() {
return true;
}
@@ -195,6 +190,11 @@ public void log(LogEvent event) {
appender.append(event);
}
+ @Override
+ public void start(LogConfig config) {
+ appender.start(config);
+ }
+
@Override
public void close() {
appender.close();
diff --git a/core/src/main/java/io/jstach/rainbowgum/LogRouter.java b/core/src/main/java/io/jstach/rainbowgum/LogRouter.java
index d6fc9c61..b43eb272 100644
--- a/core/src/main/java/io/jstach/rainbowgum/LogRouter.java
+++ b/core/src/main/java/io/jstach/rainbowgum/LogRouter.java
@@ -459,6 +459,10 @@ public void append(LogEvent event) {
public void close() {
}
+ @Override
+ public void start(LogConfig config) {
+ }
+
}
enum GlobalLogRouter implements InternalRootRouter, Route {
diff --git a/core/src/main/java/io/jstach/rainbowgum/RainbowGum.java b/core/src/main/java/io/jstach/rainbowgum/RainbowGum.java
index b0bad377..652e4bf1 100644
--- a/core/src/main/java/io/jstach/rainbowgum/RainbowGum.java
+++ b/core/src/main/java/io/jstach/rainbowgum/RainbowGum.java
@@ -24,7 +24,7 @@
*
* To register a custom RainbowGum:
*
- *
+ *
{@snippet class="snippets.RainbowGumProviderExample" region="provider" :
class RainbowGumProviderExample implements RainbowGumProvider {
@@ -208,6 +208,10 @@ static RainbowGum get() {
finally {
lock.readLock().unlock();
}
+ if (lock.writeLock().isHeldByCurrentThread()) {
+ throw new IllegalStateException("RainbowGum component tried to log too early. "
+ + "This is usually caused by dependencies calling logging.");
+ }
lock.writeLock().lock();
try {
var r = rainbowGum;
@@ -228,6 +232,10 @@ static RainbowGum get() {
static void set(Supplier rainbowGumSupplier) {
Objects.requireNonNull(rainbowGumSupplier);
+ if (lock.writeLock().isHeldByCurrentThread()) {
+ throw new IllegalStateException("RainbowGum component tried to log too early. "
+ + "This is usually caused by dependencies calling logging.");
+ }
lock.writeLock().lock();
try {
rainbowGum = null;
diff --git a/core/src/main/java/io/jstach/rainbowgum/appender/SynchronizedLogAppender.java b/core/src/main/java/io/jstach/rainbowgum/appender/SynchronizedLogAppender.java
index e11c87e9..9f303c69 100644
--- a/core/src/main/java/io/jstach/rainbowgum/appender/SynchronizedLogAppender.java
+++ b/core/src/main/java/io/jstach/rainbowgum/appender/SynchronizedLogAppender.java
@@ -5,6 +5,7 @@
import io.jstach.rainbowgum.LogAppender;
import io.jstach.rainbowgum.LogAppender.AbstractLogAppender;
import io.jstach.rainbowgum.LogAppender.ThreadSafeLogAppender;
+import io.jstach.rainbowgum.LogConfig;
import io.jstach.rainbowgum.LogEncoder;
import io.jstach.rainbowgum.LogEncoder.Buffer;
import io.jstach.rainbowgum.LogEvent;
@@ -60,6 +61,11 @@ public synchronized void append(LogEvent event) {
appender.append(event);
}
+ @Override
+ public void start(LogConfig config) {
+ appender.start(config);
+ }
+
@Override
public void close() {
appender.close();
diff --git a/core/src/main/java/io/jstach/rainbowgum/spi/RainbowGumServiceProvider.java b/core/src/main/java/io/jstach/rainbowgum/spi/RainbowGumServiceProvider.java
index df8a5589..4b7d3597 100644
--- a/core/src/main/java/io/jstach/rainbowgum/spi/RainbowGumServiceProvider.java
+++ b/core/src/main/java/io/jstach/rainbowgum/spi/RainbowGumServiceProvider.java
@@ -118,9 +118,13 @@ private static LogConfig provideConfig(ServiceLoader
.orElseGet(() -> LogConfig.of(registry, properties));
}
- private static void runInitializers(ServiceLoader loader, ServiceRegistry registry,
- LogConfig config) {
- findProviders(loader, Initializer.class).forEach(c -> c.initialize(registry, config));
+ /**
+ * Runs initializers based on config.
+ * @param loader service loader to use.
+ * @param config config before initializers have run.
+ */
+ public static void runInitializers(ServiceLoader loader, LogConfig config) {
+ findProviders(loader, Initializer.class).forEach(c -> c.initialize(config.registry(), config));
}
/**
@@ -132,7 +136,7 @@ public static LogConfig provideConfig(ServiceLoader l
ServiceRegistry registry = ServiceRegistry.of();
var properties = provideProperties(registry, loader);
var config = provideConfig(loader, registry, properties);
- runInitializers(loader, registry, config);
+ runInitializers(loader, config);
return config;
}
diff --git a/core/src/test/java/io/jstach/rainbowgum/TestSyncPublisher.java b/core/src/test/java/io/jstach/rainbowgum/TestSyncPublisher.java
index 6019d390..432f7398 100644
--- a/core/src/test/java/io/jstach/rainbowgum/TestSyncPublisher.java
+++ b/core/src/test/java/io/jstach/rainbowgum/TestSyncPublisher.java
@@ -6,15 +6,19 @@
import io.jstach.rainbowgum.LogPublisher.SyncLogPublisher;
/**
- *
+ *
*/
public class TestSyncPublisher implements SyncLogPublisher {
/**
- *
+ *
*/
public Deque events = new LinkedList<>();
+ @Override
+ public void start(LogConfig config) {
+ }
+
@Override
public void close() {
}
diff --git a/pom.xml b/pom.xml
index e9befbb9..c9187246 100644
--- a/pom.xml
+++ b/pom.xml
@@ -103,10 +103,15 @@
rainbowgum-avaje-config
${project.version}
-
+
${project.groupId}
rainbowgum-config-apt
${project.version}
+
+
+ ${project.groupId}
+ rainbowgum-rabbitmq
+ ${project.version}
diff --git a/rainbowgum-config-apt/src/main/java/io/jstach/rainbowgum/apt/BuilderModel.java b/rainbowgum-config-apt/src/main/java/io/jstach/rainbowgum/apt/BuilderModel.java
index 6897a858..9966fb01 100644
--- a/rainbowgum-config-apt/src/main/java/io/jstach/rainbowgum/apt/BuilderModel.java
+++ b/rainbowgum-config-apt/src/main/java/io/jstach/rainbowgum/apt/BuilderModel.java
@@ -71,6 +71,13 @@ public String convertMethod() {
};
}
+ boolean isLiteralType() {
+ return switch (type) {
+ case INTEGER_TYPE, STRING_TYPE, BOOLEAN_TYPE -> true;
+ default -> false;
+ };
+ }
+
public String valueMethod() {
return required ? "value" : "valueOrNull";
}
@@ -82,6 +89,27 @@ public boolean isNormal() {
public boolean isPrefixParameter() {
return kind == PropertyKind.NAME_PARAMETER;
}
+
+ public String defaultValueDoc() {
+ if (defaultValue.equals("null")) {
+ return "null
";
+ }
+ String link = linkStatic(defaultValue);
+ if (isLiteralType()) {
+ return "{@value " + link + " }";
+ }
+ return "{@link " + link + " }";
+ }
+
+ private static String linkStatic(String constant) {
+ int index = constant.lastIndexOf(".");
+ if (index < 0) {
+ return constant;
+ }
+ StringBuilder sb = new StringBuilder(constant);
+ sb.setCharAt(index, '#');
+ return sb.toString();
+ }
}
enum PropertyKind {
diff --git a/rainbowgum-config-apt/src/main/java/io/jstach/rainbowgum/apt/ConfigProcessor.java b/rainbowgum-config-apt/src/main/java/io/jstach/rainbowgum/apt/ConfigProcessor.java
index 85c7f1aa..61cc6aef 100644
--- a/rainbowgum-config-apt/src/main/java/io/jstach/rainbowgum/apt/ConfigProcessor.java
+++ b/rainbowgum-config-apt/src/main/java/io/jstach/rainbowgum/apt/ConfigProcessor.java
@@ -10,7 +10,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -51,14 +50,17 @@
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import io.jstach.rainbowgum.apt.BuilderModel.PropertyModel;
import io.jstach.rainbowgum.apt.prism.ConfigObjectPrism;
+import io.jstach.rainbowgum.apt.prism.DefaultParameterPrism;
import io.jstach.rainbowgum.apt.prism.PrefixParameterPrism;
import io.jstach.svc.ServiceProvider;
/**
* Creates ConfigBuilders from static factory methods.
*/
-@SupportedAnnotationTypes({ ConfigObjectPrism.PRISM_ANNOTATION_TYPE, PrefixParameterPrism.PRISM_ANNOTATION_TYPE })
+@SupportedAnnotationTypes({ ConfigObjectPrism.PRISM_ANNOTATION_TYPE, PrefixParameterPrism.PRISM_ANNOTATION_TYPE,
+ DefaultParameterPrism.PRISM_ANNOTATION_TYPE })
@ServiceProvider(value = Processor.class)
public class ConfigProcessor extends AbstractProcessor {
@@ -104,59 +106,27 @@ private BuilderModel model(Helper h, ConfigObjectPrism prism, ExecutableElement
TypeElement enclosingType = (TypeElement) ee.getEnclosingElement();
String builderName = prism.name();
+ if (builderName.isBlank()) {
+ builderName = h.getSimpleName(ee.getReturnType()) + "Builder";
+ }
String propertyPrefix = prism.prefix();
String packageName = h.getPackageString(enclosingType);
String targetType = h.getFullyQualifiedClassName(ee.getReturnType());
String factoryMethod = enclosingType + "." + ee.getSimpleName();
List properties = new ArrayList<>();
- var propertyParams = extractPropertyParams(propertyPrefix);
Map foundParams = new HashMap<>();
List extends VariableElement> parameters = ee.getParameters();
ConfigJavadoc methodDoc = ConfigJavadoc.of(h.getJavadoc(ee));
String description = methodDoc.description;
for (var p : parameters) {
- String name = p.getSimpleName().toString();
- String type = h.getFullyQualifiedClassName(p.asType());
- String typeWithAnnotation = ToStringTypeVisitor.toCodeSafeString(p.asType());
- String defaultValue = "null";
- boolean required = !h.isNullable(p.asType());
- BuilderModel.PropertyKind kind;
- var prefixParameter = PrefixParameterPrism.getInstanceOn(p);
- if (prefixParameter == null) {
- kind = BuilderModel.PropertyKind.NORMAL;
- }
- else {
- // TODO do validation here
- kind = BuilderModel.PropertyKind.NAME_PARAMETER;
- foundParams.put(name, p);
- }
- @Nullable
- String javadoc = methodDoc.properties.get(name);
- if (javadoc == null) {
- javadoc = "";
- }
- var prop = new BuilderModel.PropertyModel(kind, name, type, typeWithAnnotation, defaultValue, required,
- javadoc);
+ var prop = propertyModel(ee, p, h, methodDoc, foundParams);
properties.add(prop);
}
- var foundParamsKeys = foundParams.keySet();
- if (!foundParamsKeys.equals(propertyParams)) {
- for (var p : foundParams.entrySet()) {
- if (!propertyParams.contains(p.getKey())) {
- processingEnv.getMessager()
- .printMessage(Kind.ERROR, "Property parameter missing from prefix. parameter = " + p.getKey(),
- p.getValue());
- }
- }
- for (var pp : propertyParams) {
- if (!foundParamsKeys.contains(pp)) {
- processingEnv.getMessager()
- .printMessage(Kind.ERROR, "Property parameter defined but missing. parameter = " + pp, ee);
- }
- }
+ if (!validatePrefix(ee, propertyPrefix, foundParams)) {
return null;
}
+
var m = new BuilderModel(builderName, propertyPrefix, packageName, targetType, factoryMethod, description,
properties);
String java = BuilderModelRenderer.of().execute(m);
@@ -179,6 +149,66 @@ private BuilderModel model(Helper h, ConfigObjectPrism prism, ExecutableElement
return m;
}
+ private boolean validatePrefix(ExecutableElement ee, String propertyPrefix,
+ Map foundParams) {
+ var propertyParams = extractPropertyParams(propertyPrefix);
+ var foundParamsKeys = foundParams.keySet();
+ if (!foundParamsKeys.equals(propertyParams)) {
+ for (var p : foundParams.entrySet()) {
+ if (!propertyParams.contains(p.getKey())) {
+ processingEnv.getMessager()
+ .printMessage(Kind.ERROR, "Property parameter missing from prefix. parameter = " + p.getKey(),
+ p.getValue());
+ }
+ }
+ for (var pp : propertyParams) {
+ if (!foundParamsKeys.contains(pp)) {
+ processingEnv.getMessager()
+ .printMessage(Kind.ERROR, "Property parameter defined but missing. parameter = " + pp, ee);
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+
+ private PropertyModel propertyModel(ExecutableElement ee, VariableElement p, Helper h, ConfigJavadoc methodDoc,
+ Map foundParams) {
+ String name = p.getSimpleName().toString();
+ String type = h.getFullyQualifiedClassName(p.asType());
+ String typeWithAnnotation = ToStringTypeVisitor.toCodeSafeString(p.asType());
+ String defaultValue = "null";
+ var defaultParameter = DefaultParameterPrism.getInstanceOn(p);
+ if (defaultParameter != null) {
+ TypeElement enclosingType = (TypeElement) ee.getEnclosingElement();
+ String field = defaultParameter.value();
+ if (field.isBlank()) {
+ field = "DEFAULT_" + name;
+ }
+ defaultValue = h.getFullyQualifiedClassName(enclosingType.asType()) + "." + field;
+
+ }
+ boolean required = !h.isNullable(p.asType());
+ BuilderModel.PropertyKind kind;
+ var prefixParameter = PrefixParameterPrism.getInstanceOn(p);
+ if (prefixParameter == null) {
+ kind = BuilderModel.PropertyKind.NORMAL;
+ }
+ else {
+ // TODO do validation here
+ kind = BuilderModel.PropertyKind.NAME_PARAMETER;
+ foundParams.put(name, p);
+ }
+ @Nullable
+ String javadoc = methodDoc.properties.get(name);
+ if (javadoc == null) {
+ javadoc = "";
+ }
+ var prop = new BuilderModel.PropertyModel(kind, name, type, typeWithAnnotation, defaultValue, required,
+ javadoc);
+ return prop;
+ }
+
private static final Pattern pattern = Pattern.compile("\\{(.*?)\\}");
static Set extractPropertyParams(String input) {
@@ -381,7 +411,16 @@ public String getFullyQualifiedClassName(TypeMirror t) {
else {
return t.toString();
}
+ }
+ public String getSimpleName(TypeMirror t) {
+ if (t.getKind() == TypeKind.DECLARED) {
+ TypeElement te = requireNonNull((TypeElement) types.asElement(t));
+ return te.getSimpleName().toString();
+ }
+ else {
+ return t.toString();
+ }
}
public String getFullyQualifiedClassNameWithTypeAnnotations(TypeMirror t) {
diff --git a/rainbowgum-config-apt/src/main/java/io/jstach/rainbowgum/apt/prism/package-info.java b/rainbowgum-config-apt/src/main/java/io/jstach/rainbowgum/apt/prism/package-info.java
index f6bbe392..ab4dbf62 100644
--- a/rainbowgum-config-apt/src/main/java/io/jstach/rainbowgum/apt/prism/package-info.java
+++ b/rainbowgum-config-apt/src/main/java/io/jstach/rainbowgum/apt/prism/package-info.java
@@ -4,5 +4,7 @@
@io.jstach.prism.GeneratePrisms({
@io.jstach.prism.GeneratePrism(value = io.jstach.rainbowgum.ConfigObject.class, publicAccess = true),
@io.jstach.prism.GeneratePrism(value = io.jstach.rainbowgum.ConfigObject.PrefixParameter.class,
+ publicAccess = true),
+ @io.jstach.prism.GeneratePrism(value = io.jstach.rainbowgum.ConfigObject.DefaultParameter.class,
publicAccess = true) })
package io.jstach.rainbowgum.apt.prism;
\ No newline at end of file
diff --git a/rainbowgum-config-apt/src/main/resources/io/jstach/rainbowgum/apt/ConfigBuilder.java b/rainbowgum-config-apt/src/main/resources/io/jstach/rainbowgum/apt/ConfigBuilder.java
index de3d808c..dc395192 100644
--- a/rainbowgum-config-apt/src/main/resources/io/jstach/rainbowgum/apt/ConfigBuilder.java
+++ b/rainbowgum-config-apt/src/main/resources/io/jstach/rainbowgum/apt/ConfigBuilder.java
@@ -22,7 +22,7 @@
* {@value $$propertyLiteral$$ } |
* $$type$$ |
* $$required$$ |
- * $$defaultValue$$ |
+ * $$defaultValueDoc$$ |
* $$javadoc$$ |
*
$$/normal$$
@@ -93,6 +93,7 @@ public final class $$builderName$$ {
/**
* Sets $$#required$$required $$/required$$$$name$$.
+ * Default is $$defaultValueDoc$$.
* @param $$name$$ {@value #$$propertyLiteral$$ } = $$type$$
$$javadoc$$
* @return this builder.
*/
@@ -128,4 +129,21 @@ public final class $$builderName$$ {
$$/properties$$
return this;
}
+
+ /**
+ * Turns the builder into java.util.Properties like Map
+ * @return properties.
+ */
+ public java.util.Map asProperties() {
+ java.util.Map m = new java.util.LinkedHashMap<>();
+ $$#properties$$
+ $$#normal$$
+ if (this.$$name$$ != null) {
+ m.put($$propertyVar$$.key(), String.valueOf(this.$$name$$));
+ }
+ $$/normal$$
+ $$/properties$$
+ return m;
+ }
+
}
\ No newline at end of file
diff --git a/rainbowgum-rabbitmq/pom.xml b/rainbowgum-rabbitmq/pom.xml
index 103ce118..1b3677bf 100644
--- a/rainbowgum-rabbitmq/pom.xml
+++ b/rainbowgum-rabbitmq/pom.xml
@@ -25,5 +25,13 @@
true
provided
+
+ io.jstach.pistachio
+ pistachio-svc
+
+
+ io.jstach.pistachio
+ pistachio-svc-apt
+
\ No newline at end of file
diff --git a/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/IgnoreMe.java b/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/IgnoreMe.java
deleted file mode 100644
index e6e5ba71..00000000
--- a/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/IgnoreMe.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package io.jstach.rainbowgum.rabbitmq;
-
-/**
- * Ignore me
- */
-public record IgnoreMe() {
-
-}
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
new file mode 100644
index 00000000..d10626b6
--- /dev/null
+++ b/rainbowgum-rabbitmq/src/main/java/io/jstach/rainbowgum/rabbitmq/RabbitMQInitializer.java
@@ -0,0 +1,48 @@
+package io.jstach.rainbowgum.rabbitmq;
+
+import java.io.IOException;
+import java.net.URI;
+
+import io.jstach.rainbowgum.LogConfig;
+import io.jstach.rainbowgum.LogOutput;
+import io.jstach.rainbowgum.LogOutputProvider;
+import io.jstach.rainbowgum.LogProperties;
+import io.jstach.rainbowgum.ServiceRegistry;
+import io.jstach.rainbowgum.spi.RainbowGumServiceProvider;
+import io.jstach.svc.ServiceProvider;
+
+/**
+ * RabbitMQ initializer to register output provider with scheme {@value #SCHEME}.
+ */
+@ServiceProvider(RainbowGumServiceProvider.class)
+public class RabbitMQInitializer implements RainbowGumServiceProvider.Initializer {
+
+ /**
+ * Default constructor for service loader.
+ */
+ public RabbitMQInitializer() {
+ }
+
+ final static String SCHEME = "amqp";
+
+ @Override
+ public void initialize(ServiceRegistry registry, LogConfig config) {
+ config.outputRegistry().put(SCHEME, RabbitMQOutputProvider.INSTANCE);
+ }
+
+ private enum RabbitMQOutputProvider implements LogOutputProvider {
+
+ INSTANCE;
+
+ @Override
+ public LogOutput output(URI uri, String name, LogProperties properties) throws IOException {
+ name = name.equals("") ? "rabbitmq" : name;
+ RabbitMQOutputBuilder b = new RabbitMQOutputBuilder(name);
+ b.uri(uri);
+ b.fromProperties(properties);
+ return b.build();
+ }
+
+ }
+
+}
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 5c5773cd..4d222681 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
@@ -7,10 +7,12 @@
import java.util.Map;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Function;
import org.eclipse.jdt.annotation.Nullable;
import com.rabbitmq.client.AMQP.BasicProperties;
+import com.rabbitmq.client.AlreadyClosedException;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
@@ -22,7 +24,11 @@
import io.jstach.rainbowgum.LogProperties;
import io.jstach.rainbowgum.MetaLog;
-class RabbitMQOutput implements LogOutput {
+/**
+ * RabbitMQ Output that will write publish messages to a given exchange with a given
+ * routing key.
+ */
+public class RabbitMQOutput implements LogOutput {
private final URI uri;
@@ -38,7 +44,7 @@ class RabbitMQOutput implements LogOutput {
private final String exchange;
- private final String routingKey;
+ private final Function routingKeyFunction;
private final String connectionName;
@@ -46,66 +52,42 @@ class RabbitMQOutput implements LogOutput {
private final String exchangeType;
- private static final String PREFIX = LogProperties.ROOT_PREFIX + "rabbitmq.";
+ final static String DEFAULT_EXCHANGE = "logging";
- public static final String EXCHANGE_PROPERTY = PREFIX + "exchange";
+ final static String DEFAULT_EXCHANGE_TYPE = "topic";
- static final String ROUTING_KEY_PROPERTY = PREFIX + "routingKey";
-
- static final String CONNECTION_NAME_PROPERTY = PREFIX + "connectionName";
-
- static final String DECLARE_EXCHANGE_PROPERTY = PREFIX + "declareExchange";
-
- static final String EXCHANGE_TYPE_PROPERTY = PREFIX + "exchangeType";
-
- static final String USERNAME_PROPERTY = PREFIX + "username";
-
- static final String PASSWORD_PROPERTY = PREFIX + "password";
-
- static final String PORT_PROPERTY = PREFIX + "port";
-
- static final String HOST_PROPERTY = PREFIX + "host";
-
- static final String VIRTUAL_HOST_PROPERTY = PREFIX + "virtualHost";
-
- static final String APP_ID_PROPERTY = PREFIX + "appId";
-
- // public static RabbitMQOutput of(URI uri, LogProperties properties) {
- // LogProperties combined = LogProperties.of(List.of(LogProperties.of(uri)),
- // properties);
- // Property.builder().build(ROUTING_KEY_PROPERTY);
- //
- // }
-
- public RabbitMQOutput(URI uri, ConnectionFactory connectionFactory, @Nullable String appId, String exchange,
- String routingKey, String connectionName, boolean declareExchange, String exchangeType) {
+ RabbitMQOutput(URI uri, ConnectionFactory connectionFactory, @Nullable String appId, String exchange,
+ Function routingKeyFunction, String connectionName, boolean declareExchange,
+ String exchangeType) {
super();
this.uri = uri;
this.connectionFactory = connectionFactory;
this.appId = appId;
this.exchange = exchange;
- this.routingKey = routingKey;
+ this.routingKeyFunction = routingKeyFunction;
this.connectionName = connectionName;
this.declareExchange = declareExchange;
this.exchangeType = exchangeType;
}
- @ConfigObject(prefix = LogProperties.OUTPUT_PREFIX, name = "RabbitMQOutputBuilder")
- public static RabbitMQOutput of(@ConfigObject.PrefixParameter String name, //
+ @ConfigObject(prefix = LogProperties.OUTPUT_PREFIX)
+ static RabbitMQOutput of( //
+ @ConfigObject.PrefixParameter String name, //
@Nullable URI uri, //
- String exchange, //
- String routingKey, //
+ @ConfigObject.DefaultParameter("DEFAULT_EXCHANGE") String exchange, //
+ @Nullable String routingKey, //
@Nullable Boolean declareExchange, //
@Nullable String host, //
- @Nullable String username, @Nullable String password, //
+ @Nullable String username, //
+ @Nullable String password, //
@Nullable Integer port, //
@Nullable String appId, //
@Nullable String connectionName, //
- @Nullable String exchangeType, //
+ @ConfigObject.DefaultParameter("DEFAULT_EXCHANGE_TYPE") @Nullable String exchangeType, //
@Nullable String virtualHost) {
connectionName = connectionName == null ? "rainbowgumOutput" : connectionName;
declareExchange = declareExchange == null ? false : declareExchange;
- exchangeType = exchangeType == null ? "topic" : exchangeType;
+ exchangeType = exchangeType == null ? DEFAULT_EXCHANGE_TYPE : exchangeType;
ConnectionFactory factory = new ConnectionFactory();
if (uri != null) {
try {
@@ -130,7 +112,15 @@ public static RabbitMQOutput of(@ConfigObject.PrefixParameter String name, //
if (virtualHost != null) {
factory.setVirtualHost(virtualHost);
}
- return new RabbitMQOutput(uri, factory, appId, exchange, routingKey, connectionName, false, exchangeType);
+ Function routingKeyFunction;
+ if (routingKey != null) {
+ routingKeyFunction = e -> routingKey;
+ }
+ else {
+ routingKeyFunction = e -> e.level().name();
+ }
+ return new RabbitMQOutput(uri, factory, appId, exchange, routingKeyFunction, connectionName, declareExchange,
+ exchangeType);
}
@Override
@@ -173,7 +163,7 @@ public void write(LogEvent event, byte[] bytes, ContentType contentType) {
byte[] body = bytes;
try {
var c = channel();
- c.basicPublish(exchange, routingKey, props, body);
+ c.basicPublish(exchange, routingKeyFunction.apply(event), props, body);
}
catch (IOException e) {
MetaLog.error(RabbitMQOutput.class, e);
@@ -244,6 +234,9 @@ public void close() {
try {
c.close();
}
+ catch (AlreadyClosedException ae) {
+ // do nothing.
+ }
catch (IOException | TimeoutException e) {
MetaLog.error(getClass(), e);
}
@@ -252,6 +245,9 @@ public void close() {
try {
c.close();
}
+ catch (AlreadyClosedException ae) {
+ // do nothing.
+ }
catch (IOException | TimeoutException e) {
MetaLog.error(getClass(), e);
}
diff --git a/rainbowgum-rabbitmq/src/main/java/module-info.java b/rainbowgum-rabbitmq/src/main/java/module-info.java
index 5b93a20c..672ef948 100644
--- a/rainbowgum-rabbitmq/src/main/java/module-info.java
+++ b/rainbowgum-rabbitmq/src/main/java/module-info.java
@@ -1,10 +1,15 @@
+import io.jstach.rainbowgum.spi.RainbowGumServiceProvider;
+
/**
* Provides RabbitMQ Rainbow Gum output.
*/
module io.jstach.rainbowgum.rabbitmq {
exports io.jstach.rainbowgum.rabbitmq;
- requires io.jstach.rainbowgum;
+ requires transitive io.jstach.rainbowgum;
requires com.rabbitmq.client;
requires static org.eclipse.jdt.annotation;
+ requires static io.jstach.svc;
+
+ provides RainbowGumServiceProvider with io.jstach.rainbowgum.rabbitmq.RabbitMQInitializer;
}
\ No newline at end of file
diff --git a/test/pom.xml b/test/pom.xml
index 11421fa4..1d74c442 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -18,6 +18,7 @@
rainbowgum-test-avaje
rainbowgum-test-config
+ rainbowgum-test-rabbitmq
diff --git a/test/rainbowgum-test-config/src/main/java/io/jstach/rainbowgum/test/config/ExampleConfig.java b/test/rainbowgum-test-config/src/main/java/io/jstach/rainbowgum/test/config/ExampleConfig.java
index 3d2fe2e0..655f4c79 100644
--- a/test/rainbowgum-test-config/src/main/java/io/jstach/rainbowgum/test/config/ExampleConfig.java
+++ b/test/rainbowgum-test-config/src/main/java/io/jstach/rainbowgum/test/config/ExampleConfig.java
@@ -16,7 +16,13 @@ public record ExampleConfig(String name, Integer count, @Nullable URI uri) {
* @return config
*/
@ConfigObject(name = "ExampleConfigBuilder", prefix = "logging.example.{name}.")
- public static ExampleConfig of(@ConfigObject.PrefixParameter String name, Integer count, @Nullable URI uri) {
+ public static ExampleConfig of( //
+ @ConfigObject.PrefixParameter String name, //
+ @ConfigObject.DefaultParameter("DEFAULT_COUNT") Integer count, //
+ @Nullable URI uri) {
return new ExampleConfig(name, count, uri);
}
+
+ public static final int DEFAULT_COUNT = 8080;
+
}
diff --git a/test/rainbowgum-test-rabbitmq/pom.xml b/test/rainbowgum-test-rabbitmq/pom.xml
new file mode 100644
index 00000000..eb18e92b
--- /dev/null
+++ b/test/rainbowgum-test-rabbitmq/pom.xml
@@ -0,0 +1,29 @@
+
+ 4.0.0
+
+ io.jstach.rainbowgum
+ rainbowgum-test-parent
+ 0.1.3-SNAPSHOT
+
+ rainbowgum-test-rabbitmq
+
+
+ ${project.groupId}
+ rainbowgum
+
+
+ ${project.groupId}
+ rainbowgum-rabbitmq
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.testcontainers
+ rabbitmq
+ 1.19.3
+ test
+
+
+
\ No newline at end of file
diff --git a/test/rainbowgum-test-rabbitmq/src/main/java/io/jstach/rainbowgum/test/rabbitmq/RabbitMQSetup.java b/test/rainbowgum-test-rabbitmq/src/main/java/io/jstach/rainbowgum/test/rabbitmq/RabbitMQSetup.java
new file mode 100644
index 00000000..a3199ec9
--- /dev/null
+++ b/test/rainbowgum-test-rabbitmq/src/main/java/io/jstach/rainbowgum/test/rabbitmq/RabbitMQSetup.java
@@ -0,0 +1,41 @@
+package io.jstach.rainbowgum.test.rabbitmq;
+
+import java.lang.System.Logger.Level;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+import org.slf4j.LoggerFactory;
+
+import io.jstach.rainbowgum.LogConfig;
+import io.jstach.rainbowgum.LogProperties;
+import io.jstach.rainbowgum.RainbowGum;
+import io.jstach.rainbowgum.spi.RainbowGumServiceProvider;
+
+public class RabbitMQSetup {
+
+ public static void main(String[] args) {
+
+ Map properties = new LinkedHashMap<>();
+ properties.put(LogProperties.OUTPUT_PROPERTY, "amqp");
+ properties.put(LogProperties.OUTPUT_PROPERTY + ".amqp", "amqp:///");
+ var config = LogConfig.builder().logProperties(properties::get).build();
+ RainbowGumServiceProvider.runInitializers(ServiceLoader.load(RainbowGumServiceProvider.class), config);
+ RainbowGum.set(() -> RainbowGum.builder(config).build());
+ // RainbowGum.set(() -> gum);
+ var logger = LoggerFactory.getLogger(RabbitMQSetup.class);
+ logger.info("hello");
+ }
+
+ public static void run(Map properties) {
+ var config = LogConfig.builder().logProperties(properties::get).build();
+ RainbowGumServiceProvider.runInitializers(ServiceLoader.load(RainbowGumServiceProvider.class), config);
+ RainbowGum.set(() -> RainbowGum.builder(config).build());
+ RainbowGum.of();
+ // RainbowGum.set(() -> gum);
+ System.getLogger(RabbitMQSetup.class.getName()).log(Level.INFO, "hello");
+ //var logger = LoggerFactory.getLogger(RabbitMQSetup.class);
+ //logger.info("hello");
+ }
+
+}
diff --git a/test/rainbowgum-test-rabbitmq/src/main/java/io/jstach/rainbowgum/test/rabbitmq/package-info.java b/test/rainbowgum-test-rabbitmq/src/main/java/io/jstach/rainbowgum/test/rabbitmq/package-info.java
new file mode 100644
index 00000000..3f9c11ac
--- /dev/null
+++ b/test/rainbowgum-test-rabbitmq/src/main/java/io/jstach/rainbowgum/test/rabbitmq/package-info.java
@@ -0,0 +1,2 @@
+@org.eclipse.jdt.annotation.NonNullByDefault
+package io.jstach.rainbowgum.test.rabbitmq;
\ No newline at end of file
diff --git a/test/rainbowgum-test-rabbitmq/src/test/java/io/jstach/rainbowgum/test/rabbitmq/RabbitMQSetupTest.java b/test/rainbowgum-test-rabbitmq/src/test/java/io/jstach/rainbowgum/test/rabbitmq/RabbitMQSetupTest.java
new file mode 100644
index 00000000..e7958481
--- /dev/null
+++ b/test/rainbowgum-test-rabbitmq/src/test/java/io/jstach/rainbowgum/test/rabbitmq/RabbitMQSetupTest.java
@@ -0,0 +1,45 @@
+package io.jstach.rainbowgum.test.rabbitmq;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.testcontainers.containers.RabbitMQContainer;
+import org.testcontainers.utility.DockerImageName;
+
+import io.jstach.rainbowgum.LogProperties;
+import io.jstach.rainbowgum.rabbitmq.RabbitMQOutputBuilder;
+
+class RabbitMQSetupTest {
+
+ static RabbitMQContainer rabbit = new RabbitMQContainer(DockerImageName.parse("rabbitmq:3.7.25-management-alpine"));
+
+ @BeforeAll
+ public static void beforeAll() {
+ rabbit.start();
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ rabbit.stop();
+ }
+
+ @Test
+ void testMain() {
+ RabbitMQOutputBuilder b = new RabbitMQOutputBuilder("amqp");
+ //b.host(rabbit.getHost());
+ //b.port(rabbit.getAmqpPort());
+ b.uri(URI.create(rabbit.getAmqpUrl()));
+ b.declareExchange(true);
+ Map properties = b.asProperties();
+ properties.put(LogProperties.OUTPUT_PROPERTY, "amqp");
+ properties.put(LogProperties.OUTPUT_PROPERTY + ".amqp", "amqp:///");
+ System.out.println(properties);
+ System.out.println(rabbit.getAmqpUrl());
+ //LoggerFactoryFriend.reset();
+ RabbitMQSetup.run(properties);
+ }
+
+}