下面列出了org.slf4j.MDC#getCopyOfContextMap ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@DataProvider(value = {
"true",
"false"
})
@Test
public void current_thread_info_constructor_sets_fields_as_expected(boolean useStaticFactory) {
// given
Tracer.getInstance().startRequestWithRootSpan("request-" + UUID.randomUUID().toString());
Deque<Span> spanStackMock = Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> mdcInfoMock = MDC.getCopyOfContextMap();
// when
SupplierWithTracing instance = (useStaticFactory)
? withTracing(supplierMock)
: new SupplierWithTracing(supplierMock);
// then
assertThat(instance.origSupplier).isSameAs(supplierMock);
assertThat(instance.spanStackForExecution).isEqualTo(spanStackMock);
assertThat(instance.mdcContextMapForExecution).isEqualTo(mdcInfoMock);
}
@Test
public void basic_executeAsyncHttpRequest_extracts_mdc_and_tracing_info_from_current_thread_and_delegates_to_kitchen_sink_execute_method() {
// given
RequestBuilderWrapper rbw = mock(RequestBuilderWrapper.class);
AsyncResponseHandler responseHandler = mock(AsyncResponseHandler.class);
CompletableFuture cfMock = mock(CompletableFuture.class);
doReturn(cfMock).when(helperSpy).executeAsyncHttpRequest(
any(RequestBuilderWrapper.class), any(AsyncResponseHandler.class), any(Deque.class), any(Map.class)
);
Tracer.getInstance().startRequestWithRootSpan("foo");
Deque<Span> expectedSpanStack = Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> expectedMdc = MDC.getCopyOfContextMap();
// when
CompletableFuture result = helperSpy.executeAsyncHttpRequest(rbw, responseHandler);
// then
verify(helperSpy).executeAsyncHttpRequest(rbw, responseHandler, expectedSpanStack, expectedMdc);
assertThat(result).isSameAs(cfMock);
}
@Override
public K call() throws Exception {
LOG.debug("Call using MDCHystrixContextCallable...");
Map childMDC = MDC.getCopyOfContextMap();
LOG.debug("childMDC --> " + childMDC);
try {
if (parentMDC != null) {
MDC.setContextMap(parentMDC);
}
LOG.debug("parentMDC --> " + parentMDC);
return actual.call();
} finally {
if (childMDC != null) {
MDC.setContextMap(childMDC);
}
}
}
@Test
public void basic_executeAsyncHttpRequest_extracts_mdc_and_tracing_info_from_current_thread_and_delegates_to_kitchen_sink_execute_method() {
// given
RequestBuilderWrapper rbw = mock(RequestBuilderWrapper.class);
AsyncResponseHandler responseHandler = mock(AsyncResponseHandler.class);
CompletableFuture cfMock = mock(CompletableFuture.class);
doReturn(cfMock).when(helperSpy).executeAsyncHttpRequest(
any(RequestBuilderWrapper.class), any(AsyncResponseHandler.class), any(Deque.class), any(Map.class)
);
Tracer.getInstance().startRequestWithRootSpan("foo");
Deque<Span> expectedSpanStack = Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> expectedMdc = MDC.getCopyOfContextMap();
// when
CompletableFuture result = helperSpy.executeAsyncHttpRequest(rbw, responseHandler);
// then
verify(helperSpy).executeAsyncHttpRequest(rbw, responseHandler, expectedSpanStack, expectedMdc);
assertThat(result).isSameAs(cfMock);
}
@PostMapping
public Order prepare(@RequestBody Order order) throws JsonProcessingException {
int price = 0;
List<Product> products = productClient.findByIds(order.getProductIds());
LOGGER.info("Products found: {}", mapper.writeValueAsString(products));
Customer customer = customerClient.findByIdWithAccounts(order.getCustomerId());
LOGGER.info("Customer found: {}", mapper.writeValueAsString(customer));
for (Product product : products)
price += product.getPrice();
final int priceDiscounted = priceDiscount(price, customer);
LOGGER.info("Discounted price: {}", mapper.writeValueAsString(Collections.singletonMap("price", priceDiscounted)));
Optional<Account> account = customer.getAccounts().stream().filter(a -> (a.getBalance() > priceDiscounted)).findFirst();
if (account.isPresent()) {
order.setAccountId(account.get().getId());
order.setStatus(OrderStatus.ACCEPTED);
order.setPrice(priceDiscounted);
LOGGER.info("Account found: {}", mapper.writeValueAsString(account.get()));
} else {
order.setStatus(OrderStatus.REJECTED);
LOGGER.info("Account not found: {}", mapper.writeValueAsString(customer.getAccounts()));
}
Map<String, String> m = MDC.getCopyOfContextMap();
return repository.add(order);
}
@DataProvider(value = {
"true",
"false"
})
@Test
public void onFailure_handles_tracing_and_mdc_info_as_expected(boolean throwException) {
// given
throwExceptionDuringCall = throwException;
Tracer.getInstance().startRequestWithRootSpan("foo");
Deque<Span> spanStack = Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> mdcInfo = MDC.getCopyOfContextMap();
FailureCallbackWithTracing instance = new FailureCallbackWithTracing(
failureCallbackMock, spanStack, mdcInfo
);
resetTracing();
assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isNull();
assertThat(MDC.getCopyOfContextMap()).isNullOrEmpty();
// when
Throwable ex = catchThrowable(() -> instance.onFailure(inObj));
// then
verify(failureCallbackMock).onFailure(inObj);
if (throwException) {
assertThat(ex).isNotNull();
}
else {
assertThat(ex).isNull();
}
assertThat(currentSpanStackWhenFailureCallbackWasCalled.get(0)).isEqualTo(spanStack);
assertThat(currentMdcInfoWhenFailureCallbackWasCalled.get(0)).isEqualTo(mdcInfo);
assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isNull();
assertThat(MDC.getCopyOfContextMap()).isNullOrEmpty();
}
@DataProvider(value = {
"true",
"false"
})
@Test
public void call_handles_tracing_and_mdc_info_as_expected(boolean throwException) throws Exception {
// given
throwExceptionDuringCall = throwException;
Tracer.getInstance().startRequestWithRootSpan("foo");
Deque<Span> spanStack = Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> mdcInfo = MDC.getCopyOfContextMap();
CallableWithTracingAndMdcSupport instance = new CallableWithTracingAndMdcSupport(
callableMock, spanStack, mdcInfo
);
resetTracingAndMdc();
assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isNull();
assertThat(MDC.getCopyOfContextMap()).isEmpty();
// when
Throwable ex = catchThrowable(() -> instance.call());
// then
verify(callableMock).call();
if (throwException)
assertThat(ex).isNotNull();
else
assertThat(ex).isNull();
assertThat(currentSpanStackWhenCallableWasCalled.get(0)).isEqualTo(spanStack);
assertThat(currentMdcInfoWhenCallableWasCalled.get(0)).isEqualTo(mdcInfo);
assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isNull();
assertThat(MDC.getCopyOfContextMap()).isEmpty();
}
/**
* 获取 MDC 内容 同时添加 X-B3-ParentName 参数
*
* @return MDC map
*/
private static Map<String, String> buildTraceContent() {
Map<String, String> traceContentMap = MDC.getCopyOfContextMap();
if (traceContentMap == null) {
traceContentMap = new HashMap<>(16);
}
String serviceName = environment.getProperty("spring.application.name");
traceContentMap.put(Constants.LEGACY_PARENT_SERVICE_NAME, serviceName);
return traceContentMap;
}
/**
* Logs the metric using SLF4J log statement. The attributes are written into the MDC
*/
public synchronized void publish() {
final Map<String, String> copyOfMDC = MDC.getCopyOfContextMap();
attributes.forEach(MDC::put);
try {
logger.info("");
} finally {
if (copyOfMDC != null) {
MDC.setContextMap(copyOfMDC);
} else {
MDC.clear();
}
}
}
private void generateLog() {
Map<String, String> contextMap = getContextMap();
Map<String, String> currentContextMap = MDC.getCopyOfContextMap();
try {
MDC.setContextMap(contextMap);
LOG.info(Markers.REQUEST_MARKER, "{}", requestRecord);
} finally {
if (currentContextMap != null) {
MDC.setContextMap(currentContextMap);
}
}
}
public void logDebugWithMdc(Logger logger, String msg) {
Map<String, String> previousMdcContext = MDC.getCopyOfContextMap();
MDC.setContextMap(mdcContext);
try {
logger.debug(msg);
} finally{
MDC.setContextMap(previousMdcContext);
}
}
@Override
protected Map toJsonMap(ILoggingEvent iLoggingEvent) {
Map map = super.toJsonMap(iLoggingEvent);
if (! MDC_LOG_TYPE_VALUE_AUDIT.equals(MDC.get(MDC_LOG_TYPE_KEY))) {
return map;
}
Map<String, String> mdc = MDC.getCopyOfContextMap();
// Basics
this.add("serviceName", true, SERVICE_NAME, map);
this.add("methodName", true, pop(mdc, MDC_METHOD_NAME_KEY), map);
this.add("severity", true, String.valueOf(iLoggingEvent.getLevel()), map);
// Request metadata
HashMap<String, String> requestMetadata = new HashMap<>();
requestMetadata.put("callerAddress", ClientAddressServerInterceptor.CLIENT_ADDRESS_CONTEXT_KEY.get());
this.addMap("requestMetadata", true, requestMetadata, map);
// Authentication info
HashMap<String, String> authenticationInfo = new HashMap<>();
putIfExists(mdc, AbstractAuthenticationBackend.AUTHENTICATED_USER, authenticationInfo, "authenticatedUser");
putIfExists(mdc, MDC_AUTH_MODE_KEY, authenticationInfo, "authenticationMode");
putIfExists(mdc, MDC_AUTH_MODE_DELEGATED_SESSION_ID_KEY, authenticationInfo, "sessionId");
putIfExists(mdc, MDC_AUTH_MODE_PROXY_IMPERSONATED_USER_KEY, authenticationInfo, "impersonatedUser");
this.addMap("authenticationInfo", true, authenticationInfo, map);
// Status
HashMap<String, String> status = new HashMap<>();
putIfExists(mdc, MDC_STATUS_CODE_KEY, status, "code");
putIfExists(mdc, MDC_STATUS_MESSAGE_KEY, status, "message");
this.addMap("status", true, status, map);
// Extras
HashMap<String, String> extras = new HashMap<>();
for (Map.Entry<String, String> entry : mdc.entrySet()) {
extras.put(
StringUtils.removeStart(entry.getKey(), MDC_KEY_PREFIX),
entry.getValue()
);
}
this.addMap("extras", true, extras, map);
return map;
}
@DataProvider(value = {
"true",
"false"
})
@Test
public void apply_handles_tracing_and_mdc_info_as_expected(boolean throwException) {
// given
throwExceptionDuringCall = throwException;
Tracer.getInstance().startRequestWithRootSpan("foo");
Deque<Span> spanStack = Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> mdcInfo = MDC.getCopyOfContextMap();
FunctionWithTracing instance = new FunctionWithTracing(
functionMock, spanStack, mdcInfo
);
resetTracing();
assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isNull();
assertThat(MDC.getCopyOfContextMap()).isNullOrEmpty();
// when
Throwable ex = null;
Object result = null;
try {
result = instance.apply(inObj);
}
catch(Throwable t) {
ex = t;
}
// then
verify(functionMock).apply(inObj);
if (throwException) {
assertThat(ex).isNotNull();
assertThat(result).isNull();
}
else {
assertThat(ex).isNull();
assertThat(result).isSameAs(outObj);
}
assertThat(currentSpanStackWhenFunctionWasCalled.get(0)).isEqualTo(spanStack);
assertThat(currentMdcInfoWhenFunctionWasCalled.get(0)).isEqualTo(mdcInfo);
assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isNull();
assertThat(MDC.getCopyOfContextMap()).isNullOrEmpty();
}
@DataProvider(value = {
"true",
"false"
})
@Test
public void apply_handles_tracing_and_mdc_info_as_expected(boolean throwException) {
// given
throwExceptionDuringCall = throwException;
Tracer.getInstance().startRequestWithRootSpan("foo");
Deque<Span> spanStack = Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> mdcInfo = MDC.getCopyOfContextMap();
SupplierWithTracing instance = new SupplierWithTracing(
supplierMock, spanStack, mdcInfo
);
resetTracing();
assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isNull();
assertThat(MDC.getCopyOfContextMap()).isNullOrEmpty();
// when
Throwable ex = null;
Object result = null;
try {
result = instance.get();
}
catch(Throwable t) {
ex = t;
}
// then
verify(supplierMock).get();
if (throwException) {
assertThat(ex).isNotNull();
assertThat(result).isNull();
}
else {
assertThat(ex).isNull();
assertThat(result).isSameAs(outObj);
}
assertThat(currentSpanStackWhenSupplierWasCalled.get(0)).isEqualTo(spanStack);
assertThat(currentMdcInfoWhenSupplierWasCalled.get(0)).isEqualTo(mdcInfo);
assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isNull();
assertThat(MDC.getCopyOfContextMap()).isNullOrEmpty();
}
@DataProvider(value = {
"true | true",
"true | false",
"false | true",
"false | false"
}, splitBy = "\\|")
@Test
public void verify_basic_functionality(boolean surroundWithSubspan, boolean parentSpanExists) throws Exception {
// given
AsyncHttpClientHelper asyncClient = new AsyncHttpClientHelper(surroundWithSubspan);
String fullUrl = "http://localhost:" + serverPort + TestEndpoint.MATCHING_PATH + "?foo=bar";
RequestBuilderWrapper rbw = asyncClient.getRequestBuilder(fullUrl, HttpMethod.GET);
rbw.requestBuilder.setHeader(TestEndpoint.EXPECTED_HEADER_KEY, TestEndpoint.EXPECTED_HEADER_VAL);
rbw.requestBuilder.setBody(TestEndpoint.EXPECTED_REQUEST_PAYLOAD);
Deque<Span> distributedTraceStackForCall = null;
Map<String, String> mdcContextForCall = null;
Span origSpan = null;
if (parentSpanExists) {
origSpan = Tracer.getInstance().startRequestWithRootSpan("overallReqSpan");
distributedTraceStackForCall = Tracer.getInstance().getCurrentSpanStackCopy();
mdcContextForCall = MDC.getCopyOfContextMap();
resetTracing();
}
// when
Response result = asyncClient.executeAsyncHttpRequest(
rbw, response -> response, distributedTraceStackForCall, mdcContextForCall
).join();
// then
Span subspan = findSubspan();
assertThat(result.getStatusCode()).isEqualTo(200);
assertThat(result.getResponseBody()).isEqualTo(TestEndpoint.RESPONSE_PAYLOAD);
if (surroundWithSubspan) {
assertThat(subspan).isNotNull();
assertThat(result.getHeader(TraceHeaders.TRACE_ID)).isEqualTo(subspan.getTraceId());
assertThat(result.getHeader(TraceHeaders.SPAN_ID)).isEqualTo(subspan.getSpanId());
assertThat(result.getHeader(TraceHeaders.PARENT_SPAN_ID)).isEqualTo(
String.valueOf(subspan.getParentSpanId())
);
verifySubspanTags(subspan, fullUrl, "200", false);
}
else {
assertThat(subspan).isNull();
}
if (parentSpanExists) {
assertThat(result.getHeader(TraceHeaders.TRACE_ID)).isEqualTo(origSpan.getTraceId());
String expectedParentSpanId = (surroundWithSubspan) ? subspan.getParentSpanId() : "null";
assertThat(result.getHeader(TraceHeaders.PARENT_SPAN_ID)).isEqualTo(expectedParentSpanId);
String expectedSpanId = (surroundWithSubspan) ? subspan.getSpanId() : origSpan.getSpanId();
assertThat(result.getHeader(TraceHeaders.SPAN_ID)).isEqualTo(expectedSpanId);
}
if (!parentSpanExists && !surroundWithSubspan) {
assertThat(result.getHeader(TraceHeaders.TRACE_ID)).isEqualTo("null");
assertThat(result.getHeader(TraceHeaders.SPAN_ID)).isEqualTo("null");
assertThat(result.getHeader(TraceHeaders.PARENT_SPAN_ID)).isEqualTo("null");
}
}
/**
* @param completableFutureResponse
* The {@link CompletableFuture} that should be completed with {@code responseHandlerFunction}'s value (or
* completed exceptionally if an error occurs) when the downstream call returns.
* @param responseHandlerFunction
* The handler that will get notified with the downstream call's response. The value of {@link
* AsyncResponseHandler#handleResponse(Response)} will be used to complete {@code completableFutureResponse}.
* @param performSubSpanAroundDownstreamCalls
* Whether or not the downstream call should be surrounded with a subspan. If true then {@code
* distributedTraceStackToUse} will have a subspan placed on top, otherwise it will be used as-is.
* @param requestBuilderWrapper The {@link RequestBuilderWrapper} that will be used to execute the HTTP client call.
* @param circuitBreakerManualTask
* The circuit breaker manual mode task to notify of response events or exceptions, or empty if circuit breaking
* has been disabled for this call.
* @param distributedTraceStackToUse
* The distributed trace stack to use for the downstream call. If {@code performSubSpanAroundDownstreamCalls} is
* true then a new subspan will be placed on top of this, otherwise it will be used as-is.
* @param mdcContextToUse The MDC context to associate with the downstream call.
* @param tagAndNamingStrategy The {@link SpanNamingAndTaggingStrategy} to use when creating subspan names and
* response/error tagging for the subspan (only used if {@link #performSubSpanAroundDownstreamCalls} is true).
*/
AsyncCompletionHandlerWithTracingAndMdcSupport(
CompletableFuture<O> completableFutureResponse,
AsyncResponseHandler<O> responseHandlerFunction,
boolean performSubSpanAroundDownstreamCalls,
RequestBuilderWrapper requestBuilderWrapper,
Optional<CircuitBreaker.ManualModeTask<Response>> circuitBreakerManualTask,
Deque<Span> distributedTraceStackToUse,
Map<String, String> mdcContextToUse,
SpanNamingAndTaggingStrategy<RequestBuilderWrapper, Response, Span> tagAndNamingStrategy
) {
this.completableFutureResponse = completableFutureResponse;
this.responseHandlerFunction = responseHandlerFunction;
this.performSubSpanAroundDownstreamCalls = performSubSpanAroundDownstreamCalls;
this.circuitBreakerManualTask = circuitBreakerManualTask;
this.rbwCopyWithHttpMethodAndUrlOnly = new RequestBuilderWrapper(
requestBuilderWrapper.getUrl(),
requestBuilderWrapper.getHttpMethod(),
null,
null,
true
);
this.tagAndNamingStrategy = tagAndNamingStrategy;
// Grab the calling thread's dtrace stack and MDC info so we can set it back when this constructor completes.
Pair<Deque<Span>, Map<String, String>> originalThreadInfo = null;
try {
// Do a subspan around the downstream call if desired.
if (performSubSpanAroundDownstreamCalls) {
// Start by setting up the distributed trace stack and MDC for the call as specified in the method
// arguments, and grab the return value so we have the original calling thread's dtrace stack and
// MDC info (used to set everything back to original state when this constructor completes).
originalThreadInfo = linkTracingAndMdcToCurrentThread(distributedTraceStackToUse, mdcContextToUse);
// Then add the subspan.
String spanName = getSubspanSpanName(requestBuilderWrapper, tagAndNamingStrategy);
// Start a new child/subspan for this call if possible, falling back to a new trace (rather
// than child/subspan) if there's no current span on the thread. The
// startSpanInCurrentContext() method will do the right thing here in either case.
Tracer.getInstance().startSpanInCurrentContext(spanName, Span.SpanPurpose.CLIENT);
// Since we modified the stack/MDC we need to update the args that will be used for the downstream call.
distributedTraceStackToUse = Tracer.getInstance().getCurrentSpanStackCopy();
mdcContextToUse = MDC.getCopyOfContextMap();
}
this.distributedTraceStackToUse = distributedTraceStackToUse;
this.mdcContextToUse = mdcContextToUse;
}
finally {
// Reset the tracing and MDC info to what it was when the constructor was called if we messed around with
// stuff. If originalThreadInfo is null then nothing needs to be done.
if (originalThreadInfo != null)
AsyncNettyHelper.unlinkTracingAndMdcFromCurrentThread(originalThreadInfo);
}
}
@DataProvider(value = {
"true",
"false"
})
@Test
public void apply_handles_tracing_and_mdc_info_as_expected(boolean throwException) {
// given
throwExceptionDuringCall = throwException;
Tracer.getInstance().startRequestWithRootSpan("foo");
Deque<Span> spanStack = Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> mdcInfo = MDC.getCopyOfContextMap();
BiFunctionWithTracingAndMdcSupport instance = new BiFunctionWithTracingAndMdcSupport(
biFunctionMock, spanStack, mdcInfo
);
resetTracingAndMdc();
assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isNull();
assertThat(MDC.getCopyOfContextMap()).isEmpty();
// when
Throwable ex = null;
Object result = null;
try {
result = instance.apply(inObj1, inObj2);
}
catch(Throwable t) {
ex = t;
}
// then
verify(biFunctionMock).apply(inObj1, inObj2);
if (throwException) {
assertThat(ex).isNotNull();
assertThat(result).isNull();
}
else {
assertThat(ex).isNull();
assertThat(result).isSameAs(outObj);
}
assertThat(currentSpanStackWhenFunctionWasCalled.get(0)).isEqualTo(spanStack);
assertThat(currentMdcInfoWhenFunctionWasCalled.get(0)).isEqualTo(mdcInfo);
assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isNull();
assertThat(MDC.getCopyOfContextMap()).isEmpty();
}
/**
* Constructor that extracts the current tracing and MDC information from the current thread using {@link
* Tracer#getCurrentSpanStackCopy()} and {@link MDC#getCopyOfContextMap()}, and forwards the information to
* the {@link RunnableWithTracing#RunnableWithTracing(Runnable, Deque, Map)}
* constructor. That tracing and MDC information will be associated with the thread when the given operation is
* executed.
*
* <p>The operation you pass in cannot be null (an {@link IllegalArgumentException} will be thrown if you pass in
* null for the operation).
*/
public RunnableWithTracing(Runnable origRunnable) {
this(origRunnable, Tracer.getInstance().getCurrentSpanStackCopy(), MDC.getCopyOfContextMap());
}
/**
* Constructor that extracts the current tracing and MDC information from the current thread using {@link
* Tracer#getCurrentSpanStackCopy()} and {@link MDC#getCopyOfContextMap()}, and forwards the information to
* the {@link BiFunctionWithTracing#BiFunctionWithTracing(BiFunction, Deque, Map)}
* constructor. That tracing and MDC information will be associated with the thread when the given operation is
* executed.
*
* <p>The operation you pass in cannot be null (an {@link IllegalArgumentException} will be thrown if you pass in
* null for the operation).
*/
public BiFunctionWithTracing(BiFunction<T, U, R> origBiFunction) {
this(origBiFunction, Tracer.getInstance().getCurrentSpanStackCopy(), MDC.getCopyOfContextMap());
}
/**
* Constructor that extracts the current tracing and MDC information from the current thread using {@link
* Tracer#getCurrentSpanStackCopy()} and {@link MDC#getCopyOfContextMap()}, and forwards the information to
* the {@link FunctionWithTracing#FunctionWithTracing(Function, Deque, Map)}
* constructor. That tracing and MDC information will be associated with the thread when the given operation is
* executed.
*
* <p>The operation you pass in cannot be null (an {@link IllegalArgumentException} will be thrown if you pass in
* null for the operation).
*/
public FunctionWithTracing(Function<T, U> origFunction) {
this(origFunction, Tracer.getInstance().getCurrentSpanStackCopy(), MDC.getCopyOfContextMap());
}