diff --git a/sdk/clientcore/core/checkstyle-suppressions.xml b/sdk/clientcore/core/checkstyle-suppressions.xml index 88e7a72d28fef..b3fa405e097c8 100644 --- a/sdk/clientcore/core/checkstyle-suppressions.xml +++ b/sdk/clientcore/core/checkstyle-suppressions.xml @@ -24,7 +24,6 @@ - diff --git a/sdk/clientcore/core/spotbugs-exclude.xml b/sdk/clientcore/core/spotbugs-exclude.xml index a94ed75f922db..b12b08fde6878 100644 --- a/sdk/clientcore/core/spotbugs-exclude.xml +++ b/sdk/clientcore/core/spotbugs-exclude.xml @@ -79,10 +79,6 @@ - - - - diff --git a/sdk/clientcore/core/src/main/java/io/clientcore/core/http/models/HttpInstrumentationOptions.java b/sdk/clientcore/core/src/main/java/io/clientcore/core/http/models/HttpInstrumentationOptions.java new file mode 100644 index 0000000000000..5eb41ed2ef4f8 --- /dev/null +++ b/sdk/clientcore/core/src/main/java/io/clientcore/core/http/models/HttpInstrumentationOptions.java @@ -0,0 +1,341 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package io.clientcore.core.http.models; + +import io.clientcore.core.instrumentation.InstrumentationOptions; +import io.clientcore.core.util.configuration.Configuration; +import io.clientcore.core.util.configuration.ConfigurationProperty; +import io.clientcore.core.util.configuration.ConfigurationPropertyBuilder; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Configuration options for HTTP instrumentation. + *

+ * The instrumentation emits distributed traces following OpenTelemetry HTTP semantic conventions + * and, when enabled, detailed HTTP logs. + *

