ratpack.logging.MDCInterceptor Maven / Gradle / Ivy
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ratpack.logging;
import org.slf4j.MDC;
import ratpack.exec.ExecInterceptor;
import ratpack.exec.Execution;
import ratpack.util.Types;
import java.util.HashMap;
import java.util.Map;
/**
* Intercept execution and add support for SLF4J MDC described in the manual.
*
* Mapped Diagnostic Context (MDC) is a map of key-value pairs provided by client code and then automatically inserted in log messages.
* The underlying logging framework has to support MDC logging.
* Example {@code log4j2} configuration that assumes {@code value} as MDC context map value:
* {@code
*
*
*
* }
*
* When interceptor is registered with {@link ratpack.exec.ExecControl#addInterceptor}, it is possible to directly use SLF4J MDC API.
* The {@link ratpack.exec.Execution}, as registry, maintains own map of MDC entries.
* Before running the continuation, it checks if internal map contains any entry.
* If yes, it puts all of them from internal map to MDC (bounded to current thread).
* If internal map is empty, it clears MDC.
* After continuation it gets the entries from MDC's context map and stores them in execution's internal map.
*
{@code
* import java.util.List;
* import java.util.ArrayList;
* import ratpack.test.handling.RequestFixture;
* import ratpack.test.handling.HandlingResult;
* import org.slf4j.MDC;
*
* import static org.junit.Assert.assertTrue;
*
* import ratpack.logging.MDCInterceptor;
*
* public class MDCInterceptorExample {
* public static void main(String[] args) throws Exception {
* List values = new ArrayList();
* HandlingResult result = RequestFixture.requestFixture().handleChain(chain -> {
* chain
* .handler(ctx ->
* ctx.addInterceptor(new MDCInterceptor(), ctx::next)
* )
* .handler(ctx -> {
* MDC.put("value", "foo");
* values.add(MDC.get("value"));
* ctx.blocking(() -> {
* values.add(MDC.get("value"));
* return "bar3";
* }).then(str -> {
* values.add(MDC.get("value"));
* ctx.render(str);
* });
* });
* });
*
* assertTrue(values.size() == 3);
* }
* }
* }
*
* @see ratpack.exec.ExecControl#addInterceptor(ratpack.exec.ExecInterceptor, ratpack.func.NoArgAction)
*/
public class MDCInterceptor implements ExecInterceptor {
private static class MDCMap extends HashMap {
}
public MDCInterceptor() {
}
public void intercept(Execution execution, ExecType type, Runnable continuation) {
MDCMap map = execution.maybeGet(MDCMap.class).orElse(null);
if (map == null) {
map = new MDCMap();
execution.add(map);
}
MDC.setContextMap(map);
continuation.run();
map.clear();
Map ctxMap = Types.cast(MDC.getCopyOfContextMap());
if (ctxMap != null && ctxMap.size() > 0) {
map.putAll(ctxMap);
MDC.clear();
}
}
}