MCPcopy Index your code
hub / github.com/Nike-Inc/wingtips

github.com/Nike-Inc/wingtips @wingtips-v0.24.2

Chat with this repo
repository ↗ · DeepWiki ↗ · release wingtips-v0.24.2 ↗ · + Follow
2,703 symbols 13,699 edges 214 files 569 documented · 21%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Wingtips - Give Your Distributed Systems a Dapper Footprint

[![Maven Central][maven_central_img]][maven_central] [![Build][gh_action_build_img]][gh_action_build] [![Code Coverage][codecov_img]][codecov] [![License][license img]][license]

Wingtips is a distributed tracing solution for Java 7 and greater based on the Google Dapper paper.

There are a few modules associated with this project:

If you prefer hands-on exploration rather than readmes, the sample applications provide concrete examples of using Wingtips that are simple, compact, and straightforward.

Table of Contents

Overview

Distributed tracing is a mechanism to track requests through a network of distributed systems in order to create transparency and shed light on the sometimes complex interactions and behavior of those systems. For example in a cloud-based microservice architecture a single request can touch dozens or hundreds of servers as it spreads out in a tree-like fashion. Without distributed tracing it would be very difficult to identify which part(s) of such a complex system were causing performance issues - either in general or for that request in particular.

Distributed tracing provides the capability for near-realtime monitoring or historical analysis of interactions between servers given the necessary tools to collect and interpret the traces. It allows you to easily see where applications are spending their time - e.g. is it mostly in-application work, or is it mostly waiting for downstream network calls?

Distributed tracing can also be used in some cases for error debugging and problem investigations with some caveats. See the relevant section for more information on this topic.

What is a Distributed Trace Made Of?

  • Every distributed trace contains a TraceID that represents the entire request across all servers/microservices it touches. These TraceIDs are generated as probabilistically unique 64-bit integers (longs). In practice these IDs are passed around as unsigned longs in lowercase hexadecimal string format, but conceptually they are just random 64-bit integers.
  • Each unit of work that you want to track in the distributed trace is defined as a Span. Spans are usually broken down into overall-request-time for a given request in a given server/microservice, and downstream-call-time for each downstream call made for that request from the server/microservice. Spans are identified by a SpanID, which is also a pseudorandomly generated 64-bit long.
  • Spans can have Parent Spans, which is how we build a tree of the request's behavior as it branches across server boundaries. The ParentSpanID is set to the parent Span's SpanID.
  • All Spans contain the TraceID of the overall trace they are attached to, whether or not they have Parent Spans.
  • Spans include a SpanName, which is a more human readable indication of what the span was, e.g. GET_/some/endpoint for the overall span for a REST request, or downstream-POST_https://otherservice.com/other/endpoint for the span performing a downstream call to another service.
  • Spans contain timing info - a start timestamp and a duration value.

See the Output and Logging section for an example of what a span looks like when it is logged.

Quickstart and Usage

Generic Application Pseudo-Code

NOTE: The following pseudo-code only applies to thread-per-request frameworks and scenarios. For asynchronous non-blocking scenarios see this section.

import com.nike.wingtips.Span;
import com.nike.wingtips.Tracer;

// ======As early in the request cycle as possible======
try {
    // Determine if a parent span exists by inspecting the request (e.g. request headers)
    Span parentSpan = extractParentSpanFromRequest(request);

    // Start the overall request span (which becomes the "current span" for this thread unless/until a sub-span is created)
    if (parentSpan == null)
        Tracer.getInstance().startRequestWithRootSpan("newRequestSpanName");
    else
        Tracer.getInstance().startRequestWithChildSpan(parentSpan, "newRequestSpanName");

    // It's recommended that you include the trace ID of the overall request span in the response headers
    addTraceIdToResponseHeaders(response, Tracer.getInstance().getCurrentSpan());

    // Execute the normal request logic
    doRequestLogic();
}
finally {
    // ======As late in the request/response cycle as possible======
    Tracer.getInstance().completeRequestSpan(); // Completes the overall request span and logs it to SLF4J
}

