Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

re-use logic for http client configuration #11620

Merged
merged 29 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0cd13e8
re-use logic for http client configuration
zeitlinger Jun 18, 2024
22070f5
re-use logic for http client configuration
zeitlinger Jun 18, 2024
de7d263
re-use logic for http client configuration
zeitlinger Jun 18, 2024
5958458
re-use logic for http client configuration
zeitlinger Jun 18, 2024
a240324
re-use logic for http client configuration
zeitlinger Jun 18, 2024
07d8da5
re-use logic for http client configuration
zeitlinger Jun 18, 2024
da2e155
re-use logic for http client configuration
zeitlinger Jun 18, 2024
93c1423
re-use logic for http client configuration
zeitlinger Jun 18, 2024
d73f7d5
re-use logic for http client configuration
zeitlinger Jun 18, 2024
8fa7ca4
re-use logic for http client configuration
zeitlinger Jun 18, 2024
19332a9
re-use logic for http client configuration
zeitlinger Jun 18, 2024
6bd2b63
re-use logic for http client configuration
zeitlinger Jun 18, 2024
829c801
re-use logic for http client configuration
zeitlinger Jun 18, 2024
b622ca3
Renames
trask Jun 18, 2024
31df699
re-use logic for http client configuration
zeitlinger Jun 19, 2024
08ba1f4
pass in library builder
zeitlinger Jun 19, 2024
4b0a19b
use abstract library builder
zeitlinger Jun 19, 2024
2fc014e
use abstract library builder
zeitlinger Jun 19, 2024
51b3add
create instrumenter directly, aligning code between agent and library
zeitlinger Jun 19, 2024
fa45c6e
create instrumenter directly, aligning code between agent and library
zeitlinger Jun 19, 2024
a8ade9c
use delegation
zeitlinger Jun 20, 2024
8eeedb0
fix build
zeitlinger Jun 21, 2024
53535d0
remove builder interface
zeitlinger Jun 21, 2024
6dbad9a
make DefaultHttpClientTelemetryBuilder internal
zeitlinger Jun 21, 2024
ef893e6
make DefaultHttpClientTelemetryBuilder internal
zeitlinger Jun 21, 2024
2b0dc7f
move comment
zeitlinger Jun 21, 2024
2233737
updates
trask Jun 21, 2024
6a42292
Merge pull request #4 from trask/insrumentation-builder-factory
zeitlinger Jun 21, 2024
6736aa1
fix wrong refactor in groovy
zeitlinger Jun 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.api.incubator.builder.internal;

import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.context.propagation.TextMapSetter;
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientPeerServiceAttributesExtractor;
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpExperimentalAttributesExtractor;
import io.opentelemetry.instrumentation.api.incubator.semconv.net.PeerServiceResolver;
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder;
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter;
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanNameExtractorBuilder;
import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanStatusExtractor;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;

/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
* any time.
*/
public final class DefaultHttpClientTelemetryBuilder<REQUEST, RESPONSE> {

private final String instrumentationName;
private final OpenTelemetry openTelemetry;

private final List<AttributesExtractor<? super REQUEST, ? super RESPONSE>> additionalExtractors =
new ArrayList<>();
private final HttpClientAttributesExtractorBuilder<REQUEST, RESPONSE>
httpAttributesExtractorBuilder;
private final HttpClientAttributesGetter<REQUEST, RESPONSE> attributesGetter;
private final Optional<TextMapSetter<REQUEST>> headerSetter;
private final HttpSpanNameExtractorBuilder<REQUEST> httpSpanNameExtractorBuilder;
private Function<SpanNameExtractor<REQUEST>, ? extends SpanNameExtractor<? super REQUEST>>
spanNameExtractorTransformer = Function.identity();
private boolean emitExperimentalHttpClientMetrics = false;

public DefaultHttpClientTelemetryBuilder(
String instrumentationName,
OpenTelemetry openTelemetry,
HttpClientAttributesGetter<REQUEST, RESPONSE> attributesGetter,
Optional<TextMapSetter<REQUEST>> headerSetter) {
zeitlinger marked this conversation as resolved.
Show resolved Hide resolved
this.instrumentationName = instrumentationName;
this.openTelemetry = openTelemetry;
httpSpanNameExtractorBuilder = HttpSpanNameExtractor.builder(attributesGetter);
httpAttributesExtractorBuilder = HttpClientAttributesExtractor.builder(attributesGetter);
this.attributesGetter = attributesGetter;
this.headerSetter = headerSetter;
}

/**
* Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented
* items. The {@link AttributesExtractor} will be executed after all default extractors.
*/
@CanIgnoreReturnValue
public DefaultHttpClientTelemetryBuilder<REQUEST, RESPONSE> addAttributeExtractor(
AttributesExtractor<? super REQUEST, ? super RESPONSE> attributesExtractor) {
additionalExtractors.add(attributesExtractor);
return this;
}

/**
* Configures the HTTP request headers that will be captured as span attributes.
*
* @param requestHeaders A list of HTTP header names.
*/
@CanIgnoreReturnValue
public DefaultHttpClientTelemetryBuilder<REQUEST, RESPONSE> setCapturedRequestHeaders(
List<String> requestHeaders) {
httpAttributesExtractorBuilder.setCapturedRequestHeaders(requestHeaders);
return this;
}

/**
* Configures the HTTP response headers that will be captured as span attributes.
*
* @param responseHeaders A list of HTTP header names.
*/
@CanIgnoreReturnValue
public DefaultHttpClientTelemetryBuilder<REQUEST, RESPONSE> setCapturedResponseHeaders(
List<String> responseHeaders) {
httpAttributesExtractorBuilder.setCapturedResponseHeaders(responseHeaders);
return this;
}

/**
* Configures the instrumentation to recognize an alternative set of HTTP request methods.
*
* <p>By default, this instrumentation defines "known" methods as the ones listed in <a
* href="https://www.rfc-editor.org/rfc/rfc9110.html#name-methods">RFC9110</a> and the PATCH
* method defined in <a href="https://www.rfc-editor.org/rfc/rfc5789.html">RFC5789</a>.
*
* <p>Note: calling this method <b>overrides</b> the default known method sets completely; it does
* not supplement it.
*
* @param knownMethods A set of recognized HTTP request methods.
* @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set)
*/
@CanIgnoreReturnValue
public DefaultHttpClientTelemetryBuilder<REQUEST, RESPONSE> setKnownMethods(
Set<String> knownMethods) {
httpAttributesExtractorBuilder.setKnownMethods(knownMethods);
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods);
return this;
}

/**
* Configures the instrumentation to emit experimental HTTP client metrics.
*
* @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics
* are to be emitted.
*/
@CanIgnoreReturnValue
public DefaultHttpClientTelemetryBuilder<REQUEST, RESPONSE> setEmitExperimentalHttpClientMetrics(
boolean emitExperimentalHttpClientMetrics) {
this.emitExperimentalHttpClientMetrics = emitExperimentalHttpClientMetrics;
return this;
}

/** Sets custom {@link SpanNameExtractor} via transform function. */
@CanIgnoreReturnValue
public DefaultHttpClientTelemetryBuilder<REQUEST, RESPONSE> setSpanNameExtractor(
Function<SpanNameExtractor<REQUEST>, ? extends SpanNameExtractor<? super REQUEST>>
spanNameExtractorTransformer) {
this.spanNameExtractorTransformer = spanNameExtractorTransformer;
return this;
}

/** Sets custom {@link PeerServiceResolver}. */
@CanIgnoreReturnValue
public DefaultHttpClientTelemetryBuilder<REQUEST, RESPONSE> setPeerServiceResolver(
PeerServiceResolver peerServiceResolver) {
return addAttributeExtractor(
HttpClientPeerServiceAttributesExtractor.create(attributesGetter, peerServiceResolver));
}

public Instrumenter<REQUEST, RESPONSE> instrumenter() {
return instrumenter(b -> {});
}

public Instrumenter<REQUEST, RESPONSE> instrumenter(
Consumer<InstrumenterBuilder<REQUEST, RESPONSE>> instrumenterBuilderConsumer) {
SpanNameExtractor<? super REQUEST> spanNameExtractor =
spanNameExtractorTransformer.apply(httpSpanNameExtractorBuilder.build());

InstrumenterBuilder<REQUEST, RESPONSE> builder =
Instrumenter.<REQUEST, RESPONSE>builder(
openTelemetry, instrumentationName, spanNameExtractor)
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(attributesGetter))
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
.addAttributesExtractors(additionalExtractors)
.addOperationMetrics(HttpClientMetrics.get());
if (emitExperimentalHttpClientMetrics) {
builder
.addAttributesExtractor(HttpExperimentalAttributesExtractor.create(attributesGetter))
.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
instrumenterBuilderConsumer.accept(builder);

if (headerSetter.isPresent()) {
return builder.buildClientInstrumenter(headerSetter.get());
}
return builder.buildInstrumenter(SpanKindExtractor.alwaysClient());
}

