Fix mdc cleanup, propagate level header, code clean up.
This commit is contained in:
parent
5a5fa8a408
commit
0a7a34cb34
10 changed files with 119 additions and 36 deletions
31
README.md
31
README.md
|
@ -6,15 +6,15 @@
|
||||||
|
|
||||||
Buildin appender:
|
Buildin appender:
|
||||||
* console format
|
* console format
|
||||||
* stackdriver format (with support for error reporting)
|
* Stackdriver format (with support for error reporting)
|
||||||
|
|
||||||
### Set log level based on MDC values
|
### Set log level based on MDC values
|
||||||
|
|
||||||
Confguration:
|
Configuration:
|
||||||
* *enabled*: enable MDC filter (`true` is default)
|
* *enabled*: enable MDC filter (`true` is default)
|
||||||
* *key*: MDC key, is optional (will use name instead, see example `user` below)
|
* *key*: MDC key, is optional (will use name instead, see example `user` below)
|
||||||
* *level*: log level to use (`TRACE` is default)
|
* *level*: log level to use (`TRACE` is default)
|
||||||
* *loggers*: whitelist of logger names, matches all loggers if empty
|
* *loggers*: passlist of logger names, matches all loggers if empty
|
||||||
* *values*: values for matching MDC key, matches all values if empty
|
* *values*: values for matching MDC key, matches all values if empty
|
||||||
|
|
||||||
Example for setting different values for different values/logger:
|
Example for setting different values for different values/logger:
|
||||||
|
@ -66,21 +66,32 @@ logger:
|
||||||
|
|
||||||
### Set log level based on HTTP request header
|
### Set log level based on HTTP request header
|
||||||
|
|
||||||
Confguration:
|
Configuration for server filter (prefixed with *logger.request.filter*):
|
||||||
* *enabled*: enable HTTP request filter (`true` is default)
|
* *enabled*: enable HTTP server filter (`true` is default)
|
||||||
* *order*: order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/master/core/src/main/java/io/micronaut/core/order/Ordered.java) (highest is default)
|
* *order*: order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/master/core/src/main/java/io/micronaut/core/order/Ordered.java) (highest is default)
|
||||||
* *pattern*: filter pattern (`/**` is default)
|
* *path*: filter path (`/**` is default)
|
||||||
* *header*: name of HTTP header (`x-log-level` is default)
|
* *header*: name of HTTP header (`x-log-level` is default)
|
||||||
|
|
||||||
|
Configuration for client filter for propagation (prefixed with *logger.request.propagation*):
|
||||||
|
* *enabled*: enable HTTP client filter (`true` is default)
|
||||||
|
* *order*: order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/master/core/src/main/java/io/micronaut/core/order/Ordered.java) (tracing is default)
|
||||||
|
* *path*: filter path (`/**` is default)
|
||||||
|
* *header*: name of HTTP header (server header is default)
|
||||||
|
|
||||||
Example with default configuration:
|
Example with default configuration:
|
||||||
```
|
```
|
||||||
logger:
|
logger:
|
||||||
request:
|
request:
|
||||||
header:
|
filter:
|
||||||
enabled: true
|
enabled: true
|
||||||
order: -2147483648
|
order: -2147483648
|
||||||
pattern: /**
|
path: /**
|
||||||
header: x-log-level
|
header: x-log-level
|
||||||
|
propagation:
|
||||||
|
enabled: true
|
||||||
|
order: 19000
|
||||||
|
path: /**
|
||||||
|
header: ${logger.request.header.header-name}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Add princial for request to MDC
|
### Add princial for request to MDC
|
||||||
|
@ -88,7 +99,7 @@ logger:
|
||||||
Confguration:
|
Confguration:
|
||||||
* *enabled*: enable HTTP principal filter (`true` is default)
|
* *enabled*: enable HTTP principal filter (`true` is default)
|
||||||
* *order*: order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/master/core/src/main/java/io/micronaut/core/order/Ordered.java) ([ServerFilterPhase.SECURITY.after()](https://github.com/micronaut-projects/micronaut-core/blob/v2.0.1/http/src/main/java/io/micronaut/http/filter/ServerFilterPhase.java#L54) is default)
|
* *order*: order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/master/core/src/main/java/io/micronaut/core/order/Ordered.java) ([ServerFilterPhase.SECURITY.after()](https://github.com/micronaut-projects/micronaut-core/blob/v2.0.1/http/src/main/java/io/micronaut/http/filter/ServerFilterPhase.java#L54) is default)
|
||||||
* *pattern*: filter pattern (`/**` is default)
|
* *path*: filter path (`/**` is default)
|
||||||
* *key*: name of MDC header (`principal` is default)
|
* *key*: name of MDC header (`principal` is default)
|
||||||
|
|
||||||
Example with default configuration:
|
Example with default configuration:
|
||||||
|
@ -98,7 +109,7 @@ logger:
|
||||||
principal:
|
principal:
|
||||||
enabled: true
|
enabled: true
|
||||||
order: 39250
|
order: 39250
|
||||||
pattern: /**
|
path: /**
|
||||||
key: principal
|
key: principal
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -42,7 +42,7 @@
|
||||||
<!-- ===================================================================== -->
|
<!-- ===================================================================== -->
|
||||||
|
|
||||||
<version.ch.qos.logback.contrib>0.1.5</version.ch.qos.logback.contrib>
|
<version.ch.qos.logback.contrib>0.1.5</version.ch.qos.logback.contrib>
|
||||||
<version.io.micronaut>2.0.1</version.io.micronaut>
|
<version.io.micronaut>2.0.2</version.io.micronaut>
|
||||||
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import io.micronaut.context.annotation.Requires;
|
||||||
import io.micronaut.context.env.Environment;
|
import io.micronaut.context.env.Environment;
|
||||||
import io.micronaut.core.annotation.Internal;
|
import io.micronaut.core.annotation.Internal;
|
||||||
import io.micronaut.core.type.Argument;
|
import io.micronaut.core.type.Argument;
|
||||||
|
import io.micronaut.core.util.StringUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,7 +20,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
*/
|
*/
|
||||||
@Requires(beans = LogbackUtil.class)
|
@Requires(beans = LogbackUtil.class)
|
||||||
@Requires(property = MDCTurboFilterConfigurer.PREFIX)
|
@Requires(property = MDCTurboFilterConfigurer.PREFIX)
|
||||||
@Requires(property = MDCTurboFilterConfigurer.ENABLED, notEquals = "false")
|
@Requires(property = MDCTurboFilterConfigurer.PREFIX + ".enabled", notEquals = StringUtils.FALSE)
|
||||||
@BootstrapContextCompatible
|
@BootstrapContextCompatible
|
||||||
@Context
|
@Context
|
||||||
@Internal
|
@Internal
|
||||||
|
@ -27,7 +28,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
public class MDCTurboFilterConfigurer {
|
public class MDCTurboFilterConfigurer {
|
||||||
|
|
||||||
public static final String PREFIX = "logger.mdc";
|
public static final String PREFIX = "logger.mdc";
|
||||||
public static final String ENABLED = PREFIX + ".enabled";
|
|
||||||
|
|
||||||
private final LogbackUtil logback;
|
private final LogbackUtil logback;
|
||||||
private final Environment environment;
|
private final Environment environment;
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package io.kokuwa.micronaut.logging.request;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.reactivestreams.Publisher;
|
||||||
|
|
||||||
|
import io.micronaut.context.annotation.Requires;
|
||||||
|
import io.micronaut.context.annotation.Value;
|
||||||
|
import io.micronaut.core.util.StringUtils;
|
||||||
|
import io.micronaut.http.HttpResponse;
|
||||||
|
import io.micronaut.http.MutableHttpRequest;
|
||||||
|
import io.micronaut.http.annotation.Filter;
|
||||||
|
import io.micronaut.http.context.ServerRequestContext;
|
||||||
|
import io.micronaut.http.filter.ClientFilterChain;
|
||||||
|
import io.micronaut.http.filter.HttpClientFilter;
|
||||||
|
import io.micronaut.http.filter.ServerFilterPhase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Http request logging filter.
|
||||||
|
*
|
||||||
|
* @author Stephan Schnabel
|
||||||
|
*/
|
||||||
|
@Requires(beans = HeaderLoggingServerHttpFilter.class)
|
||||||
|
@Requires(property = HeaderLoggingClientHttpFilter.PREFIX + ".enabled", notEquals = StringUtils.FALSE)
|
||||||
|
@Filter("${" + HeaderLoggingClientHttpFilter.PREFIX + ".path:/**}")
|
||||||
|
public class HeaderLoggingClientHttpFilter implements HttpClientFilter {
|
||||||
|
|
||||||
|
public static final String PREFIX = "logger.request.propagation";
|
||||||
|
public static final int DEFAULT_ORDER = ServerFilterPhase.TRACING.order();
|
||||||
|
|
||||||
|
private final String serverHeader;
|
||||||
|
private final String propagationHeader;
|
||||||
|
private final int order;
|
||||||
|
|
||||||
|
public HeaderLoggingClientHttpFilter(
|
||||||
|
@Value("${" + HeaderLoggingServerHttpFilter.PREFIX + ".header}") Optional<String> serverHeader,
|
||||||
|
@Value("${" + PREFIX + ".header}") Optional<String> propagationHeader,
|
||||||
|
@Value("${" + PREFIX + ".order}") Optional<Integer> order) {
|
||||||
|
this.serverHeader = serverHeader.orElse(HeaderLoggingServerHttpFilter.DEFAULT_HEADER);
|
||||||
|
this.propagationHeader = propagationHeader.orElse(this.serverHeader);
|
||||||
|
this.order = order.orElse(DEFAULT_ORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Publisher<? extends HttpResponse<?>> doFilter(MutableHttpRequest<?> targetRequest, ClientFilterChain chain) {
|
||||||
|
ServerRequestContext.currentRequest()
|
||||||
|
.flatMap(currentRequest -> currentRequest.getHeaders().getFirst(serverHeader))
|
||||||
|
.ifPresent(level -> targetRequest.getHeaders().add(propagationHeader, level));
|
||||||
|
return chain.proceed(targetRequest);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,8 @@ import ch.qos.logback.classic.turbo.TurboFilter;
|
||||||
import io.kokuwa.micronaut.logging.LogbackUtil;
|
import io.kokuwa.micronaut.logging.LogbackUtil;
|
||||||
import io.micronaut.context.annotation.Requires;
|
import io.micronaut.context.annotation.Requires;
|
||||||
import io.micronaut.context.annotation.Value;
|
import io.micronaut.context.annotation.Value;
|
||||||
|
import io.micronaut.core.async.publisher.Publishers;
|
||||||
|
import io.micronaut.core.util.StringUtils;
|
||||||
import io.micronaut.http.HttpRequest;
|
import io.micronaut.http.HttpRequest;
|
||||||
import io.micronaut.http.MutableHttpResponse;
|
import io.micronaut.http.MutableHttpResponse;
|
||||||
import io.micronaut.http.annotation.Filter;
|
import io.micronaut.http.annotation.Filter;
|
||||||
|
@ -26,29 +28,27 @@ import io.micronaut.runtime.server.EmbeddedServer;
|
||||||
* @author Stephan Schnabel
|
* @author Stephan Schnabel
|
||||||
*/
|
*/
|
||||||
@Requires(beans = EmbeddedServer.class)
|
@Requires(beans = EmbeddedServer.class)
|
||||||
@Requires(property = HeaderLoggingHttpFilter.ENABLED, notEquals = "false")
|
@Requires(property = HeaderLoggingServerHttpFilter.PREFIX + ".enabled", notEquals = StringUtils.FALSE)
|
||||||
@Filter("${" + HeaderLoggingHttpFilter.PREFIX + ".pattern:" + HeaderLoggingHttpFilter.DEFAULT_PATTERN + ":/**}")
|
@Filter("${" + HeaderLoggingServerHttpFilter.PREFIX + ".path:/**}")
|
||||||
public class HeaderLoggingHttpFilter implements HttpServerFilter {
|
public class HeaderLoggingServerHttpFilter implements HttpServerFilter {
|
||||||
|
|
||||||
public static final String PREFIX = "logger.request.header";
|
public static final String PREFIX = "logger.request.filter";
|
||||||
public static final String ENABLED = PREFIX + ".enabled";
|
public static final String MDC_FILTER = PREFIX;
|
||||||
public static final String MDC_FILTER = PREFIX + ".filter";
|
|
||||||
public static final String MDC_KEY = "level";
|
public static final String MDC_KEY = "level";
|
||||||
|
|
||||||
public static final String DEFAULT_HEADER = "x-log-level";
|
public static final String DEFAULT_HEADER = "x-log-level";
|
||||||
public static final String DEFAULT_PATTERN = "/**";
|
|
||||||
public static final int DEFAULT_ORDER = ServerFilterPhase.FIRST.before();
|
public static final int DEFAULT_ORDER = ServerFilterPhase.FIRST.before();
|
||||||
|
|
||||||
private final LogbackUtil logback;
|
private final LogbackUtil logback;
|
||||||
private final String header;
|
private final String header;
|
||||||
private final int order;
|
private final int order;
|
||||||
|
|
||||||
public HeaderLoggingHttpFilter(
|
public HeaderLoggingServerHttpFilter(
|
||||||
LogbackUtil logback,
|
LogbackUtil logback,
|
||||||
@Value("${" + PREFIX + ".header:" + DEFAULT_HEADER + "}") String header,
|
@Value("${" + PREFIX + ".header}") Optional<String> header,
|
||||||
@Value("${" + PREFIX + ".order}") Optional<Integer> order) {
|
@Value("${" + PREFIX + ".order}") Optional<Integer> order) {
|
||||||
this.logback = logback;
|
this.logback = logback;
|
||||||
this.header = header;
|
this.header = header.orElse(DEFAULT_HEADER);
|
||||||
this.order = order.orElse(DEFAULT_ORDER);
|
this.order = order.orElse(DEFAULT_ORDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,15 @@ public class HeaderLoggingHttpFilter implements HttpServerFilter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
|
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
|
||||||
request.getHeaders().getFirst(header).ifPresent(level -> MDC.put(MDC_KEY, level));
|
var level = request.getHeaders().getFirst(header);
|
||||||
|
if (level.isPresent()) {
|
||||||
|
MDC.put(MDC_KEY, level.get());
|
||||||
|
return Publishers.map(chain.proceed(request), response -> {
|
||||||
|
MDC.remove(MDC_KEY);
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
return chain.proceed(request);
|
return chain.proceed(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ public class HeaderLoggingTurboFilter extends TurboFilter {
|
||||||
return FilterReply.NEUTRAL;
|
return FilterReply.NEUTRAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
var value = MDC.get(HeaderLoggingHttpFilter.MDC_KEY);
|
var value = MDC.get(HeaderLoggingServerHttpFilter.MDC_KEY);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return FilterReply.NEUTRAL;
|
return FilterReply.NEUTRAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ import org.slf4j.MDC;
|
||||||
|
|
||||||
import io.micronaut.context.annotation.Requires;
|
import io.micronaut.context.annotation.Requires;
|
||||||
import io.micronaut.context.annotation.Value;
|
import io.micronaut.context.annotation.Value;
|
||||||
|
import io.micronaut.core.async.publisher.Publishers;
|
||||||
|
import io.micronaut.core.util.StringUtils;
|
||||||
import io.micronaut.http.HttpRequest;
|
import io.micronaut.http.HttpRequest;
|
||||||
import io.micronaut.http.MutableHttpResponse;
|
import io.micronaut.http.MutableHttpResponse;
|
||||||
import io.micronaut.http.annotation.Filter;
|
import io.micronaut.http.annotation.Filter;
|
||||||
|
@ -21,15 +23,13 @@ import io.micronaut.runtime.server.EmbeddedServer;
|
||||||
* @author Stephan Schnabel
|
* @author Stephan Schnabel
|
||||||
*/
|
*/
|
||||||
@Requires(beans = EmbeddedServer.class)
|
@Requires(beans = EmbeddedServer.class)
|
||||||
@Requires(property = PrincipalHttpFilter.ENABLED, notEquals = "false")
|
@Requires(property = PrincipalHttpFilter.PREFIX + ".enabled", notEquals = StringUtils.FALSE)
|
||||||
@Filter("${" + PrincipalHttpFilter.PREFIX + ".pattern:" + PrincipalHttpFilter.DEFAULT_PATTERN + ":/**}")
|
@Filter("${" + PrincipalHttpFilter.PREFIX + ".path:/**}")
|
||||||
public class PrincipalHttpFilter implements HttpServerFilter {
|
public class PrincipalHttpFilter implements HttpServerFilter {
|
||||||
|
|
||||||
public static final String PREFIX = "logger.request.principal";
|
public static final String PREFIX = "logger.request.principal";
|
||||||
public static final String ENABLED = PREFIX + ".enabled";
|
|
||||||
|
|
||||||
public static final String DEFAULT_KEY = "principal";
|
public static final String DEFAULT_KEY = "principal";
|
||||||
public static final String DEFAULT_PATTERN = "/**";
|
|
||||||
public static final int DEFAULT_ORDER = ServerFilterPhase.SECURITY.after();
|
public static final int DEFAULT_ORDER = ServerFilterPhase.SECURITY.after();
|
||||||
|
|
||||||
private final String key;
|
private final String key;
|
||||||
|
@ -49,7 +49,15 @@ public class PrincipalHttpFilter implements HttpServerFilter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
|
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
|
||||||
request.getUserPrincipal().ifPresent(princial -> MDC.put(key, princial.getName()));
|
var princial = request.getUserPrincipal();
|
||||||
|
if (princial.isPresent()) {
|
||||||
|
MDC.put(key, princial.get().getName());
|
||||||
|
return Publishers.map(chain.proceed(request), response -> {
|
||||||
|
MDC.remove(key);
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
return chain.proceed(request);
|
return chain.proceed(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import ch.qos.logback.classic.Level;
|
||||||
import io.kokuwa.micronaut.logging.AbstractTest;
|
import io.kokuwa.micronaut.logging.AbstractTest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for {@link HeaderLoggingHttpFilter}.
|
* Test for {@link HeaderLoggingServerHttpFilter}.
|
||||||
*
|
*
|
||||||
* @author Stephan Schnabel
|
* @author Stephan Schnabel
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -19,7 +19,7 @@ import io.micronaut.http.client.annotation.Client;
|
||||||
import io.micronaut.security.token.jwt.signature.SignatureGeneratorConfiguration;
|
import io.micronaut.security.token.jwt.signature.SignatureGeneratorConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contoller for testing {@link HeaderLoggingHttpFilter} and {@link PrincipalHttpFilter}.
|
* Contoller for testing {@link HeaderLoggingServerHttpFilter} and {@link PrincipalHttpFilter}.
|
||||||
*
|
*
|
||||||
* @author Stephan Schnabel
|
* @author Stephan Schnabel
|
||||||
*/
|
*/
|
||||||
|
@ -48,7 +48,7 @@ public class TestClient {
|
||||||
request.bearerAuth(token);
|
request.bearerAuth(token);
|
||||||
}
|
}
|
||||||
if (header != null) {
|
if (header != null) {
|
||||||
request.getHeaders().add(HeaderLoggingHttpFilter.DEFAULT_HEADER, header);
|
request.getHeaders().add(HeaderLoggingServerHttpFilter.DEFAULT_HEADER, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = client.toBlocking().exchange(request, TestResponse.class);
|
var response = client.toBlocking().exchange(request, TestResponse.class);
|
||||||
|
|
|
@ -13,7 +13,7 @@ import lombok.NoArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for testing {@link HeaderLoggingHttpFilter} and {@link PrincipalHttpFilter}.
|
* Controller for testing {@link HeaderLoggingServerHttpFilter} and {@link PrincipalHttpFilter}.
|
||||||
*
|
*
|
||||||
* @author Stephan Schnabel
|
* @author Stephan Schnabel
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue