Riptide: OpenTracing adds sophisticated OpenTracing support to Riptide.
Http.builder()
.plugin(new OpenTracingPlugin(tracer))
.build();
- Client span lifecycle management
- Span context injection into HTTP headers of requests
- Extensible span decorators for tags and logs
- Seamless integration with Riptide: Failsafe
- Java 8
- Riptide Core
- OpenTracing Java API
- Riptide: Failsafe (optional)
Add the following dependency to your project:
<dependency>
<groupId>org.zalando</groupId>
<artifactId>riptide-opentracing</artifactId>
<version>${riptide.version}</version>
</dependency>
Http.builder()
.baseUrl("https://www.example.com")
.plugin(new OpenTracingPlugin(tracer)
.withLifecycle(new NewSpanLifecycle())
.withActivation(new NoOpActivation())
.withAdditionalSpanDecorators(new HttpUrlSpanDecorator))
.build();
By default a new span will be started for each request and it will be activated.
The following tags/logs are supported out of the box:
Tag/Log Field | Decorator | Example |
---|---|---|
CallSiteSpanDecorator |
admin=true |
|
component |
ComponentSpanDecorator |
Riptide |
CompositeSpanDecorator ³ |
||
message (log) |
ErrorMessageSpanDecorator ¹ |
Connection timed out |
error |
ErrorSpanDecorator |
false |
error.kind (log) |
ErrorSpanDecorator |
SocketTimeoutException |
error.object (log) |
ErrorSpanDecorator |
(exception instance) |
stack (log) |
ErrorStackSpanDecorator |
SocketTimeoutException at [...] |
http.method_override |
HttpMethodOverrideSpanDecorator |
GET |
http.method |
HttpMethodSpanDecorator |
POST |
http.url |
HttpUrlSpanDecorator ¹ |
https://www.github.com/users/me |
http.path |
HttpPathSpanDecorator |
/users/{user_id} |
http.prefer |
HttpPreferSpanDecorator |
respond-async |
http.retry_after (log) |
HttpRetryAfterSpanDecorator |
120 |
http.status_code |
HttpStatusCodeSpanDecorator |
200 |
peer.address |
PeerSpanDecorator |
www.github.com:80 |
peer.hostname |
PeerSpanDecorator |
www.github.com |
peer.port |
PeerSpanDecorator |
80 |
retry |
RetrySpanDecorator ¹ |
true |
retry_number (log) |
RetrySpanDecorator ¹ |
3 |
ServiceLoaderSpanDecorator ² |
||
StaticTagSpanDecorator ¹ |
zone=aws:eu-central-1a |
|
UriVariablesTagSpanDecorator ¹ |
user_id=me |
¹ Not registered by default.
² The ServiceLoaderSpanDecorator
will load all custom SpanDecorator
implementations that are registered using Java's Service Provider Interface mechanism and delegate to them.
³ The CompositeSpanDecorator
allows to treat multiple decorators as one.
Be aware: The http.url
tag is disabled by default because the full request URI may contain
sensitive, personal data.
As an alternative we introduced the http.path
tag which favors the URI template over the
already expanded version. That has the additional benefit of a significant lower cardinality
compared to what http.url
would provide.
If you still want to enable it, you can do so by just registering the missing span decorator:
new OpenTracingPlugin(tracer)
.withAdditionalSpanDecorators(new HttpUrlSpanDecorator())
A lifecycle policy can be used to specify which spans are reused or whether a new one is created:
new OpenTracingPlugin(tracer)
.withLifecycle(new NewSpanLifecycle());
The ActiveSpanLifecycle
reuses the current active span. This approach might be useful if some other
facility already provided a span that can be used to decorate with tags.
Http http = Http.builder()
.baseUrl("https://www.example.com")
.plugin(new OpenTracingPlugin(tracer)
.withLifecycle(new ActiveSpanLifecycle()))
.build();
Span span = tracer.buildSpan("test").start();
try (final Scope ignored = tracer.activateSpan(span)) {
http.get("/users/{user}", "me")
.dispatch(..)
.join();
} finally {
span.finish();
}
The ExplicitSpanLifecycle
reuses the span passed with the OpenTracingPlugin.SPAN
attribute.
That allows to pass a span explicitly rather than implicitly via the active span mechanism. This might be needed
for system that can't rely on ThreadLocal
state, e.g. non-blocking, event-loop based reactive applications.
Http http = Http.builder()
.baseUrl("https://www.example.com")
.plugin(new OpenTracingPlugin(tracer)
.withLifecycle(new ExplicitSpanLifecycle()))
.build();
Span span = tracer.buildSpan("test").start();
http.get("/users/{user}", "me")
.attribute(OpenTracingPlugin.SPAN, span)
.dispatch(..)
.join();
span.finish();
The NewSpanLifecycle
starts and finishes a new span for every request. This policy is the most common approach and therefore the default (in conjunction with the ExplicitSpanLifecycle
).
Http http = Http.builder()
.baseUrl("https://www.example.com")
.plugin(new OpenTracingPlugin(tracer)
.withLifecycle(new NewSpanLifecycle()))
.build();
http.get("/users/{user}", "me")
.dispatch(..)
.join();
Different lifecycle policies can be chained together:
new OpenTracingPlugin(tracer)
.withLifecycle(Lifecycle.composite(
new ActiveSpanLifecycle(),
new ExplicitSpanLifecycle(),
new NewSpanLifecycle()
));
If a policy doesn't produce a span the next one will be used and so on and so forth. Tracing will effectively be disabled if none of the policies produces a span.
An activation policy can be used to specify whether a span will be activated or not. This might be desired for system that can't rely on ThreadLocal
state, e.g. non-blocking, event-loop based reactive applications.
new OpenTracingPlugin(tracer)
.withActivation(new NoOpActivation());
An injection policy can be used to specify whether (or how) the span context will be injected into outgoing requests. The default configuration enables span context propagation, but it's not always desired and can be disabled:
new OpenTracingPlugin(tracer)
.withInjection(new NoOpInjection())
Span decorators are a simple, yet powerful tool to manipulate the span, i.e. they allow you to add tags, logs and baggage to spans. The default set of decorators can be extended by using OpenTracingPlugin#withAdditionalSpanDecorators(..)
:
new OpenTracingPlugin(tracer)
.withAdditionalSpanDecorators(new StaticSpanDecorator(singletonMap(
"environment", "local"
)))
If the default span decorators are not desired you can replace them completely using OpenTracingPlugin#withSpanDecorators(..)
:
new OpenTracingPlugin(tracer)
.withSpanDecorators(
new ComponentSpanDecorator("MSIE"),
new PeerSpanDecorator(),
new HttpMethodSpanDecorator(),
new HttpPathSpanDecorator(),
new HttpUrlSpanDecorator(),
new HttpStatusCodeSpanDecorator(),
new ErrorSpanDecorator(),
new CallSiteSpanDecorator())
Typically you won't need to do anything at the call-site regarding OpenTracing, i.e. your usages of Riptide should work exactly as before:
http.get("/users/{id}", userId)
.dispatch(series(),
on(SUCCESSFUL).call(User.class, this::greet),
anySeries().call(problemHandling()))
By default the HTTP method will be used as the operation name, which might not fit your needs. Since deriving a meaningful operation name from request arguments alone is unreliable, you can specify the OpenTracingPlugin.OPERATION_NAME
request attribute to override the default:
http.get("/users/{id}", userId)
.attribute(OpenTracingPlugin.OPERATION_NAME, "get_user")
.dispatch(series(),
on(SUCCESSFUL).call(User.class, this::greet),
anySeries().call(problemHandling()))
Assuming you have the CallSiteSpanDecorator
registered (it is by default), you can also specify custom tags based on context information which wouldn't be available within the plugin anymore:
http.get("/users/{id}", userId)
.attribute(OpenTracingPlugin.TAGS, singletonMap("retry", "true"))
.dispatch(series(),
on(SUCCESSFUL).call(User.class, this::greet),
anySeries().call(problemHandling()))
URI templates are not just safer to use (see Configuration), they can also be used to generate tags from URI variables. Given you have the UriVariablesTagSpanDecorator
registered then the following will produce a user_id=123
tag:
http.get("/users/{user_id}", 123)
The same warning applies as mentioned before regarding http.url
. This feature may
expose personal data and should be used with care.
If you have questions, concerns, bug reports, etc., please file an issue in this repository's Issue Tracker.
To contribute, simply open a pull request and add a brief description (1-2 sentences) of your addition or change. For more details, check the contribution guidelines.