All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nike.wingtips.spring.util.WingtipsSpringUtil Maven / Gradle / Ivy

There is a newer version: 0.24.2
Show newest version
package com.nike.wingtips.spring.util;

import com.nike.internal.util.Pair;
import com.nike.wingtips.Span;
import com.nike.wingtips.Tracer;
import com.nike.wingtips.http.HttpRequestTracingUtils;
import com.nike.wingtips.spring.interceptor.WingtipsAsyncClientHttpRequestInterceptor;
import com.nike.wingtips.spring.interceptor.WingtipsClientHttpRequestInterceptor;
import com.nike.wingtips.spring.interceptor.tag.SpringHttpClientTagAdapter;
import com.nike.wingtips.spring.util.asynchelperwrapper.FailureCallbackWithTracing;
import com.nike.wingtips.spring.util.asynchelperwrapper.ListenableFutureCallbackWithTracing;
import com.nike.wingtips.spring.util.asynchelperwrapper.SuccessCallbackWithTracing;
import com.nike.wingtips.tags.HttpTagAndSpanNamingAdapter;
import com.nike.wingtips.tags.HttpTagAndSpanNamingStrategy;
import com.nike.wingtips.tags.NoOpHttpTagAdapter;
import com.nike.wingtips.tags.NoOpHttpTagStrategy;
import com.nike.wingtips.tags.ZipkinHttpTagStrategy;
import com.nike.wingtips.util.TracingState;

import org.slf4j.MDC;
import org.springframework.http.HttpMessage;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.concurrent.FailureCallback;
import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.util.concurrent.SuccessCallback;
import org.springframework.web.client.AsyncRestTemplate;
import org.springframework.web.client.RestTemplate;

import java.util.Deque;
import java.util.Map;

/**
 * Contains helper methods for integrating Wingtips in a Spring environment. In particular there are helpers for
 * creating a {@link RestTemplate} or {@link AsyncRestTemplate} with Wingtips tracing interceptors ({@link
 * WingtipsClientHttpRequestInterceptor} or {@link WingtipsAsyncClientHttpRequestInterceptor}) already applied.
 *
 * @author Ales Justin
 * @author Nic Munroe
 */
@SuppressWarnings("WeakerAccess")
public class WingtipsSpringUtil {

    /**
     * Intentionally protected - use the static methods.
     */
    protected WingtipsSpringUtil() {
        // Do nothing
    }

    /**
     * @return A new {@link RestTemplate} instance with a {@link WingtipsClientHttpRequestInterceptor} already added
     * and configured to surround downstream calls with a subspan, and using the default
     * {@link HttpTagAndSpanNamingStrategy} and {@link HttpTagAndSpanNamingAdapter} ({@link ZipkinHttpTagStrategy} and
     * {@link SpringHttpClientTagAdapter}).
     */
    public static RestTemplate createTracingEnabledRestTemplate() {
        return createTracingEnabledRestTemplate(true);
    }

    /**
     * @param surroundCallsWithSubspan Pass in true to have the returned {@link RestTemplate} surround all calls with
     * a subspan and propagate the subspan's tracing info, or false to have only the current span propagated at the
     * time of the call (no subspan).
     * @return A new {@link RestTemplate} instance with a {@link WingtipsClientHttpRequestInterceptor} already added
     * and with the subspan option on or off depending on the value of the {@code surroundCallsWithSubspan} argument,
     * and using the default {@link HttpTagAndSpanNamingStrategy} and {@link HttpTagAndSpanNamingAdapter}
     * ({@link ZipkinHttpTagStrategy} and {@link SpringHttpClientTagAdapter}).
     */
    public static RestTemplate createTracingEnabledRestTemplate(boolean surroundCallsWithSubspan) {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getInterceptors().add(
            new WingtipsClientHttpRequestInterceptor(surroundCallsWithSubspan)
        );
        return restTemplate;
    }

    /**
     * @param tagAndNamingStrategy The span tag and naming strategy to use - cannot be null. If you really want no
     * tag and naming strategy, then pass in {@link NoOpHttpTagStrategy#getDefaultInstance()}.
     * @param tagAndNamingAdapter The tag and naming adapter to use - cannot be null. If you really want no tag and
     * naming adapter, then pass in {@link NoOpHttpTagAdapter#getDefaultInstance()}.
     * @return A new {@link RestTemplate} instance with a {@link WingtipsClientHttpRequestInterceptor}
     * already added, and with the subspan option and tag/naming strategy and adapter set to the given arguments.
     */
    public static RestTemplate createTracingEnabledRestTemplate(
        boolean surroundCallsWithSubspan,
        HttpTagAndSpanNamingStrategy tagAndNamingStrategy,
        HttpTagAndSpanNamingAdapter tagAndNamingAdapter
    ) {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getInterceptors().add(
            new WingtipsClientHttpRequestInterceptor(
                surroundCallsWithSubspan,
                tagAndNamingStrategy,
                tagAndNamingAdapter
            )
        );
        return restTemplate;
    }

    /**
     * @return A new {@link AsyncRestTemplate} instance with a {@link WingtipsAsyncClientHttpRequestInterceptor}
     * already added and configured to surround downstream calls with a subspan, and using the default
     * {@link HttpTagAndSpanNamingStrategy} and {@link HttpTagAndSpanNamingAdapter} ({@link ZipkinHttpTagStrategy} and
     * {@link SpringHttpClientTagAdapter}).
     */
    public static AsyncRestTemplate createTracingEnabledAsyncRestTemplate() {
        return createTracingEnabledAsyncRestTemplate(true);
    }

    /**
     * @param surroundCallsWithSubspan Pass in true to have the returned {@link AsyncRestTemplate} surround all calls
     * with a subspan and propagate the subspan's tracing info, or false to have only the current span propagated at
     * the time of the call (no subspan).
     * @return A new {@link AsyncRestTemplate} instance with a {@link WingtipsAsyncClientHttpRequestInterceptor}
     * already added and with the subspan option on or off depending on the value of the {@code
     * surroundCallsWithSubspan} argument, and using the default {@link HttpTagAndSpanNamingStrategy} and
     * {@link HttpTagAndSpanNamingAdapter} ({@link ZipkinHttpTagStrategy} and {@link SpringHttpClientTagAdapter}).
     */
    public static AsyncRestTemplate createTracingEnabledAsyncRestTemplate(boolean surroundCallsWithSubspan) {
        AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
        asyncRestTemplate.getInterceptors().add(
            new WingtipsAsyncClientHttpRequestInterceptor(surroundCallsWithSubspan)
        );
        return asyncRestTemplate;
    }
    
    /**
     * @param tagAndNamingStrategy The span tag and naming strategy to use - cannot be null. If you really want no
     * tag and naming strategy, then pass in {@link NoOpHttpTagStrategy#getDefaultInstance()}.
     * @param tagAndNamingAdapter The tag and naming adapter to use - cannot be null. If you really want no tag and
     * naming adapter, then pass in {@link NoOpHttpTagAdapter#getDefaultInstance()}.
     * @return A new {@link AsyncRestTemplate} instance with a {@link WingtipsAsyncClientHttpRequestInterceptor}
     * already added, and with the subspan option and tag/naming strategy and adapter set to the given arguments.
     */
    public static AsyncRestTemplate createTracingEnabledAsyncRestTemplate(
        boolean surroundCallsWithSubspan,
        HttpTagAndSpanNamingStrategy tagAndNamingStrategy,
        HttpTagAndSpanNamingAdapter tagAndNamingAdapter
    ) {
        AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
        asyncRestTemplate.getInterceptors().add(
            new WingtipsAsyncClientHttpRequestInterceptor(
                surroundCallsWithSubspan,
                tagAndNamingStrategy,
                tagAndNamingAdapter
            )
        );
        return asyncRestTemplate;
    }