Generic Application Pseudo-Code Explanation

In a typical usage scenario you'll want to call one of the Tracer.getInstance().startRequest...() methods as soon as possible when a request enters your application, and you'll want to call Tracer.getInstance().completeRequestSpan() as late as possible in the request/response cycle. In between these two calls the span that was started (the "overall-request-span") is considered the "current span" for this thread and can be retrieved if necessary by calling Tracer.getInstance().getCurrentSpan().

The extractParentSpanFromRequest() method is potentially different for different applications, however for HTTP-based frameworks the pattern is usually the same - look for and extract distributed-tracing-related information from the HTTP headers and use that information to create a parent span. There is a utility method that performs this work for you: HttpRequestTracingUtils.fromRequestWithHeaders(RequestWithHeaders, List<String>). You simply need to provide the HTTP request wrapped by an implementation of RequestWithHeaders and the list of user ID header keys for your application (if any) and it will do the rest using the standard distributed tracing header key constants found in TraceHeaders. See the javadocs for those classes and methods for more information and usage instructions.

NOTE: Given the thread-local nature of this library you'll want to make sure the span completion call is in a finally block or otherwise guaranteed to be called no matter what (even if the request fails with an error) to prevent problems when subsequent requests are processed on the same thread. The Tracer class does its best to recover from incorrect thread usage scenarios and log information about what happened but the best solution is to prevent the problems from occurring in the first place. See the section below on try-with-resources for some tips on foolproof ways to safely complete your spans.

Is your application running in a Servlet-based framework?

If your application is running in a Servlet environment (e.g. Spring Boot w/ Spring MVC, raw Spring MVC, Jersey, raw Servlets, etc) then this entire lifecycle can be handled by a Servlet Filter. We've created one for you that's ready to drop in and go - see the wingtips-servlet-api Wingtips plugin module library for details. That plugin module is also a good resource to see how the code for a production-ready implementation of this library might look.

Simplified Span Management using Java try-with-resources Statements

Spans support Java try-with-resources statements to help guarantee proper usage in blocking/non-asynchronous scenarios (for asynchronous scenarios please refer to the asynchronous usage section of this readme). As previously mentioned, Spans that are not properly completed can lead to incorrect distributed tracing information showing up, and the try-with-resources statements guarantee that spans are completed appropriately. Here are some examples (note: there are some important tradeoffs you should consider before using this feature):

Overall request span using try-with-resources

try(Span requestSpan = Tracer.getInstance().startRequestWith*(...)) {
    // Traced blocking code for overall request (not asynchronous) goes here ...
}
// No finally block needed to properly complete the overall request span

Subspan using try-with-resources

try (Span subspan = Tracer.getInstance().startSubSpan(...)) {
    // Traced blocking code for subspan (not asynchronous) goes here ...
}
// No finally block needed to properly complete the subspan

Warning about error handling when using try-with-resources to autoclose spans

The try-with-resources feature t

Extension points exported contracts — how you extend this code

SpanLifecycleListener (Interface)
Listener interface for com.nike.wingtips.Tracer that allows you to be notified during various span lifecycle eve [34 implementers]
wingtips-core/src/main/java/com/nike/wingtips/lifecyclelistener/SpanLifecycleListener.java
AsyncWingtipsHelper (Interface)
Helper class that provides methods for dealing with async stuff in Wingtips, mainly providing easy ways to support distr [2 …
wingtips-java8/src/main/java/com/nike/wingtips/util/AsyncWingtipsHelper.java
WingtipsToZipkinSpanConverter (Interface)
Simple interface for a class that knows how to convert a Wingtips Span to a zipkin2.Span. @author Nic M [2 implementers]
wingtips-zipkin2/src/main/java/com/nike/wingtips/zipkin2/util/WingtipsToZipkinSpanConverter.java
HttpObjectForPropagation (Interface)
Represents an HTTP object that can have its headers set in order to propagate tracing info downstream. This can wrap a h [4 …
wingtips-core/src/main/java/com/nike/wingtips/http/HttpObjectForPropagation.java
ErrorSpanTagger (Interface)
A functional interface that handles error tagging for spans when an operation fails with an exception. Used by {@link Op [2 …
wingtips-java8/src/main/java/com/nike/wingtips/util/spantagger/ErrorSpanTagger.java
RequestWithHeaders (Interface)
Facade around a request that contains headers (and optionally attributes). Allows HttpRequestTracingUtils to be [4 implementers]
wingtips-core/src/main/java/com/nike/wingtips/http/RequestWithHeaders.java
SpanTagger (Interface)
A functional interface that handles extra tagging for spans. Used by OperationWrapperOptions, which is in turn u
wingtips-java8/src/main/java/com/nike/wingtips/util/spantagger/SpanTagger.java
RootSpanSamplingStrategy (Interface)
Pluggable strategy for com.nike.wingtips.Tracer that determines whether or not the next root span should be samp [3 implementers]
wingtips-core/src/main/java/com/nike/wingtips/sampling/RootSpanSamplingStrategy.java

Core symbols most depended-on inside this repo

getInstance
called by 665
wingtips-core/src/main/java/com/nike/wingtips/Tracer.java
get
called by 625
wingtips-java8/src/main/java/com/nike/wingtips/util/asynchelperwrapper/SupplierWithTracing.java
toString
called by 428
wingtips-core/src/main/java/com/nike/wingtips/Span.java
getTraceId
called by 208
wingtips-core/src/main/java/com/nike/wingtips/Span.java
getRight
called by 178
wingtips-core/src/main/java/com/nike/wingtips/util/TracingState.java
getLeft
called by 173
wingtips-core/src/main/java/com/nike/wingtips/util/TracingState.java
startRequestWithRootSpan
called by 153
wingtips-core/src/main/java/com/nike/wingtips/Tracer.java
isCompleted
called by 145
wingtips-core/src/main/java/com/nike/wingtips/Span.java

Shape

Method 2,342
Class 301
Enum 50
Interface 10

Languages

Java100%

Modules by API surface

wingtips-core/src/test/java/com/nike/wingtips/TracerTest.java91 symbols
wingtips-java8/src/test/java/com/nike/wingtips/util/AsyncWingtipsHelperTest.java90 symbols
wingtips-core/src/test/java/com/nike/wingtips/SpanTest.java89 symbols
wingtips-servlet-api/src/test/java/com/nike/wingtips/servlet/RequestTracingFilterTest.java67 symbols
wingtips-core/src/test/java/com/nike/wingtips/util/parser/SpanParserTest.java63 symbols
wingtips-core/src/main/java/com/nike/wingtips/Span.java62 symbols
wingtips-spring-webflux/src/test/java/com/nike/wingtips/componenttest/WingtipsSpringWebfluxComponentTest.java50 symbols
wingtips-spring-webflux/src/test/java/com/nike/wingtips/spring/webflux/server/WingtipsSpringWebfluxWebFilterTest.java44 symbols
wingtips-spring-webflux/src/test/java/com/nike/wingtips/spring/webflux/client/WingtipsSpringWebfluxExchangeFilterFunctionTest.java44 symbols
wingtips-core/src/main/java/com/nike/wingtips/Tracer.java44 symbols
wingtips-spring-boot2-webflux/src/test/java/com/nike/wingtips/springboot2/webflux/WingtipsSpringBoot2WebfluxConfigurationTest.java39 symbols
wingtips-servlet-api/src/test/java/com/nike/wingtips/componenttest/RequestTracingFilterComponentTest.java39 symbols

Datastores touched

(mysql)Database · 1 repos
customersDatabase · 1 repos

For agents

$ claude mcp add wingtips \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact