将关联 ID 追加到每条日志中 Java

huangapple go评论78阅读模式
英文:

Append correlation id to every log java

问题

这里是你的翻译内容:

我需要将关联 ID 添加到我收到的每个请求的日志中。

以下是我的过滤器。它在遇到像 runAsync() 这样的异步块之前工作得很好。

将关联 ID 追加到每条日志中 Java

我了解了关于 MDC 以及它如何使用 ThreadLocal 的信息,但无法理解在异步中如何使用它,因为它使用了 ForkJoinPool。

@Component
public class Slf4jFilter extends OncePerRequestFilter {

private static final String CORRELATION_ID_HEADER_NAME = "correlation-id";
private static final String CORRELATION_ID_LOG_VAR_NAME = "correlationId";

@Override
protected void doFilterInternal(HttpServletRequest request,
    HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
    try {
        ofNullable(request.getHeader(CORRELATION_ID_HEADER_NAME)).ifPresent(correlationId -> MDC
            .put(CORRELATION_ID_LOG_VAR_NAME, correlationId));
        chain.doFilter(request, response);
    }finally {
        removeCorrelationId();
    }
}

protected void removeCorrelationId() {
    MDC.remove(CORRELATION_ID_LOG_VAR_NAME);
}
}

logback.xml

<configuration>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread %X{correlationId}] %-5level %logger{36} - %msg %n</pattern>
    </encoder>
</appender>
<root level="INFO">
    <appender-ref ref="stdout" />
</root>
</configuration>
英文:

I need to append correlation id to logs from every request I get.

Here is my filter. It works good until I get to async block like runAsync().

将关联 ID 追加到每条日志中 Java

I read about MDC and how it use ThreadLocal but can't understand how to use it in async because it uses ForkJoinPool.

@Component
public class Slf4jFilter extends OncePerRequestFilter {

private static final String CORRELATION_ID_HEADER_NAME = &quot;correlation-id&quot;;
private static final String CORRELATION_ID_LOG_VAR_NAME = &quot;correlationId&quot;;

@Override
protected void doFilterInternal(HttpServletRequest request,
    HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
    try {
        ofNullable(request.getHeader(CORRELATION_ID_HEADER_NAME)).ifPresent(correlationId -&gt; MDC
            .put(CORRELATION_ID_LOG_VAR_NAME, correlationId));
        chain.doFilter(request, response);
    }finally {
        removeCorrelationId();
    }
}

protected void removeCorrelationId() {
    MDC.remove(CORRELATION_ID_LOG_VAR_NAME);
}
}

logback.xml

&lt;configuration&gt;
&lt;appender name=&quot;stdout&quot; class=&quot;ch.qos.logback.core.ConsoleAppender&quot;&gt;
    &lt;encoder class=&quot;ch.qos.logback.classic.encoder.PatternLayoutEncoder&quot;&gt;
        &lt;pattern&gt;%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread %X{correlationId}] %-5level %logger{36} - %msg %n&lt;/pattern&gt;
    &lt;/encoder&gt;
&lt;/appender&gt;
&lt;root level=&quot;INFO&quot;&gt;
    &lt;appender-ref ref=&quot;stdout&quot; /&gt;
&lt;/root&gt;

</configuration>

答案1

得分: 1

这是我得出的解决方案。感谢 @M.Prokhorov。

在您的项目中创建一个名为 MdcRetention 的类。

public final class MdcRetention {

    public static Runnable wrap(final Runnable delegate) {
        return new MdcRetainingRunnable() {
            @Override
            protected void runInContext() {
                delegate.run();
            }
        };
    }

    private static abstract class MdcRetentionSupport {
        protected final Map<String, String> originalMdc;

        protected MdcRetentionSupport() {
            Map<String, String> originalMdc = MDC.getCopyOfContextMap();
            this.originalMdc = originalMdc == null ? Collections.emptyMap() : originalMdc;
        }
    }

    public static abstract class MdcRetainingRunnable extends MdcRetentionSupport implements Runnable {

        @Override
        public final void run() {
            Map<String, String> currentMdc = MDC.getCopyOfContextMap();
            MDC.setContextMap(originalMdc);
            try {
                runInContext();
            } finally {
                MDC.setContextMap(currentMdc);
            }
        }

        abstract protected void runInContext();
    }
}

然后,使用静态方法 MdcRetention.wrap() 将您的 Runnable 包装在 runAsync() 块中。

之前:

runAsync(() -> someMethod());

之后:

runAsync(wrap(() -> someMethod()));
英文:

Here's the solution I ended up. Thanks to @M.Prokhorov

Create a class called MdcRetention inside your project.

public final class MdcRetention {

public static Runnable wrap(final Runnable delegate) {
	return new MdcRetainingRunnable() {
		@Override
		protected void runInContext() {
			delegate.run();
		}
	};
}

private static abstract class MdcRetentionSupport {
	protected final Map&lt;String, String&gt; originalMdc;

	protected MdcRetentionSupport() {
		Map&lt;String, String&gt; originalMdc = MDC.getCopyOfContextMap();
		this.originalMdc = originalMdc == null ? Collections.emptyMap() : originalMdc;
	}
}

public static abstract class MdcRetainingRunnable extends MdcRetentionSupport implements Runnable {

	@Override
	public final void run() {
		Map&lt;String, String&gt; currentMdc = MDC.getCopyOfContextMap();
		MDC.setContextMap(originalMdc);
		try {
			runInContext();
		} finally {
			MDC.setContextMap(currentMdc);
		}
	}

	abstract protected void runInContext();
}}

Then wrap your Runnable inside runAsync() block using static method MdcRetention.wrap()

Before:
runAsync(() -&gt; someMethod());

After:
runAsync(wrap(() -&gt; someMethod()));

huangapple
  • 本文由 发表于 2020年10月6日 01:38:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/64213601.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定