Add tests, add docu, use subpackage.

This commit is contained in:
Stephan Schnabel 2020-08-13 18:32:41 +02:00
parent 333f3302ec
commit c4b1d1d2f6
Signed by: stephan.schnabel
GPG key ID: F74FE2422AA07290
10 changed files with 345 additions and 110 deletions

View file

@ -0,0 +1,50 @@
package io.kokuwa.micronaut.logging;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import javax.inject.Singleton;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.turbo.TurboFilter;
import io.micronaut.context.annotation.BootstrapContextCompatible;
import io.micronaut.context.annotation.Requires;
import io.micronaut.core.annotation.Internal;
/**
* Utility class for Logback operations.
*
* @author Stephan Schnabel
*/
@Requires(classes = LoggerContext.class)
@BootstrapContextCompatible
@Singleton
@Internal
public class LogbackUtil {
private final LoggerContext context;
public LogbackUtil() {
this.context = (LoggerContext) LoggerFactory.getILoggerFactory();
}
public <T extends TurboFilter> Optional<T> getTurboFilter(Class<T> type, String name) {
return context.getTurboFilterList().stream()
.filter(filter -> Objects.equals(name, filter.getName()))
.filter(type::isInstance)
.map(type::cast).findAny();
}
public <T extends TurboFilter> T getTurboFilter(Class<T> type, String name, Supplier<T> defaultFilter) {
return getTurboFilter(type, name).orElseGet(() -> {
var filter = defaultFilter.get();
filter.setName(name);
filter.setContext(context);
context.addTurboFilter(filter);
return filter;
});
}
}

View file

@ -1,86 +0,0 @@
package io.kokuwa.micronaut.logging;
import java.util.Objects;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import io.micronaut.context.annotation.BootstrapContextCompatible;
import io.micronaut.context.annotation.Context;
import io.micronaut.context.annotation.Requires;
import io.micronaut.context.env.Environment;
import io.micronaut.context.event.ApplicationEventListener;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.type.Argument;
import io.micronaut.runtime.context.scope.refresh.RefreshEvent;
/**
* Configure mdc filter.
*
* @author Stephan Schnabel
*/
@BootstrapContextCompatible
@Context
@Requires(classes = LoggerContext.class)
@Requires(property = MDCTurboFilterConfigurer.LOGGER_MDCS_PROPERTY_PREFIX)
@Internal
public class MDCTurboFilterConfigurer implements ApplicationEventListener<RefreshEvent> {
public static final String LOGGER_MDCS_PROPERTY_PREFIX = "logger.mdc";
private static final Logger log = LoggerFactory.getLogger(MDCTurboFilterConfigurer.class);
private final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
private final Environment environment;
public MDCTurboFilterConfigurer(Environment environment) {
this.environment = environment;
configure();
}
@Override
public void onApplicationEvent(RefreshEvent event) {
if (event.getSource().keySet().stream().anyMatch(key -> key.startsWith(LOGGER_MDCS_PROPERTY_PREFIX))) {
configure();
}
}
private void configure() {
for (var name : environment.getPropertyEntries(LOGGER_MDCS_PROPERTY_PREFIX)) {
var prefix = LOGGER_MDCS_PROPERTY_PREFIX + "." + name + ".";
var key = environment.getProperty(prefix + "key", String.class, name);
var loggers = environment.getProperty(prefix + "loggers", Argument.setOf(String.class)).orElseGet(Set::of);
var values = environment.getProperty(prefix + "values", Argument.setOf(String.class)).orElseGet(Set::of);
var level = Level.valueOf(environment.getProperty(prefix + "level", String.class, Level.TRACE.toString()));
getFilter(name, key).setLoggers(loggers).setValues(values).setLevel(level);
log.info("Configured MDC filter {} for key {} with level {}.", name, key, level);
}
}
private MDCTurboFilter getFilter(String name, String key) {
// get filter
var filterName = LOGGER_MDCS_PROPERTY_PREFIX + "." + key;
var filterOptional = context.getTurboFilterList().stream()
.filter(f -> Objects.equals(filterName, f.getName()))
.filter(MDCTurboFilter.class::isInstance)
.map(MDCTurboFilter.class::cast)
.findAny();
if (filterOptional.isPresent()) {
return filterOptional.get();
}
// add filter
var filter = new MDCTurboFilter(name, key, context);
filter.start();
context.addTurboFilter(filter);
return filter;
}
}

