io.opentelemetry.instrumentation.apachehttpclient.v4_3.TracingProtocolExec Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of opentelemetry-apache-httpclient-4.3 Show documentation
Show all versions of opentelemetry-apache-httpclient-4.3 Show documentation
Instrumentation of Java libraries using OpenTelemetry.
The newest version!
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.apachehttpclient.v4_3;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientRequestResendCount;
import java.io.IOException;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpExecutionAware;
import org.apache.http.client.methods.HttpRequestWrapper;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.impl.execchain.ClientExecChain;
final class TracingProtocolExec implements ClientExecChain {
private static final String REQUEST_PARENT_CONTEXT_ATTRIBUTE_ID =
TracingProtocolExec.class.getName() + ".context";
private final Instrumenter instrumenter;
private final ContextPropagators propagators;
private final ClientExecChain exec;
TracingProtocolExec(
Instrumenter instrumenter,
ContextPropagators propagators,
ClientExecChain exec) {
this.instrumenter = instrumenter;
this.propagators = propagators;
this.exec = exec;
}
@Override
public CloseableHttpResponse execute(
HttpRoute route,
HttpRequestWrapper request,
HttpClientContext httpContext,
HttpExecutionAware httpExecutionAware)
throws IOException, HttpException {
Context parentContext =
httpContext.getAttribute(REQUEST_PARENT_CONTEXT_ATTRIBUTE_ID, Context.class);
if (parentContext == null) {
parentContext = HttpClientRequestResendCount.initialize(Context.current());
httpContext.setAttribute(REQUEST_PARENT_CONTEXT_ATTRIBUTE_ID, parentContext);
}
HttpHost host = null;
if (route.getTargetHost() != null) {
host = route.getTargetHost();
} else if (httpContext.getTargetHost() != null) {
host = httpContext.getTargetHost();
}
if (host != null) {
if ((host.getSchemeName().equals("https") && host.getPort() == 443)
|| (host.getSchemeName().equals("http") && host.getPort() == 80)) {
// port seems to be added to the host by route planning for standard ports even if not
// specified in the URL. There doesn't seem to be a way to differentiate between explicit
// and implicit port, but ignore in both cases to match the more common case.
host = new HttpHost(host.getHostName(), -1, host.getSchemeName());
}
}
ApacheHttpClientRequest instrumenterRequest = new ApacheHttpClientRequest(host, request);
if (!instrumenter.shouldStart(parentContext, instrumenterRequest)) {
return exec.execute(route, request, httpContext, httpExecutionAware);
}
Context context = instrumenter.start(parentContext, instrumenterRequest);
propagators.getTextMapPropagator().inject(context, request, HttpHeaderSetter.INSTANCE);
return execute(route, request, instrumenterRequest, httpContext, httpExecutionAware, context);
}
private CloseableHttpResponse execute(
HttpRoute route,
HttpRequestWrapper request,
ApacheHttpClientRequest instrumenterRequest,
HttpClientContext httpContext,
HttpExecutionAware httpExecutionAware,
Context context)
throws IOException, HttpException {
CloseableHttpResponse response = null;
Throwable error = null;
try (Scope ignored = context.makeCurrent()) {
response = exec.execute(route, request, httpContext, httpExecutionAware);
return response;
} catch (Throwable e) {
error = e;
throw e;
} finally {
instrumenter.end(context, instrumenterRequest, response, error);
}
}
}