    /**
     * Sets the tracing headers on the given {@link HttpMessage#getHeaders()} with values from the given {@link Span}.
     * Does nothing if any of the given arguments are null (i.e. it is safe to pass null, but nothing will happen).
     * Usually you'd want to use one of the interceptors to handle tracing propagation for you
     * ({@link WingtipsClientHttpRequestInterceptor} or {@link WingtipsAsyncClientHttpRequestInterceptor}), however
     * you can call this method to do manual propagation if needed.
     *
     * 

This method conforms to the B3 propagation spec. * * @param httpMessage The {@link HttpMessage} to set tracing headers on. Can be null - if this is null then this * method will do nothing. * @param span The {@link Span} to get the tracing info from to set on the headers. Can be null - if this is null * then this method will do nothing. */ public static void propagateTracingHeaders(HttpMessage httpMessage, Span span) { HttpHeadersForPropagation headersForPropagation = (httpMessage == null) ? null : new HttpHeadersForPropagation(httpMessage); HttpRequestTracingUtils.propagateTracingHeaders(headersForPropagation, span); } /** * @param method The HTTP method. * @return "UNKNOWN_HTTP_METHOD" if the method is null, otherwise {@link HttpMethod#name()}. */ public static String getRequestMethodAsString(HttpMethod method) { if (method == null) { return "UNKNOWN_HTTP_METHOD"; } return method.name(); } /** * @return A {@link SuccessCallback} that wraps the given original so that the current thread's tracing and MDC * information is registered with the thread and therefore available during execution and unregistered after * execution. * *

NOTE: The current thread's tracing and MDC info will be extracted using {@link * Tracer#getCurrentSpanStackCopy()} and {@link MDC#getCopyOfContextMap()}. */ public static SuccessCallback successCallbackWithTracing(SuccessCallback successCallback) { return new SuccessCallbackWithTracing<>(successCallback); } /** * @return A {@link SuccessCallback} that wraps the given original so that the given distributed tracing and MDC * information is registered with the thread and therefore available during execution and unregistered after * execution. You can pass in a {@link TracingState} for clearer less verbose code since it extends * {@code Pair, Map>}. */ public static SuccessCallback successCallbackWithTracing( SuccessCallback successCallback, Pair, Map> threadInfoToLink ) { return new SuccessCallbackWithTracing<>(successCallback, threadInfoToLink); } /** * @return A {@link SuccessCallback} that wraps the given original so that the given distributed tracing and MDC * information is registered with the thread and therefore available during execution and unregistered after * execution. */ public static SuccessCallback successCallbackWithTracing( SuccessCallback successCallback, Deque spanStackToLink, Map mdcContextMapToLink ) { return new SuccessCallbackWithTracing<>(successCallback, spanStackToLink, mdcContextMapToLink); } /** * @return A {@link FailureCallback} that wraps the given original so that the current thread's tracing and MDC * information is registered with the thread and therefore available during execution and unregistered after * execution. * *

NOTE: The current thread's tracing and MDC info will be extracted using {@link * Tracer#getCurrentSpanStackCopy()} and {@link MDC#getCopyOfContextMap()}. */ public static FailureCallback failureCallbackWithTracing(FailureCallback failureCallback) { return new FailureCallbackWithTracing(failureCallback); } /** * @return A {@link FailureCallback} that wraps the given original so that the given distributed tracing and MDC * information is registered with the thread and therefore available during execution and unregistered after * execution. You can pass in a {@link TracingState} for clearer less verbose code since it extends * {@code Pair, Map>}. */ public static FailureCallback failureCallbackWithTracing(FailureCallback failureCallback, Pair, Map> threadInfoToLink) { return new FailureCallbackWithTracing(failureCallback, threadInfoToLink); } /** * @return A {@link FailureCallback} that wraps the given original so that the given distributed tracing and MDC * information is registered with the thread and therefore available during execution and unregistered after * execution. */ public static FailureCallback failureCallbackWithTracing(FailureCallback failureCallback, Deque spanStackToLink, Map mdcContextMapToLink) { return new FailureCallbackWithTracing(failureCallback, spanStackToLink, mdcContextMapToLink); } /** * @return A {@link ListenableFutureCallback} that wraps the given original so that the current thread's tracing and MDC * information is registered with the thread and therefore available during execution and unregistered after * execution. * *

NOTE: The current thread's tracing and MDC info will be extracted using {@link * Tracer#getCurrentSpanStackCopy()} and {@link MDC#getCopyOfContextMap()}. */ public static ListenableFutureCallback listenableFutureCallbackWithTracing( ListenableFutureCallback listenableFutureCallback ) { return new ListenableFutureCallbackWithTracing<>(listenableFutureCallback); } /** * @return A {@link ListenableFutureCallback} that wraps the given original so that the given distributed tracing and MDC * information is registered with the thread and therefore available during execution and unregistered after * execution. You can pass in a {@link TracingState} for clearer less verbose code since it extends * {@code Pair, Map>}. */ public static ListenableFutureCallback listenableFutureCallbackWithTracing( ListenableFutureCallback listenableFutureCallback, Pair, Map> threadInfoToLink ) { return new ListenableFutureCallbackWithTracing<>(listenableFutureCallback, threadInfoToLink); } /** * @return A {@link ListenableFutureCallback} that wraps the given original so that the given distributed tracing and MDC * information is registered with the thread and therefore available during execution and unregistered after * execution. */ public static ListenableFutureCallback listenableFutureCallbackWithTracing( ListenableFutureCallback listenableFutureCallback, Deque spanStackToLink, Map mdcContextMapToLink ) { return new ListenableFutureCallbackWithTracing<>(listenableFutureCallback, spanStackToLink, mdcContextMapToLink); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy