Skip to content

Brave 4.10

Compare
Choose a tag to compare
@codefromthecrypt codefromthecrypt released this 29 Nov 03:17
· 945 commits to master since this release

Brave v4.10 adds Netty and Apache HC caching instrumentation, improves MDC integration and adds tracing tools.

Netty Http Server instrumentation

Netty is a popular I/O library used underneath popular frameworks such as gRPC,
CXF and Ratpack. If you are using Brave with a Netty library now, you likely
configure a framework-specific hook. If you aren't writing a Netty framework or
configuring an http pipeline, you can skip this section.

Due to popular demand, we've added trace instrumentation for any
netty-codec-http pipeline. Add NettyHttpTracing.serverHandler() between
infrastructure and application handlers to precisely measure the server-side of
http calls. This is a more precise alternative to doing so at higher layers,
such as servlet, because it is closer to the wire. Thanks to @songxin1990 for
the hard work on this, as well @normanmaurer and @nicmunroe for review.

Depend on io.zipkin.brave:brave-instrumentation-netty-codec-http and
configure your handlers like so to transparently trace http server calls:

NettyHttpTracing nettyHttpTracing = NettyHttpTracing.create(httpTracing);
ChannelPipeline pipeline = ch.pipeline();
... add your infrastructure handlers, in particular HttpRequestDecoder and HttpResponseEncoder
pipeline.addLast("tracing", nettyHttpTracing.serverHandler());
... add your application handlers

Adding parentId to logging contexts

Brave 4.x not only provides tracing, but also logging integration. Even when
a request isn't sampled for tracing, you can see stable trace identifiers in
logs for correlation purposes or for integration with other tools.

Before, we attached traceId and spanId to logging contexts such as SLF4J,
log4j or log4j2. Some integrations, such as PCF metrics, parse logs to create
traces independent of Zipkin. We added parentId to the trace context to
ensure tooling like this can place spans at the right place in the trace tree.

Apache httpclient-cache integration

While commonly done, Apache 4.x HttpClient interceptors cannot reliably attach
trace identifiers to logging contexts. Instead, Brave decorates
HttpClientBuilder to allow both tracing and logging to work properly. One
downside to decorating builders is there are more than one.

You can now substitute TracingCachingHttpClientBuilder to trace and integrate
logs with caching http clients.

New tools for instrumentors

Brave serves at least two audiences: those who want to configure tracing and
those who provide trace instrumentation to others. This section is for those
writing tracing code on behalf of others.

Better Tracer.toString()

Troubleshooting state can be difficult due to overlapping scopes. We've added
a couple things to Tracer.toString() which can significantly demystify state
when debugging. Note: this format is subject to change based on your feedback!

Tracer.toString() always includes the reporter (where spans are going).

Tracer{reporter=AsyncReporter(OkHttpSender(http://myhost:9411/api/v2/spans))}

When spans are in-flight, Tracer.toString() includes a snapshot of each even
if the thread calling toString() is not actively tracing. This part might
change based on feedback. For example, it could be moved to a utility which you
can plumb to an http endpoint (as there could be very many spans in flight!).

Tracer{inFlight=[{"traceId":"48485a3953bb61246b221d5bc9e6496c","id":"6b221d5bc9e6496c","timestamp":1461750491274000,"localEndpoint":{"serviceName":"my-service"}}], reporter=...

When the current thread is tracing, Tracer.toString() includes the current
trace context. Most tracing bugs are about this part.. for example, a callback
wasn't scoped properly. Knowing what's in scope helps those writing tracing
code fix bugs faster.

Tracer{currentSpan=48485a3953bb61246b221d5bc9e6496c/6b221d5bc9e6496c, reporter=...

ThreadLocalSpan

Sometimes you have to instrument a library where There's no attribute namespace
shared across request and response. For this scenario, you can use
ThreadLocalSpan to temporarily store the span between callbacks.

Here's an example:

class MyFilter extends Filter {
  final ThreadLocalSpan threadLocalSpan;

  public void onStart(Request request) {
    // Assume you have code to start the span and add relevant tags...

    // We now set the span in scope so that any code between here and
    // the end of the request can see it with Tracer.currentSpan()
    threadLocalSpan.set(span);
  }

  public void onFinish(Response response, Attributes attributes) {
    // as long as we are on the same thread, we can read the span started above
    Span span = threadLocalSpan.remove();
    if (span == null) return;

    // Assume you have code to complete the span
  }
}