
brave.http.HttpServerHandler Maven / Gradle / Ivy
/*
* Copyright 2013-2020 The OpenZipkin Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package brave.http;
import brave.Span;
import brave.Tracer;
import brave.http.HttpServerAdapters.FromResponseAdapter;
import brave.internal.Nullable;
import brave.propagation.TraceContext.Extractor;
import brave.propagation.TraceContextOrSamplingFlags;
import brave.sampler.SamplerFunction;
/**
* This standardizes a way to instrument http servers, particularly in a way that encourages use of
* portable customizations via {@link HttpRequestParser} and {@link HttpResponseParser}.
*
* Synchronous interception is the most straight forward instrumentation.
*
*
You generally need to:
*
* - Extract any trace IDs from headers and start the span
* - Put the span in scope so things like log integration works
* - Process the request
* - Catch any errors
* - Complete the span
*
* {@code
* HttpServerRequestWrapper wrapper = new HttpServerRequestWrapper(request);
* Span span = handler.handleReceive(wrapper); // 1.
* Result result = null;
* Throwable error = null;
* try (Scope ws = currentTraceContext.newScope(span.context())) { // 2.
* return result = process(request); // 3.
* } catch (RuntimeException | Error e) {
* error = e; // 4.
* throw e;
* } finally {
* HttpServerResponseWrapper response = result != null
* ? new HttpServerResponseWrapper(wrapper, result, error)
* : null;
* handler.handleSend(response, error, span); // 5.
* }
* }
*
* @param the native http request type of the server.
* @param the native http response type of the server.
* @since 4.3
*/
// The generic type parameters should always be . Even if the
// deprecated methods are removed in Brave v6, we should not remove these parameters as that would
// cause a compilation break and lead to revlock.
public final class HttpServerHandler extends HttpHandler {
/** @since 5.7 */
public static HttpServerHandler create(
HttpTracing httpTracing) {
if (httpTracing == null) throw new NullPointerException("httpTracing == null");
return new HttpServerHandler<>(httpTracing, null);
}
/**
* @since 4.3
* @deprecated Since 5.7, use {@link #create(HttpTracing)} as it is more portable.
*/
@Deprecated
public static HttpServerHandler create(HttpTracing httpTracing,
HttpServerAdapter adapter) {
if (httpTracing == null) throw new NullPointerException("httpTracing == null");
if (adapter == null) throw new NullPointerException("adapter == null");
return new HttpServerHandler<>(httpTracing, adapter);
}
final Tracer tracer;
final SamplerFunction sampler;
@Deprecated @Nullable final HttpServerAdapter adapter; // null when using default types
final Extractor defaultExtractor;
HttpServerHandler(HttpTracing httpTracing, @Deprecated HttpServerAdapter adapter) {
super(httpTracing.serverRequestParser(), httpTracing.serverResponseParser());
this.adapter = adapter;
this.tracer = httpTracing.tracing().tracer();
this.sampler = httpTracing.serverRequestSampler();
// The following allows us to add the method: handleReceive(HttpServerRequest request) without
// duplicating logic from the superclass or deprecated handleReceive methods.
this.defaultExtractor = httpTracing.tracing().propagation().extractor(HttpServerRequest.GETTER);
}
/**
* Conditionally joins a span, or starts a new trace, depending on if a trace context was
* extracted from the request. Tags are added before the span is started.
*
* This is typically called before the request is processed by the actual library.
*
* @see HttpTracing#serverRequestSampler()
* @see HttpTracing#serverRequestParser()
* @since 5.7
*/
public Span handleReceive(HttpServerRequest request) {
Span span = nextSpan(defaultExtractor.extract(request), request);
return handleStart(request, span);
}
/**
* @since 4.3
* @deprecated Since 5.7, use {@link #handleReceive(HttpServerRequest)}
*/
@Deprecated public Span handleReceive(Extractor extractor, Req request) {
return handleReceive(extractor, request, request);
}
/**
* @since 4.3
* @deprecated Since 5.7, use {@link #handleReceive(HttpServerRequest)}
*/
@Deprecated public Span handleReceive(Extractor extractor, C carrier, Req request) {
if (request == null) throw new NullPointerException("request == null");
HttpServerRequest serverRequest;
if (request instanceof HttpServerRequest) {
serverRequest = (HttpServerRequest) request;
} else {
serverRequest = new HttpServerAdapters.FromRequestAdapter<>(adapter, request);
}
Span span = nextSpan(extractor.extract(carrier), serverRequest);
return handleStart(serverRequest, span);
}
@Override void parseRequest(HttpRequest request, Span span) {
((HttpServerRequest) request).parseClientIpAndPort(span);
requestParser.parse(request, span.context(), span.customizer());
}
/** Creates a potentially noop span representing this request */
Span nextSpan(TraceContextOrSamplingFlags extracted, HttpServerRequest request) {
Boolean sampled = extracted.sampled();
// only recreate the context if the http sampler made a decision
if (sampled == null && (sampled = sampler.trySample(request)) != null) {
extracted = extracted.sampled(sampled.booleanValue());
}
return extracted.context() != null
? tracer.joinSpan(extracted.context())
: tracer.nextSpan(extracted);
}
/**
* Finishes the server span after assigning it tags according to the response or error.
*
* This is typically called once the response headers are sent, and after the span is {@link
* brave.Tracer.SpanInScope#close() no longer in scope}.
*
*
Note: Either the response or error parameters may be null, but not both.
*
* @see HttpTracing#serverResponseParser()
* @since 4.3
*/
public void handleSend(@Nullable Resp response, @Nullable Throwable error, Span span) {
HttpServerResponse serverResponse;
if (response == null || response instanceof HttpServerResponse) {
serverResponse = (HttpServerResponse) response;
} else {
serverResponse = new FromResponseAdapter<>(adapter, response);
}
handleFinish(serverResponse, error, span);
}
}