View file

@ -1,4 +1,4 @@
package io.kokuwa.micronaut.logging;
package io.kokuwa.micronaut.logging.mdc;
import java.util.HashMap;
import java.util.HashSet;
@ -11,29 +11,21 @@ import org.slf4j.Marker;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.spi.FilterReply;
/**
* Filter for log levels based on mdc.
* Filter for log levels based on MDC.
*
* @author Stephan Schnabel
*/
public class MDCTurboFilter extends TurboFilter {
private final String key;
private final Map<String, Boolean> cache = new HashMap<>();
private final Set<String> loggers = new HashSet<>();
private final Set<String> values = new HashSet<>();
private String key;
private Level level;
public MDCTurboFilter(String name, String key, Context context) {
this.key = key;
this.level = Level.TRACE;
this.setName(name);
this.setContext(context);
}
public MDCTurboFilter setLoggers(Set<String> loggers) {
this.cache.clear();
this.loggers.clear();
@ -47,6 +39,11 @@ public class MDCTurboFilter extends TurboFilter {
return this;
}
public MDCTurboFilter setKey(String key) {
this.key = key;
return this;
}
public MDCTurboFilter setLevel(Level level) {
this.level = level;
return this;
@ -55,17 +52,18 @@ public class MDCTurboFilter extends TurboFilter {
@Override
public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) {
if (logger == null || !isStarted() || values.isEmpty() || loggers.isEmpty()) {
if (logger == null || !isStarted()) {
return FilterReply.NEUTRAL;
}
var value = MDC.get(key);
if (value == null || !values.contains(value)) {
if (value == null || !values.isEmpty() && !values.contains(value)) {
return FilterReply.NEUTRAL;
}
var isLoggerIncluded = !cache.computeIfAbsent(logger.getName(), k -> loggers.stream().anyMatch(k::startsWith));
if (isLoggerIncluded) {
var isLoggerIncluded = loggers.isEmpty()
|| cache.computeIfAbsent(logger.getName(), k -> loggers.stream().anyMatch(k::startsWith));
if (!isLoggerIncluded) {
return FilterReply.NEUTRAL;
}

View file

@ -0,0 +1,60 @@
package io.kokuwa.micronaut.logging.mdc;
import java.util.Set;
import ch.qos.logback.classic.Level;
import io.kokuwa.micronaut.logging.LogbackUtil;
import io.micronaut.context.annotation.BootstrapContextCompatible;
import io.micronaut.context.annotation.Context;
import io.micronaut.context.annotation.Requires;
import io.micronaut.context.env.Environment;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.type.Argument;
import lombok.extern.slf4j.Slf4j;
/**
* Configure MDC filter.
*
* @author Stephan Schnabel
*/
@Requires(beans = LogbackUtil.class)
@Requires(property = MDCTurboFilterConfigurer.PREFIX)
@Requires(property = MDCTurboFilterConfigurer.ENABLED, notEquals = "false")
@BootstrapContextCompatible
@Context
@Internal
@Slf4j
public class MDCTurboFilterConfigurer {
public static final String PREFIX = "logger.mdc";
public static final String ENABLED = PREFIX + ".enabled";
private final LogbackUtil logback;
private final Environment environment;
public MDCTurboFilterConfigurer(LogbackUtil logback, Environment environment) {
this.logback = logback;
this.environment = environment;
configure();
}
public void configure() {
for (var name : environment.getPropertyEntries(PREFIX)) {
var prefix = PREFIX + "." + name + ".";
var key = environment.getProperty(prefix + "key", String.class, name);
var loggers = environment.getProperty(prefix + "loggers", Argument.setOf(String.class)).orElseGet(Set::of);
var values = environment.getProperty(prefix + "values", Argument.setOf(String.class)).orElseGet(Set::of);
var level = Level.valueOf(environment.getProperty(prefix + "level", String.class, Level.TRACE.toString()));
logback.getTurboFilter(MDCTurboFilter.class, name, MDCTurboFilter::new)
.setKey(key)
.setLevel(level)
.setLoggers(loggers)
.setValues(values)
.start();
log.info("Configured MDC filter {} for key {} with level {}.", name, key, level);
}
}
}