package com.nike.wingtips.tags; import com.nike.internal.util.StringUtils; import com.nike.wingtips.Span; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * Applies {@code Zipkin} standard tags for: * <ul> * <li>http.method</li> * <li>http.path</li> * <li>http.url</li> * <li>http.route</li> * <li>http.status_code</li> * <li>error</li> * </ul> * * The following known Zipkin tags are <strong>unimplemented</strong> in this strategy: * <ul> * <li>http.request.size</li> * <li>http.response.size</li> * <li>http.host</li> * </ul> * * @param <REQ> The expected request object type to be inspected * @param <RES> The expected response object type to be inspected * * @see <a href='https://github.com/openzipkin/brave/tree/master/instrumentation/http#span-data-policy'>Zipkin's Span Data Policy</a> * * @author Brandon Currie * @author Nic Munroe */ public class ZipkinHttpTagStrategy<REQ, RES> extends HttpTagAndSpanNamingStrategy<REQ, RES> { @SuppressWarnings("WeakerAccess") protected static final ZipkinHttpTagStrategy<?, ?> DEFAULT_INSTANCE = new ZipkinHttpTagStrategy<>(); /** * @return A reusable, thread-safe, singleton instance of this class that can be used by anybody who wants to use * this class and does not need any customization. */ @SuppressWarnings("unchecked") public static <REQ, RES> ZipkinHttpTagStrategy<REQ, RES> getDefaultInstance() { return (ZipkinHttpTagStrategy<REQ, RES>) DEFAULT_INSTANCE; } @Override protected void doHandleRequestTagging( @NotNull Span span, @NotNull REQ request, @NotNull HttpTagAndSpanNamingAdapter<REQ, ?> adapter ) { putTagIfValueIsNotBlank(span, KnownZipkinTags.HTTP_METHOD, adapter.getRequestHttpMethod(request)); putTagIfValueIsNotBlank(span, KnownZipkinTags.HTTP_PATH, adapter.getRequestPath(request)); putTagIfValueIsNotBlank(span, KnownZipkinTags.HTTP_URL, adapter.getRequestUrl(request)); putTagIfValueIsNotBlank(span, KnownZipkinTags.HTTP_ROUTE, adapter.getRequestUriPathTemplate(request, null)); } @Override protected void doHandleResponseAndErrorTagging( @NotNull Span span, @Nullable REQ request, @Nullable RES response, @Nullable Throwable error, @NotNull HttpTagAndSpanNamingAdapter<REQ, RES> adapter ) { // Now that we have both request and response, we'll re-try to get the route. putTagIfValueIsNotBlank(span, KnownZipkinTags.HTTP_ROUTE, adapter.getRequestUriPathTemplate(request, response)); putTagIfValueIsNotBlank(span, KnownZipkinTags.HTTP_STATUS_CODE, adapter.getResponseHttpStatus(response)); // For error tagging, we'll defer to the error Throwable if it's not null. if (error != null) { String message = error.getMessage(); if (message == null) { message = error.getClass().getSimpleName(); } addErrorTagToSpan(span, message); } else { // The error Throwable was null, so we'll see if the adapter thinks this is an error response. String errorTagValue = adapter.getErrorResponseTagValue(response); if (StringUtils.isNotBlank(errorTagValue)) { addErrorTagToSpan(span, errorTagValue); } } } @SuppressWarnings("WeakerAccess") protected void addErrorTagToSpan(Span span, String errorTagValue) { putTagIfValueIsNotBlank(span, KnownZipkinTags.ERROR, errorTagValue); } }