
brave.http.HttpParser Maven / Gradle / Ivy
package brave.http;
import brave.ErrorParser;
import brave.SpanCustomizer;
import brave.Tracing;
import brave.internal.Nullable;
public class HttpParser {
static final ErrorParser DEFAULT_ERROR_PARSER = new ErrorParser();
/**
* Override when making custom types. Typically, you'll use {@link Tracing#errorParser()}
*
* {@code
* class MyHttpClientParser extends HttpClientParser {
* ErrorParser errorParser;
*
* MyHttpClientParser(Tracing tracing) {
* errorParser = tracing.errorParser();
* }
*
* protected ErrorParser errorParser() {
* return errorParser;
* }
* --snip--
* }
*/
protected ErrorParser errorParser() {
return DEFAULT_ERROR_PARSER;
}
/**
* Override to change what data from the http request are parsed into the span representing it. By
* default, this sets the span name to the http method and tags "http.method" and "http.path".
*
* If you only want to change the span name, you can override {@link #spanName(HttpAdapter,
* Object)} instead.
*
* @see #spanName(HttpAdapter, Object)
*/
// Eventhough the default span name is the method, we have no way of knowing that a user hasn't
// overwritten the name to something else. If that occurs during response parsing, it is too late
// to go back and get the http method. Adding http method by default ensures span naming doesn't
// prevent basic HTTP info from being visible. A cost of this is another tag, but it is small with
// very limited cardinality. Moreover, users who care strictly about size can override this.
public void request(HttpAdapter adapter, Req req, SpanCustomizer customizer) {
customizer.name(spanName(adapter, req));
String method = adapter.method(req);
if (method != null) customizer.tag("http.method", method);
String path = adapter.path(req);
if (path != null) customizer.tag("http.path", path);
}
/** Returns the span name of the request. Defaults to the http method. */
protected String spanName(HttpAdapter adapter, Req req) {
return adapter.method(req);
}
/**
* Override to change what data from the http response or error are parsed into the span modeling
* it.
*
* By default, this tags "http.status_code" when it is not 2xx. If there's an exception or the
* status code is neither 2xx nor 3xx, it tags "error". This also overrides the span name based on
* the {@link HttpAdapter#methodFromResponse(Object)} and {@link HttpAdapter#route(Object)} where
* possible (ex "get /users/:userId").
*
*
If routing is supported, and a GET didn't match due to 404, the span name will be
* "get not_found". If it didn't match due to redirect, the span name will be "get redirected".
* If routing is not supported, the span name is left alone.
*
*
If you only want to change how exceptions are parsed, override {@link #error(Integer,
* Throwable, SpanCustomizer)} instead.
*
*
Note: Either the response or error parameters may be null, but not both.
*
* @see #error(Integer, Throwable, SpanCustomizer)
*/
// This accepts response or exception because sometimes http 500 is an exception and sometimes not
// If this were not an abstraction, we'd use separate hooks for response and error.
public void response(HttpAdapter, Resp> adapter, @Nullable Resp res,
@Nullable Throwable error, SpanCustomizer customizer) {
int statusCode = 0;
if (res != null) {
statusCode = adapter.statusCodeAsInt(res);
String nameFromRoute = spanNameFromRoute(adapter, res, statusCode);
if (nameFromRoute != null) customizer.name(nameFromRoute);
String maybeStatus = maybeStatusAsString(statusCode, 299);
if (maybeStatus != null) customizer.tag("http.status_code", maybeStatus);
}
error(statusCode, error, customizer);
}
static String spanNameFromRoute(HttpAdapter, Resp> adapter, Resp res, int statusCode) {
String method = adapter.methodFromResponse(res);
if (method == null) return null; // don't undo a valid name elsewhere
String route = adapter.route(res);
if (route == null) return null; // don't undo a valid name elsewhere
if (!"".equals(route)) return method + " " + route;
if (statusCode / 100 == 3) return method + " redirected";
if (statusCode == 404) return method + " not_found";
return null; // unexpected
}
/**
* Override to change what data from the http error are parsed into the span modeling it. By
* default, this tags "error" as the exception or the status code if it is neither 2xx nor 3xx.
*
* Note: Either the httpStatus or error parameters may be null, but not both
*
*
Conventionally associated with the tag key "error"
*/
// BRAVE6: httpStatus is a Integer, not a int. We can't change this api as users expect this to be
// called by default. Unfortunately, this implies boxing until we can change it.
protected void error(@Nullable Integer httpStatus, @Nullable Throwable error,
SpanCustomizer customizer) {
if (error != null) {
errorParser().error(error, customizer);
} else if (httpStatus != null) {
String maybeErrorStatus = maybeStatusAsString(httpStatus, 399);
if (maybeErrorStatus != null) customizer.tag("error", maybeErrorStatus);
}
}
@Nullable String maybeStatusAsString(int statusCode, int upperRange) {
if (statusCode != 0 && (statusCode < 200 || statusCode > upperRange)) {
return String.valueOf(statusCode);
}
return null;
}
}