public OpenTelemetry getOpenTelemetry() {
return openTelemetry;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,10 @@
import akka.http.scaladsl.model.HttpRequest;
import akka.http.scaladsl.model.HttpResponse;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientPeerServiceAttributesExtractor;
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpExperimentalAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanStatusExtractor;
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
import io.opentelemetry.javaagent.bootstrap.internal.JavaagentHttpClientInstrumenterBuilder;
import io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpUtil;
import java.util.Optional;

public class AkkaHttpClientSingletons {

Expand All @@ -28,31 +20,11 @@ public class AkkaHttpClientSingletons {

static {
SETTER = new HttpHeaderSetter(GlobalOpenTelemetry.getPropagators());
AkkaHttpClientAttributesGetter httpAttributesGetter = new AkkaHttpClientAttributesGetter();
InstrumenterBuilder<HttpRequest, HttpResponse> builder =
Instrumenter.<HttpRequest, HttpResponse>builder(
GlobalOpenTelemetry.get(),
AkkaHttpUtil.instrumentationName(),
HttpSpanNameExtractor.builder(httpAttributesGetter)
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
.build())
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(
HttpClientAttributesExtractor.builder(httpAttributesGetter)
.setCapturedRequestHeaders(CommonConfig.get().getClientRequestHeaders())
.setCapturedResponseHeaders(CommonConfig.get().getClientResponseHeaders())
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
.build())
.addAttributesExtractor(
HttpClientPeerServiceAttributesExtractor.create(
httpAttributesGetter, CommonConfig.get().getPeerServiceResolver()))
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientTelemetry()) {
builder
.addAttributesExtractor(HttpExperimentalAttributesExtractor.create(httpAttributesGetter))
.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildInstrumenter(SpanKindExtractor.alwaysClient());
INSTRUMENTER =
JavaagentHttpClientInstrumenterBuilder.create(
AkkaHttpUtil.instrumentationName(),
new AkkaHttpClientAttributesGetter(),
Optional.empty());
}

public static Instrumenter<HttpRequest, HttpResponse> instrumenter() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,9 @@

package io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient;

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientPeerServiceAttributesExtractor;
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpExperimentalAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanStatusExtractor;
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
import io.opentelemetry.javaagent.bootstrap.internal.JavaagentHttpClientInstrumenterBuilder;
import java.util.Optional;
import org.apache.http.HttpResponse;

public final class ApacheHttpAsyncClientSingletons {
Expand All @@ -24,33 +16,11 @@ public final class ApacheHttpAsyncClientSingletons {
private static final Instrumenter<ApacheHttpClientRequest, HttpResponse> INSTRUMENTER;

static {
ApacheHttpAsyncClientHttpAttributesGetter httpAttributesGetter =
new ApacheHttpAsyncClientHttpAttributesGetter();

InstrumenterBuilder<ApacheHttpClientRequest, HttpResponse> builder =
Instrumenter.<ApacheHttpClientRequest, HttpResponse>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
HttpSpanNameExtractor.builder(httpAttributesGetter)
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
.build())
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(
HttpClientAttributesExtractor.builder(httpAttributesGetter)
.setCapturedRequestHeaders(CommonConfig.get().getClientRequestHeaders())
.setCapturedResponseHeaders(CommonConfig.get().getClientResponseHeaders())
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
.build())
.addAttributesExtractor(
HttpClientPeerServiceAttributesExtractor.create(
httpAttributesGetter, CommonConfig.get().getPeerServiceResolver()))
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientTelemetry()) {
builder
.addAttributesExtractor(HttpExperimentalAttributesExtractor.create(httpAttributesGetter))
.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
INSTRUMENTER =
JavaagentHttpClientInstrumenterBuilder.create(
INSTRUMENTATION_NAME,
new ApacheHttpAsyncClientHttpAttributesGetter(),
Optional.of(HttpHeaderSetter.INSTANCE));
}

public static Instrumenter<ApacheHttpClientRequest, HttpResponse> instrumenter() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,9 @@

package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v2_0;

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientPeerServiceAttributesExtractor;
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpExperimentalAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanStatusExtractor;
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
import io.opentelemetry.javaagent.bootstrap.internal.JavaagentHttpClientInstrumenterBuilder;
import java.util.Optional;
import org.apache.commons.httpclient.HttpMethod;

public final class ApacheHttpClientSingletons {
Expand All @@ -24,33 +16,11 @@ public final class ApacheHttpClientSingletons {
private static final Instrumenter<HttpMethod, HttpMethod> INSTRUMENTER;

static {
ApacheHttpClientHttpAttributesGetter httpAttributesGetter =
new ApacheHttpClientHttpAttributesGetter();

InstrumenterBuilder<HttpMethod, HttpMethod> builder =
Instrumenter.<HttpMethod, HttpMethod>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
HttpSpanNameExtractor.builder(httpAttributesGetter)
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
.build())
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(
HttpClientAttributesExtractor.builder(httpAttributesGetter)
.setCapturedRequestHeaders(CommonConfig.get().getClientRequestHeaders())
.setCapturedResponseHeaders(CommonConfig.get().getClientResponseHeaders())
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
.build())
.addAttributesExtractor(
HttpClientPeerServiceAttributesExtractor.create(
httpAttributesGetter, CommonConfig.get().getPeerServiceResolver()))
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientTelemetry()) {
builder
.addAttributesExtractor(HttpExperimentalAttributesExtractor.create(httpAttributesGetter))
.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
INSTRUMENTER =
JavaagentHttpClientInstrumenterBuilder.create(
INSTRUMENTATION_NAME,
new ApacheHttpClientHttpAttributesGetter(),
Optional.of(HttpHeaderSetter.INSTANCE));
}

public static Instrumenter<HttpMethod, HttpMethod> instrumenter() {
Expand Down
Loading
Loading