Skip to content

Commit

Permalink
Remove pesky low cohesion Defaults
Browse files Browse the repository at this point in the history
  • Loading branch information
agentgt committed Jan 6, 2024
1 parent 2378422 commit 565da32
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 171 deletions.
139 changes: 3 additions & 136 deletions core/src/main/java/io/jstach/rainbowgum/Defaults.java
Original file line number Diff line number Diff line change
@@ -1,150 +1,17 @@
package io.jstach.rainbowgum;

import java.net.URI;
import java.util.EnumMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;

import org.eclipse.jdt.annotation.Nullable;

import io.jstach.rainbowgum.LogAppender.ThreadSafeLogAppender;
import io.jstach.rainbowgum.LogOutput.OutputType;
import io.jstach.rainbowgum.LogProperties.Property;
import io.jstach.rainbowgum.format.StandardEventFormatter;
import io.jstach.rainbowgum.publisher.BlockingQueueAsyncLogPublisher;

/**
* Static defaults that should probably be in the config class.
*
* @author agentgt
*/
public class Defaults {
final class Defaults {

static final String SHUTDOWN = "#SHUTDOWN#";

/**
* Default async buffer size.
*/
public static final int ASYNC_BUFFER_SIZE = 1024;

private static final ReentrantReadWriteLock staticLock = new ReentrantReadWriteLock();

private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

private static CopyOnWriteArrayList<AutoCloseable> shutdownHooks = new CopyOnWriteArrayList<>();

// we do not need the newer VarHandle because there is only one of these guys
private static AtomicBoolean shutdownHookRegistered = new AtomicBoolean(false);

private final EnumMap<OutputType, Supplier<? extends LogFormatter>> formatters = new EnumMap<>(OutputType.class);

private final LogProperties properties;

private static final Property<Boolean> defaultsAppenderBufferProperty = Property.builder()
.map(s -> Boolean.parseBoolean(s))
.orElse(false)
.build(LogProperties.concatKey("defaults.appender.buffer"));

static final Property<URI> fileProperty = Property.builder().map(URI::new).build(LogProperties.FILE_PROPERTY);

static final Property<List<String>> outputProperty = Property.builder()
.map(p -> Stream.of(p.split(",")).filter(s -> !s.trim().isEmpty()).toList())
.build(LogProperties.OUTPUT_PROPERTY);

Defaults(LogProperties logProperties) {
this.properties = logProperties;
}

static Function<LogAppender, ThreadSafeLogAppender> threadSafeAppender = (appender) -> {
return new LockingLogAppender(appender);
};

LogPublisher.AsyncLogPublisher asyncPublisher(List<? extends LogAppender> appenders, int bufferSize) {
return BlockingQueueAsyncLogPublisher.of(appenders, bufferSize);
}

LogAppender logAppender(LogOutput output, @Nullable LogEncoder encoder) {
if (encoder == null) {
encoder = LogEncoder.of(formatterForOutputType(output.type()));
}
;
return defaultsAppenderBufferProperty.get(properties).value() ? new BufferLogAppender(output, encoder)
: new DefaultLogAppender(output, encoder);
}
// static final Property<URI> fileProperty =
// Property.builder().map(URI::new).build(LogProperties.FILE_PROPERTY);

static final String NEW_LINE = "\n";

/**
* Associates a default formatter with a specific output type
* @param outputType output type to use for finding best default formatter.
* @return formatter for output type.
*/
public LogFormatter formatterForOutputType(OutputType outputType) {
lock.readLock().lock();
try {
var formatter = formatters.get(outputType);
if (formatter == null) {
return StandardEventFormatter.builder().build();
}
return formatter.get();
}
finally {
lock.readLock().unlock();
}
}

/**
* Sets a default formatter for a specific output type.
* @param outputType output type.
* @param formatter formatter.
*/
public void setFormatterForOutputType(OutputType outputType, Supplier<? extends LogFormatter> formatter) {
lock.writeLock().lock();
try {
formatters.put(outputType, formatter);
}
finally {
lock.writeLock().unlock();
}
}

static void addShutdownHook(AutoCloseable hook) {
staticLock.writeLock().lock();
try {
if (shutdownHookRegistered.compareAndSet(false, true)) {
var thread = new Thread(() -> {
runShutdownHooks();
});
thread.setName("rainbowgum-shutdown");
Runtime.getRuntime().addShutdownHook(thread);
}
shutdownHooks.add(hook);
}
finally {
staticLock.writeLock().unlock();
}
}

private static void runShutdownHooks() {
/*
* We do not lock here since we are in the shutdown thread luckily shutdownHooks
* is thread safe
*/
for (var hook : shutdownHooks) {
try {
hook.close();
}
catch (Exception e) {
MetaLog.error(Defaults.class, e);
}
}
// Help the GC or whatever final cleanup is going on
shutdownHooks.clear();
}

}
29 changes: 27 additions & 2 deletions core/src/main/java/io/jstach/rainbowgum/LogAppender.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package io.jstach.rainbowgum;

import java.net.URI;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;

import org.eclipse.jdt.annotation.Nullable;

import io.jstach.rainbowgum.LogAppender.AbstractLogAppender;
import io.jstach.rainbowgum.LogAppender.ThreadSafeLogAppender;
import io.jstach.rainbowgum.LogEncoder.Buffer;
import io.jstach.rainbowgum.LogProperties.Property;

/**
* Appenders are guaranteed to be written synchronously much like an actor in actor
Expand Down Expand Up @@ -143,10 +146,26 @@ public AppenderProvider build() {
var output = this.output;
var encoder = this.encoder;
return config -> {
return config.defaults().logAppender(output, encoder);
return logAppender(config, output, encoder);
};
}

private static final Property<Boolean> defaultsAppenderBufferProperty = Property.builder()
.map(s -> Boolean.parseBoolean(s))
.orElse(false)
.build(LogProperties.concatKey("defaults.appender.buffer"));

private static LogAppender logAppender(LogConfig config, LogOutput output, @Nullable LogEncoder encoder) {
var formatterRegistry = config.formatterRegistry();
var properties = config.properties();
if (encoder == null) {
encoder = LogEncoder.of(formatterRegistry.formatterForOutputType(output.type()));
}

return defaultsAppenderBufferProperty.get(properties).value() ? new BufferLogAppender(output, encoder)
: new DefaultLogAppender(output, encoder);
}

}

@Override
Expand All @@ -167,7 +186,7 @@ public static ThreadSafeLogAppender of(LogAppender appender) {
if (appender instanceof ThreadSafeLogAppender lo) {
return lo;
}
return Defaults.threadSafeAppender.apply(appender);
return DefaultLogAppender.threadSafeAppender.apply(appender);
}

}
Expand Down Expand Up @@ -317,6 +336,12 @@ public void close() {
*/
class DefaultLogAppender extends AbstractLogAppender implements ThreadSafeLogAppender {

static Function<LogAppender, ThreadSafeLogAppender> threadSafeAppender = (appender) -> {
return new LockingLogAppender(appender);
};

static final Property<URI> fileProperty = Property.builder().map(URI::new).build(LogProperties.FILE_PROPERTY);

protected final ReentrantLock lock = new ReentrantLock();

public DefaultLogAppender(LogOutput output, LogEncoder encoder) {
Expand Down
22 changes: 11 additions & 11 deletions core/src/main/java/io/jstach/rainbowgum/LogConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ default <T> PropertyValue<T> get(Property<T> property) {
public LevelConfig levelResolver();

/**
* Special defaults. Internal for now.
* @return defaults.
* Registered formatters.
* @return formatter registry.
*/
public Defaults defaults();
public LogFormatterRegistry formatterRegistry();

/**
* Output provider that uses URI to find output.
Expand Down Expand Up @@ -224,25 +224,25 @@ final class DefaultLogConfig implements LogConfig {

private final LevelConfig levelResolver;

private final Defaults defaults;

private final ChangePublisher publisher;

private final LogOutputRegistry outputRegistry;

private final LogFormatterRegistry formatterRegistry;

public DefaultLogConfig(ServiceRegistry registry, LogProperties properties) {
super();
this.registry = registry;
this.properties = properties;
this.levelResolver = new ConfigLevelResolver(properties);
this.defaults = new Defaults(properties);
this.publisher = new AbstractChangePublisher() {
@Override
protected LogConfig _config() {
return DefaultLogConfig.this;
}
};
this.outputRegistry = LogOutputRegistry.of();
this.formatterRegistry = LogFormatterRegistry.of();
}

@Override
Expand All @@ -255,11 +255,6 @@ public LevelConfig levelResolver() {
return this.levelResolver;
}

@Override
public Defaults defaults() {
return defaults;
}

@Override
public ServiceRegistry registry() {
return this.registry;
Expand All @@ -275,4 +270,9 @@ public LogOutputRegistry outputRegistry() {
return this.outputRegistry;
}

@Override
public LogFormatterRegistry formatterRegistry() {
return this.formatterRegistry;
}

}
79 changes: 79 additions & 0 deletions core/src/main/java/io/jstach/rainbowgum/LogFormatterRegistry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package io.jstach.rainbowgum;

import java.util.EnumMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Supplier;

import io.jstach.rainbowgum.LogOutput.OutputType;
import io.jstach.rainbowgum.format.StandardEventFormatter;

/**
* Formatters that are registered based on output type.
*/
public sealed interface LogFormatterRegistry permits DefaultLogFormatterRegistry {

/**
* Creates a log formatter registry.
* @return new created log formatter registry.
*/
public static LogFormatterRegistry of() {
return new DefaultLogFormatterRegistry();
}

/**
* Associates a default formatter with a specific output type
* @param outputType output type to use for finding best default formatter.
* @return formatter for output type.
*/
public LogFormatter formatterForOutputType(OutputType outputType);

/**
* Sets a default formatter for a specific output type.
* @param outputType output type.
* @param formatter formatter.
*/
public void setFormatterForOutputType(OutputType outputType, Supplier<? extends LogFormatter> formatter);

}

final class DefaultLogFormatterRegistry implements LogFormatterRegistry {

private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

private final EnumMap<OutputType, Supplier<? extends LogFormatter>> formatters = new EnumMap<>(OutputType.class);

/**
* Associates a default formatter with a specific output type
* @param outputType output type to use for finding best default formatter.
* @return formatter for output type.
*/
public LogFormatter formatterForOutputType(OutputType outputType) {
lock.readLock().lock();
try {
var formatter = formatters.get(outputType);
if (formatter == null) {
return StandardEventFormatter.builder().build();
}
return formatter.get();
}
finally {
lock.readLock().unlock();
}
}

/**
* Sets a default formatter for a specific output type.
* @param outputType output type.
* @param formatter formatter.
*/
public void setFormatterForOutputType(OutputType outputType, Supplier<? extends LogFormatter> formatter) {
lock.writeLock().lock();
try {
formatters.put(outputType, formatter);
}
finally {
lock.writeLock().unlock();
}
}

}
Loading

0 comments on commit 565da32

Please sign in to comment.