+ * The following information is recorded on distributed traces: + *

    + *
  • Request method, URI. The URI is sanitized based on allowed query parameters configurable with {@link #setAllowedQueryParamNames(Set)} and {@link #addAllowedQueryParamName(String)}
  • + *
  • Response status code
  • + *
  • Error details if the request fails
  • + *
  • Time it takes to receive response
  • + *
  • Correlation identifiers
  • + *
+ * + The following information is recorded on detailed HTTP logs: + *
    + *
  • Request method, URI, and body size. URI is sanitized based on allowed query parameters configurable with {@link #setAllowedQueryParamNames(Set)} and {@link #addAllowedQueryParamName(String)}
  • + *
  • Response status code and body size
  • + *
  • Request and response headers from allow-list configured via {@link #setAllowedHeaderNames(Set)} and {@link #addAllowedHeaderName(HttpHeaderName)}.
  • + *
  • Error details if the request fails
  • + *
  • Time it takes to receive response
  • + *
  • Correlation identifiers
  • + *
  • When content logging is enabled via {@link HttpLogDetailLevel#BODY_AND_HEADERS}: request and response body, and time-to-last-byte
  • + *
+ * + * Client libraries auto-discover global OpenTelemetry SDK instance configured by the java agent or + * in the application code. Just create a client instance as usual as shown in the following code snippet: + * + *

Clients auto-discover global OpenTelemetry

+ * + * + *
+ *
+ * AutoConfiguredOpenTelemetrySdk.initialize();
+ *
+ * SampleClient client = new SampleClientBuilder().build();
+ *
+ * // this call will be traced using OpenTelemetry SDK initialized globally
+ * client.clientCall();
+ *
+ * 
+ * + *

+ * + * Alternatively, application developers can pass OpenTelemetry SDK instance explicitly to the client libraries. + * + *

Pass configured OpenTelemetry instance explicitly

+ * + * + *
+ *
+ * OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk();
+ * HttpInstrumentationOptions instrumentationOptions = new HttpInstrumentationOptions()
+ *     .setTelemetryProvider(openTelemetry);
+ *
+ * SampleClient client = new SampleClientBuilder().instrumentationOptions(instrumentationOptions).build();
+ *
+ * // this call will be traced using OpenTelemetry SDK provided explicitly
+ * client.clientCall();
+ *
+ * 
+ * + */ +public final class HttpInstrumentationOptions extends InstrumentationOptions { + private HttpLogDetailLevel logDetailLevel; + private boolean isRedactedHeaderNamesLoggingEnabled; + private Set allowedHeaderNames; + private Set allowedQueryParamNames; + private static final List DEFAULT_HEADERS_ALLOWLIST + = Arrays.asList(HttpHeaderName.TRACEPARENT, HttpHeaderName.ACCEPT, HttpHeaderName.CACHE_CONTROL, + HttpHeaderName.CONNECTION, HttpHeaderName.CONTENT_LENGTH, HttpHeaderName.CONTENT_TYPE, HttpHeaderName.DATE, + HttpHeaderName.ETAG, HttpHeaderName.EXPIRES, HttpHeaderName.IF_MATCH, HttpHeaderName.IF_MODIFIED_SINCE, + HttpHeaderName.IF_NONE_MATCH, HttpHeaderName.IF_UNMODIFIED_SINCE, HttpHeaderName.LAST_MODIFIED, + HttpHeaderName.PRAGMA, HttpHeaderName.RETRY_AFTER, HttpHeaderName.SERVER, HttpHeaderName.TRANSFER_ENCODING, + HttpHeaderName.USER_AGENT, HttpHeaderName.WWW_AUTHENTICATE); + + static final HttpLogDetailLevel ENVIRONMENT_HTTP_LOG_DETAIL_LEVEL + = HttpLogDetailLevel.fromConfiguration(Configuration.getGlobalConfiguration()); + private static final List DEFAULT_QUERY_PARAMS_ALLOWLIST = Collections.singletonList("api-version"); + + /** + * Creates a new instance using default options: + *
    + *
  • Detailed HTTP logging is disabled.
  • + *
  • Distributed tracing is enabled.
  • + *
+ */ + public HttpInstrumentationOptions() { + super(); + logDetailLevel = ENVIRONMENT_HTTP_LOG_DETAIL_LEVEL; + isRedactedHeaderNamesLoggingEnabled = true; + allowedHeaderNames = new HashSet<>(DEFAULT_HEADERS_ALLOWLIST); + allowedQueryParamNames = new HashSet<>(DEFAULT_QUERY_PARAMS_ALLOWLIST); + } + + /** + * Gets the level of detail for HTTP request logs. Default is {@link HttpLogDetailLevel#NONE}. + *

+ * When HTTP logging is disabled, basic information about the request and response is still recorded + * on distributed tracing spans. + * + * @return The {@link HttpLogDetailLevel}. + */ + public HttpLogDetailLevel getHttpLogLevel() { + return logDetailLevel; + } + + /** + * Flag indicating whether HTTP request and response header values are added to the logs + * when their name is not explicitly allowed via {@link HttpInstrumentationOptions#setAllowedHeaderNames(Set)} or + * {@link HttpInstrumentationOptions#addAllowedHeaderName(HttpHeaderName)}. + * True by default. + * + * @return True if redacted header names logging is enabled, false otherwise. + */ + public boolean isRedactedHeaderNamesLoggingEnabled() { + return isRedactedHeaderNamesLoggingEnabled; + } + + /** + * Enables or disables logging of redacted header names. + * @param redactedHeaderNamesLoggingEnabled True to enable logging of redacted header names, false otherwise. + * Default is true. + * @return The updated {@link HttpInstrumentationOptions} object. + */ + public HttpInstrumentationOptions setRedactedHeaderNamesLoggingEnabled(boolean redactedHeaderNamesLoggingEnabled) { + isRedactedHeaderNamesLoggingEnabled = redactedHeaderNamesLoggingEnabled; + return this; + } + + /** + * Sets the level of detail for HTTP request logs. + * Default is {@link HttpLogDetailLevel#NONE}. + * + * @param logDetailLevel The {@link HttpLogDetailLevel}. + * + * @return The updated {@link HttpInstrumentationOptions} object. + */ + public HttpInstrumentationOptions setHttpLogLevel(HttpLogDetailLevel logDetailLevel) { + this.logDetailLevel = logDetailLevel; + return this; + } + + /** + * Gets the allowed headers that should be logged when they appear on the request or response. + * + * @return The list of allowed headers. + */ + public Set getAllowedHeaderNames() { + return Collections.unmodifiableSet(allowedHeaderNames); + } + + /** + * Sets the given allowed headers that should be logged. + * Note: headers are not recorded on traces. + * + *

+ * This method sets the provided header names to be the allowed header names which will be logged for all HTTP + * requests and responses, overwriting any previously configured headers. Additionally, users can use + * {@link HttpInstrumentationOptions#addAllowedHeaderName(HttpHeaderName)} or {@link HttpInstrumentationOptions#getAllowedHeaderNames()} to add or + * remove more headers names to the existing set of allowed header names. + *

+ * + * @param allowedHeaderNames The list of allowed header names from the user. + * + * @return The updated HttpLogOptions object. + */ + public HttpInstrumentationOptions setAllowedHeaderNames(final Set allowedHeaderNames) { + this.allowedHeaderNames = allowedHeaderNames == null ? new HashSet<>() : new HashSet<>(allowedHeaderNames); + + return this; + } + + /** + * Sets the given allowed header to the default header set that should be logged when they appear on the request or response. + *

+ * Note: headers are not recorded on traces. + * + * @param allowedHeaderName The allowed header name from the user. + * + * @return The updated HttpLogOptions object. + * + * @throws NullPointerException If {@code allowedHeaderName} is {@code null}. + */ + public HttpInstrumentationOptions addAllowedHeaderName(final HttpHeaderName allowedHeaderName) { + Objects.requireNonNull(allowedHeaderName); + this.allowedHeaderNames.add(allowedHeaderName); + + return this; + } + + /** + * Gets the allowed query parameters. + * + * @return The list of allowed query parameters. + */ + public Set getAllowedQueryParamNames() { + return Collections.unmodifiableSet(allowedQueryParamNames); + } + + /** + * Sets the given allowed query params to be recorded on logs and traces. + * + * @param allowedQueryParamNames The list of allowed query params from the user. + * + * @return The updated {@code allowedQueryParamName} object. + */ + public HttpInstrumentationOptions setAllowedQueryParamNames(final Set allowedQueryParamNames) { + this.allowedQueryParamNames + = allowedQueryParamNames == null ? new HashSet<>() : new HashSet<>(allowedQueryParamNames); + + return this; + } + + /** + * Sets the given allowed query param that can be recorded on logs and traces. + * + * @param allowedQueryParamName The allowed query param name from the user. + * + * @return The updated {@link HttpInstrumentationOptions} object. + * + * @throws NullPointerException If {@code allowedQueryParamName} is {@code null}. + */ + public HttpInstrumentationOptions addAllowedQueryParamName(final String allowedQueryParamName) { + this.allowedQueryParamNames.add(allowedQueryParamName); + return this; + } + + @Override + public HttpInstrumentationOptions setTracingEnabled(boolean isTracingEnabled) { + super.setTracingEnabled(isTracingEnabled); + return this; + } + + @Override + public HttpInstrumentationOptions setTelemetryProvider(Object telemetryProvider) { + super.setTelemetryProvider(telemetryProvider); + return this; + } + + /** + * The level of detail for HTTP request logs. + */ + public enum HttpLogDetailLevel { + /** + * HTTP logging is turned off. + */ + NONE, + + /** + * Enables logging the following information on detailed HTTP logs + *

    + *
  • Request method, URI, and body size. URI is sanitized based on allowed query parameters configurable with {@link #setAllowedQueryParamNames(Set)} and {@link #addAllowedQueryParamName(String)}
  • + *
  • Response status code and body size
  • + *
  • Request and response headers from allow-list configured via {@link #setAllowedHeaderNames(Set)} and {@link #addAllowedHeaderName(HttpHeaderName)}.
  • + *
  • Error details if the request fails
  • + *
  • Time it takes to receive response
  • + *
  • Correlation identifiers
  • + *
+ */ + HEADERS, + + /** + * Enables logging the following information on detailed HTTP logs + *
    + *
  • Request method, URI, and body size. URI is sanitized based on allowed query parameters configurable with {@link #setAllowedQueryParamNames(Set)} and {@link #addAllowedQueryParamName(String)}
  • + *
  • Response status code and body size
  • + *
  • Error details if the request fails
  • + *
  • Time it takes to receive response
  • + *
  • Correlation identifiers
  • + *
  • Request and response bodies
  • + *
  • Time-to-last-byte
  • + *
+ * + *

+ * The request and response body will be buffered into memory even if it is never consumed by an application, possibly impacting + * performance. + *

+ * Body is not logged (and not buffered) for requests and responses where the content length is not known or greater than 16KB. + */ + BODY, + + /** + * Enables logging everything in {@link #HEADERS} and {@link #BODY}. + * + *

+ * The request and response body will be buffered into memory even if it is never consumed by an application, possibly impacting + * performance. + *

+ * Body is not logged (and not buffered) for requests and responses where the content length is not known or greater than 16KB. + */ + BODY_AND_HEADERS; + + private static final String HEADERS_VALUE = "headers"; + private static final String BODY_VALUE = "body"; + private static final String BODY_AND_HEADERS_VALUE = "body_and_headers"; + + private static final ConfigurationProperty HTTP_LOG_DETAIL_LEVEL + = ConfigurationPropertyBuilder.ofString("http.log.detail.level") + .shared(true) + .environmentVariableName(Configuration.PROPERTY_HTTP_LOG_DETAIL_LEVEL) + .defaultValue("none") + .build(); + + static HttpLogDetailLevel fromConfiguration(Configuration configuration) { + String detailLevel = configuration.get(HTTP_LOG_DETAIL_LEVEL); + + HttpLogDetailLevel logDetailLevel; + + if (HEADERS_VALUE.equalsIgnoreCase(detailLevel)) { + logDetailLevel = HEADERS; + } else if (BODY_VALUE.equalsIgnoreCase(detailLevel)) { + logDetailLevel = BODY; + } else if (BODY_AND_HEADERS_VALUE.equalsIgnoreCase(detailLevel)) { + logDetailLevel = BODY_AND_HEADERS; + } else { + logDetailLevel = NONE; + } + + return logDetailLevel; + } + } +} diff --git a/sdk/clientcore/core/src/main/java/io/clientcore/core/http/models/HttpLogOptions.java b/sdk/clientcore/core/src/main/java/io/clientcore/core/http/models/HttpLogOptions.java deleted file mode 100644 index 1814586f3779d..0000000000000 --- a/sdk/clientcore/core/src/main/java/io/clientcore/core/http/models/HttpLogOptions.java +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package io.clientcore.core.http.models; - -import io.clientcore.core.util.configuration.Configuration; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import static io.clientcore.core.util.configuration.Configuration.getGlobalConfiguration; - -/** - * The log configurations for HTTP messages. - */ -public final class HttpLogOptions { - private HttpLogDetailLevel logLevel; - private Set allowedHeaderNames; - private Set allowedQueryParamNames; - private static final List DEFAULT_HEADERS_ALLOWLIST - = Arrays.asList(HttpHeaderName.TRACEPARENT, HttpHeaderName.ACCEPT, HttpHeaderName.CACHE_CONTROL, - HttpHeaderName.CONNECTION, HttpHeaderName.CONTENT_LENGTH, HttpHeaderName.CONTENT_TYPE, HttpHeaderName.DATE, - HttpHeaderName.ETAG, HttpHeaderName.EXPIRES, HttpHeaderName.IF_MATCH, HttpHeaderName.IF_MODIFIED_SINCE, - HttpHeaderName.IF_NONE_MATCH, HttpHeaderName.IF_UNMODIFIED_SINCE, HttpHeaderName.LAST_MODIFIED, - HttpHeaderName.PRAGMA, HttpHeaderName.RETRY_AFTER, HttpHeaderName.SERVER, HttpHeaderName.TRANSFER_ENCODING, - HttpHeaderName.USER_AGENT, HttpHeaderName.WWW_AUTHENTICATE); - - private static final List DEFAULT_QUERY_PARAMS_ALLOWLIST = Collections.singletonList("api-version"); - - /** - * Creates a new instance that does not log any information about HTTP requests or responses. - */ - public HttpLogOptions() { - logLevel = HttpLogDetailLevel.ENVIRONMENT_HTTP_LOG_DETAIL_LEVEL; - allowedHeaderNames = new HashSet<>(DEFAULT_HEADERS_ALLOWLIST); - allowedQueryParamNames = new HashSet<>(DEFAULT_QUERY_PARAMS_ALLOWLIST); - } - - /** - * Gets the level of detail to log on HTTP messages. - * - * @return The {@link HttpLogDetailLevel}. - */ - public HttpLogDetailLevel getLogLevel() { - return logLevel; - } - - /** - * Sets the level of detail to log on Http messages. - * - *

If logLevel is not provided, default value of {@link HttpLogDetailLevel#NONE} is set.

- * - * @param logLevel The {@link HttpLogDetailLevel}. - * - * @return The updated HttpLogOptions object. - */ - public HttpLogOptions setLogLevel(final HttpLogDetailLevel logLevel) { - this.logLevel = logLevel == null ? HttpLogDetailLevel.NONE : logLevel; - - return this; - } - - /** - * Gets the allowed headers that should be logged. - * - * @return The list of allowed headers. - */ - public Set getAllowedHeaderNames() { - return Collections.unmodifiableSet(allowedHeaderNames); - } - - /** - * Sets the given allowed headers that should be logged. - * - *

- * This method sets the provided header names to be the allowed header names which will be logged for all HTTP - * requests and responses, overwriting any previously configured headers. Additionally, users can use - * {@link HttpLogOptions#addAllowedHeaderName(HttpHeaderName)} or {@link HttpLogOptions#getAllowedHeaderNames()} to add or - * remove more headers names to the existing set of allowed header names. - *

- * - * @param allowedHeaderNames The list of allowed header names from the user. - * - * @return The updated HttpLogOptions object. - */ - public HttpLogOptions setAllowedHeaderNames(final Set allowedHeaderNames) { - this.allowedHeaderNames = allowedHeaderNames == null ? new HashSet<>() : allowedHeaderNames; - - return this; - } - - /** - * Sets the given allowed header to the default header set that should be logged. - * - * @param allowedHeaderName The allowed header name from the user. - * - * @return The updated HttpLogOptions object. - * - * @throws NullPointerException If {@code allowedHeaderName} is {@code null}. - */ - public HttpLogOptions addAllowedHeaderName(final HttpHeaderName allowedHeaderName) { - Objects.requireNonNull(allowedHeaderName); - this.allowedHeaderNames.add(allowedHeaderName); - - return this; - } - - /** - * Gets the allowed query parameters. - * - * @return The list of allowed query parameters. - */ - public Set getAllowedQueryParamNames() { - return Collections.unmodifiableSet(allowedQueryParamNames); - } - - /** - * Sets the given allowed query params to be displayed in the logging info. - * - * @param allowedQueryParamNames The list of allowed query params from the user. - * - * @return The updated HttpLogOptions object. - */ - public HttpLogOptions setAllowedQueryParamNames(final Set allowedQueryParamNames) { - this.allowedQueryParamNames = allowedQueryParamNames == null ? new HashSet<>() : allowedQueryParamNames; - - return this; - } - - /** - * Sets the given allowed query param that should be logged. - * - * @param allowedQueryParamName The allowed query param name from the user. - * - * @return The updated HttpLogOptions object. - * - * @throws NullPointerException If {@code allowedQueryParamName} is {@code null}. - */ - public HttpLogOptions addAllowedQueryParamName(final String allowedQueryParamName) { - this.allowedQueryParamNames.add(allowedQueryParamName); - return this; - } - - /** - * The level of detail to log on HTTP messages. - */ - public enum HttpLogDetailLevel { - /** - * Logging is turned off. - */ - NONE, - - /** - * Logs only URIs, HTTP methods, and time to finish the request. - */ - BASIC, - - /** - * Logs everything in BASIC, plus all allowed request and response headers. - */ - HEADERS, - - /** - * Logs everything in BASIC, plus all the request and response body. Note that only payloads in plain text or - * plain text encoded in GZIP will be logged. - */ - BODY, - - /** - * Logs everything in HEADERS and BODY. - */ - BODY_AND_HEADERS; - - static final String BASIC_VALUE = "basic"; - static final String HEADERS_VALUE = "headers"; - static final String BODY_VALUE = "body"; - static final String BODY_AND_HEADERS_VALUE = "body_and_headers"; - static final String BODYANDHEADERS_VALUE = "bodyandheaders"; - static final HttpLogDetailLevel ENVIRONMENT_HTTP_LOG_DETAIL_LEVEL = fromConfiguration(getGlobalConfiguration()); - - static HttpLogDetailLevel fromConfiguration(Configuration configuration) { - String detailLevel = configuration.get(Configuration.PROPERTY_HTTP_LOG_DETAIL_LEVEL, "none"); - - HttpLogDetailLevel logDetailLevel; - - if (BASIC_VALUE.equalsIgnoreCase(detailLevel)) { - logDetailLevel = BASIC; - } else if (HEADERS_VALUE.equalsIgnoreCase(detailLevel)) { - logDetailLevel = HEADERS; - } else if (BODY_VALUE.equalsIgnoreCase(detailLevel)) { - logDetailLevel = BODY; - } else if (BODY_AND_HEADERS_VALUE.equalsIgnoreCase(detailLevel) - || BODYANDHEADERS_VALUE.equalsIgnoreCase(detailLevel)) { - - logDetailLevel = BODY_AND_HEADERS; - } else { - logDetailLevel = NONE; - } - - return logDetailLevel; - } - - /** - * Whether a URI should be logged. - * - * @return Whether a URI should be logged. - */ - public boolean shouldLogUri() { - return this != NONE; - } - - /** - * Whether headers should be logged. - * - * @return Whether headers should be logged. - */ - public boolean shouldLogHeaders() { - return this == HEADERS || this == BODY_AND_HEADERS; - } - - /** - * Whether a body should be logged. - * - * @return Whether a body should be logged. - */ - public boolean shouldLogBody() { - return this == BODY || this == BODY_AND_HEADERS; - } - } -} diff --git a/sdk/clientcore/core/src/main/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicy.java b/sdk/clientcore/core/src/main/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicy.java index 679d30246ee7a..40f0d7e7ea4e0 100644 --- a/sdk/clientcore/core/src/main/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicy.java +++ b/sdk/clientcore/core/src/main/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicy.java @@ -6,7 +6,7 @@ import io.clientcore.core.http.models.HttpHeader; import io.clientcore.core.http.models.HttpHeaderName; import io.clientcore.core.http.models.HttpHeaders; -import io.clientcore.core.http.models.HttpLogOptions; +import io.clientcore.core.http.models.HttpInstrumentationOptions; import io.clientcore.core.http.models.HttpRequest; import io.clientcore.core.http.models.HttpResponse; import io.clientcore.core.http.models.RequestOptions; @@ -16,7 +16,6 @@ import io.clientcore.core.instrumentation.Instrumentation; import io.clientcore.core.instrumentation.InstrumentationContext; import io.clientcore.core.instrumentation.LibraryInstrumentationOptions; -import io.clientcore.core.instrumentation.InstrumentationOptions; import io.clientcore.core.instrumentation.tracing.SpanBuilder; import io.clientcore.core.instrumentation.tracing.TracingScope; import io.clientcore.core.instrumentation.tracing.Span; @@ -69,7 +68,7 @@ * {@link HttpRetryPolicy} and {@link HttpRedirectPolicy} so that it's executed on each try or redirect and logging happens * in the scope of the span. *

- * The policy supports basic customizations using {@link InstrumentationOptions} and {@link HttpLogOptions}. + * The policy supports basic customizations using {@link HttpInstrumentationOptions}. *

* If your client library needs a different approach to distributed tracing, * you can create a custom policy and use it instead of the {@link HttpInstrumentationPolicy}. If you want to enrich instrumentation @@ -83,7 +82,7 @@ * HttpPipeline pipeline = new HttpPipelineBuilder() * .policies( * new HttpRetryPolicy(), - * new HttpInstrumentationPolicy(instrumentationOptions, logOptions)) + * new HttpInstrumentationPolicy(instrumentationOptions)) * .build(); * * @@ -95,13 +94,13 @@ * * // You can configure URL sanitization to include additional query parameters to preserve * // in `url.full` attribute. - * HttpLogOptions logOptions = new HttpLogOptions(); - * logOptions.addAllowedQueryParamName("documentId"); + * HttpInstrumentationOptions instrumentationOptions = new HttpInstrumentationOptions(); + * instrumentationOptions.addAllowedQueryParamName("documentId"); * * HttpPipeline pipeline = new HttpPipelineBuilder() * .policies( * new HttpRetryPolicy(), - * new HttpInstrumentationPolicy(instrumentationOptions, logOptions)) + * new HttpInstrumentationPolicy(instrumentationOptions)) * .build(); * * @@ -125,7 +124,7 @@ * HttpPipeline pipeline = new HttpPipelineBuilder() * .policies( * new HttpRetryPolicy(), - * new HttpInstrumentationPolicy(instrumentationOptions, logOptions), + * new HttpInstrumentationPolicy(instrumentationOptions), * enrichingPolicy) * .build(); * @@ -136,7 +135,7 @@ */ public final class HttpInstrumentationPolicy implements HttpPipelinePolicy { private static final ClientLogger LOGGER = new ClientLogger(HttpInstrumentationPolicy.class); - private static final HttpLogOptions DEFAULT_LOG_OPTIONS = new HttpLogOptions(); + private static final HttpInstrumentationOptions DEFAULT_OPTIONS = new HttpInstrumentationOptions(); private static final String LIBRARY_NAME; private static final String LIBRARY_VERSION; private static final LibraryInstrumentationOptions LIBRARY_OPTIONS; @@ -170,23 +169,29 @@ public final class HttpInstrumentationPolicy implements HttpPipelinePolicy { private final Tracer tracer; private final TraceContextPropagator traceContextPropagator; private final Set allowedQueryParameterNames; - private final HttpLogOptions.HttpLogDetailLevel httpLogDetailLevel; private final Set allowedHeaderNames; + private final boolean isLoggingEnabled; + private final boolean isContentLoggingEnabled; + private final boolean isRedactedHeadersLoggingEnabled; /** * Creates a new instrumentation policy. * @param instrumentationOptions Application telemetry options. - * @param logOptions Http log options. TODO: we should merge this with telemetry options. */ - public HttpInstrumentationPolicy(InstrumentationOptions instrumentationOptions, HttpLogOptions logOptions) { + public HttpInstrumentationPolicy(HttpInstrumentationOptions instrumentationOptions) { Instrumentation instrumentation = Instrumentation.create(instrumentationOptions, LIBRARY_OPTIONS); this.tracer = instrumentation.getTracer(); this.traceContextPropagator = instrumentation.getW3CTraceContextPropagator(); - HttpLogOptions logOptionsToUse = logOptions == null ? DEFAULT_LOG_OPTIONS : logOptions; - this.httpLogDetailLevel = logOptionsToUse.getLogLevel(); - this.allowedHeaderNames = logOptionsToUse.getAllowedHeaderNames(); - this.allowedQueryParameterNames = logOptionsToUse.getAllowedQueryParamNames() + HttpInstrumentationOptions optionsToUse + = instrumentationOptions == null ? DEFAULT_OPTIONS : instrumentationOptions; + this.isLoggingEnabled = optionsToUse.getHttpLogLevel() != HttpInstrumentationOptions.HttpLogDetailLevel.NONE; + this.isContentLoggingEnabled + = optionsToUse.getHttpLogLevel() == HttpInstrumentationOptions.HttpLogDetailLevel.BODY + || optionsToUse.getHttpLogLevel() == HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS; + this.isRedactedHeadersLoggingEnabled = optionsToUse.isRedactedHeaderNamesLoggingEnabled(); + this.allowedHeaderNames = optionsToUse.getAllowedHeaderNames(); + this.allowedQueryParameterNames = optionsToUse.getAllowedQueryParamNames() .stream() .map(queryParamName -> queryParamName.toLowerCase(Locale.ROOT)) .collect(Collectors.toSet()); @@ -199,7 +204,7 @@ public HttpInstrumentationPolicy(InstrumentationOptions instrumentationOption @Override public Response process(HttpRequest request, HttpPipelineNextPolicy next) { boolean isTracingEnabled = tracer.isEnabled(); - if (!isTracingEnabled && httpLogDetailLevel == HttpLogOptions.HttpLogDetailLevel.NONE) { + if (!isTracingEnabled && !isLoggingEnabled) { return next.process(); } @@ -355,7 +360,7 @@ private static Map getProperties(String propertiesFileName) { private void logRequest(ClientLogger logger, HttpRequest request, long startNanoTime, long requestContentLength, String redactedUrl, int tryCount, InstrumentationContext context) { ClientLogger.LoggingEvent logBuilder = logger.atLevel(HTTP_REQUEST_LOG_LEVEL); - if (!logBuilder.isEnabled() || httpLogDetailLevel == HttpLogOptions.HttpLogDetailLevel.NONE) { + if (!logBuilder.isEnabled() || !isLoggingEnabled) { return; } @@ -368,7 +373,7 @@ private void logRequest(ClientLogger logger, HttpRequest request, long startNano addHeadersToLogMessage(request.getHeaders(), logBuilder); - if (httpLogDetailLevel.shouldLogBody() && canLogBody(request.getBody())) { + if (isContentLoggingEnabled && canLogBody(request.getBody())) { try { BinaryData bufferedBody = request.getBody().toReplayableBinaryData(); request.setBody(bufferedBody); @@ -386,7 +391,7 @@ private void logRequest(ClientLogger logger, HttpRequest request, long startNano private Response logResponse(ClientLogger logger, Response response, long startNanoTime, long requestContentLength, String redactedUrl, int tryCount, InstrumentationContext context) { ClientLogger.LoggingEvent logBuilder = logger.atLevel(HTTP_RESPONSE_LOG_LEVEL); - if (httpLogDetailLevel == HttpLogOptions.HttpLogDetailLevel.NONE) { + if (!isLoggingEnabled) { return response; } @@ -408,7 +413,7 @@ private Response logResponse(ClientLogger logger, Response response, long addHeadersToLogMessage(response.getHeaders(), logBuilder); } - if (httpLogDetailLevel.shouldLogBody() && canLogBody(response.getBody())) { + if (isContentLoggingEnabled && canLogBody(response.getBody())) { return new LoggingHttpResponse<>(response, content -> { if (logBuilder.isEnabled()) { logBuilder.addKeyValue(HTTP_RESPONSE_BODY_CONTENT_KEY, content.toString()) @@ -431,7 +436,7 @@ private T logException(ClientLogger logger, HttpRequest re int tryCount, InstrumentationContext context) { ClientLogger.LoggingEvent log = logger.atLevel(ClientLogger.LogLevel.WARNING); - if (!log.isEnabled() || httpLogDetailLevel == HttpLogOptions.HttpLogDetailLevel.NONE) { + if (!log.isEnabled() || !isLoggingEnabled) { return throwable; } @@ -484,11 +489,12 @@ private static boolean canLogBody(BinaryData data) { * @param logBuilder Log message builder. */ private void addHeadersToLogMessage(HttpHeaders headers, ClientLogger.LoggingEvent logBuilder) { - if (httpLogDetailLevel.shouldLogHeaders()) { - for (HttpHeader header : headers) { - HttpHeaderName headerName = header.getName(); - String headerValue = allowedHeaderNames.contains(headerName) ? header.getValue() : REDACTED_PLACEHOLDER; - logBuilder.addKeyValue(headerName.toString(), headerValue); + for (HttpHeader header : headers) { + HttpHeaderName headerName = header.getName(); + if (allowedHeaderNames.contains(headerName)) { + logBuilder.addKeyValue(headerName.toString(), header.getValue()); + } else if (isRedactedHeadersLoggingEnabled) { + logBuilder.addKeyValue(headerName.toString(), REDACTED_PLACEHOLDER); } } } diff --git a/sdk/clientcore/core/src/main/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackInstrumentation.java b/sdk/clientcore/core/src/main/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackInstrumentation.java index 109398c9efbd0..9c282c9eb380b 100644 --- a/sdk/clientcore/core/src/main/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackInstrumentation.java +++ b/sdk/clientcore/core/src/main/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackInstrumentation.java @@ -17,7 +17,7 @@ public class FallbackInstrumentation implements Instrumentation { public static final FallbackInstrumentation DEFAULT_INSTANCE = new FallbackInstrumentation(null, null); - private final InstrumentationOptions instrumentationOptions; + private final InstrumentationOptions instrumentationOptions; private final LibraryInstrumentationOptions libraryOptions; /** @@ -25,7 +25,7 @@ public class FallbackInstrumentation implements Instrumentation { * @param instrumentationOptions the application instrumentation options * @param libraryOptions the library instrumentation options */ - public FallbackInstrumentation(InstrumentationOptions instrumentationOptions, + public FallbackInstrumentation(InstrumentationOptions instrumentationOptions, LibraryInstrumentationOptions libraryOptions) { this.instrumentationOptions = instrumentationOptions; this.libraryOptions = libraryOptions; diff --git a/sdk/clientcore/core/src/main/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackTracer.java b/sdk/clientcore/core/src/main/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackTracer.java index 006d86ebeacf2..15ac5def63ad6 100644 --- a/sdk/clientcore/core/src/main/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackTracer.java +++ b/sdk/clientcore/core/src/main/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackTracer.java @@ -19,15 +19,15 @@ final class FallbackTracer implements Tracer { private final boolean isEnabled; private final ClientLogger logger; - FallbackTracer(InstrumentationOptions instrumentationOptions, LibraryInstrumentationOptions libraryOptions) { + FallbackTracer(InstrumentationOptions instrumentationOptions, LibraryInstrumentationOptions libraryOptions) { // TODO (limolkova): do we need additional config to enable fallback tracing? Or maybe we enable it only if logs are enabled? this.isEnabled = instrumentationOptions == null || instrumentationOptions.isTracingEnabled(); this.logger = isEnabled ? getLogger(instrumentationOptions, libraryOptions) : LOGGER; } - private static ClientLogger getLogger(InstrumentationOptions instrumentationOptions, + private static ClientLogger getLogger(InstrumentationOptions instrumentationOptions, LibraryInstrumentationOptions libraryOptions) { - Object providedLogger = instrumentationOptions == null ? null : instrumentationOptions.getProvider(); + Object providedLogger = instrumentationOptions == null ? null : instrumentationOptions.getTelemetryProvider(); if (providedLogger instanceof ClientLogger) { return (ClientLogger) providedLogger; } diff --git a/sdk/clientcore/core/src/main/java/io/clientcore/core/implementation/instrumentation/otel/OTelInstrumentation.java b/sdk/clientcore/core/src/main/java/io/clientcore/core/implementation/instrumentation/otel/OTelInstrumentation.java index 38783b3bf6bc4..1fcf5b29fa6c9 100644 --- a/sdk/clientcore/core/src/main/java/io/clientcore/core/implementation/instrumentation/otel/OTelInstrumentation.java +++ b/sdk/clientcore/core/src/main/java/io/clientcore/core/implementation/instrumentation/otel/OTelInstrumentation.java @@ -78,9 +78,9 @@ public class OTelInstrumentation implements Instrumentation { * @param applicationOptions the application options * @param libraryOptions the library options */ - public OTelInstrumentation(InstrumentationOptions applicationOptions, + public OTelInstrumentation(InstrumentationOptions applicationOptions, LibraryInstrumentationOptions libraryOptions) { - Object explicitOTel = applicationOptions == null ? null : applicationOptions.getProvider(); + Object explicitOTel = applicationOptions == null ? null : applicationOptions.getTelemetryProvider(); if (explicitOTel != null && !OTEL_CLASS.isInstance(explicitOTel)) { throw LOGGER.atError() .addKeyValue("expectedProvider", OTEL_CLASS.getName()) diff --git a/sdk/clientcore/core/src/main/java/io/clientcore/core/instrumentation/Instrumentation.java b/sdk/clientcore/core/src/main/java/io/clientcore/core/instrumentation/Instrumentation.java index c1de07959f73d..aefbdc64551ad 100644 --- a/sdk/clientcore/core/src/main/java/io/clientcore/core/instrumentation/Instrumentation.java +++ b/sdk/clientcore/core/src/main/java/io/clientcore/core/instrumentation/Instrumentation.java @@ -30,7 +30,7 @@ public interface Instrumentation { * .setLibraryVersion("1.0.0") * .setSchemaUrl("https://opentelemetry.io/schemas/1.29.0"); * - * InstrumentationOptions<?> instrumentationOptions = new InstrumentationOptions<>(); + * InstrumentationOptions instrumentationOptions = new InstrumentationOptions(); * * Tracer tracer = Instrumentation.create(instrumentationOptions, libraryOptions).getTracer(); * @@ -61,7 +61,7 @@ public interface Instrumentation { * @param libraryOptions Library-specific telemetry collection options. * @return The instance of telemetry provider implementation. */ - static Instrumentation create(InstrumentationOptions applicationOptions, + static Instrumentation create(InstrumentationOptions applicationOptions, LibraryInstrumentationOptions libraryOptions) { Objects.requireNonNull(libraryOptions, "'libraryOptions' cannot be null"); if (OTelInitializer.isInitialized()) { diff --git a/sdk/clientcore/core/src/main/java/io/clientcore/core/instrumentation/InstrumentationOptions.java b/sdk/clientcore/core/src/main/java/io/clientcore/core/instrumentation/InstrumentationOptions.java index 230f6068ce4ab..37a57a2fe0e09 100644 --- a/sdk/clientcore/core/src/main/java/io/clientcore/core/instrumentation/InstrumentationOptions.java +++ b/sdk/clientcore/core/src/main/java/io/clientcore/core/instrumentation/InstrumentationOptions.java @@ -13,12 +13,10 @@ * Library should use them on all instance of {@link io.clientcore.core.instrumentation.tracing.Tracer} * it creates and, if it sets up {@link HttpInstrumentationPolicy}, it should pass * {@link InstrumentationOptions} to the policy. - * - * @param The type of the provider. Only {@code io.opentelemetry.api.OpenTelemetry} is supported. */ -public class InstrumentationOptions { +public class InstrumentationOptions { private boolean isTracingEnabled = true; - private T provider = null; + private Object telemetryProvider = null; /** * Enables or disables distributed tracing. Distributed tracing is enabled by default when @@ -29,7 +27,7 @@ public class InstrumentationOptions { * *

      *
-     * InstrumentationOptions<?> instrumentationOptions = new InstrumentationOptions<>()
+     * HttpInstrumentationOptions instrumentationOptions = new HttpInstrumentationOptions()
      *     .setTracingEnabled(false);
      *
      * SampleClient client = new SampleClientBuilder().instrumentationOptions(instrumentationOptions).build();
@@ -41,14 +39,14 @@ public class InstrumentationOptions {
      * @param isTracingEnabled true to enable distributed tracing, false to disable.
      * @return The updated {@link InstrumentationOptions} object.
      */
-    public InstrumentationOptions setTracingEnabled(boolean isTracingEnabled) {
+    public InstrumentationOptions setTracingEnabled(boolean isTracingEnabled) {
         this.isTracingEnabled = isTracingEnabled;
         return this;
     }
 
     /**
-     * Sets the provider to use for telemetry. Only {@code io.opentelemetry.api.OpenTelemetry} and
-     * derived classes are supported.
+     * Sets the telemetry provider. Only {@code io.opentelemetry.api.OpenTelemetry} and
+     * derived classes are currently supported.
      * 

* * When provider is not passed explicitly, clients will attempt to use global OpenTelemetry instance. @@ -58,21 +56,23 @@ public InstrumentationOptions setTracingEnabled(boolean isTracingEnabled) { * *

      *
-     * OpenTelemetry openTelemetry =  AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk();
-     * InstrumentationOptions<OpenTelemetry> instrumentationOptions = new InstrumentationOptions<OpenTelemetry>()
-     *     .setProvider(openTelemetry);
+     * OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk();
+     * HttpInstrumentationOptions instrumentationOptions = new HttpInstrumentationOptions()
+     *     .setTelemetryProvider(openTelemetry);
      *
      * SampleClient client = new SampleClientBuilder().instrumentationOptions(instrumentationOptions).build();
+     *
+     * // this call will be traced using OpenTelemetry SDK provided explicitly
      * client.clientCall();
      *
      * 
* * - * @param provider The provider to use for telemetry. + * @param telemetryProvider The provider to use for telemetry. * @return The updated {@link InstrumentationOptions} object. */ - public InstrumentationOptions setProvider(T provider) { - this.provider = provider; + public InstrumentationOptions setTelemetryProvider(Object telemetryProvider) { + this.telemetryProvider = telemetryProvider; return this; } @@ -90,8 +90,8 @@ public boolean isTracingEnabled() { * * @return The telemetry provider instance. */ - public T getProvider() { - return provider; + public Object getTelemetryProvider() { + return telemetryProvider; } /** diff --git a/sdk/clientcore/core/src/main/java/io/clientcore/core/instrumentation/package-info.java b/sdk/clientcore/core/src/main/java/io/clientcore/core/instrumentation/package-info.java index 63fa95b9eba61..59391cb272a54 100644 --- a/sdk/clientcore/core/src/main/java/io/clientcore/core/instrumentation/package-info.java +++ b/sdk/clientcore/core/src/main/java/io/clientcore/core/instrumentation/package-info.java @@ -27,6 +27,8 @@ * AutoConfiguredOpenTelemetrySdk.initialize(); * * SampleClient client = new SampleClientBuilder().build(); + * + * // this call will be traced using OpenTelemetry SDK initialized globally * client.clientCall(); * *
@@ -40,11 +42,13 @@ * *
  *
- * OpenTelemetry openTelemetry =  AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk();
- * InstrumentationOptions<OpenTelemetry> instrumentationOptions = new InstrumentationOptions<OpenTelemetry>()
- *     .setProvider(openTelemetry);
+ * OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk();
+ * HttpInstrumentationOptions instrumentationOptions = new HttpInstrumentationOptions()
+ *     .setTelemetryProvider(openTelemetry);
  *
  * SampleClient client = new SampleClientBuilder().instrumentationOptions(instrumentationOptions).build();
+ *
+ * // this call will be traced using OpenTelemetry SDK provided explicitly
  * client.clientCall();
  *
  * 
diff --git a/sdk/clientcore/core/src/main/java/io/clientcore/core/models/traits/HttpTrait.java b/sdk/clientcore/core/src/main/java/io/clientcore/core/models/traits/HttpTrait.java index b18fd73229f54..045a42a7c9ea9 100644 --- a/sdk/clientcore/core/src/main/java/io/clientcore/core/models/traits/HttpTrait.java +++ b/sdk/clientcore/core/src/main/java/io/clientcore/core/models/traits/HttpTrait.java @@ -4,7 +4,7 @@ package io.clientcore.core.models.traits; import io.clientcore.core.http.client.HttpClient; -import io.clientcore.core.http.models.HttpLogOptions; +import io.clientcore.core.http.models.HttpInstrumentationOptions; import io.clientcore.core.http.models.HttpRedirectOptions; import io.clientcore.core.http.models.HttpRetryOptions; import io.clientcore.core.http.pipeline.HttpPipeline; @@ -30,7 +30,7 @@ * @see HttpClient * @see HttpPipeline * @see HttpPipelinePolicy - * @see HttpLogOptions + * @see HttpInstrumentationOptions * @see HttpRetryOptions * @see HttpRedirectOptions */ @@ -106,9 +106,21 @@ public interface HttpTrait> { T httpRetryOptions(HttpRetryOptions retryOptions); /** - * Sets the {@link HttpLogOptions logging configuration} to use when sending and receiving requests to and from the - * service. If a {@code logLevel} is not provided, default value of {@link HttpLogOptions.HttpLogDetailLevel#NONE} - * is set. + * Sets the {@link HttpInstrumentationOptions instrumentation configuration} to use when recording telemetry about HTTP + * requests sent to the service and responses received from it. + *

+ * By default, when instrumentation options are not provided (explicitly or via environment variables), the following + * defaults are used: + *

    + *
  • Detailed HTTP logging about requests and responses is disabled
  • + *
  • Distributed tracing is enabled. If OpenTelemetry is found on the classpath, HTTP requests are + * captured as OpenTelemetry spans. + * If OpenTelemetry is not found on the classpath, the same information is captured in logs. + * HTTP request spans contain basic information about the request, such as the HTTP method, URL, status code and + * duration. + * See {@link io.clientcore.core.http.pipeline.HttpInstrumentationPolicy} for + * the details.
  • + *
* *

Note: It is important to understand the precedence order of the {@link HttpTrait} APIs. In * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and @@ -117,13 +129,13 @@ public interface HttpTrait> { * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the * documentation of types that implement this trait to understand the full set of implications.

* - * @param logOptions The {@link HttpLogOptions logging configuration} to use when sending and receiving requests to - * and from the service. + * @param instrumentationOptions The {@link HttpInstrumentationOptions configuration} to use when recording telemetry about HTTP + * requests sent to the service and responses received from it. * * @return Returns the same concrete type with the appropriate properties updated, to allow for fluent chaining of * operations. */ - T httpLogOptions(HttpLogOptions logOptions); + T httpInstrumentationOptions(HttpInstrumentationOptions instrumentationOptions); /** * Sets the {@link HttpRedirectOptions} for all the requests made through the client. diff --git a/sdk/clientcore/core/src/main/resources/META-INF/native-image.io.clientcore.core/native-image.properties b/sdk/clientcore/core/src/main/resources/META-INF/native-image.io.clientcore.core/native-image.properties index 2298920b76204..e037782549eeb 100644 --- a/sdk/clientcore/core/src/main/resources/META-INF/native-image.io.clientcore.core/native-image.properties +++ b/sdk/clientcore/core/src/main/resources/META-INF/native-image.io.clientcore.core/native-image.properties @@ -17,10 +17,10 @@ Args=\ org.slf4j.MDC,\ org.slf4j.LoggerFactory,\ org.slf4j.impl.StaticLoggerBinder,\ - io.clientcore.core.util.ClientLogger.LogLevel,\ io.clientcore.core.util.Configuration,\ io.clientcore.core.util.implementation.ImplUtils,\ - io.clientcore.core.util.ClientLogger.LoggingEvent,\ + io.clientcore.core.instrumentation.logging.ClientLogger.LogLevel,\ + io.clientcore.core.instrumentation.logging.ClientLogger.LoggingEvent,\ diff --git a/sdk/clientcore/core/src/samples/java/io/clientcore/core/instrumentation/TelemetryJavaDocCodeSnippets.java b/sdk/clientcore/core/src/samples/java/io/clientcore/core/instrumentation/TelemetryJavaDocCodeSnippets.java index 11779e0bbf1ba..7778f3b097e33 100644 --- a/sdk/clientcore/core/src/samples/java/io/clientcore/core/instrumentation/TelemetryJavaDocCodeSnippets.java +++ b/sdk/clientcore/core/src/samples/java/io/clientcore/core/instrumentation/TelemetryJavaDocCodeSnippets.java @@ -3,6 +3,7 @@ package io.clientcore.core.instrumentation; +import io.clientcore.core.http.models.HttpInstrumentationOptions; import io.clientcore.core.http.models.HttpMethod; import io.clientcore.core.http.models.HttpRequest; import io.clientcore.core.http.models.RequestOptions; @@ -59,8 +60,8 @@ public void useCustomLogger() { ClientLogger logger = new ClientLogger("sample-client-traces"); - InstrumentationOptions instrumentationOptions = new InstrumentationOptions() - .setProvider(logger); + HttpInstrumentationOptions instrumentationOptions = new HttpInstrumentationOptions() + .setTelemetryProvider(logger); SampleClient client = new SampleClientBuilder().instrumentationOptions(instrumentationOptions).build(); client.clientCall(); @@ -75,7 +76,7 @@ public void useCustomLogger() { public void disableDistributedTracing() { // BEGIN: io.clientcore.core.telemetry.fallback.disabledistributedtracing - InstrumentationOptions instrumentationOptions = new InstrumentationOptions<>() + HttpInstrumentationOptions instrumentationOptions = new HttpInstrumentationOptions() .setTracingEnabled(false); SampleClient client = new SampleClientBuilder().instrumentationOptions(instrumentationOptions).build(); @@ -137,16 +138,15 @@ public Span getSpan() { } static class SampleClientBuilder { - private InstrumentationOptions instrumentationOptions; - // TODO (limolkova): do we need InstrumnetationTrait? - public SampleClientBuilder instrumentationOptions(InstrumentationOptions instrumentationOptions) { + private HttpInstrumentationOptions instrumentationOptions; + public SampleClientBuilder instrumentationOptions(HttpInstrumentationOptions instrumentationOptions) { this.instrumentationOptions = instrumentationOptions; return this; } public SampleClient build() { return new SampleClient(instrumentationOptions, new HttpPipelineBuilder() - .policies(new HttpInstrumentationPolicy(instrumentationOptions, null)) + .policies(new HttpInstrumentationPolicy(instrumentationOptions)) .build()); } } @@ -156,7 +156,7 @@ static class SampleClient { private final HttpPipeline httpPipeline; private final io.clientcore.core.instrumentation.tracing.Tracer tracer; - SampleClient(InstrumentationOptions instrumentationOptions, HttpPipeline httpPipeline) { + SampleClient(InstrumentationOptions instrumentationOptions, HttpPipeline httpPipeline) { this.httpPipeline = httpPipeline; this.tracer = Instrumentation.create(instrumentationOptions, LIBRARY_OPTIONS).getTracer(); } diff --git a/sdk/clientcore/core/src/samples/java/io/clientcore/core/instrumentation/TracingForLibraryDevelopersJavaDocCodeSnippets.java b/sdk/clientcore/core/src/samples/java/io/clientcore/core/instrumentation/TracingForLibraryDevelopersJavaDocCodeSnippets.java index 5d294a02fa726..637e2c5d55a57 100644 --- a/sdk/clientcore/core/src/samples/java/io/clientcore/core/instrumentation/TracingForLibraryDevelopersJavaDocCodeSnippets.java +++ b/sdk/clientcore/core/src/samples/java/io/clientcore/core/instrumentation/TracingForLibraryDevelopersJavaDocCodeSnippets.java @@ -4,7 +4,7 @@ package io.clientcore.core.instrumentation; import io.clientcore.core.http.models.HttpHeaderName; -import io.clientcore.core.http.models.HttpLogOptions; +import io.clientcore.core.http.models.HttpInstrumentationOptions; import io.clientcore.core.http.models.RequestOptions; import io.clientcore.core.http.pipeline.HttpInstrumentationPolicy; import io.clientcore.core.http.pipeline.HttpPipeline; @@ -37,7 +37,7 @@ public void createTracer() { .setLibraryVersion("1.0.0") .setSchemaUrl("https://opentelemetry.io/schemas/1.29.0"); - InstrumentationOptions instrumentationOptions = new InstrumentationOptions<>(); + InstrumentationOptions instrumentationOptions = new InstrumentationOptions(); Tracer tracer = Instrumentation.create(instrumentationOptions, libraryOptions).getTracer(); @@ -117,42 +117,38 @@ public void traceWithAttributes() { } public void configureInstrumentationPolicy() { - InstrumentationOptions instrumentationOptions = new InstrumentationOptions<>(); - HttpLogOptions logOptions = new HttpLogOptions(); + HttpInstrumentationOptions instrumentationOptions = new HttpInstrumentationOptions(); // BEGIN: io.clientcore.core.telemetry.tracing.instrumentationpolicy HttpPipeline pipeline = new HttpPipelineBuilder() .policies( new HttpRetryPolicy(), - new HttpInstrumentationPolicy(instrumentationOptions, logOptions)) + new HttpInstrumentationPolicy(instrumentationOptions)) .build(); // END: io.clientcore.core.telemetry.tracing.instrumentationpolicy } public void customizeInstrumentationPolicy() { - InstrumentationOptions instrumentationOptions = new InstrumentationOptions<>(); - // BEGIN: io.clientcore.core.telemetry.tracing.customizeinstrumentationpolicy // You can configure URL sanitization to include additional query parameters to preserve // in `url.full` attribute. - HttpLogOptions logOptions = new HttpLogOptions(); - logOptions.addAllowedQueryParamName("documentId"); + HttpInstrumentationOptions instrumentationOptions = new HttpInstrumentationOptions(); + instrumentationOptions.addAllowedQueryParamName("documentId"); HttpPipeline pipeline = new HttpPipelineBuilder() .policies( new HttpRetryPolicy(), - new HttpInstrumentationPolicy(instrumentationOptions, logOptions)) + new HttpInstrumentationPolicy(instrumentationOptions)) .build(); // END: io.clientcore.core.telemetry.tracing.customizeinstrumentationpolicy } public void enrichInstrumentationPolicySpans() { - InstrumentationOptions instrumentationOptions = new InstrumentationOptions<>(); - HttpLogOptions logOptions = new HttpLogOptions(); + HttpInstrumentationOptions instrumentationOptions = new HttpInstrumentationOptions(); // BEGIN: io.clientcore.core.telemetry.tracing.enrichhttpspans @@ -170,7 +166,7 @@ public void enrichInstrumentationPolicySpans() { HttpPipeline pipeline = new HttpPipelineBuilder() .policies( new HttpRetryPolicy(), - new HttpInstrumentationPolicy(instrumentationOptions, logOptions), + new HttpInstrumentationPolicy(instrumentationOptions), enrichingPolicy) .build(); diff --git a/sdk/clientcore/core/src/test/java/io/clientcore/core/http/pipeline/HttpInstrumentationLoggingTests.java b/sdk/clientcore/core/src/test/java/io/clientcore/core/http/pipeline/HttpInstrumentationLoggingTests.java index f66fbf73974c0..456dd76bcccc2 100644 --- a/sdk/clientcore/core/src/test/java/io/clientcore/core/http/pipeline/HttpInstrumentationLoggingTests.java +++ b/sdk/clientcore/core/src/test/java/io/clientcore/core/http/pipeline/HttpInstrumentationLoggingTests.java @@ -7,7 +7,7 @@ import io.clientcore.core.http.models.HttpHeader; import io.clientcore.core.http.models.HttpHeaderName; import io.clientcore.core.http.models.HttpHeaders; -import io.clientcore.core.http.models.HttpLogOptions; +import io.clientcore.core.http.models.HttpInstrumentationOptions; import io.clientcore.core.http.models.HttpMethod; import io.clientcore.core.http.models.HttpRequest; import io.clientcore.core.http.models.HttpRetryOptions; @@ -16,7 +16,6 @@ import io.clientcore.core.implementation.AccessibleByteArrayOutputStream; import io.clientcore.core.implementation.http.HttpRequestAccessHelper; import io.clientcore.core.instrumentation.InstrumentationContext; -import io.clientcore.core.instrumentation.InstrumentationOptions; import io.clientcore.core.instrumentation.logging.ClientLogger; import io.clientcore.core.util.binarydata.BinaryData; import org.junit.jupiter.api.Test; @@ -56,10 +55,11 @@ public class HttpInstrumentationLoggingTests { private static final String URI = "https://example.com?param=value&api-version=42"; private static final String REDACTED_URI = "https://example.com?param=REDACTED&api-version=42"; - private static final Set DEFAULT_ALLOWED_QUERY_PARAMS = new HttpLogOptions().getAllowedQueryParamNames(); - private static final Set DEFAULT_ALLOWED_HEADERS = new HttpLogOptions().getAllowedHeaderNames(); + private static final Set DEFAULT_ALLOWED_QUERY_PARAMS + = new HttpInstrumentationOptions().getAllowedQueryParamNames(); + private static final Set DEFAULT_ALLOWED_HEADERS + = new HttpInstrumentationOptions().getAllowedHeaderNames(); private static final HttpHeaderName CUSTOM_REQUEST_ID = HttpHeaderName.fromString("custom-request-id"); - private static final InstrumentationOptions DEFAULT_INSTRUMENTATION_OPTIONS = null; private final AccessibleByteArrayOutputStream logCaptureStream; @@ -69,12 +69,11 @@ public HttpInstrumentationLoggingTests() { @ParameterizedTest @MethodSource("disabledHttpLoggingSource") - public void testDisabledHttpLogging(ClientLogger.LogLevel logLevel, HttpLogOptions.HttpLogDetailLevel httpLogLevel) - throws IOException { + public void testDisabledHttpLogging(ClientLogger.LogLevel logLevel, + HttpInstrumentationOptions.HttpLogDetailLevel detailLevel) throws IOException { ClientLogger logger = setupLogLevelAndGetLogger(logLevel, logCaptureStream); - HttpPipeline pipeline - = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, new HttpLogOptions().setLogLevel(httpLogLevel)); + HttpPipeline pipeline = createPipeline(new HttpInstrumentationOptions().setHttpLogLevel(detailLevel)); HttpRequest request = new HttpRequest(HttpMethod.GET, URI); request.setRequestOptions(new RequestOptions().setLogger(logger)); @@ -84,21 +83,22 @@ public void testDisabledHttpLogging(ClientLogger.LogLevel logLevel, HttpLogOptio } public static Stream disabledHttpLoggingSource() { - return Stream.of(Arguments.of(ClientLogger.LogLevel.VERBOSE, HttpLogOptions.HttpLogDetailLevel.NONE), - Arguments.of(ClientLogger.LogLevel.WARNING, HttpLogOptions.HttpLogDetailLevel.BASIC), - Arguments.of(ClientLogger.LogLevel.WARNING, HttpLogOptions.HttpLogDetailLevel.HEADERS), - Arguments.of(ClientLogger.LogLevel.WARNING, HttpLogOptions.HttpLogDetailLevel.BODY), - Arguments.of(ClientLogger.LogLevel.WARNING, HttpLogOptions.HttpLogDetailLevel.BODY_AND_HEADERS)); + return Stream.of( + Arguments.of(ClientLogger.LogLevel.VERBOSE, HttpInstrumentationOptions.HttpLogDetailLevel.NONE), + Arguments.of(ClientLogger.LogLevel.WARNING, HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS), + Arguments.of(ClientLogger.LogLevel.WARNING, HttpInstrumentationOptions.HttpLogDetailLevel.BODY), Arguments + .of(ClientLogger.LogLevel.WARNING, HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS)); } @ParameterizedTest @MethodSource("allowQueryParamSource") public void testBasicHttpLogging(Set allowedParams, String expectedUri) throws IOException { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BASIC) - .setAllowedQueryParamNames(allowedParams); + HttpInstrumentationOptions options + = new HttpInstrumentationOptions().setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS) + .setAllowedQueryParamNames(allowedParams); - HttpPipeline pipeline = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options); + HttpPipeline pipeline = createPipeline(options); HttpRequest request = createRequest(HttpMethod.GET, URI, logger); Response response = pipeline.send(request); @@ -108,19 +108,51 @@ public void testBasicHttpLogging(Set allowedParams, String expectedUri) assertEquals(2, logMessages.size()); assertRequestLog(logMessages.get(0), expectedUri, request, null, 0); - assertEquals(7, logMessages.get(0).size()); + assertEquals(10, logMessages.get(0).size()); + assertEquals("REDACTED", logMessages.get(0).get("Authorization")); + assertEquals("application/json", logMessages.get(0).get("Content-Type")); assertResponseLog(logMessages.get(1), expectedUri, response, 0); - assertEquals(11, logMessages.get(1).size()); + assertEquals(14, logMessages.get(1).size()); + assertEquals("13", logMessages.get(1).get("Content-Length")); + assertEquals("application/text", logMessages.get(1).get("Content-Type")); + assertEquals("REDACTED", logMessages.get(1).get("not-safe-to-log")); + } + + @Test + public void testBasicHttpLoggingNoRedactedHeaders() throws IOException { + ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); + HttpInstrumentationOptions options + = new HttpInstrumentationOptions().setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS) + .setRedactedHeaderNamesLoggingEnabled(false); + + HttpPipeline pipeline = createPipeline(options); + + HttpRequest request = createRequest(HttpMethod.GET, URI, logger); + Response response = pipeline.send(request); + response.close(); + + List> logMessages = parseLogMessages(logCaptureStream); + assertEquals(2, logMessages.size()); + + assertRequestLog(logMessages.get(0), request); + assertEquals(9, logMessages.get(0).size()); + assertEquals("application/json", logMessages.get(0).get("Content-Type")); + + assertResponseLog(logMessages.get(1), response); + assertEquals(13, logMessages.get(1).size()); + assertEquals("13", logMessages.get(1).get("Content-Length")); + assertEquals("application/text", logMessages.get(1).get("Content-Type")); } @Test public void testHttpLoggingTracingDisabled() throws IOException { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - InstrumentationOptions instrumentationOptions = new InstrumentationOptions<>().setTracingEnabled(false); - HttpLogOptions logOptions = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BASIC); - HttpPipeline pipeline = createPipeline(instrumentationOptions, logOptions); + HttpInstrumentationOptions options = new HttpInstrumentationOptions().setTracingEnabled(false) + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS) + .setRedactedHeaderNamesLoggingEnabled(false); + HttpPipeline pipeline = createPipeline(options); HttpRequest request = createRequest(HttpMethod.GET, URI, logger); Response response = pipeline.send(request); @@ -130,19 +162,19 @@ public void testHttpLoggingTracingDisabled() throws IOException { assertEquals(2, logMessages.size()); assertRequestLog(logMessages.get(0), request); - assertEquals(5, logMessages.get(0).size()); + assertEquals(6, logMessages.get(0).size()); assertResponseLog(logMessages.get(1), response); - assertEquals(9, logMessages.get(1).size()); + assertEquals(11, logMessages.get(1).size()); } @Test public void testHttpLoggingTracingDisabledCustomContext() throws IOException { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - InstrumentationOptions instrumentationOptions = new InstrumentationOptions<>().setTracingEnabled(false); - HttpLogOptions logOptions = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BASIC); + HttpInstrumentationOptions options = new HttpInstrumentationOptions().setTracingEnabled(false) + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS); - HttpPipeline pipeline = createPipeline(instrumentationOptions, logOptions); + HttpPipeline pipeline = createPipeline(options); InstrumentationContext instrumentationContext = createInstrumentationContext("1234567890abcdef1234567890abcdef", "1234567890abcdef"); @@ -155,18 +187,19 @@ public void testHttpLoggingTracingDisabledCustomContext() throws IOException { assertEquals(2, logMessages.size()); assertRequestLog(logMessages.get(0), request); - assertEquals(7, logMessages.get(0).size()); + assertEquals(10, logMessages.get(0).size()); assertResponseLog(logMessages.get(1), response); - assertEquals(11, logMessages.get(1).size()); + assertEquals(14, logMessages.get(1).size()); } @Test public void testTryCount() throws IOException { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BASIC); + HttpInstrumentationOptions options + = new HttpInstrumentationOptions().setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS); - HttpPipeline pipeline = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options); + HttpPipeline pipeline = createPipeline(options); HttpRequest request = createRequest(HttpMethod.GET, URI, logger); HttpRequestAccessHelper.setTryCount(request, 42); @@ -184,10 +217,11 @@ public void testTryCount() throws IOException { @MethodSource("testExceptionSeverity") public void testConnectionException(ClientLogger.LogLevel level, boolean expectExceptionLog) { ClientLogger logger = setupLogLevelAndGetLogger(level, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.HEADERS); + HttpInstrumentationOptions options + = new HttpInstrumentationOptions().setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS); RuntimeException expectedException = new RuntimeException("socket error"); - HttpPipeline pipeline = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options, request -> { + HttpPipeline pipeline = createPipeline(options, request -> { throw expectedException; }); @@ -207,12 +241,13 @@ public void testConnectionException(ClientLogger.LogLevel level, boolean expectE @MethodSource("testExceptionSeverity") public void testRequestBodyException(ClientLogger.LogLevel level, boolean expectExceptionLog) { ClientLogger logger = setupLogLevelAndGetLogger(level, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BODY); + HttpInstrumentationOptions options = new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS); IOException expectedException = new IOException("socket error"); TestStream requestStream = new TestStream(1024, expectedException); BinaryData requestBody = BinaryData.fromStream(requestStream, 1024L); - HttpPipeline pipeline = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options); + HttpPipeline pipeline = createPipeline(options); HttpRequest request = createRequest(HttpMethod.POST, URI, logger); request.setBody(requestBody); @@ -231,11 +266,12 @@ public void testRequestBodyException(ClientLogger.LogLevel level, boolean expect @MethodSource("testExceptionSeverity") public void testResponseBodyException(ClientLogger.LogLevel level, boolean expectExceptionLog) { ClientLogger logger = setupLogLevelAndGetLogger(level, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BODY); + HttpInstrumentationOptions options = new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS); IOException expectedException = new IOException("socket error"); TestStream responseStream = new TestStream(1024, expectedException); - HttpPipeline pipeline = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options, + HttpPipeline pipeline = createPipeline(options, request -> new MockHttpResponse(request, 200, BinaryData.fromStream(responseStream, 1024L))); HttpRequest request = createRequest(HttpMethod.GET, URI, logger); @@ -254,9 +290,10 @@ public void testResponseBodyException(ClientLogger.LogLevel level, boolean expec @Test public void testResponseBodyLoggingOnClose() throws IOException { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.INFORMATIONAL, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BODY); + HttpInstrumentationOptions options = new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS); - HttpPipeline pipeline = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options, + HttpPipeline pipeline = createPipeline(options, request -> new MockHttpResponse(request, 200, BinaryData.fromString("Response body"))); HttpRequest request = createRequest(HttpMethod.GET, URI, logger); @@ -273,9 +310,10 @@ public void testResponseBodyLoggingOnClose() throws IOException { @Test public void testResponseBodyRequestedMultipleTimes() { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.INFORMATIONAL, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BODY); + HttpInstrumentationOptions options = new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS); - HttpPipeline pipeline = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options, + HttpPipeline pipeline = createPipeline(options, request -> new MockHttpResponse(request, 200, BinaryData.fromString("Response body"))); HttpRequest request = createRequest(HttpMethod.GET, URI, logger); @@ -293,10 +331,11 @@ public void testResponseBodyRequestedMultipleTimes() { @MethodSource("allowQueryParamSource") public void testBasicHttpLoggingRequestOff(Set allowedParams, String expectedUri) throws IOException { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.INFORMATIONAL, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BASIC) - .setAllowedQueryParamNames(allowedParams); + HttpInstrumentationOptions options + = new HttpInstrumentationOptions().setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS) + .setAllowedQueryParamNames(allowedParams); - HttpPipeline pipeline = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options); + HttpPipeline pipeline = createPipeline(options); HttpRequest request = createRequest(HttpMethod.POST, URI, logger); Response response = pipeline.send(request); @@ -306,17 +345,18 @@ public void testBasicHttpLoggingRequestOff(Set allowedParams, String exp assertEquals(1, logMessages.size()); assertResponseLog(logMessages.get(0), expectedUri, response, 0); - assertEquals(11, logMessages.get(0).size()); + assertEquals(14, logMessages.get(0).size()); } @ParameterizedTest @MethodSource("allowedHeaders") public void testHeadersHttpLogging(Set allowedHeaders) throws IOException { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.HEADERS) - .setAllowedHeaderNames(allowedHeaders); + HttpInstrumentationOptions options + = new HttpInstrumentationOptions().setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS) + .setAllowedHeaderNames(allowedHeaders); - HttpPipeline pipeline = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options); + HttpPipeline pipeline = createPipeline(options); HttpRequest request = createRequest(HttpMethod.GET, URI, logger); request.getHeaders().set(CUSTOM_REQUEST_ID, "12345"); @@ -350,9 +390,10 @@ public void testHeadersHttpLogging(Set allowedHeaders) throws IO @Test public void testStringBodyLogging() throws IOException { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BODY); + HttpInstrumentationOptions options = new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS); - HttpPipeline pipeline = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options, + HttpPipeline pipeline = createPipeline(options, request -> new MockHttpResponse(request, 200, BinaryData.fromString("Response body"))); HttpRequest request = createRequest(HttpMethod.PUT, URI, logger); @@ -378,14 +419,14 @@ public void testStringBodyLogging() throws IOException { @Test public void testStreamBodyLogging() { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BODY); + HttpInstrumentationOptions options = new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS); BinaryData responseBody = BinaryData.fromString("Response body"); TestStream responseStream = new TestStream(responseBody); - HttpPipeline pipeline - = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options, request -> new MockHttpResponse(request, 200, - BinaryData.fromStream(responseStream, responseBody.getLength()))); + HttpPipeline pipeline = createPipeline(options, request -> new MockHttpResponse(request, 200, + BinaryData.fromStream(responseStream, responseBody.getLength()))); BinaryData requestBody = BinaryData.fromString("Request body"); TestStream requestStream = new TestStream(requestBody); @@ -417,11 +458,12 @@ public void testStreamBodyLogging() { @Test public void testHugeBodyNotLogged() throws IOException { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BODY); + HttpInstrumentationOptions options = new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS); TestStream requestStream = new TestStream(1024 * 1024); TestStream responseStream = new TestStream(1024 * 1024); - HttpPipeline pipeline = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options, + HttpPipeline pipeline = createPipeline(options, request -> new MockHttpResponse(request, 200, BinaryData.fromStream(responseStream, (long) 1024 * 1024))); HttpRequest request = createRequest(HttpMethod.PUT, URI, logger); @@ -448,11 +490,12 @@ public void testHugeBodyNotLogged() throws IOException { @Test public void testBodyWithUnknownLengthNotLogged() throws IOException { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BODY); + HttpInstrumentationOptions options = new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS); TestStream requestStream = new TestStream(1024); TestStream responseStream = new TestStream(1024); - HttpPipeline pipeline = createPipeline(DEFAULT_INSTRUMENTATION_OPTIONS, options, + HttpPipeline pipeline = createPipeline(options, request -> new MockHttpResponse(request, 200, BinaryData.fromStream(responseStream))); HttpRequest request = createRequest(HttpMethod.PUT, URI, logger); @@ -482,23 +525,24 @@ public void testBodyWithUnknownLengthNotLogged() throws IOException { public void tracingWithRetriesException() throws IOException { AtomicInteger count = new AtomicInteger(0); ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BASIC); + HttpInstrumentationOptions options = new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS); AtomicReference firstTryContext = new AtomicReference<>(); UnknownHostException expectedException = new UnknownHostException("test exception"); - HttpPipeline pipeline = new HttpPipelineBuilder() - .policies(new HttpRetryPolicy(), new HttpInstrumentationPolicy(DEFAULT_INSTRUMENTATION_OPTIONS, options)) - .httpClient(request -> { - assertEquals(traceparent(request.getRequestOptions().getInstrumentationContext()), - request.getHeaders().get(TRACEPARENT).getValue()); - if (count.getAndIncrement() == 0) { - firstTryContext.set(request.getRequestOptions().getInstrumentationContext()); - throw expectedException; - } else { - return new MockHttpResponse(request, 200); - } - }) - .build(); + HttpPipeline pipeline + = new HttpPipelineBuilder().policies(new HttpRetryPolicy(), new HttpInstrumentationPolicy(options)) + .httpClient(request -> { + assertEquals(traceparent(request.getRequestOptions().getInstrumentationContext()), + request.getHeaders().get(TRACEPARENT).getValue()); + if (count.getAndIncrement() == 0) { + firstTryContext.set(request.getRequestOptions().getInstrumentationContext()); + throw expectedException; + } else { + return new MockHttpResponse(request, 200); + } + }) + .build(); InstrumentationContext parentContext = createInstrumentationContext("1234567890abcdef1234567890abcdef", "1234567890abcdef"); @@ -522,21 +566,22 @@ public void tracingWithRetriesException() throws IOException { public void tracingWithRetriesStatusCode() throws IOException { AtomicInteger count = new AtomicInteger(0); ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BASIC); + HttpInstrumentationOptions options = new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS); AtomicReference firstTryContext = new AtomicReference<>(); - HttpPipeline pipeline = new HttpPipelineBuilder() - .policies(new HttpRetryPolicy(), new HttpInstrumentationPolicy(DEFAULT_INSTRUMENTATION_OPTIONS, options)) - .httpClient(request -> { - if (count.getAndIncrement() == 0) { - firstTryContext.set(request.getRequestOptions().getInstrumentationContext()); - return new MockHttpResponse(request, 500); - } else { - return new MockHttpResponse(request, 200); - } - }) - .build(); + HttpPipeline pipeline + = new HttpPipelineBuilder().policies(new HttpRetryPolicy(), new HttpInstrumentationPolicy(options)) + .httpClient(request -> { + if (count.getAndIncrement() == 0) { + firstTryContext.set(request.getRequestOptions().getInstrumentationContext()); + return new MockHttpResponse(request, 500); + } else { + return new MockHttpResponse(request, 200); + } + }) + .build(); InstrumentationContext parentContext = createRandomInstrumentationContext(); HttpRequest request = createRequest(HttpMethod.PUT, URI, logger, parentContext); @@ -594,23 +639,24 @@ public void retryPolicyLoggingRetriesExhausted(ClientLogger.LogLevel logLevel, b public void tracingWithRedirects() throws IOException { AtomicInteger count = new AtomicInteger(0); ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - HttpLogOptions options = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BASIC); + HttpInstrumentationOptions options = new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS); AtomicReference firstRedirectContext = new AtomicReference<>(); - HttpPipeline pipeline = new HttpPipelineBuilder() - .policies(new HttpRedirectPolicy(), new HttpInstrumentationPolicy(DEFAULT_INSTRUMENTATION_OPTIONS, options)) - .httpClient(request -> { - if (count.getAndIncrement() == 0) { - firstRedirectContext.set(request.getRequestOptions().getInstrumentationContext()); - HttpHeaders httpHeaders = new HttpHeaders().set(HttpHeaderName.LOCATION, - "http://redirecthost/" + count.get() + "?param=value&api-version=42"); - return new MockHttpResponse(request, 302, httpHeaders); - } else { - return new MockHttpResponse(request, 200); - } - }) - .build(); + HttpPipeline pipeline + = new HttpPipelineBuilder().policies(new HttpRedirectPolicy(), new HttpInstrumentationPolicy(options)) + .httpClient(request -> { + if (count.getAndIncrement() == 0) { + firstRedirectContext.set(request.getRequestOptions().getInstrumentationContext()); + HttpHeaders httpHeaders = new HttpHeaders().set(HttpHeaderName.LOCATION, + "http://redirecthost/" + count.get() + "?param=value&api-version=42"); + return new MockHttpResponse(request, 302, httpHeaders); + } else { + return new MockHttpResponse(request, 200); + } + }) + .build(); InstrumentationContext parentContext = createRandomInstrumentationContext(); HttpRequest request = createRequest(HttpMethod.GET, URI, logger, parentContext); @@ -935,18 +981,24 @@ private void assertExceptionLog(Map log, String expectedUri, Htt assertTraceContext(log, context); } - private HttpPipeline createPipeline(InstrumentationOptions instrumentationOptions, HttpLogOptions options) { - return createPipeline(instrumentationOptions, options, request -> { + private HttpPipeline createPipeline(HttpInstrumentationOptions instrumentationOptions) { + return createPipeline(instrumentationOptions, request -> { if (request.getBody() != null) { request.getBody().toString(); } - return new MockHttpResponse(request, 200, BinaryData.fromString("Hello, world!")); + BinaryData responseBody = BinaryData.fromString("Hello, world!"); + MockHttpResponse response = new MockHttpResponse(request, 200, responseBody); + response.getHeaders() + .set(HttpHeaderName.CONTENT_TYPE, "application/text") + .set(HttpHeaderName.CONTENT_LENGTH, responseBody.getLength().toString()) + .set(HttpHeaderName.fromString("not-safe-to-log"), "12345"); + return response; }); } - private HttpPipeline createPipeline(InstrumentationOptions instrumentationOptions, HttpLogOptions options, + private HttpPipeline createPipeline(HttpInstrumentationOptions instrumentationOptions, Function> httpClient) { - return new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(instrumentationOptions, options)) + return new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(instrumentationOptions)) .httpClient(httpClient::apply) .build(); } diff --git a/sdk/clientcore/core/src/test/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicyFallbackTests.java b/sdk/clientcore/core/src/test/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicyFallbackTests.java index 2417835db52f1..508c20ce2ca58 100644 --- a/sdk/clientcore/core/src/test/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicyFallbackTests.java +++ b/sdk/clientcore/core/src/test/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicyFallbackTests.java @@ -5,11 +5,10 @@ import io.clientcore.core.http.MockHttpResponse; import io.clientcore.core.http.models.HttpHeaderName; -import io.clientcore.core.http.models.HttpLogOptions; +import io.clientcore.core.http.models.HttpInstrumentationOptions; import io.clientcore.core.http.models.HttpMethod; import io.clientcore.core.http.models.HttpRequest; import io.clientcore.core.http.models.Response; -import io.clientcore.core.instrumentation.InstrumentationOptions; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -22,19 +21,18 @@ import static org.junit.jupiter.api.Assertions.assertNull; public class HttpInstrumentationPolicyFallbackTests { - private static final InstrumentationOptions OPTIONS = new InstrumentationOptions<>(); - private static final InstrumentationOptions DISABLED_TRACING_OPTIONS - = new InstrumentationOptions<>().setTracingEnabled(false); - private static final HttpLogOptions ENABLED_HTTP_LOG_OPTIONS - = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.HEADERS); private static final HttpHeaderName TRACESTATE = HttpHeaderName.fromString("tracestate"); @Test public void simpleRequestTracingDisabled() throws IOException { - HttpPipeline pipeline = new HttpPipelineBuilder() - .policies(new HttpInstrumentationPolicy(DISABLED_TRACING_OPTIONS, ENABLED_HTTP_LOG_OPTIONS)) - .httpClient(request -> new MockHttpResponse(request, 200)) - .build(); + HttpInstrumentationOptions tracingOffLoggingOnOptions + = new HttpInstrumentationOptions().setTracingEnabled(false) + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS); + + HttpPipeline pipeline + = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(tracingOffLoggingOnOptions)) + .httpClient(request -> new MockHttpResponse(request, 200)) + .build(); // should not throw try (Response response = pipeline.send(new HttpRequest(HttpMethod.GET, "https://localhost/"))) { @@ -47,8 +45,11 @@ public void simpleRequestTracingDisabled() throws IOException { @ParameterizedTest @ValueSource(ints = { 200, 201, 206, 302, 400, 404, 500, 503 }) public void simpleRequestTracingEnabled(int statusCode) throws IOException { + HttpInstrumentationOptions tracingOnLoggingOnOptions + = new HttpInstrumentationOptions().setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS); + HttpPipeline pipeline - = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(OPTIONS, ENABLED_HTTP_LOG_OPTIONS)) + = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(tracingOnLoggingOnOptions)) .httpClient(request -> new MockHttpResponse(request, statusCode)) .build(); diff --git a/sdk/clientcore/core/src/test/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackInstrumentationTests.java b/sdk/clientcore/core/src/test/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackInstrumentationTests.java index 84a301a12564c..019b7f3af09ed 100644 --- a/sdk/clientcore/core/src/test/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackInstrumentationTests.java +++ b/sdk/clientcore/core/src/test/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackInstrumentationTests.java @@ -324,7 +324,7 @@ public static Stream instrumentationContextSource() { @Test @SuppressWarnings("try") public void basicTracingDisabledTests() { - InstrumentationOptions options = new InstrumentationOptions<>().setTracingEnabled(false); + InstrumentationOptions options = new InstrumentationOptions().setTracingEnabled(false); Instrumentation instrumentation = Instrumentation.create(options, DEFAULT_LIB_OPTIONS); Tracer tracer = instrumentation.getTracer(); @@ -354,7 +354,8 @@ public void basicTracingDisabledTests() { @Test public void createTracerUnknownProvider() { // should not throw - InstrumentationOptions options = new InstrumentationOptions<>().setProvider("this is not a valid provider"); + InstrumentationOptions options + = new InstrumentationOptions().setTelemetryProvider("this is not a valid provider"); Tracer tracer = Instrumentation.create(options, DEFAULT_LIB_OPTIONS).getTracer(); assertTrue(tracer.isEnabled()); } @@ -362,14 +363,14 @@ public void createTracerUnknownProvider() { @Test public void createInstrumentationBadOptions() { assertThrows(NullPointerException.class, - () -> Instrumentation.create(new InstrumentationOptions<>(), null).getTracer()); + () -> Instrumentation.create(new InstrumentationOptions(), null).getTracer()); } @ParameterizedTest @MethodSource("logLevels") public void basicTracingLogsLevel(ClientLogger.LogLevel logLevel, boolean expectLogs) { ClientLogger logger = setupLogLevelAndGetLogger(logLevel, logCaptureStream); - InstrumentationOptions options = new InstrumentationOptions<>().setProvider(logger); + InstrumentationOptions options = new InstrumentationOptions().setTelemetryProvider(logger); Instrumentation instrumentation = Instrumentation.create(options, DEFAULT_LIB_OPTIONS); Tracer tracer = instrumentation.getTracer(); @@ -394,7 +395,7 @@ public static Stream logLevels() { @Test public void basicTracingLogsEnabled() { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - InstrumentationOptions options = new InstrumentationOptions<>().setProvider(logger); + InstrumentationOptions options = new InstrumentationOptions().setTelemetryProvider(logger); Instrumentation instrumentation = Instrumentation.create(options, DEFAULT_LIB_OPTIONS); Tracer tracer = instrumentation.getTracer(); @@ -422,7 +423,7 @@ public void basicTracingLogsEnabled() { @Test public void tracingWithAttributesLogsEnabled() { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - InstrumentationOptions options = new InstrumentationOptions<>().setProvider(logger); + InstrumentationOptions options = new InstrumentationOptions().setTelemetryProvider(logger); Tracer tracer = Instrumentation.create(options, DEFAULT_LIB_OPTIONS).getTracer(); Span span = tracer.spanBuilder("test-span", PRODUCER, null) @@ -460,7 +461,7 @@ public void tracingWithAttributesLogsEnabled() { @Test public void tracingWithExceptionLogsEnabled() { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - InstrumentationOptions options = new InstrumentationOptions<>().setProvider(logger); + InstrumentationOptions options = new InstrumentationOptions().setTelemetryProvider(logger); Tracer tracer = Instrumentation.create(options, DEFAULT_LIB_OPTIONS).getTracer(); Span span = tracer.spanBuilder("test-span", SERVER, null).startSpan(); @@ -478,7 +479,7 @@ public void tracingWithExceptionLogsEnabled() { @Test public void tracingLogsEnabledParent() { ClientLogger logger = setupLogLevelAndGetLogger(ClientLogger.LogLevel.VERBOSE, logCaptureStream); - InstrumentationOptions options = new InstrumentationOptions<>().setProvider(logger); + InstrumentationOptions options = new InstrumentationOptions().setTelemetryProvider(logger); Tracer tracer = Instrumentation.create(options, DEFAULT_LIB_OPTIONS).getTracer(); Span parent = tracer.spanBuilder("parent", CONSUMER, null).startSpan(); diff --git a/sdk/clientcore/core/src/test/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackTracingBenchmarks.java b/sdk/clientcore/core/src/test/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackTracingBenchmarks.java index 821c2bda69fc2..9cd22d8395423 100644 --- a/sdk/clientcore/core/src/test/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackTracingBenchmarks.java +++ b/sdk/clientcore/core/src/test/java/io/clientcore/core/implementation/instrumentation/fallback/FallbackTracingBenchmarks.java @@ -44,19 +44,18 @@ public class FallbackTracingBenchmarks { public void setupOtel() { LibraryInstrumentationOptions libraryOptions = new LibraryInstrumentationOptions("test"); fallbackTracerDisabled - = Instrumentation.create(new InstrumentationOptions<>().setTracingEnabled(false), libraryOptions) - .getTracer(); + = Instrumentation.create(new InstrumentationOptions().setTracingEnabled(false), libraryOptions).getTracer(); ClientLogger loggerDisabled = InstrumentationTestUtils.setupLogLevelAndGetLogger(ClientLogger.LogLevel.WARNING, new NoopStream()); fallbackTracerEnabledNoLogs - = Instrumentation.create(new InstrumentationOptions<>().setProvider(loggerDisabled), libraryOptions) + = Instrumentation.create(new InstrumentationOptions().setTelemetryProvider(loggerDisabled), libraryOptions) .getTracer(); ClientLogger loggerEnabled = InstrumentationTestUtils.setupLogLevelAndGetLogger(ClientLogger.LogLevel.INFORMATIONAL, new NoopStream()); fallbackTracerEnabledWithLogs - = Instrumentation.create(new InstrumentationOptions<>().setProvider(loggerEnabled), libraryOptions) + = Instrumentation.create(new InstrumentationOptions().setTelemetryProvider(loggerEnabled), libraryOptions) .getTracer(); } diff --git a/sdk/clientcore/core/src/test/java/io/clientcore/core/shared/HttpClientTests.java b/sdk/clientcore/core/src/test/java/io/clientcore/core/shared/HttpClientTests.java index 5fab3a5472d60..d9c4d6a52fa33 100644 --- a/sdk/clientcore/core/src/test/java/io/clientcore/core/shared/HttpClientTests.java +++ b/sdk/clientcore/core/src/test/java/io/clientcore/core/shared/HttpClientTests.java @@ -18,7 +18,7 @@ import io.clientcore.core.http.models.HttpHeader; import io.clientcore.core.http.models.HttpHeaderName; import io.clientcore.core.http.models.HttpHeaders; -import io.clientcore.core.http.models.HttpLogOptions; +import io.clientcore.core.http.models.HttpInstrumentationOptions; import io.clientcore.core.http.models.HttpMethod; import io.clientcore.core.http.models.HttpRequest; import io.clientcore.core.http.models.RequestOptions; @@ -1492,8 +1492,8 @@ public void binaryDataUploadTest() throws Exception { // Order in which policies applied will be the order in which they added to builder final HttpPipeline httpPipeline = new HttpPipelineBuilder().httpClient(httpClient) - .policies(new HttpInstrumentationPolicy(null, - new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.BODY_AND_HEADERS))) + .policies(new HttpInstrumentationPolicy(new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.BODY_AND_HEADERS))) .build(); Response response diff --git a/sdk/clientcore/http-stress/pom.xml b/sdk/clientcore/http-stress/pom.xml index fd62f75211683..37937738aa198 100644 --- a/sdk/clientcore/http-stress/pom.xml +++ b/sdk/clientcore/http-stress/pom.xml @@ -32,7 +32,7 @@ io.clientcore core - 1.0.0-beta.2 + 1.0.0-beta.3 io.clientcore diff --git a/sdk/clientcore/http-stress/src/main/java/io/clientcore/http/stress/HttpGet.java b/sdk/clientcore/http-stress/src/main/java/io/clientcore/http/stress/HttpGet.java index 9ed784836eb7f..8debe2834b63d 100644 --- a/sdk/clientcore/http-stress/src/main/java/io/clientcore/http/stress/HttpGet.java +++ b/sdk/clientcore/http-stress/src/main/java/io/clientcore/http/stress/HttpGet.java @@ -6,7 +6,7 @@ import com.azure.perf.test.core.PerfStressOptions; import io.clientcore.core.http.client.DefaultHttpClientBuilder; import io.clientcore.core.http.models.HttpHeaderName; -import io.clientcore.core.http.models.HttpLogOptions; +import io.clientcore.core.http.models.HttpInstrumentationOptions; import io.clientcore.core.http.models.HttpMethod; import io.clientcore.core.http.models.HttpRequest; import io.clientcore.core.http.models.Response; @@ -142,17 +142,16 @@ private Runnable runAsyncWithVirtualThreadInternal() { private HttpRequest createRequest() { HttpRequest request = new HttpRequest(HttpMethod.GET, uri); - request.getHeaders().set(HttpHeaderName.USER_AGENT, "azsdk-java-clientcore-stress"); + request.getHeaders().set(HttpHeaderName.USER_AGENT, "clientcore-stress"); request.getHeaders() .set(HttpHeaderName.fromString("x-client-id"), String.valueOf(clientRequestId.incrementAndGet())); return request; } private HttpPipelineBuilder getPipelineBuilder() { - HttpLogOptions logOptions = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.HEADERS); - HttpPipelineBuilder builder = new HttpPipelineBuilder().policies(new HttpRetryPolicy(), - new HttpInstrumentationPolicy(null, logOptions)); + new HttpInstrumentationPolicy(new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS))); if (options.getHttpClient() == PerfStressOptions.HttpClientType.OKHTTP) { builder.httpClient(new OkHttpHttpClientProvider().getSharedInstance()); diff --git a/sdk/clientcore/http-stress/src/main/java/io/clientcore/http/stress/HttpPatch.java b/sdk/clientcore/http-stress/src/main/java/io/clientcore/http/stress/HttpPatch.java index 192003ae4499a..477fcae22243e 100644 --- a/sdk/clientcore/http-stress/src/main/java/io/clientcore/http/stress/HttpPatch.java +++ b/sdk/clientcore/http-stress/src/main/java/io/clientcore/http/stress/HttpPatch.java @@ -6,7 +6,7 @@ import com.azure.perf.test.core.PerfStressOptions; import io.clientcore.core.http.client.DefaultHttpClientBuilder; import io.clientcore.core.http.models.HttpHeaderName; -import io.clientcore.core.http.models.HttpLogOptions; +import io.clientcore.core.http.models.HttpInstrumentationOptions; import io.clientcore.core.http.models.HttpMethod; import io.clientcore.core.http.models.HttpRequest; import io.clientcore.core.http.models.Response; @@ -78,7 +78,7 @@ private HttpRequest createRequest() { String body = "{\"id\": \"1\", \"name\": \"test\"}"; HttpRequest request = new HttpRequest(HttpMethod.PATCH, uri).setBody(BinaryData.fromString(body)); request.getHeaders().set(HttpHeaderName.CONTENT_LENGTH, String.valueOf(body.length())); - request.getHeaders().set(HttpHeaderName.USER_AGENT, "azsdk-java-stress"); + request.getHeaders().set(HttpHeaderName.USER_AGENT, "clientcore-stress"); request.getHeaders() .set(HttpHeaderName.fromString("x-client-id"), String.valueOf(clientRequestId.incrementAndGet())); request.getHeaders().set(HttpHeaderName.CONTENT_TYPE, "application/json"); @@ -87,10 +87,9 @@ private HttpRequest createRequest() { } private HttpPipelineBuilder getPipelineBuilder() { - HttpLogOptions logOptions = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.HEADERS); - HttpPipelineBuilder builder = new HttpPipelineBuilder().policies(new HttpRetryPolicy(), - new HttpInstrumentationPolicy(null, logOptions)); + new HttpInstrumentationPolicy(new HttpInstrumentationOptions() + .setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS))); if (options.getHttpClient() == PerfStressOptions.HttpClientType.OKHTTP) { builder.httpClient(new OkHttpHttpClientProvider().getSharedInstance()); diff --git a/sdk/clientcore/optional-dependency-tests/src/samples/java/io/clientcore/core/instrumentation/TelemetryJavaDocCodeSnippets.java b/sdk/clientcore/optional-dependency-tests/src/samples/java/io/clientcore/core/instrumentation/TelemetryJavaDocCodeSnippets.java index 157d476671c2f..f695c68b8a138 100644 --- a/sdk/clientcore/optional-dependency-tests/src/samples/java/io/clientcore/core/instrumentation/TelemetryJavaDocCodeSnippets.java +++ b/sdk/clientcore/optional-dependency-tests/src/samples/java/io/clientcore/core/instrumentation/TelemetryJavaDocCodeSnippets.java @@ -3,6 +3,7 @@ package io.clientcore.core.instrumentation; +import io.clientcore.core.http.models.HttpInstrumentationOptions; import io.clientcore.core.http.models.HttpMethod; import io.clientcore.core.http.models.HttpRequest; import io.clientcore.core.http.models.RequestOptions; @@ -58,6 +59,8 @@ public void useGlobalOpenTelemetry() { AutoConfiguredOpenTelemetrySdk.initialize(); SampleClient client = new SampleClientBuilder().build(); + + // this call will be traced using OpenTelemetry SDK initialized globally client.clientCall(); // END: io.clientcore.core.telemetry.useglobalopentelemetry @@ -70,11 +73,13 @@ public void useGlobalOpenTelemetry() { public void useExplicitOpenTelemetry() { // BEGIN: io.clientcore.core.telemetry.useexplicitopentelemetry - OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); - InstrumentationOptions instrumentationOptions = new InstrumentationOptions() - .setProvider(openTelemetry); + OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); + HttpInstrumentationOptions instrumentationOptions = new HttpInstrumentationOptions() + .setTelemetryProvider(openTelemetry); SampleClient client = new SampleClientBuilder().instrumentationOptions(instrumentationOptions).build(); + + // this call will be traced using OpenTelemetry SDK provided explicitly client.clientCall(); // END: io.clientcore.core.telemetry.useexplicitopentelemetry @@ -87,7 +92,7 @@ public void useExplicitOpenTelemetry() { public void disableDistributedTracing() { // BEGIN: io.clientcore.core.telemetry.disabledistributedtracing - InstrumentationOptions instrumentationOptions = new InstrumentationOptions<>() + HttpInstrumentationOptions instrumentationOptions = new HttpInstrumentationOptions() .setTracingEnabled(false); SampleClient client = new SampleClientBuilder().instrumentationOptions(instrumentationOptions).build(); @@ -148,16 +153,16 @@ public void correlationWithExplicitContext() { } static class SampleClientBuilder { - private InstrumentationOptions instrumentationOptions; + private HttpInstrumentationOptions instrumentationOptions; // TODO (limolkova): do we need InstrumentationTrait? - public SampleClientBuilder instrumentationOptions(InstrumentationOptions instrumentationOptions) { + public SampleClientBuilder instrumentationOptions(HttpInstrumentationOptions instrumentationOptions) { this.instrumentationOptions = instrumentationOptions; return this; } public SampleClient build() { return new SampleClient(instrumentationOptions, new HttpPipelineBuilder() - .policies(new HttpInstrumentationPolicy(instrumentationOptions, null)) + .policies(new HttpInstrumentationPolicy(instrumentationOptions)) .build()); } } @@ -167,7 +172,7 @@ static class SampleClient { private final HttpPipeline httpPipeline; private final io.clientcore.core.instrumentation.tracing.Tracer tracer; - SampleClient(InstrumentationOptions instrumentationOptions, HttpPipeline httpPipeline) { + SampleClient(InstrumentationOptions instrumentationOptions, HttpPipeline httpPipeline) { this.httpPipeline = httpPipeline; this.tracer = Instrumentation.create(instrumentationOptions, LIBRARY_OPTIONS).getTracer(); } diff --git a/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicyTests.java b/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicyTests.java index f6b4c6d122360..381d6dca13439 100644 --- a/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicyTests.java +++ b/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicyTests.java @@ -5,14 +5,13 @@ import io.clientcore.core.http.MockHttpResponse; import io.clientcore.core.http.models.HttpHeaderName; -import io.clientcore.core.http.models.HttpLogOptions; +import io.clientcore.core.http.models.HttpInstrumentationOptions; import io.clientcore.core.http.models.HttpMethod; import io.clientcore.core.http.models.HttpRequest; import io.clientcore.core.http.models.RequestOptions; import io.clientcore.core.instrumentation.Instrumentation; import io.clientcore.core.instrumentation.InstrumentationContext; import io.clientcore.core.instrumentation.LibraryInstrumentationOptions; -import io.clientcore.core.instrumentation.InstrumentationOptions; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.trace.Span; @@ -76,7 +75,7 @@ public class HttpInstrumentationPolicyTests { private InMemorySpanExporter exporter; private SdkTracerProvider tracerProvider; private OpenTelemetry openTelemetry; - private InstrumentationOptions otelOptions; + private HttpInstrumentationOptions otelOptions; @BeforeEach public void setUp() { @@ -84,7 +83,7 @@ public void setUp() { tracerProvider = SdkTracerProvider.builder().addSpanProcessor(SimpleSpanProcessor.create(exporter)).build(); openTelemetry = OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build(); - otelOptions = new InstrumentationOptions().setProvider(openTelemetry); + otelOptions = new HttpInstrumentationOptions().setTelemetryProvider(openTelemetry); } @AfterEach @@ -98,15 +97,14 @@ public void tearDown() { public void simpleRequestIsRecorded(int statusCode) throws IOException { AtomicReference current = new AtomicReference<>(); - HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions, null)) - .httpClient(request -> { + HttpPipeline pipeline + = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions)).httpClient(request -> { assertStartAttributes((ReadableSpan) Span.current(), request.getHttpMethod(), request.getUri()); assertNull(request.getHeaders().get(TRACESTATE)); assertEquals(traceparent(Span.current()), request.getHeaders().get(TRACEPARENT).getValue()); current.set(Span.current()); return new MockHttpResponse(request, statusCode); - }) - .build(); + }).build(); pipeline.send(new HttpRequest(HttpMethod.GET, "https://localhost/")).close(); assertNotNull(exporter.getFinishedSpanItems()); @@ -127,7 +125,7 @@ public void simpleRequestIsRecorded(int statusCode) throws IOException { @ParameterizedTest @ValueSource(ints = { 400, 404, 500, 503 }) public void errorResponseIsRecorded(int statusCode) throws IOException { - HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions, null)) + HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions)) .httpClient(request -> new MockHttpResponse(request, statusCode)) .build(); @@ -152,17 +150,17 @@ public void tracingWithRetries() throws IOException { try (Scope scope = testSpan.makeCurrent()) { AtomicInteger count = new AtomicInteger(0); - HttpPipeline pipeline = new HttpPipelineBuilder() - .policies(new HttpRetryPolicy(), new HttpInstrumentationPolicy(otelOptions, null)) - .httpClient(request -> { - assertEquals(traceparent(Span.current()), request.getHeaders().get(TRACEPARENT).getValue()); - if (count.getAndIncrement() == 0) { - throw new UnknownHostException("test exception"); - } else { - return new MockHttpResponse(request, 200); - } - }) - .build(); + HttpPipeline pipeline + = new HttpPipelineBuilder().policies(new HttpRetryPolicy(), new HttpInstrumentationPolicy(otelOptions)) + .httpClient(request -> { + assertEquals(traceparent(Span.current()), request.getHeaders().get(TRACEPARENT).getValue()); + if (count.getAndIncrement() == 0) { + throw new UnknownHostException("test exception"); + } else { + return new MockHttpResponse(request, 200); + } + }) + .build(); pipeline.send(new HttpRequest(HttpMethod.GET, "https://localhost:8080/path/to/resource?query=param")) .close(); @@ -195,16 +193,14 @@ public void unsampledSpan() throws IOException { .addSpanProcessor(SimpleSpanProcessor.create(exporter)) .build(); OpenTelemetry openTelemetry = OpenTelemetrySdk.builder().setTracerProvider(sampleNone).build(); - InstrumentationOptions otelOptions - = new InstrumentationOptions().setProvider(openTelemetry); + HttpInstrumentationOptions otelOptions = new HttpInstrumentationOptions().setTelemetryProvider(openTelemetry); - HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions, null)) - .httpClient(request -> { + HttpPipeline pipeline + = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions)).httpClient(request -> { assertTrue(Span.current().getSpanContext().isValid()); assertEquals(traceparent(Span.current()), request.getHeaders().get(TRACEPARENT).getValue()); return new MockHttpResponse(request, 200); - }) - .build(); + }).build(); pipeline.send(new HttpRequest(HttpMethod.GET, "http://localhost/")).close(); assertNotNull(exporter.getFinishedSpanItems()); @@ -218,13 +214,12 @@ public void tracestateIsPropagated() throws IOException { = SpanContext.create(IdGenerator.random().generateTraceId(), IdGenerator.random().generateSpanId(), TraceFlags.getSampled(), TraceState.builder().put("key", "value").build()); - HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions, null)) - .httpClient(request -> { + HttpPipeline pipeline + = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions)).httpClient(request -> { assertEquals("key=value", request.getHeaders().get(TRACESTATE).getValue()); assertEquals(traceparent(Span.current()), request.getHeaders().get(TRACEPARENT).getValue()); return new MockHttpResponse(request, 200); - }) - .build(); + }).build(); try (Scope scope = Span.wrap(parentContext).makeCurrent()) { pipeline.send(new HttpRequest(HttpMethod.GET, "http://localhost/")).close(); @@ -259,15 +254,13 @@ public io.opentelemetry.context.Context extract(io.opentelemetry.context.Con .setPropagators(ContextPropagators.create(testPropagator)) .build(); - InstrumentationOptions otelOptions - = new InstrumentationOptions().setProvider(openTelemetry); + HttpInstrumentationOptions otelOptions = new HttpInstrumentationOptions().setTelemetryProvider(openTelemetry); - HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions, null)) - .httpClient(request -> { + HttpPipeline pipeline + = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions)).httpClient(request -> { assertEquals(traceparent(Span.current()), request.getHeaders().get(TRACEPARENT).getValue()); return new MockHttpResponse(request, 200); - }) - .build(); + }).build(); pipeline.send(new HttpRequest(HttpMethod.GET, "http://localhost/")).close(); } @@ -275,11 +268,10 @@ public io.opentelemetry.context.Context extract(io.opentelemetry.context.Con @Test public void exceptionIsRecorded() { SocketException exception = new SocketException("test exception"); - HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions, null)) - .httpClient(request -> { + HttpPipeline pipeline + = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions)).httpClient(request -> { throw exception; - }) - .build(); + }).build(); assertThrows(UncheckedIOException.class, () -> pipeline.send(new HttpRequest(HttpMethod.GET, "https://localhost/")).close()); @@ -295,10 +287,10 @@ public void exceptionIsRecorded() { @Test public void tracingIsDisabledOnInstance() throws IOException { - InstrumentationOptions options - = new InstrumentationOptions().setTracingEnabled(false).setProvider(openTelemetry); + HttpInstrumentationOptions options + = new HttpInstrumentationOptions().setTracingEnabled(false).setTelemetryProvider(openTelemetry); HttpPipeline pipeline - = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(options, null)).httpClient(request -> { + = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(options)).httpClient(request -> { assertFalse(Span.current().getSpanContext().isValid()); assertFalse(Span.current().isRecording()); assertNull(request.getHeaders().get(TRACEPARENT)); @@ -313,7 +305,7 @@ public void tracingIsDisabledOnInstance() throws IOException { @Test public void userAgentIsRecorded() throws IOException { - HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions, null)) + HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions)) .httpClient(request -> new MockHttpResponse(request, 200)) .build(); @@ -332,9 +324,8 @@ public void userAgentIsRecorded() throws IOException { @Test public void enrichSpans() throws IOException { - HttpLogOptions logOptions = new HttpLogOptions().setLogLevel(HttpLogOptions.HttpLogDetailLevel.HEADERS); - - HttpInstrumentationPolicy httpInstrumentationPolicy = new HttpInstrumentationPolicy(otelOptions, logOptions); + HttpInstrumentationPolicy httpInstrumentationPolicy = new HttpInstrumentationPolicy( + otelOptions.setHttpLogLevel(HttpInstrumentationOptions.HttpLogDetailLevel.HEADERS)); HttpPipelinePolicy enrichingPolicy = (request, next) -> { io.clientcore.core.instrumentation.tracing.Span span @@ -371,7 +362,7 @@ public void implicitParent() throws IOException { Span testSpan = testTracer.spanBuilder("test").startSpan(); try (Scope scope = testSpan.makeCurrent()) { - HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions, null)) + HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions)) .httpClient(request -> new MockHttpResponse(request, 200)) .build(); @@ -395,7 +386,7 @@ public void explicitParent() throws IOException { Tracer testTracer = tracerProvider.get("test"); Span testSpan = testTracer.spanBuilder("test").startSpan(); - HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions, null)) + HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions)) .httpClient(request -> new MockHttpResponse(request, 200)) .build(); @@ -417,11 +408,10 @@ public void explicitParent() throws IOException { @Test public void customUrlRedaction() throws IOException { - HttpLogOptions logOptions = new HttpLogOptions().setAllowedQueryParamNames(Collections.singleton("key1")); - HttpPipeline pipeline - = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions, logOptions)) - .httpClient(request -> new MockHttpResponse(request, 200)) - .build(); + otelOptions.setAllowedQueryParamNames(Collections.singleton("key1")); + HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions)) + .httpClient(request -> new MockHttpResponse(request, 200)) + .build(); pipeline .send(new HttpRequest(HttpMethod.GET, "https://localhost:8080/path/to/resource?query=param&key1=value1")) @@ -446,7 +436,7 @@ public void explicitLibraryCallParent() throws IOException { requestOptions.setInstrumentationContext(parent.getInstrumentationContext()); - HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions, null)) + HttpPipeline pipeline = new HttpPipelineBuilder().policies(new HttpInstrumentationPolicy(otelOptions)) .httpClient(request -> new MockHttpResponse(request, 200)) .build(); diff --git a/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/ContextPropagationTests.java b/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/ContextPropagationTests.java index d603fdf3c0ea4..d37277f70b6bb 100644 --- a/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/ContextPropagationTests.java +++ b/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/ContextPropagationTests.java @@ -49,7 +49,7 @@ public String get(Map carrier, String key) { private InMemorySpanExporter exporter; private SdkTracerProvider tracerProvider; - private InstrumentationOptions otelOptions; + private InstrumentationOptions otelOptions; private Tracer tracer; private TraceContextPropagator contextPropagator; private Instrumentation instrumentation; @@ -60,7 +60,7 @@ public void setUp() { tracerProvider = SdkTracerProvider.builder().addSpanProcessor(SimpleSpanProcessor.create(exporter)).build(); OpenTelemetry openTelemetry = OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build(); - otelOptions = new InstrumentationOptions().setProvider(openTelemetry); + otelOptions = new InstrumentationOptions().setTelemetryProvider(openTelemetry); instrumentation = Instrumentation.create(otelOptions, DEFAULT_LIB_OPTIONS); tracer = instrumentation.getTracer(); contextPropagator = instrumentation.getW3CTraceContextPropagator(); diff --git a/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/InstrumentationTests.java b/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/InstrumentationTests.java index aa766c1a51e55..92f10092db33e 100644 --- a/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/InstrumentationTests.java +++ b/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/InstrumentationTests.java @@ -11,7 +11,6 @@ import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; -import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; @@ -66,8 +65,8 @@ public void createTracerOTelNotConfigured() { public void createTracerTracingDisabled() { OpenTelemetry otel = OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).buildAndRegisterGlobal(); - InstrumentationOptions options - = new InstrumentationOptions().setTracingEnabled(false).setProvider(otel); + InstrumentationOptions options + = new InstrumentationOptions().setTracingEnabled(false).setTelemetryProvider(otel); Tracer tracer = Instrumentation.create(options, DEFAULT_LIB_OPTIONS).getTracer(); assertFalse(tracer.isEnabled()); @@ -109,7 +108,7 @@ public void createTracerExplicitOTel() throws Exception { OpenTelemetry localOTel = OpenTelemetrySdk.builder().setTracerProvider(localTracerProvider).build(); Tracer tracer = Instrumentation - .create(new InstrumentationOptions().setProvider(localOTel), DEFAULT_LIB_OPTIONS) + .create(new InstrumentationOptions().setTelemetryProvider(localOTel), DEFAULT_LIB_OPTIONS) .getTracer(); assertTrue(tracer.isEnabled()); @@ -123,8 +122,7 @@ public void createTracerExplicitOTel() throws Exception { @Test public void createTracerBadArguments() { - InstrumentationOptions options - = new InstrumentationOptions().setProvider(tracerProvider); + InstrumentationOptions options = new InstrumentationOptions().setTelemetryProvider(tracerProvider); assertThrows(IllegalArgumentException.class, () -> Instrumentation.create(options, DEFAULT_LIB_OPTIONS).getTracer()); @@ -175,7 +173,7 @@ public void createInstrumentationContextFromOTelSpan() { assertEquals(otelSpan.getSpanContext().getTraceFlags().asHex(), context.getTraceFlags()); Tracer tracer - = Instrumentation.create(new InstrumentationOptions().setProvider(otel), DEFAULT_LIB_OPTIONS) + = Instrumentation.create(new InstrumentationOptions().setTelemetryProvider(otel), DEFAULT_LIB_OPTIONS) .getTracer(); Span span = tracer.spanBuilder("test", INTERNAL, context).startSpan(); assertEquals(otelSpan.getSpanContext().getTraceId(), span.getInstrumentationContext().getTraceId()); @@ -219,7 +217,7 @@ public void createInstrumentationContextFromOTelSpanContext() { assertEquals(otelSpanContext.getTraceFlags().asHex(), context.getTraceFlags()); Tracer tracer - = Instrumentation.create(new InstrumentationOptions().setProvider(otel), DEFAULT_LIB_OPTIONS) + = Instrumentation.create(new InstrumentationOptions().setTelemetryProvider(otel), DEFAULT_LIB_OPTIONS) .getTracer(); Span span = tracer.spanBuilder("test", INTERNAL, context).startSpan(); assertEquals(otelSpanContext.getTraceId(), span.getInstrumentationContext().getTraceId()); diff --git a/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/SuppressionTests.java b/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/SuppressionTests.java index 0787d9bc74358..e085fee1db34a 100644 --- a/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/SuppressionTests.java +++ b/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/SuppressionTests.java @@ -49,7 +49,7 @@ public class SuppressionTests { private InMemorySpanExporter exporter; private SdkTracerProvider tracerProvider; - private InstrumentationOptions otelOptions; + private InstrumentationOptions otelOptions; private Tracer tracer; @BeforeEach @@ -57,7 +57,7 @@ public void setUp() { exporter = InMemorySpanExporter.create(); tracerProvider = SdkTracerProvider.builder().addSpanProcessor(SimpleSpanProcessor.create(exporter)).build(); OpenTelemetry openTelemetry = OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build(); - otelOptions = new InstrumentationOptions().setProvider(openTelemetry); + otelOptions = new InstrumentationOptions().setTelemetryProvider(openTelemetry); tracer = Instrumentation.create(otelOptions, DEFAULT_LIB_OPTIONS).getTracer(); } @@ -307,7 +307,7 @@ static class SampleClient { private final HttpPipeline pipeline; private final Tracer tracer; - SampleClient(HttpPipeline pipeline, InstrumentationOptions options) { + SampleClient(HttpPipeline pipeline, InstrumentationOptions options) { this.pipeline = pipeline; this.tracer = Instrumentation.create(options, DEFAULT_LIB_OPTIONS).getTracer(); } diff --git a/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/TracerTests.java b/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/TracerTests.java index 6b9cd3c528e04..fb8330dfc8c87 100644 --- a/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/TracerTests.java +++ b/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/TracerTests.java @@ -36,7 +36,8 @@ public class TracerTests { private InMemorySpanExporter exporter; private SdkTracerProvider tracerProvider; - private InstrumentationOptions otelOptions; + private InstrumentationOptions otelOptions; + private OpenTelemetry openTelemetry; private Tracer tracer; @BeforeEach @@ -44,8 +45,8 @@ public void setUp() { exporter = InMemorySpanExporter.create(); tracerProvider = SdkTracerProvider.builder().addSpanProcessor(SimpleSpanProcessor.create(exporter)).build(); - OpenTelemetry openTelemetry = OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build(); - otelOptions = new InstrumentationOptions().setProvider(openTelemetry); + openTelemetry = OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build(); + otelOptions = new InstrumentationOptions().setTelemetryProvider(openTelemetry); tracer = Instrumentation.create(otelOptions, DEFAULT_LIB_OPTIONS).getTracer(); } @@ -152,7 +153,7 @@ public void testKinds(SpanKind kind, io.opentelemetry.api.trace.SpanKind expecte @SuppressWarnings("try") @Test public void implicitParent() throws Exception { - io.opentelemetry.api.trace.Tracer otelTracer = otelOptions.getProvider().getTracer("test"); + io.opentelemetry.api.trace.Tracer otelTracer = openTelemetry.getTracer("test"); io.opentelemetry.api.trace.Span parent = otelTracer.spanBuilder("parent").startSpan(); try (AutoCloseable scope = parent.makeCurrent()) { Span child = tracer.spanBuilder("child", INTERNAL, null).startSpan(); @@ -171,8 +172,8 @@ public void implicitParent() throws Exception { } @Test - public void explicitParent() throws Exception { - io.opentelemetry.api.trace.Tracer otelTracer = otelOptions.getProvider().getTracer("test"); + public void explicitParent() { + io.opentelemetry.api.trace.Tracer otelTracer = openTelemetry.getTracer("test"); io.opentelemetry.api.trace.Span parent = otelTracer.spanBuilder("parent").startSpan(); Span child = tracer.spanBuilder("child", INTERNAL, OTelSpanContext.fromOTelContext(Context.root().with(parent))) diff --git a/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/TracingShimBenchmarks.java b/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/TracingShimBenchmarks.java index 8f029d16e5db9..ec16ab5a692cc 100644 --- a/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/TracingShimBenchmarks.java +++ b/sdk/clientcore/optional-dependency-tests/src/test/java/io/clientcore/core/instrumentation/TracingShimBenchmarks.java @@ -62,12 +62,12 @@ public void setupOtel() { otelTracerDisabled = TracerProvider.noop().get("test"); shimTracer = Instrumentation - .create(new InstrumentationOptions().setProvider(openTelemetry), + .create(new InstrumentationOptions().setTelemetryProvider(openTelemetry), new LibraryInstrumentationOptions("test")) .getTracer(); shimTracerDisabled = Instrumentation - .create(new InstrumentationOptions().setProvider(OpenTelemetry.noop()), + .create(new InstrumentationOptions().setTelemetryProvider(OpenTelemetry.noop()), new LibraryInstrumentationOptions("test")) .getTracer(); } diff --git a/sdk/clientcore/tools/annotation-processor/src/main/java/io/clientcore/tools/codegen/templating/JavaPoetTemplateProcessor.java b/sdk/clientcore/tools/annotation-processor/src/main/java/io/clientcore/tools/codegen/templating/JavaPoetTemplateProcessor.java index 129fc54adf159..8b7794de0083b 100644 --- a/sdk/clientcore/tools/annotation-processor/src/main/java/io/clientcore/tools/codegen/templating/JavaPoetTemplateProcessor.java +++ b/sdk/clientcore/tools/annotation-processor/src/main/java/io/clientcore/tools/codegen/templating/JavaPoetTemplateProcessor.java @@ -37,7 +37,7 @@ public class JavaPoetTemplateProcessor implements TemplateProcessor { private TypeSpec.Builder classBuilder; final ClassName HTTP_PIPELINE = ClassName.get("io.clientcore.core.http.pipeline", "HttpPipeline"); static ClassName SERVICE_VERSION_TYPE; - final ClassName CLIENTLOGGER_NAME = ClassName.get("io.clientcore.core.util", "ClientLogger"); + final ClassName CLIENTLOGGER_NAME = ClassName.get("io.clientcore.core.instrumentation.logging", "ClientLogger"); @Override public void process(TemplateInput templateInput, ProcessingEnvironment processingEnv) { diff --git a/sdk/clientcore/tools/annotation-processor/src/test/java/io/clientcore/tools/codegen/templating/HttpPipelineBuilderMethodTest.java b/sdk/clientcore/tools/annotation-processor/src/test/java/io/clientcore/tools/codegen/templating/HttpPipelineBuilderMethodTest.java index 857b221106e8d..f22f7c492b951 100644 --- a/sdk/clientcore/tools/annotation-processor/src/test/java/io/clientcore/tools/codegen/templating/HttpPipelineBuilderMethodTest.java +++ b/sdk/clientcore/tools/annotation-processor/src/test/java/io/clientcore/tools/codegen/templating/HttpPipelineBuilderMethodTest.java @@ -119,6 +119,6 @@ public void testLoggerFieldGeneration() { loggerField.modifiers); assertEquals(processor.CLIENTLOGGER_NAME, loggerField.type); assertEquals("LOGGER", loggerField.name); - assertTrue(loggerField.initializer.toString().contains("new io.clientcore.core.util.ClientLogger(com.example.ExampleClientServiceImpl.class)")); + assertTrue(loggerField.initializer.toString().contains("new io.clientcore.core.instrumentation.logging.ClientLogger(com.example.ExampleClientServiceImpl.class)")); } }