|
8 | 8 | import com.google.errorprone.annotations.CanIgnoreReturnValue; |
9 | 9 | import io.opentelemetry.api.OpenTelemetry; |
10 | 10 | import io.opentelemetry.context.propagation.TextMapSetter; |
| 11 | +import io.opentelemetry.instrumentation.api.incubator.config.internal.CoreCommonConfig; |
11 | 12 | import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientExperimentalMetrics; |
12 | 13 | import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientPeerServiceAttributesExtractor; |
13 | 14 | import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpExperimentalAttributesExtractor; |
|
24 | 25 | import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanNameExtractor; |
25 | 26 | import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanNameExtractorBuilder; |
26 | 27 | import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanStatusExtractor; |
| 28 | +import java.lang.reflect.Field; |
27 | 29 | import java.util.ArrayList; |
28 | 30 | import java.util.List; |
29 | 31 | import java.util.Set; |
30 | 32 | import java.util.function.Consumer; |
31 | 33 | import java.util.function.Function; |
| 34 | +import java.util.function.Supplier; |
32 | 35 | import javax.annotation.Nullable; |
33 | 36 |
|
34 | 37 | /** |
@@ -192,4 +195,45 @@ public Instrumenter<REQUEST, RESPONSE> build() { |
192 | 195 | public OpenTelemetry getOpenTelemetry() { |
193 | 196 | return openTelemetry; |
194 | 197 | } |
| 198 | + |
| 199 | + public static <REQUEST, RESPONSE> |
| 200 | + DefaultHttpClientInstrumenterBuilder<REQUEST, RESPONSE> unwrapAndConfigure( |
| 201 | + CoreCommonConfig config, Object builder) { |
| 202 | + DefaultHttpClientInstrumenterBuilder<REQUEST, RESPONSE> defaultBuilder = unwrapBuilder(builder); |
| 203 | + set(config::getKnownHttpRequestMethods, defaultBuilder::setKnownMethods); |
| 204 | + set(config::getClientRequestHeaders, defaultBuilder::setCapturedRequestHeaders); |
| 205 | + set(config::getClientResponseHeaders, defaultBuilder::setCapturedResponseHeaders); |
| 206 | + set(config::getPeerServiceResolver, defaultBuilder::setPeerServiceResolver); |
| 207 | + set( |
| 208 | + config::shouldEmitExperimentalHttpClientTelemetry, |
| 209 | + defaultBuilder::setEmitExperimentalHttpClientMetrics); |
| 210 | + return defaultBuilder; |
| 211 | + } |
| 212 | + |
| 213 | + private static <T> void set(Supplier<T> supplier, Consumer<T> consumer) { |
| 214 | + T t = supplier.get(); |
| 215 | + if (t != null) { |
| 216 | + consumer.accept(t); |
| 217 | + } |
| 218 | + } |
| 219 | + |
| 220 | + /** |
| 221 | + * This method is used to access the builder field of the builder object. |
| 222 | + * |
| 223 | + * <p>This approach allows us to re-use the existing builder classes from the library modules |
| 224 | + */ |
| 225 | + @SuppressWarnings("unchecked") |
| 226 | + private static <REQUEST, RESPONSE> |
| 227 | + DefaultHttpClientInstrumenterBuilder<REQUEST, RESPONSE> unwrapBuilder(Object builder) { |
| 228 | + if (builder instanceof DefaultHttpClientInstrumenterBuilder<?, ?>) { |
| 229 | + return (DefaultHttpClientInstrumenterBuilder<REQUEST, RESPONSE>) builder; |
| 230 | + } |
| 231 | + try { |
| 232 | + Field field = builder.getClass().getDeclaredField("builder"); |
| 233 | + field.setAccessible(true); |
| 234 | + return (DefaultHttpClientInstrumenterBuilder<REQUEST, RESPONSE>) field.get(builder); |
| 235 | + } catch (Exception e) { |
| 236 | + throw new IllegalStateException("Could not access builder field", e); |
| 237 | + } |
| 238 | + } |
195 | 239 | } |
0 commit comments