diff --git a/.github/workflows/linux-ci-md.yml b/.github/workflows/ci-md.yml similarity index 74% rename from .github/workflows/linux-ci-md.yml rename to .github/workflows/ci-md.yml index 5b7008872e4..1dde2355a3e 100644 --- a/.github/workflows/linux-ci-md.yml +++ b/.github/workflows/ci-md.yml @@ -5,7 +5,7 @@ # IMPORTANT: This workflow MUST use the same 'name' as the non -md workflow. -name: Linux +name: Build on: pull_request: @@ -15,11 +15,14 @@ on: jobs: build-test: - runs-on: ubuntu-latest - strategy: matrix: - version: [net6.0] + os: [ windows-latest, ubuntu-latest ] + version: [ net462, net6.0, net7.0 ] + exclude: + - os: ubuntu-latest + version: net462 + runs-on: ubuntu-latest steps: - - run: 'echo "No build required"' + - run: 'echo "No build required"' diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/ci.yml similarity index 63% rename from .github/workflows/windows-ci.yml rename to .github/workflows/ci.yml index b88ef208dd2..216e71c5248 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: Windows +name: Build on: push: @@ -12,12 +12,16 @@ on: jobs: build-test: - runs-on: windows-latest - strategy: + fail-fast: false # ensures the entire test matrix is run, even if one permutation fails matrix: - version: [net462,net6.0,net7.0] + os: [ windows-latest, ubuntu-latest ] + version: [ net462, net6.0, net7.0 ] + exclude: + - os: ubuntu-latest + version: net462 + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 with: @@ -34,4 +38,4 @@ jobs: run: dotnet build --configuration Release --no-restore - name: Test ${{ matrix.version }} - run: dotnet test **\bin\**\${{ matrix.version }}\*Tests.dll --configuration Release --no-build --logger:"console;verbosity=detailed" + run: dotnet test **/bin/**/${{ matrix.version }}/*Tests.dll --configuration Release --no-build --logger:"console;verbosity=detailed" diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml deleted file mode 100644 index 6834fdc7f8b..00000000000 --- a/.github/workflows/linux-ci.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Linux - -on: - push: - branches: [ 'main*' ] - paths-ignore: - - '**.md' - pull_request: - branches: [ 'main*' ] - paths-ignore: - - '**.md' - -jobs: - build-test: - runs-on: ubuntu-latest - - strategy: - matrix: - version: [net6.0, net7.0] - - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 # fetching all - - - uses: actions/setup-dotnet@v3.0.3 - with: - dotnet-version: '6.0.x' - - - uses: actions/setup-dotnet@v3.0.3 - with: - dotnet-version: '7.0.x' - - - name: Install dependencies - run: dotnet restore - - - name: Build - run: dotnet build --configuration Release --no-restore - - - name: Test ${{ matrix.version }} - run: dotnet test **/bin/**/${{ matrix.version }}/*.Tests.dll --configuration Release --no-build --logger:"console;verbosity=detailed" diff --git a/.github/workflows/windows-ci-md.yml b/.github/workflows/windows-ci-md.yml deleted file mode 100644 index 894773ddb37..00000000000 --- a/.github/workflows/windows-ci-md.yml +++ /dev/null @@ -1,25 +0,0 @@ -# Syntax: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions -# See also: https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks - -# Description: This workflow exists to unblock documentation-only PRs. - -# IMPORTANT: This workflow MUST use the same 'name' as the non -md workflow. - -name: Windows - -on: - pull_request: - branches: [ 'main*' ] - paths: - - '**.md' - -jobs: - build-test: - runs-on: ubuntu-latest - - strategy: - matrix: - version: [net462,net6.0,net7.0] - - steps: - - run: 'echo "No build required"' diff --git a/.vscode/settings.json b/.vscode/settings.json index 80311886304..b94b3d3678d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "cSpell.words": [ "appsettings", "asax", + "bankwar", "cijo", "cncf", "codebases", @@ -50,6 +51,7 @@ "unencrypted", "unvalidated", "utkarsh", + "vishwesh", "xunit", "zipkin", "zpages" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9aa487e4afa..6f713ae1146 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,7 +59,7 @@ of Windows. * Visual Studio 2022+ or Visual Studio Code * .NET Framework 4.6.2+ -**NOTE** : Visual Studio 2022 preview is **recommended** due to projects +**Note:** : Visual Studio 2022 preview is **recommended** due to projects targeting `.net7.0` which is in preview currently. ### Public API diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln index 1b961fc5f7b..471a28502a8 100644 --- a/OpenTelemetry.sln +++ b/OpenTelemetry.sln @@ -93,19 +93,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ ProjectSection(SolutionItems) = preProject .github\workflows\apicompatibility.yml = .github\workflows\apicompatibility.yml .github\workflows\code-coverage.yml = .github\workflows\code-coverage.yml + .github\workflows\ci.yml = .github\workflows\ci.yml + .github\workflows\ci-md.yml = .github\workflows\ci-md.yml .github\workflows\codeql-analysis.yml = .github\workflows\codeql-analysis.yml .github\workflows\docfx.yml = .github\workflows\docfx.yml .github\workflows\dotnet-format-md.yml = .github\workflows\dotnet-format-md.yml .github\workflows\dotnet-format.yml = .github\workflows\dotnet-format.yml .github\workflows\integration-md.yml = .github\workflows\integration-md.yml .github\workflows\integration.yml = .github\workflows\integration.yml - .github\workflows\linux-ci-md.yml = .github\workflows\linux-ci-md.yml - .github\workflows\linux-ci.yml = .github\workflows\linux-ci.yml .github\workflows\markdownlint.yml = .github\workflows\markdownlint.yml .github\workflows\publish-packages-1.0.yml = .github\workflows\publish-packages-1.0.yml .github\workflows\sanitycheck.yml = .github\workflows\sanitycheck.yml - .github\workflows\windows-ci-md.yml = .github\workflows\windows-ci-md.yml - .github\workflows\windows-ci.yml = .github\workflows\windows-ci.yml EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C1542297-8763-4DF4-957C-489ED771C21D}" diff --git a/README.md b/README.md index 5ef0b03e1a7..f681bc1709c 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,11 @@ files. Logs](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry.Exporter.OpenTelemetryProtocol#otlp-logs) is still non-stable. +See [Spec Compliance +Matrix](https://github.com/open-telemetry/opentelemetry-specification/blob/main/spec-compliance-matrix.md) +to understand which portions of the specification has been implemented in this +repo. + ## Getting Started If you are new here, please read the getting started docs: @@ -70,8 +75,10 @@ libraries](https://github.com/open-telemetry/opentelemetry-specification/blob/ma * [Prometheus AspNetCore](./src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md) * [Zipkin](./src/OpenTelemetry.Exporter.Zipkin/README.md) -See the [OpenTelemetry registry](https://opentelemetry.io/registry/?s=net) for -more exporters. +See the [OpenTelemetry registry](https://opentelemetry.io/registry/?s=net) and +[OpenTelemetry .NET Contrib +repo](https://github.com/open-telemetry/opentelemetry-dotnet-contrib) for more +components. ## Extensibility diff --git a/build/Common.props b/build/Common.props index ea961e63739..0906bb0a67b 100644 --- a/build/Common.props +++ b/build/Common.props @@ -43,7 +43,7 @@ [2.8.0,3.0) [1.2.0-beta.435,2.0) 1.4.0 - 7.0.0-rc.2.22472.3 + 7.0.0 4.7.0 4.7.2 4.5.4 diff --git a/docs/metrics/customizing-the-sdk/README.md b/docs/metrics/customizing-the-sdk/README.md index bf5ecdae364..d700d6da54f 100644 --- a/docs/metrics/customizing-the-sdk/README.md +++ b/docs/metrics/customizing-the-sdk/README.md @@ -251,7 +251,7 @@ default boundaries. This requires the use of new ExplicitBucketHistogramConfiguration { Boundaries = new double[] { 10, 20 } }) // If you provide an empty `double` array as `Boundaries` to the `ExplicitBucketHistogramConfiguration`, - // the SDK will only export the sum and count for the measurements. + // the SDK will only export the sum, count, min and max for the measurements. // There are no buckets exported in this case. .AddView( instrumentName: "MyHistogram", @@ -276,7 +276,7 @@ default boundaries. This requires the use of }) ``` -**NOTE:** The SDK currently does not support any changes to `Aggregation` type +**Note:** The SDK currently does not support any changes to `Aggregation` type by using Views. See [Program.cs](./Program.cs) for a complete example. @@ -329,9 +329,9 @@ ignored. The SDK chooses the key/value combinations in the order in which they are emitted. `SetMaxMetricPointsPerMetricStream` can be used to override the default. -**NOTE**: One `MetricPoint` is reserved for every `MetricStream` for the special -case where there is no key/value pair associated with the metric. The maximum -number of `MetricPoint`s has to accommodate for this special case. +**Note:**: One `MetricPoint` is reserved for every `MetricStream` for the +special case where there is no key/value pair associated with the metric. The +maximum number of `MetricPoint`s has to accommodate for this special case. Consider the below example. Here we set the maximum number of `MetricPoint`s allowed to be `3`. This means that for every `MetricStream`, the SDK will export @@ -395,7 +395,7 @@ AnotherFruitCounter.Add(5, new("name", "banana"), new("color", "yellow")); // Ex AnotherFruitCounter.Add(4, new("name", "mango"), new("color", "yellow")); // Not exported ``` -**NOTE:** The above limit is *per* metric stream, and applies to all the metric +**Note:** The above limit is *per* metric stream, and applies to all the metric streams. There is no ability to apply different limits for each instrument at this moment. diff --git a/docs/metrics/getting-started-prometheus-grafana/README.md b/docs/metrics/getting-started-prometheus-grafana/README.md index 1e2f2e35e99..8c57ed65853 100644 --- a/docs/metrics/getting-started-prometheus-grafana/README.md +++ b/docs/metrics/getting-started-prometheus-grafana/README.md @@ -172,18 +172,19 @@ Follow the instructions in the Grafana getting started [doc](https://grafana.com/docs/grafana/latest/getting-started/getting-started/#step-2-log-in) to log in. -After successfully logging in, click on the Configuration icon -on the panel at the left hand side, and click on Prometheus. -Type in the default endpoint of Prometheus as suggested by the UI -as the value for the URI. +After successfully logging in, hover on the Configuration icon +on the panel at the left hand side, and click on Plugins. +Find and click on the Prometheus plugin. Next click on +`Create a Prometheus data source` button. Type in the default endpoint of +Prometheus as suggested by the UI as the value for the URI. ```console http://localhost:9090 ``` -Then, click on the Explore icon on the left panel of -the website - we should be able to write some queries to explore our metrics -now! +At the bottom of the page click `Save & test` to ensure the data source is +working. Then, click on the `Explore` button - we should be able to write +some queries to explore our metrics now! Feel free to find some handy PromQL [here](https://promlabs.com/promql-cheat-sheet/). diff --git a/docs/trace/customizing-the-sdk/README.md b/docs/trace/customizing-the-sdk/README.md index d162574a954..ead1fd85986 100644 --- a/docs/trace/customizing-the-sdk/README.md +++ b/docs/trace/customizing-the-sdk/README.md @@ -38,9 +38,10 @@ tracerProvider.Dispose() ``` **Note:** The `Sdk.CreateTracerProviderBuilder()` API is available for all -runtimes. Additionally, for `ASP.NET Core` and [.NET Generic -Host](https://learn.microsoft.com/dotnet/core/extensions/generic-host) users, -helper extensions are provided in the +runtimes. Additionally, for [ASP.NET +Core](https://learn.microsoft.com/aspnet/core/fundamentals/host/web-host) and +[.NET Generic](https://learn.microsoft.com/dotnet/core/extensions/generic-host) +host users, helper extensions are provided in the [OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md) package to simplify configuration and management of the `TracerProvider`. @@ -109,7 +110,7 @@ var tracerProvider = Sdk.CreateTracerProviderBuilder() See [Program.cs](./Program.cs) for complete example. -**Note** A common mistake while configuring `TracerProvider` is forgetting to +**Note:** A common mistake while configuring `TracerProvider` is forgetting to add all `ActivitySources` to the provider. It is recommended to leverage the wild card subscription model where it makes sense. For example, if your application is expecting to enable tracing from a number of libraries from a @@ -153,8 +154,8 @@ processor classes `SimpleExportProcessor` & `BatchExportProcessor` are provided to support invoking exporters through the processor pipeline and implement the standard behaviors prescribed by the OpenTelemetry specification. -**Note** The SDK only ever invokes processors and has no direct knowledge of any -registered exporters. +**Note:** The SDK only ever invokes processors and has no direct knowledge of +any registered exporters. #### Processor Configuration @@ -175,11 +176,11 @@ var tracerProvider = Sdk.CreateTracerProviderBuilder() tracerProvider.AddProcessor(new MyProcessor3()); ``` -**Note** A `TracerProvider` assumes ownership of **all** processors added to it. -This means that the provider will call the `Shutdown` method on all registered -processors when it is shutting down and call the `Dispose` method on all -registered processors when it is disposed. If multiple providers are being set -up in an application then separate instances of processors **MUST** be +**Note:** A `TracerProvider` assumes ownership of **all** processors added to +it. This means that the provider will call the `Shutdown` method on all +registered processors when it is shutting down and call the `Dispose` method on +all registered processors when it is disposed. If multiple providers are being +set up in an application then separate instances of processors **MUST** be registered on each provider. Otherwise shutting down one provider will cause the shared processor(s) in other providers to be shut down as well which may lead to undesired results. @@ -213,12 +214,12 @@ For exporting purposes, the SDK provides the following built-in processors: : This is an exporting processor which passes telemetry to the configured exporter immediately without any batching. -**Note** A special processor +**Note:** A special processor [CompositeProcessor<T>](../../../src/OpenTelemetry/CompositeProcessor.cs) is used by the SDK to chain multiple processors together and may be used as needed by users to define sub-pipelines. -**Note** The processors shipped from this SDK are generic implementations and +**Note:** The processors shipped from this SDK are generic implementations and support tracing and logging by implementing `Activity` and `LogRecord` respectively. @@ -240,19 +241,6 @@ var tracerProvider = Sdk.CreateTracerProviderBuilder() .Build(); ``` -To make exporter registration easier an `AddExporter` extension is also -provided. The snippet below shows how to add an export processor using - `AddExporter` to the provider before it is built. - - ```csharp -using OpenTelemetry; -using OpenTelemetry.Trace; - -var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddExporter(ExportProcessorType.Batch) - .Build(); -``` - It is also common for exporters to provide their own extensions to simplify registration. The snippet below shows how to add the [JaegerExporter](../../../src/OpenTelemetry.Exporter.Jaeger/README.md) to the @@ -359,10 +347,314 @@ using OpenTelemetry; Sdk.SetDefaultTextMapPropagator(new MyCustomPropagator()); ``` -## Dependency Injection Support +## Dependency injection support + +**Note:** This information applies to the OpenTelemetry SDK version 1.4.0 and +newer only. + +The SDK implementation of `TracerProviderBuilder` is backed by an +`IServiceCollection` and supports a wide range of APIs to enable what is +generally known as [dependency +injection](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection). + +### Dependency injection examples -// TODO: Add details here +For the below examples imagine a processor with this constructor: + +```csharp +public class MyCustomProcessor : BaseProcessor +{ + public MyCustomProcessor(MyCustomService myCustomService) + { + // Implementation not important + } +} +``` + +We want to inject `MyCustomService` dependency into our `MyCustomProcessor` +instance. + +#### Using Sdk.CreateTracerProviderBuilder() + +To register `MyCustomProcessor` and `MyCustomService` we can use the +`ConfigureServices` and `AddProcessor` methods: + +```csharp +using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .ConfigureServices(services => + { + services.AddSingleton(); + }) + .AddProcessor() + .Build(); +``` + +When using the `Sdk.CreateTracerProviderBuilder` method the `TracerProvider` +owns its own `IServiceCollection`. It will only be able to see services +registered into that collection. + +**Note:** It is important to correctly manage the lifecycle of the +`TracerProvider`. See [Building a TracerProvider](#building-a-tracerprovider) +for details. + +#### Using the OpenTelemetry.Extensions.Hosting package + +**Note:** If you are authoring an [ASP.NET Core +application](https://learn.microsoft.com/aspnet/core/fundamentals/host/web-host) +or using the [.NET Generic +Host](https://learn.microsoft.com/dotnet/core/extensions/generic-host) the +[OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md) +package is the recommended mechanism. + +```csharp +var appBuilder = WebApplication.CreateBuilder(args); -## Configuration files and Environment Variables +appBuilder.Services.AddSingleton(); -// TODO: Add details here +appBuilder.Services.AddOpenTelemetryTracing(builder => builder + .AddProcessor(); +``` + +When using the `AddOpenTelemetryTracing` method the `TracerProvider` does not +own its `IServiceCollection` and instead registers into an existing collection +(typically the collection used is the one managed by the application host). The +`TracerProviderBuilder` will be able to access all services registered into that +collection. For lifecycle management, an [IHostedService +](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice) +is used to automatically start the `TracerProvider` when the host starts and the +host will automatically shutdown and dispose the `TracerProvider` when it is +shutdown. + +**Note:** Multiple calls to `AddOpenTelemetryTracing` will configure the same +`TracerProvider`. Only a single `TraceProvider` may exist in an +`IServiceCollection` \ `IServiceProvider`. + +### Dependency injection `TracerProviderBuilder` extension method reference + +* `AddInstrumentation`: Adds instrumentation of type `T` into the + `TracerProvider`. + +* `AddProcessor`: Adds a processor of type `T` (must derive from + `BaseProcessor`) into the `TracerProvider`. + +* `SetSampler`: Register type `T` (must derive from `Sampler`) as the sampler + for the `TracerProvider`. + +* `ConfigureServices`: Registers a callback function for configuring the + `IServiceCollection` used by the `TracerProviderBuilder`. **Note:** + `ConfigureServices` may only be called before the `IServiceProvider` has been + created after which point service can no longer be added. + +* `ConfigureBuilder`: Registers a callback function for configuring the + `TracerProviderBuilder` once the `IServiceProvider` is available. + + ```csharp + var appBuilder = WebApplication.CreateBuilder(args); + + appBuilder.Services.AddOpenTelemetryTracing(builder => builder + .ConfigureBuilder((sp, builder) => + { + builder.AddProcessor( + new MyCustomProcessor( + // Note: This example uses the final IServiceProvider once it is available. + sp.GetRequiredService(), + sp.GetRequiredService>().Value)); + })); + ``` + + **Note:** `ConfigureBuilder` is an advanced API and is expected to be used + primarily by library authors. Services may NOT be added to the + `IServiceCollection` during `ConfigureBuilder` because the `IServiceProvider` + has already been created. + +## Configuration files and environment variables + +**Note:** This information applies to the OpenTelemetry SDK version 1.4.0 and +newer only. + +The OpenTelemetry .NET SDK integrates with the standard +[configuration](https://learn.microsoft.com/dotnet/core/extensions/configuration) +and [options](https://learn.microsoft.com/dotnet/core/extensions/options) +patterns provided by .NET. The configuration pattern supports building a +composited view of settings from external sources and the options pattern helps +use those settings to configure features by binding to simple classes. + +### How to set up configuration + +The following sections describe how to set up configuration based on the host +and OpenTelemetry API being used. + +#### Using .NET hosts with the OpenTelemetry.Extensions.Hosting package + +[ASP.NET +Core](https://learn.microsoft.com/aspnet/core/fundamentals/host/web-host) and +[.NET Generic](https://learn.microsoft.com/dotnet/core/extensions/generic-host) +host users using the +[OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md) +package do not need to do anything extra to enable `IConfiguration` support. The +OpenTelemetry SDK will automatically use whatever `IConfiguration` has been +supplied by the host. The host by default will load environment variables, +command-line arguments, and config files. See [Configuration in +.NET](https://learn.microsoft.com/dotnet/core/extensions/configuration) for +details. + +#### Using Sdk.CreateTracerProviderBuilder directly + +By default the `Sdk.CreateTracerProviderBuilder` API will create an +`IConfiguration` from environment variables. The following example shows how to +customize the `IConfiguration` used by `Sdk.CreateTracerProviderBuilder` for +cases where additional sources beyond environment variables are required. + +```csharp +// Build configuration from sources. Order is important. +var configuration = new ConfigurationBuilder() + .AddJsonFile("./myOTelSettings.json") + .AddEnvironmentVariables() + .AddCommandLine(args) + .Build(); + +// Set up a TracerProvider using the configuration. +var provider = Sdk.CreateTracerProviderBuilder() + .ConfigureServices(services => services.AddSingleton(configuration)) + .Build(); +``` + +### OpenTelemetry Specification environment variables + +The [OpenTelemetry +Specification](https://github.com/open-telemetry/opentelemetry-specification) +defines [specific environment +variables](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md) +which may be used to configure SDK implementations. + +The OpenTelemetry .NET SDK will look for the environment variables defined in +the specification using `IConfiguration` which means in addition to environment +variables users may also manage these settings via the command-line, +configuration files, or any other source registered with the .NET configuration +engine. This provides greater flexibility than what the specification defines. + +**Note:** Not all of the environment variables defined in the specification are +supported. Consult the individual project README files for details on specific +environment variable support. + +As an example the OpenTelemetry Specification defines the `OTEL_SERVICE_NAME` +environment variable which may be used to configure the service name emitted on +telemetry by the SDK. + +A traditional environment variable is set using a command like `set +OTEL_SERVICE_NAME=MyService` on Windows or `export OTEL_SERVICE_NAME=MyService` +on Linux. + +That works as expected but the OpenTelemetry .NET SDK is actually looking for +the `OTEL_SERVICE_NAME` key in `IConfiguration` which means it may also be +configured in any configuration source registered with the +`IConfigurationBuilder` used to create the final configuration for the host. + +Below are two examples of configuring the `OTEL_SERVICE_NAME` setting beyond +environment variables. + +* Using appsettings.json: + + ```json + { + "OTEL_SERVICE_NAME": "MyService" + } + ``` + +* Using command-line: + + ```sh + dotnet run --OTEL_SERVICE_NAME "MyService" + ``` + +**Note:** The [.NET + Configuration](https://learn.microsoft.com/dotnet/core/extensions/configuration) + pattern is hierarchical meaning the order of registered configuration sources + controls which value will seen by the SDK when it is defined in multiple + sources. + +### Using the .NET Options pattern to configure the SDK + +Options are typically simple classes containing only properties with public +"getters" and "setters" (aka POCOs) and have "Options" at the end of the class +name. These options classes are primarily used when interacting with the +`TracerProviderBuilder` to control settings and features of the different SDK +components. + +Options classes can always be configured through code but users typically want to +control key settings through configuration. + +The following example shows how to configure `JaegerExporterOptions` by binding +to an `IConfiguration` section. + +Json config file (usually appsettings.json): + +```json +{ + "OpenTelemetry": { + "Jaeger": { + "Protocol": "UdpCompactThrift" + "AgentHost": "localhost", + "AgentPort": 6831, + "BatchExportProcessorOptions": { + "ScheduledDelayMilliseconds": 5000 + } + } + } +} +``` + +Code: + +```csharp +var appBuilder = WebApplication.CreateBuilder(args); + +appBuilder.Services.Configure( + appBuilder.Configuration.GetSection("OpenTelemetry:Jaeger")); + +appBuilder.Services.AddOpenTelemetryTracing( + builder => builder.AddJaegerExporter()); +``` + +The OpenTelemetry .NET SDK supports running multiple `TracerProvider`s inside +the same application and it also supports registering multiple similar +components such as exporters into a single `TracerProvider`. In order to allow +users to target configuration at specific components a "name" parameter is +typically supported on configuration extensions to control the options instance +used for the component being registered. + +The below example shows how to configure two `JaegerExporter` instances inside a +single `TracerProvider` sending to different ports. + +Json config file (usually appsettings.json): + +```json +{ + "OpenTelemetry": { + "JaegerPrimary": { + "AgentPort": 1818 + }, + "JaegerSecondary": { + "AgentPort": 8818 + } + } +} +``` + +Code: + +```csharp +var appBuilder = WebApplication.CreateBuilder(args); + +appBuilder.Services.Configure( + "JaegerPrimary", + appBuilder.Configuration.GetSection("OpenTelemetry:JaegerPrimary")); + +appBuilder.Services.Configure( + "JaegerSecondary", + appBuilder.Configuration.GetSection("OpenTelemetry:JaegerSecondary")); + +appBuilder.Services.AddOpenTelemetryTracing(builder => builder + .AddJaegerExporter(name: "JaegerPrimary", configure: null) + .AddJaegerExporter(name: "JaegerSecondary", configure: null)); +``` diff --git a/docs/trace/extending-the-sdk/README.md b/docs/trace/extending-the-sdk/README.md index d9324d21812..8d62577cb1b 100644 --- a/docs/trace/extending-the-sdk/README.md +++ b/docs/trace/extending-the-sdk/README.md @@ -1,10 +1,13 @@ # Extending the OpenTelemetry .NET SDK +Quick links: + * [Building your own exporter](#exporter) * [Building your own instrumentation library](#instrumentation-library) * [Building your own processor](#processor) * [Building your own sampler](#sampler) * [Building your own resource detector](#resource-detector) +* [Registration extension method guidance for library authors](#registration-extension-method-guidance-for-library-authors) * [References](#references) ## Exporter @@ -62,7 +65,9 @@ A demo exporter which simply writes activity name to the console is shown Apart from the exporter itself, you should also provide extension methods as shown [here](./MyExporterExtensions.cs). This allows users to add the Exporter -to the `TracerProvider` as shown in the example [here](./Program.cs). +to the `TracerProvider` as shown in the example [here](./Program.cs). See +[here](#registration-extension-method-guidance-for-library-authors) for more +detailed extension method guidance. ### Exporting Activity Status @@ -114,40 +119,44 @@ Contrib](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/mai If you are writing an instrumentation library yourself, use the following guidelines. -### Writing own instrumentation library +### Writing a custom instrumentation library -This section describes the steps required to write your own instrumentation +This section describes the steps required to write a custom instrumentation library. -*If you are writing a new library or modifying an existing library, the -recommendation is to use [ActivitySource API/OpenTelemetry +**Note:** If you are writing a new library or modifying an existing library the +recommendation is to use the [ActivitySource API/OpenTelemetry API](../../../src/OpenTelemetry.Api/README.md#introduction-to-opentelemetry-net-tracing-api) -to instrument it and emit activity/span. If a library is instrumented using -ActivitySource API, then there is no need of writing a separate instrumentation -library, as instrumented and instrumentation library become same in this case. -For applications to collect traces from this library, all that is needed is to -enable the ActivitySource for the library using `AddSource` method of the -`TracerProviderBuilder`. The following section is applicable only if you are -writing an instrumentation library for an instrumented library which you cannot -modify to emit activities directly.* +to emit activity/span instances directly. If a library is instrumented using the +`ActivitySource` API then there isn't a need for a separate instrumentation +library to exist. Users simply need to configure the OpenTelemetry SDK to listen +to the `ActivitySource` used by the library by calling `AddSource` on the +`TracerProviderBuilder` being configured. The following section is applicable +only if you are writing an instrumentation library for something you cannot +modify to emit activity/span instances directly. Writing an instrumentation library typically involves 3 steps. -1. First step involves "hijacking" into the target library. The exact mechanism - of this depends on the target library itself. For example, - System.Data.SqlClient for .NET Framework, which publishes events using - `EventSource`. The [SqlClient instrumentation - library](../../../src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs), - in this case subscribes to the `EventSource` callbacks. - -2. Second step is to emit activities using the [ActivitySource - API](../../../src/OpenTelemetry.Api/README.md#introduction-to-opentelemetry-net-tracing-api). - In this step, the instrumentation library emits activities *on behalf of* the - target instrumented library. Irrespective of the actual mechanism used in - first step, this should be uniform across all instrumentation libraries. The - `ActivitySource` must be created using the name and version of the - instrumentation library (eg: "OpenTelemetry.Instrumentation.Http") and *not* - the instrumented library (eg: "System.Net.Http") +1. The first step involves attaching to the target library. The exact attachment + mechanism will depend on the implementation details of the target library + itself. For example, System.Data.SqlClient when running on .NET Framework + happens to publish events using an `EventSource` which the [SqlClient + instrumentation + library](../../../src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs) + listens to in order to trigger code as Sql commands are executed. The [.NET + Framework HttpWebRequest + instrumentation](../../../src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs) + patches the runtime code (using reflection) and swaps a static reference that + gets invoked as requests are processed for custom code. Every library will be + different. + +2. The second step is to emit activity instances using the [ActivitySource + API](../../../src/OpenTelemetry.Api/README.md#introduction-to-opentelemetry-net-tracing-api) + **on behalf of** the target library. Irrespective of the actual mechanism + used in first step, this should be uniform across all instrumentation + libraries. The `ActivitySource` must be created using the name and version of + the instrumentation library (eg: "OpenTelemetry.Instrumentation.Http") and + **NOT** the instrumented library (eg: "System.Net.Http") 1. [Context Propagation](../../../src/OpenTelemetry.Api/README.md#context-propagation): If your library initiates out of process requests or accepts them, the @@ -161,33 +170,42 @@ Writing an instrumentation library typically involves 3 steps. GrpcClient, this is already provided to you and **do not require** injecting/extracting `PropagationContext` explicitly again.) -3. Third step is an optional step, and involves providing extension methods on - `TracerProviderBuilder`, to enable the instrumentation. This is optional, and - the below guidance must be followed: - - 1. If the instrumentation library requires state management tied to that of - `TracerProvider`, then it must register itself with the provider with the - `AddInstrumentation` method on the `TracerProviderBuilder`. This causes - the instrumentation to be created and disposed along with - `TracerProvider`. If the above is required, then it must provide an - extension method on `TracerProviderBuilder`. Inside this extension - method, it should call the `AddInstrumentation` method, and `AddSource` - method to enable its ActivitySource for the provider. An example - instrumentation using this approach is [SqlClient +3. The third step is an optional step, and involves providing extension methods + on `TracerProviderBuilder` and/or `IServiceCollection` to enable the + instrumentation. For help in choosing see: [Registration extension method + guidance for library + authors](#registration-extension-method-guidance-for-library-authors). This + is optional, and the below guidance should be followed: + + * If the instrumentation library requires state management tied to that of + `TracerProvider` then it should: + + * Implement `IDisposable`. + + * Provide an extension method which calls `AddSource` (to enable its + `ActivitySource`) and `AddInstrumentation` (to enable state management) + on the `TracerProviderBuilder` being configured. + + An example instrumentation using this approach is [SqlClient instrumentation](../../../src/OpenTelemetry.Instrumentation.SqlClient/TracerProviderBuilderExtensions.cs). - **CAUTION**: The instrumentation libraries requiring state management - are usually hard to auto-instrument. Therefore, they take the risk of not - being supported by [OpenTelemetry .NET Automatic Instrumentation](https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation). - 2. If the instrumentation library does not requires any state management - tied to that of `TracerProvider`, then providing `TracerProviderBuilder` - extension method is optional. If provided, then it must call `AddSource` - to enable its ActivitySource for the provider. + **CAUTION**: The instrumentation libraries requiring state management are + usually hard to auto-instrument. Therefore, they take the risk of not + being supported by [OpenTelemetry .NET Automatic + Instrumentation](https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation). - 3. If instrumentation library does not require state management, and is not - providing extension method, then the name of the `ActivitySource` used by - the instrumented library must be documented so that end users can enable - it using `AddSource` method on `TracerProviderBuilder`. + * If the instrumentation library does not require any state management, then + providing an extension method is optional. + + * If an extension is provided it should call `AddSource` on the + `TracerProviderBuilder` being configured to enable its + `ActivitySource`. + + * If an extension is not provided, then the name of the `ActivitySource` + used by the instrumented library must be documented so that end users + can enable it by calling `AddSource` on the `TracerProviderBuilder` + being configured. **Note:** Changing the name of the source should be + considered a breaking change. ### Special case : Instrumentation for libraries producing legacy Activity @@ -334,6 +352,289 @@ Custom resource detectors can be implemented: A demo ResourceDetector is shown [here](./MyResourceDetector.cs). +## Registration extension method guidance for library authors + +**Note:** This information applies to the OpenTelemetry SDK version 1.4.0 and +newer only. + +Library authors are encouraged to provide extension methods users may call to +register custom OpenTelemetry components into their `TracerProvider`s. These +extension methods can target either the `TracerProviderBuilder` or the +`IServiceCollection` classes. Both of these patterns are described below. + +When providing registration extensions: + +* **DO** support the [.NET Options + pattern](https://learn.microsoft.com/dotnet/core/extensions/options) and + **DO** support [named + options](https://learn.microsoft.com/dotnet/core/extensions/options#named-options-support-using-iconfigurenamedoptions). + The Options pattern allows users to bind + [configuration](https://learn.microsoft.com/dotnet/core/extensions/configuration) + to options classes and provides extension points for working with instances as + they are created. Multiple providers may exist in the same application for a + single configuration and multiple components (for example exporters) may exist + in the same provider. Named options help users target configuration to + specific components. + + * Use the + [Configure](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.optionsservicecollectionextensions.configure#microsoft-extensions-dependencyinjection-optionsservicecollectionextensions-configure-1(microsoft-extensions-dependencyinjection-iservicecollection-system-string-system-action((-0)))) + extension to register configuration callbacks for a given name. + + * Use the + [IOptionsMonitor<T>.Get](https://learn.microsoft.com/dotnet/api/microsoft.extensions.options.ioptionsmonitor-1.get) + method to access options class instances by name. + +* **DO** throw exceptions for issues that prevent the component being registered + from starting. The OpenTelemetry SDK is allowed to crash if it cannot be + started. It **MUST NOT** crash once running. + +**Note:** The SDK implementation of `TracerProviderBuilder` ensures that the +[.NET +Configuration](https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration) +engine is always available by creating a root `IConfiguration` from environment +variables if it does not already exist in the `IServiceCollection` containing +the `TracerProvider`. Library authors can rely on `IConfiguration` always being +present in the final `IServiceProvider`. + +### TracerProviderBuilder extension methods + +When registering pipeline components (for example samplers, exporters, or +resource detectors) it is recommended to use the `TracerProviderBuilder` as the +target type for registration extension methods. These extensions will be highly +discoverable for users interacting with the `TracerProviderBuilder` in their IDE +of choice. + +The following example shows how to register a custom exporter with named options +support using a `TracerProviderBuilder` extension. + +```csharp +using System.Diagnostics; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; +using MyLibrary; +using OpenTelemetry; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; + +namespace OpenTelemetry.Trace +{ + public static class MyLibraryTracerProviderBuilderRegistrationExtensions + { + public static TracerProviderBuilder AddMyLibraryExporter( + this TracerProviderBuilder builder, + string? name = null, + Action? configureExporterOptions = null, + Action? configureBatchProcessorOptions = null) + { + ArgumentNullException.ThrowIfNull(builder); + + // Support named options. + name ??= Options.DefaultName; + + builder.ConfigureServices(services => + { + if (configureExporterOptions != null) + { + // Support configuration through Options API. + services.Configure(name, configureExporterOptions); + } + + if (configureBatchProcessorOptions != null) + { + // Support configuration through Options API. + services.Configure(name, configureBatchProcessorOptions); + } + + // Register custom service as a singleton. + services.TryAddSingleton(); + }); + + builder.ConfigureBuilder((sp, builder) => + { + // Retrieve MyExporterOptions instance using name. + var exporterOptions = serviceProvider.GetRequiredService>().Get(name); + + // Retrieve BatchExportActivityProcessorOptions instance using name. + var batchOptions = serviceProvider.GetRequiredService>().Get(name); + + // Retrieve MyCustomService singleton. + var myCustomService = sp.GetRequiredService(); + + // Registers MyCustomExporter with a batch processor. + builder.AddProcessor( + new BatchActivityExportProcessor( + new MyCustomExporter(exporterOptions, myCustomService), + batchOptions.MaxQueueSize, + batchOptions.ScheduledDelayMilliseconds, + batchOptions.ExporterTimeoutMilliseconds, + batchOptions.MaxExportBatchSize)); + }); + + // Return builder for call chaining. + return builder; + } + } +} + +namespace MyLibrary +{ + // Options class can be bound to IConfiguration or configured by code. + public class MyExporterOptions + { + public Uri? IngestionUri { get; set; } + } + + internal sealed class MyCustomExporter : BaseExporter + { + public MyCustomExporter( + MyExporterOptions options, + MyCustomService myCustomService) + { + // Implementation not shown. + } + + public override ExportResult Export(in Batch batch) + { + // Implementation not shown. + + return ExportResult.Success; + } + } + + internal sealed class MyCustomService + { + // Implementation not shown. + } +} +``` + +When providing `TracerProviderBuilder` registration extensions: + +* **DO** Use the `OpenTelemetry.Trace` namespace for `TracerProviderBuilder` + registration extensions to help with discoverability. + +* **DO** Return the `TracerProviderBuilder` passed in to support call chaining + of registration methods. + +* **DO** Use the `TracerProviderBuilder.ConfigureServices` extension method to + register dependent services. + +* **DO** Use the `TracerProviderBuilder.ConfigureBuilder` extension method to + peform configuration once the final `IServiceProvider` is available. + +### IServiceCollection extension methods + +When registering instrumentation or listening to telemetry in a library +providing other features it is recommended to use the `IServiceCollection` as +the target type for registration extension methods. + +The following example shows how a library might enable tracing and metric +support using an `IServiceCollection` extension by calling +`ConfigureOpenTelemetryTracing`. + +```csharp +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; +using MyLibrary; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class MyLibraryServiceCollectionRegistrationExtensions + { + public static IServiceCollection AddMyLibrary( + this IServiceCollection services, + string? name = null, + Action? configure = null) + { + ArgumentNullException.ThrowIfNull(services); + + // Register library services. + services.TryAddSingleton(); + + // Support named options. + name ??= Options.DefaultName; + + if (configure != null) + { + // Support configuration through Options API. + services.Configure(name, configure); + } + + // Configure OpenTelemetry tracing. + services.ConfigureOpenTelemetryTracing(builder => builder.ConfigureBuilder((sp, builder) => + { + var options = sp.GetRequiredService>().Get(name); + if (options.EnableTracing) + { + builder.AddSource("MyLibrary"); + } + })); + + // Configure OpenTelemetry metrics. + services.ConfigureOpenTelemetryMetrics(builder => builder.ConfigureBuilder((sp, builder) => + { + var options = sp.GetRequiredService>().Get(name); + if (options.EnableMetrics) + { + builder.AddMeter("MyLibrary"); + } + })); + + return services; + } + } +} + +namespace MyLibrary +{ + // Options class can be bound to IConfiguration or configured by code. + public class MyLibraryOptions + { + public bool EnableTracing { get; set; } + + public bool EnableMetrics { get; set; } + } + + internal sealed class MyLibraryService : IMyLibraryService + { + // Implementation not shown. + } + + public interface IMyLibraryService + { + // Implementation not shown. + } +} +``` + +The benefit to using the `IServiceCollection` style is users only need to call a +single `AddMyLibrary` extension to configure the library itself and optionally +turn on OpenTelemetry integration for multiple signals (tracing & metrics in +this case). + +**Note:** `ConfigureOpenTelemetryTracing` does not automatically start +OpenTelemetry. The host is responsible for either calling +`AddOpenTelemetryTracing` in the +[OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md) +package, calling `Build` when using the `Sdk.CreateTracerProviderBuilder` +method, or by accessing the `TracerProvider` from the `IServiceCollection` where +`ConfigureOpenTelemetryTracing` was performed. + +When providing `IServiceCollection` registration extensions: + +* **DO** Use the `Microsoft.Extensions.DependencyInjection` namespace for + `IServiceCollection` registration extensions to help with discoverability. + +* **DO** Return the `IServiceCollection` passed in to support call chaining of + registration methods. + +* **DO** Use the `IServiceCollection` directly to register dependent services. + +* **DO** Use the `TracerProviderBuilder.ConfigureBuilder` extension method to + peform configuration once the final `IServiceProvider` is available. + ## References * [Exporter diff --git a/examples/AspNetCore/appsettings.json b/examples/AspNetCore/appsettings.json index e2826c577b6..10f9feba43f 100644 --- a/examples/AspNetCore/appsettings.json +++ b/examples/AspNetCore/appsettings.json @@ -2,8 +2,7 @@ "Logging": { "LogLevel": { "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" + "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", diff --git a/global.json b/global.json index 4dbb7aa3237..40b4707710e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { "rollForward": "latestFeature", - "version": "7.0.100-preview" + "version": "7.0.100" } } diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md index c09057cd125..49a72a0d579 100644 --- a/src/OpenTelemetry.Api/CHANGELOG.md +++ b/src/OpenTelemetry.Api/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +* Updated to System.Diagnostics.DiagnosticSource version `7.0.0`. + +## 1.4.0-beta.3 + +Released 2022-Nov-07 + * Updated to System.Diagnostics.DiagnosticSource version `7.0.0-rc.2.22472.3`. ## 1.4.0-beta.2 diff --git a/src/OpenTelemetry.Api/README.md b/src/OpenTelemetry.Api/README.md index 26da2644258..7148cbf8917 100644 --- a/src/OpenTelemetry.Api/README.md +++ b/src/OpenTelemetry.Api/README.md @@ -137,7 +137,7 @@ Processors/Exporters see the same data. The recommended way of instrumenting is by using the [.NET Activity API](#instrumenting-a-libraryapplication-with-net-activity-api). Users are required to just take dependency on the -[DiagnosticSource](https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource/5.0.0). +[DiagnosticSource](https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource). Adding dependency to [OpenTelemetry.API](https://www.nuget.org/packages/opentelemetry.api) is required only for the following scenarios: @@ -160,7 +160,7 @@ required only for the following scenarios: [Context propagation](#context-propagation) section. 3. You want to leverage - [Baggage](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/baggage/api.md) + [Baggage](#baggage-api) API. ## Instrumenting a library/application with .NET Activity API @@ -172,16 +172,11 @@ is the .NET `Activity` API. Guidance for instrumenting using this API is documented fully in the TBD(dotnet activity user guide link), but is described here as well. -1. Install the `System.Diagnostics.DiagnosticSource` package version `5.0.1` or - above to your application or library. +1. Install the latest stable `System.Diagnostics.DiagnosticSource` to your + application or library. - ```xml - - - + ```shell + dotnet add package System.Diagnostics.DiagnosticSource ``` 2. Create an `ActivitySource`, providing the name and version of the @@ -462,7 +457,7 @@ context. Metrics in OpenTelemetry .NET are a somewhat unique implementation of the OpenTelemetry project, as the Metrics API is incorporated directly into the .NET runtime itself, as part of the -[`System.Diagnostics.DiagnosticSource`](https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource/6.0.0) +[`System.Diagnostics.DiagnosticSource`](https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource) package. This means, users can instrument their applications/libraries to emit metrics by simply using the `System.Diagnostics.DiagnosticSource` package. This package can be used in applications targeting any of the officially supported @@ -474,13 +469,11 @@ Windows-based .NET implementation). ### Basic metric usage -1. Install the `System.Diagnostics.DiagnosticSource` package version `6.0.0` or - above to your application or library. +1. Install the latest stable version of `System.Diagnostics.DiagnosticSource` to + your application or library. - ```xml - - - + ```shell + dotnet add package System.Diagnostics.DiagnosticSource ``` 2. Create a `Meter`, providing the name and version of the library/application @@ -520,7 +513,7 @@ describes more kinds of instruments. ### Instrument types -// TODO - add all instruments. +See [this](../../docs/metrics/learning-more-instruments/README.md). ## Troubleshooting diff --git a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md index 1fc404b042e..4f202cb891d 100644 --- a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-beta.3 + +Released 2022-Nov-07 + * Bumped the minimum required version of `System.Text.Json` to 4.7.2 in response to [CVE-2021-26701](https://github.com/dotnet/runtime/issues/49377). ([#3789](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3789)) diff --git a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md index 948cd03d977..8f7cd2b278c 100644 --- a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-beta.3 + +Released 2022-Nov-07 + ## 1.4.0-beta.2 Released 2022-Oct-17 diff --git a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md index 78c6c7bbddd..3dedfcc6166 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-beta.3 + +Released 2022-Nov-07 + * Bumped the minimum required version of `System.Text.Json` to 4.7.2 in response to [CVE-2021-26701](https://github.com/dotnet/runtime/issues/49377). ([#3789](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3789)) diff --git a/src/OpenTelemetry.Exporter.Jaeger/JaegerExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.Jaeger/JaegerExporterHelperExtensions.cs index 6a6bd83efc0..df4c4180ccc 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/JaegerExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/JaegerExporterHelperExtensions.cs @@ -69,7 +69,10 @@ public static TracerProviderBuilder AddJaegerExporter( services.Configure(name, configure); } - services.RegisterOptionsFactory(configuration => new JaegerExporterOptions(configuration)); + services.RegisterOptionsFactory( + (sp, configuration) => new JaegerExporterOptions( + configuration, + sp.GetRequiredService>().Get(name))); }); return builder.ConfigureBuilder((sp, builder) => diff --git a/src/OpenTelemetry.Exporter.Jaeger/JaegerExporterOptions.cs b/src/OpenTelemetry.Exporter.Jaeger/JaegerExporterOptions.cs index 592fd554330..a2286a71bc1 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/JaegerExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/JaegerExporterOptions.cs @@ -48,12 +48,17 @@ public class JaegerExporterOptions /// Initializes a new instance of the class. /// public JaegerExporterOptions() - : this(new ConfigurationBuilder().AddEnvironmentVariables().Build()) + : this(new ConfigurationBuilder().AddEnvironmentVariables().Build(), new()) { } - internal JaegerExporterOptions(IConfiguration configuration) + internal JaegerExporterOptions( + IConfiguration configuration, + BatchExportActivityProcessorOptions defaultBatchOptions) { + Debug.Assert(configuration != null, "configuration was null"); + Debug.Assert(defaultBatchOptions != null, "defaultBatchOptions was null"); + if (configuration.TryGetValue( OTelProtocolEnvVarKey, JaegerExporterProtocolParser.TryParse, @@ -77,7 +82,7 @@ internal JaegerExporterOptions(IConfiguration configuration) this.Endpoint = endpoint; } - this.BatchExportProcessorOptions = new BatchExportActivityProcessorOptions(configuration); + this.BatchExportProcessorOptions = defaultBatchOptions; } /// diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs/CHANGELOG.md index b5977bd237e..fbf1ac1c2b5 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-beta.3 + +Released 2022-Nov-07 + ## 1.4.0-beta.2 Released 2022-Oct-17 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index 2289b9a12f5..a9d38568311 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-beta.3 + +Released 2022-Nov-07 + * Log Exporter modified to no longer prefix scope-depth when exporting ILogger scopes as attributes. Empty keys and {OriginalFormat} key will be ignored from scopes. diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs index 2bf0f7e980f..00c7ab6ac3a 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs @@ -52,12 +52,16 @@ public class OtlpExporterOptions /// Initializes a new instance of the class. /// public OtlpExporterOptions() - : this(new ConfigurationBuilder().AddEnvironmentVariables().Build()) + : this(new ConfigurationBuilder().AddEnvironmentVariables().Build(), new()) { } - internal OtlpExporterOptions(IConfiguration configuration) + internal OtlpExporterOptions( + IConfiguration configuration, + BatchExportActivityProcessorOptions defaultBatchOptions = null) { + Debug.Assert(configuration != null, "configuration was null"); + if (configuration.TryGetUriValue(EndpointEnvVarName, out var endpoint)) { this.endpoint = endpoint; @@ -89,7 +93,7 @@ internal OtlpExporterOptions(IConfiguration configuration) }; }; - this.BatchExportProcessorOptions = new BatchExportActivityProcessorOptions(configuration); + this.BatchExportProcessorOptions = defaultBatchOptions; } /// diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs index 741314ab8b4..27695a881cd 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs @@ -67,7 +67,8 @@ public static MeterProviderBuilder AddOtlpExporter( services.Configure(name, configureExporter); } - services.RegisterOptionsFactory(configuration => new OtlpExporterOptions(configuration)); + services.RegisterOptionsFactory(configuration + => new OtlpExporterOptions(configuration, defaultBatchOptions: null)); }); return builder.ConfigureBuilder((sp, builder) => @@ -113,7 +114,8 @@ public static MeterProviderBuilder AddOtlpExporter( builder.ConfigureServices(services => { - services.RegisterOptionsFactory(configuration => new OtlpExporterOptions(configuration)); + services.RegisterOptionsFactory(configuration + => new OtlpExporterOptions(configuration, defaultBatchOptions: null)); }); return builder.ConfigureBuilder((sp, builder) => diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs index 889fe7fca5d..dab607ec5be 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs @@ -70,7 +70,10 @@ public static TracerProviderBuilder AddOtlpExporter( } services.RegisterOptionsFactory(configuration => new SdkLimitOptions(configuration)); - services.RegisterOptionsFactory(configuration => new OtlpExporterOptions(configuration)); + services.RegisterOptionsFactory( + (sp, configuration) => new OtlpExporterOptions( + configuration, + sp.GetRequiredService>().Get(name))); }); return builder.ConfigureBuilder((sp, builder) => @@ -108,7 +111,7 @@ internal static TracerProviderBuilder AddOtlpExporter( } else { - var batchOptions = exporterOptions.BatchExportProcessorOptions ?? new(); + var batchOptions = exporterOptions.BatchExportProcessorOptions ?? new BatchExportActivityProcessorOptions(); return builder.AddProcessor(new BatchActivityExportProcessor( otlpExporter, diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md index 89f34d18923..c4675700423 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-beta.3 + +Released 2022-Nov-07 + * Support named options in `UseOpenTelemetryPrometheusScrapingEndpoint` & `MapPrometheusScrapingEndpoint` extensions ([#3780](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3780)) diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md index 57270498735..ae1bd07664e 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-beta.3 + +Released 2022-Nov-07 + ## 1.4.0-beta.2 Released 2022-Oct-17 diff --git a/src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md b/src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md index 27760d5ac4e..8e236b83aa2 100644 --- a/src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.0.0-rc9.9 + +Released 2022-Nov-07 + ## 1.0.0-rc9.8 Released 2022-Oct-17 diff --git a/src/OpenTelemetry.Exporter.ZPages/README.md b/src/OpenTelemetry.Exporter.ZPages/README.md index 3f9c2ee0b37..28d49716560 100644 --- a/src/OpenTelemetry.Exporter.ZPages/README.md +++ b/src/OpenTelemetry.Exporter.ZPages/README.md @@ -6,7 +6,7 @@ ## Installation ```shell -dotnet add package OpenTelemetry.Exporter.ZPages +dotnet add package --prerelease OpenTelemetry.Exporter.ZPages ``` ## Configuration diff --git a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md index 4ea2b381680..53570ab853e 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-beta.3 + +Released 2022-Nov-07 + * Bumped the minimum required version of `System.Text.Json` to 4.7.2 in response to [CVE-2021-26701](https://github.com/dotnet/runtime/issues/49377). ([#3789](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3789)) diff --git a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs index 93a43014874..e4a1ecf2c9e 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs @@ -69,7 +69,10 @@ public static TracerProviderBuilder AddZipkinExporter( services.Configure(name, configure); } - services.RegisterOptionsFactory(configuration => new ZipkinExporterOptions(configuration)); + services.RegisterOptionsFactory( + (sp, configuration) => new ZipkinExporterOptions( + configuration, + sp.GetRequiredService>().Get(name))); }); return builder.ConfigureBuilder((sp, builder) => diff --git a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterOptions.cs b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterOptions.cs index f9d8e7c62c4..32f6a031ad4 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterOptions.cs @@ -45,18 +45,23 @@ public sealed class ZipkinExporterOptions /// Initializes zipkin endpoint. /// public ZipkinExporterOptions() - : this(new ConfigurationBuilder().AddEnvironmentVariables().Build()) + : this(new ConfigurationBuilder().AddEnvironmentVariables().Build(), new()) { } - internal ZipkinExporterOptions(IConfiguration configuration) + internal ZipkinExporterOptions( + IConfiguration configuration, + BatchExportActivityProcessorOptions defaultBatchOptions) { + Debug.Assert(configuration != null, "configuration was null"); + Debug.Assert(defaultBatchOptions != null, "defaultBatchOptions was null"); + if (configuration.TryGetUriValue(ZipkinEndpointEnvVar, out var endpoint)) { this.Endpoint = endpoint; } - this.BatchExportProcessorOptions = new BatchExportActivityProcessorOptions(configuration); + this.BatchExportProcessorOptions = defaultBatchOptions; } /// diff --git a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md index 1f75cb9920c..8d31ce75b4e 100644 --- a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md +++ b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.0.0-rc9.9 + +Released 2022-Nov-07 + ## 1.0.0-rc9.8 Released 2022-Oct-17 diff --git a/src/OpenTelemetry.Extensions.Hosting/README.md b/src/OpenTelemetry.Extensions.Hosting/README.md index a1c8341958c..e8e35c03383 100644 --- a/src/OpenTelemetry.Extensions.Hosting/README.md +++ b/src/OpenTelemetry.Extensions.Hosting/README.md @@ -6,95 +6,69 @@ ## Installation ```shell -dotnet add package OpenTelemetry.Extensions.Hosting +dotnet add package --prerelease OpenTelemetry.Extensions.Hosting ``` -## Usage - -### Tracing +## Overview -#### Simple Configuration +The OpenTelemetry.Extensions.Hosting package provides extension methods for +automatically starting (and stopping) OpenTelemetry tracing (`TracerProvider`) +and metrics (`MeterProvider`) in [ASP.NET + Core](https://learn.microsoft.com/aspnet/core/fundamentals/host/web-host) and + [.NET Generic](https://learn.microsoft.com/dotnet/core/extensions/generic-host) + hosts. These are completely optional extensions meant to simplify the + management of the OpenTelemetry SDK lifecycle. -The following example registers tracing using the `ZipkinExporter` and binds -options to the "Zipkin" configuration section: +## Extension method reference -```csharp -services.AddOpenTelemetryTracing((builder) => builder - .AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddZipkinExporter()); +**Note:** The below extension methods target +`Microsoft.Extensions.DependencyInjection.IServiceCollection`. -services.Configure(this.Configuration.GetSection("Zipkin")); -``` +**Note:** The below extension methods should be called by application host code +only. Library authors see: [Registration extension method guidance for library +authors](../../docs/trace/extending-the-sdk/README.md#registration-extension-method-guidance-for-library-authors). -#### Using Dependency Injection +**Note:** Multiple calls to the below extensions will **NOT** result in multiple +providers. To establish multiple providers use the +`Sdk.CreateTracerProviderBuilder()` and/or `Sdk.CreateMeterProviderBuilder()` +methods. See [TracerProvider +configuration](../../docs/trace/customizing-the-sdk/README.md#tracerprovider-configuration) +and [Building a +MeterProvider](../../docs/metrics/customizing-the-sdk/README.md#building-a-meterprovider) +for more details. -The following example registers a processor of the type "MyProcessor" which has -been registered as a singleton with the `IServiceCollection`: +* `AddOpenTelemetryTracing`: Configure OpenTelemetry and register an + [IHostedService](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice) + to automatically start tracing services in the supplied + [IServiceCollection](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.iservicecollection). -```csharp -services.AddSingleton(); - -services.AddOpenTelemetryTracing((builder) => builder - .AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddProcessor()); -``` +* `AddOpenTelemetryMetrics`: Configure OpenTelemetry and register an + [IHostedService](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice) + to automatically start metric services in the supplied + [IServiceCollection](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.iservicecollection). -Similar methods exist for registering instrumentation (`AddInstrumentation`) -and setting a sampler (`SetSampler`). +## Usage -You can also access the application `IServiceProvider` directly and accomplish -the same registration using the `ConfigureBuilder` extension like this: +The following example shows how to register OpenTelemetry tracing & metrics in +an ASP.NET Core host using the OpenTelemetry.Extensions.Hosting extensions. ```csharp -services.AddSingleton(); +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; -services.AddOpenTelemetryTracing(hostingBuilder => hostingBuilder - .ConfigureBuilder((sp, builder) => builder - .AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddProcessor(sp.GetRequiredService()))); -``` +var appBuilder = WebApplication.CreateBuilder(args); -**Note:** `ConfigureBuilder` is called _after_ the `IServiceProvider` has been built -from the application `IServiceCollection` so any services registered in the -`ConfigureBuilder` callback will be ignored. +appBuilder.Services.AddOpenTelemetryTracing( + builder => builder.AddConsoleExporter()); -#### Building Extension Methods +appBuilder.Services.AddOpenTelemetryMetrics( + builder => builder.AddConsoleExporter()); -Library authors may want to configure the OpenTelemetry `TracerProvider` and -register application services to provide more complex features. This can be -accomplished concisely by using the `TracerProviderBuilder.ConfigureServices` -extension method inside of a more general `TracerProviderBuilder` configuration -extension like this: +var app = appBuilder.Build(); -```csharp -public static class MyLibraryExtensions -{ - public static TracerProviderBuilder AddMyFeature(this TracerProviderBuilder tracerProviderBuilder) - { - return tracerProviderBuilder - .ConfigureServices(services => - services - .AddHostedService() - .AddSingleton() - .AddSingleton() - .AddSingleton()) - .AddProcessor() - .SetSampler(); - } -} -``` - -Such an extension method can be consumed like this: - -```csharp -services.AddOpenTelemetryTracing((builder) => builder - .AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddMyFeature() - .AddZipkinExporter()); +app.Run(); ``` ## References diff --git a/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md b/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md index 130ef3aa83a..93710084119 100644 --- a/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md +++ b/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-beta.3 + +Released 2022-Nov-07 + ## 1.4.0-beta.2 Released 2022-Oct-17 diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md index 5b3b1e04bf1..65fdeb38f39 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md @@ -2,6 +2,14 @@ ## Unreleased +* **Breaking change** `http.host` will no longer be populated on activity. + `net.host.name` and `net.host.port` attributes will be populated instead. + ([#3858](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3858)) + +## 1.0.0-rc9.9 + +Released 2022-Nov-07 + * **Breaking change** The `Enrich` callback option has been removed. For better usability, it has been replaced by three separate options: `EnrichWithHttpRequest`, `EnrichWithHttpResponse` and `EnrichWithException`. diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs b/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs index 3be0d4065ef..836a24deb19 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs @@ -198,14 +198,14 @@ public void OnStartActivity(Activity activity, object payload) activity.DisplayName = path; // see the spec https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md - - if (request.Host.Port is null or 80 or 443) - { - activity.SetTag(SemanticConventions.AttributeHttpHost, request.Host.Host); - } - else + if (request.Host.HasValue) { - activity.SetTag(SemanticConventions.AttributeHttpHost, request.Host.Host + ":" + request.Host.Port); + activity.SetTag(SemanticConventions.AttributeNetHostName, request.Host.Host); + + if (request.Host.Port is not null && request.Host.Port != 80 && request.Host.Port != 443) + { + activity.SetTag(SemanticConventions.AttributeNetHostPort, request.Host.Port); + } } activity.SetTag(SemanticConventions.AttributeHttpMethod, request.Method); diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/README.md b/src/OpenTelemetry.Instrumentation.AspNetCore/README.md index d27566f0419..a5801839648 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/README.md +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/README.md @@ -31,7 +31,7 @@ Add a reference to the package. Also, add any other instrumentations & exporters you will need. ```shell -dotnet add package OpenTelemetry.Instrumentation.AspNetCore +dotnet add package --prerelease OpenTelemetry.Instrumentation.AspNetCore ``` ### Step 2: Enable ASP.NET Core Instrumentation at application startup diff --git a/src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md index 08545533222..d90c0780fba 100644 --- a/src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.0.0-rc9.9 + +Released 2022-Nov-07 + **Breaking change** The `Enrich` callback option has been removed. For better usability, it has been replaced by two separate options: `EnrichWithHttpRequestMessage`and `EnrichWithHttpResponseMessage`. Previously, diff --git a/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md b/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md index 462f5439321..9f39c155ada 100644 --- a/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md +++ b/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md @@ -32,7 +32,7 @@ Add a reference to the package. Also, add any other instrumentations & exporters you will need. ```shell -dotnet add package OpenTelemetry.Instrumentation.GrpcNetClient +dotnet add package --prerelease OpenTelemetry.Instrumentation.GrpcNetClient ``` ### Step 2: Enable Grpc.Net.Client Instrumentation at application startup diff --git a/src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md index bf596e774fc..f7d6a98cd2f 100644 --- a/src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md @@ -2,6 +2,18 @@ ## Unreleased +* Added `net.peer.name` and `net.peer.port` as dimensions on + `http.client.duration` metric. + ([#3907](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3907)) + +* **Breaking change** `http.host` will no longer be populated on activity. + `net.peer.name` and `net.peer.port` attributes will be populated instead. + ([#3832](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3832)) + +## 1.0.0-rc9.9 + +Released 2022-Nov-07 + * Added back `netstandard2.0` target. ([#3787](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3787)) diff --git a/src/OpenTelemetry.Instrumentation.Http/HttpClientInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.Http/HttpClientInstrumentationOptions.cs index 2c5b478c8aa..a4ef77bdb53 100644 --- a/src/OpenTelemetry.Instrumentation.Http/HttpClientInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.Http/HttpClientInstrumentationOptions.cs @@ -33,12 +33,12 @@ public class HttpClientInstrumentationOptions /// collect telemetry about requests on a per request basis. /// /// - /// Notes: - /// - /// FilterHttpRequestMessage is only executed on .NET and .NET + /// FilterHttpRequestMessage is only executed on .NET and .NET /// Core runtimes. and on .NET and .NET Core are both implemented - /// using . + /// using . + /// Notes: + /// /// The return value for the filter function is interpreted as: /// /// If filter returns , the request is @@ -51,38 +51,32 @@ public class HttpClientInstrumentationOptions public Func FilterHttpRequestMessage { get; set; } /// - /// Gets or sets an action to enrich an Activity with . + /// Gets or sets an action to enrich an with . /// /// /// EnrichWithHttpRequestMessage is only executed on .NET and .NET /// Core runtimes. and on .NET and .NET Core are both implemented /// using . - /// : the activity being enriched. - /// object from which additional information can be extracted to enrich the activity. /// public Action EnrichWithHttpRequestMessage { get; set; } /// - /// Gets or sets an action to enrich an Activity with . + /// Gets or sets an action to enrich an with . /// /// /// EnrichWithHttpResponseMessage is only executed on .NET and .NET /// Core runtimes. and on .NET and .NET Core are both implemented /// using . - /// : the activity being enriched. - /// object from which additional information can be extracted to enrich the activity. /// public Action EnrichWithHttpResponseMessage { get; set; } /// - /// Gets or sets an action to enrich an Activity with . + /// Gets or sets an action to enrich an with . /// /// /// EnrichWithException is called for all runtimes. - /// : the activity being enriched. - /// object from which additional information can be extracted to enrich the activity. /// public Action EnrichWithException { get; set; } @@ -91,12 +85,12 @@ public class HttpClientInstrumentationOptions /// collect telemetry about requests on a per request basis. /// /// - /// Notes: - /// - /// FilterHttpWebRequest is only executed on .NET Framework + /// FilterHttpWebRequest is only executed on .NET Framework /// runtimes. and /// on .NET Framework are both implemented using . + /// cref="HttpWebRequest"/>. + /// Notes: + /// /// The return value for the filter function is interpreted as: /// /// If filter returns , the request is @@ -109,36 +103,37 @@ public class HttpClientInstrumentationOptions public Func FilterHttpWebRequest { get; set; } /// - /// Gets or sets an action to enrich an Activity with . + /// Gets or sets an action to enrich an with . /// /// /// EnrichWithHttpWebRequest is only executed on .NET Framework /// runtimes. and /// on .NET Framework are both implemented using . - /// : the activity being enriched. - /// object from which additional information can be extracted to enrich the activity. /// public Action EnrichWithHttpWebRequest { get; set; } /// - /// Gets or sets an action to enrich an Activity with . + /// Gets or sets an action to enrich an with . /// /// /// EnrichWithHttpWebResponse is only executed on .NET Framework /// runtimes. and /// on .NET Framework are both implemented using . - /// : the activity being enriched. - /// object from which additional information can be extracted to enrich the activity. /// public Action EnrichWithHttpWebResponse { get; set; } /// - /// Gets or sets a value indicating whether exception will be recorded as an or not. + /// Gets or sets a value indicating whether exception will be recorded + /// as an or not. Default value: . /// /// - /// See: . + /// RecordException is supported on all runtimes. + /// For specification details see: . /// public bool RecordException { get; set; } diff --git a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs index 5e0b2fae944..f2ac51c6432 100644 --- a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs +++ b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs @@ -159,7 +159,12 @@ public void OnStartActivity(Activity activity, object payload) activity.SetTag(SemanticConventions.AttributeHttpScheme, request.RequestUri.Scheme); activity.SetTag(SemanticConventions.AttributeHttpMethod, HttpTagHelper.GetNameForHttpMethod(request.Method)); - activity.SetTag(SemanticConventions.AttributeHttpHost, HttpTagHelper.GetHostTagValueFromRequestUri(request.RequestUri)); + activity.SetTag(SemanticConventions.AttributeNetPeerName, request.RequestUri.Host); + if (!request.RequestUri.IsDefaultPort) + { + activity.SetTag(SemanticConventions.AttributeNetPeerPort, request.RequestUri.Port); + } + activity.SetTag(SemanticConventions.AttributeHttpUrl, HttpTagHelper.GetUriTagValueFromRequestUri(request.RequestUri)); activity.SetTag(SemanticConventions.AttributeHttpFlavor, HttpTagHelper.GetFlavorTagValueFromProtocolVersion(request.Version)); diff --git a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerMetricsDiagnosticListener.cs b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerMetricsDiagnosticListener.cs index 8b2ebf0a678..c1924529108 100644 --- a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerMetricsDiagnosticListener.cs +++ b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerMetricsDiagnosticListener.cs @@ -49,15 +49,17 @@ public override void OnEventWritten(string name, object payload) { var request = response.RequestMessage; - // TODO: This is just a minimal set of attributes. See the spec for additional attributes: - // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/semantic_conventions/http-metrics.md#http-client - var tags = new KeyValuePair[] + TagList tags = default; + tags.Add(new KeyValuePair(SemanticConventions.AttributeHttpMethod, HttpTagHelper.GetNameForHttpMethod(request.Method))); + tags.Add(new KeyValuePair(SemanticConventions.AttributeHttpScheme, request.RequestUri.Scheme)); + tags.Add(new KeyValuePair(SemanticConventions.AttributeHttpStatusCode, (int)response.StatusCode)); + tags.Add(new KeyValuePair(SemanticConventions.AttributeHttpFlavor, HttpTagHelper.GetFlavorTagValueFromProtocolVersion(request.Version))); + tags.Add(new KeyValuePair(SemanticConventions.AttributeNetPeerName, request.RequestUri.Host)); + + if (!request.RequestUri.IsDefaultPort) { - new KeyValuePair(SemanticConventions.AttributeHttpMethod, HttpTagHelper.GetNameForHttpMethod(request.Method)), - new KeyValuePair(SemanticConventions.AttributeHttpScheme, request.RequestUri.Scheme), - new KeyValuePair(SemanticConventions.AttributeHttpStatusCode, (int)response.StatusCode), - new KeyValuePair(SemanticConventions.AttributeHttpFlavor, HttpTagHelper.GetFlavorTagValueFromProtocolVersion(request.Version)), - }; + tags.Add(new KeyValuePair(SemanticConventions.AttributeNetPeerPort, request.RequestUri.Port)); + } this.httpClientDuration.Record(activity.Duration.TotalMilliseconds, tags); } diff --git a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpTagHelper.cs b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpTagHelper.cs index 52bf6dada5c..6616029ef4e 100644 --- a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpTagHelper.cs +++ b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpTagHelper.cs @@ -27,7 +27,6 @@ internal static class HttpTagHelper private static readonly ConcurrentDictionary MethodOperationNameCache = new(); private static readonly ConcurrentDictionary HttpMethodOperationNameCache = new(); private static readonly ConcurrentDictionary HttpMethodNameCache = new(); - private static readonly ConcurrentDictionary> HostAndPortToStringCache = new(); private static readonly ConcurrentDictionary ProtocolVersionToStringCache = new(); private static readonly Func ConvertMethodToOperationNameRef = ConvertMethodToOperationName; @@ -63,37 +62,6 @@ internal static class HttpTagHelper /// Span flavor value. public static string GetFlavorTagValueFromProtocolVersion(Version protocolVersion) => ProtocolVersionToStringCache.GetOrAdd(protocolVersion, ConvertProtocolVersionToStringRef); - /// - /// Gets the OpenTelemetry standard host tag value for a span based on its request . - /// - /// . - /// Span host value. - public static string GetHostTagValueFromRequestUri(Uri requestUri) - { - string host = requestUri.Host; - - if (requestUri.IsDefaultPort) - { - return host; - } - - int port = requestUri.Port; - - if (!HostAndPortToStringCache.TryGetValue(host, out ConcurrentDictionary portCache)) - { - portCache = new ConcurrentDictionary(); - HostAndPortToStringCache.TryAdd(host, portCache); - } - - if (!portCache.TryGetValue(port, out string hostTagValue)) - { - hostTagValue = $"{requestUri.Host}:{requestUri.Port}"; - portCache.TryAdd(port, hostTagValue); - } - - return hostTagValue; - } - /// /// Gets the OpenTelemetry standard uri tag value for a span based on its request . /// diff --git a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs index 078997b1b10..b011719cb6f 100644 --- a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs +++ b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs @@ -99,8 +99,13 @@ private static void AddRequestTagsAndInstrumentRequest(HttpWebRequest request, A if (activity.IsAllDataRequested) { activity.SetTag(SemanticConventions.AttributeHttpMethod, request.Method); + activity.SetTag(SemanticConventions.AttributeNetPeerName, request.RequestUri.Host); + if (!request.RequestUri.IsDefaultPort) + { + activity.SetTag(SemanticConventions.AttributeNetPeerPort, request.RequestUri.Port); + } + activity.SetTag(SemanticConventions.AttributeHttpScheme, request.RequestUri.Scheme); - activity.SetTag(SemanticConventions.AttributeHttpHost, HttpTagHelper.GetHostTagValueFromRequestUri(request.RequestUri)); activity.SetTag(SemanticConventions.AttributeHttpUrl, HttpTagHelper.GetUriTagValueFromRequestUri(request.RequestUri)); activity.SetTag(SemanticConventions.AttributeHttpFlavor, HttpTagHelper.GetFlavorTagValueFromProtocolVersion(request.ProtocolVersion)); diff --git a/src/OpenTelemetry.Instrumentation.Http/README.md b/src/OpenTelemetry.Instrumentation.Http/README.md index d7375f467a4..36135841716 100644 --- a/src/OpenTelemetry.Instrumentation.Http/README.md +++ b/src/OpenTelemetry.Instrumentation.Http/README.md @@ -33,7 +33,7 @@ Add a reference to the package. Also, add any other instrumentations & exporters you will need. ```shell -dotnet add package OpenTelemetry.Instrumentation.Http +dotnet add package --prerelease OpenTelemetry.Instrumentation.Http ``` ### Step 2: Enable HTTP Instrumentation at application startup diff --git a/src/OpenTelemetry.Instrumentation.SqlClient/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.SqlClient/.publicApi/net462/PublicAPI.Unshipped.txt index 83aa554a2e0..4958bb839fd 100644 --- a/src/OpenTelemetry.Instrumentation.SqlClient/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.SqlClient/.publicApi/net462/PublicAPI.Unshipped.txt @@ -3,8 +3,14 @@ OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.EnableCo OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.EnableConnectionLevelAttributes.set -> void OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.Enrich.get -> System.Action OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.Enrich.set -> void -OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.SetDbStatement.get -> bool -OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.SetDbStatement.set -> void +OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.Filter.get -> System.Func +OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.Filter.set -> void +OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.RecordException.get -> bool +OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.RecordException.set -> void +OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.SetDbStatementForStoredProcedure.get -> bool +OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.SetDbStatementForStoredProcedure.set -> void +OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.SetDbStatementForText.get -> bool +OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.SetDbStatementForText.set -> void OpenTelemetry.Instrumentation.SqlClient.SqlClientInstrumentationOptions.SqlClientInstrumentationOptions() -> void OpenTelemetry.Trace.TracerProviderBuilderExtensions static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddSqlClientInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action configureSqlClientInstrumentationOptions = null) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry.Instrumentation.SqlClient/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.SqlClient/CHANGELOG.md index 63b5dec1c1c..aa7938f49d3 100644 --- a/src/OpenTelemetry.Instrumentation.SqlClient/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.SqlClient/CHANGELOG.md @@ -2,6 +2,18 @@ ## Unreleased +* **Breaking change**: The same API is now exposed for `net462` and + `netstandard2.0` targets. `SetDbStatement` has been removed. Use + `SetDbStatementForText` to capture command text and stored procedure names on + .NET Framework. Note: `Enrich`, `Filter`, `RecordException`, and + `SetDbStatementForStoredProcedure` options are NOT supported on .NET + Framework. + ([#3900](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3900)) + +## 1.0.0-rc9.9 + +Released 2022-Nov-07 + ## 1.0.0-rc9.8 Released 2022-Oct-17 diff --git a/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs b/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs index fde30c97575..c2065174776 100644 --- a/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs +++ b/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + #if NETFRAMEWORK using System; using System.Diagnostics; @@ -30,13 +31,9 @@ namespace OpenTelemetry.Instrumentation.SqlClient.Implementation /// We hook into these event sources and process their BeginExecute/EndExecute events. /// /// - /// Note that before version 2.0.0, Microsoft.Data.SqlClient used "Microsoft-AdoNet-SystemData" - /// EventSource (same as System.Data.SqlClient), but since 2.0.0 has switched to "Microsoft.Data.SqlClient.EventSource". - /// - /// Due to the limitation of the "Microsoft-AdoNet-SystemData", it is not possible to capture sql statement text - /// for CommandType.Text when using that EventSource. It only reports text for CommandType.StoredProcedure. - /// - /// "Microsoft.Data.SqlClient.EventSource" doesn't have that issue. + /// Note that before version 2.0.0, Microsoft.Data.SqlClient used + /// "Microsoft-AdoNet-SystemData" (same as System.Data.SqlClient), but since + /// 2.0.0 has switched to "Microsoft.Data.SqlClient.EventSource". /// internal sealed class SqlEventSourceListener : EventListener { @@ -115,8 +112,12 @@ private void OnBeginExecute(EventWrittenEventArgs eventData) [3] -> CommandText Note: - - For "Microsoft-AdoNet-SystemData": [3] CommandText = (CommandType == CommandType.StoredProcedure ? CommandText : string.Empty; - - For "Microsoft.Data.SqlClient.EventSource": [3] CommandText = sqlCommand.CommandText (so it is set for all command types). + - For "Microsoft-AdoNet-SystemData" v1.0: [3] CommandText = CommandType == CommandType.StoredProcedure ? CommandText : string.Empty; (so it is set for only StoredProcedure command types) + (https://github.com/dotnet/SqlClient/blob/v1.0.19239.1/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs#L6369) + - For "Microsoft-AdoNet-SystemData" v1.1: [3] CommandText = sqlCommand.CommandText (so it is set for all command types) + (https://github.com/dotnet/SqlClient/blob/v1.1.0/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs#L7459) + - For "Microsoft.Data.SqlClient.EventSource" v2.0+: [3] CommandText = sqlCommand.CommandText (so it is set for all command types). + (https://github.com/dotnet/SqlClient/blob/f4568ce68da21db3fe88c0e72e1287368aaa1dc8/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs#L6641) */ if ((eventData?.Payload?.Count ?? 0) < 4) @@ -148,7 +149,7 @@ private void OnBeginExecute(EventWrittenEventArgs eventData) this.options.AddConnectionLevelDetailsToActivity((string)eventData.Payload[1], activity); string commandText = (string)eventData.Payload[3]; - if (!string.IsNullOrEmpty(commandText) && this.options.SetDbStatement) + if (!string.IsNullOrEmpty(commandText) && this.options.SetDbStatementForText) { activity.SetTag(SemanticConventions.AttributeDbStatement, commandText); } diff --git a/src/OpenTelemetry.Instrumentation.SqlClient/README.md b/src/OpenTelemetry.Instrumentation.SqlClient/README.md index 7999dfe91a5..7d20c1976ee 100644 --- a/src/OpenTelemetry.Instrumentation.SqlClient/README.md +++ b/src/OpenTelemetry.Instrumentation.SqlClient/README.md @@ -30,7 +30,7 @@ Add a reference to the package. Also, add any other instrumentations & exporters you will need. ```shell -dotnet add package OpenTelemetry.Instrumentation.SqlClient +dotnet add package --prerelease OpenTelemetry.Instrumentation.SqlClient ``` ### Step 2: Enable SqlClient Instrumentation at application startup @@ -71,18 +71,20 @@ For an ASP.NET application, adding instrumentation is typically done in the This instrumentation can be configured to change the default behavior by using `SqlClientInstrumentationOptions`. -### Capturing 'db.statement' +### Capturing database statements -The `SqlClientInstrumentationOptions` class exposes several properties that can -be used to configure how the +The `SqlClientInstrumentationOptions` class exposes two properties that can be +used to configure how the [`db.statement`](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/database.md#call-level-attributes) -attribute is captured upon execution of a query. +attribute is captured upon execution of a query but the behavior depends on the +runtime used. -#### .NET Core - SetDbStatementForStoredProcedure and SetDbStatementForText +#### .NET and .NET Core -On .NET Core, two properties are available: `SetDbStatementForStoredProcedure` -and `SetDbStatementForText`. These properties control capturing of -`CommandType.StoredProcedure` and `CommandType.Text` respectively. +On .NET and .NET Core, two properties are available: +`SetDbStatementForStoredProcedure` and `SetDbStatementForText`. These properties +control capturing of `CommandType.StoredProcedure` and `CommandType.Text` +respectively. `SetDbStatementForStoredProcedure` is _true_ by default and will set [`db.statement`](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/database.md#call-level-attributes) @@ -115,25 +117,16 @@ using var tracerProvider = Sdk.CreateTracerProviderBuilder() .Build(); ``` -#### .NET Framework - SetDbStatement +#### .NET Framework -For .NET Framework, `SetDbStatementForStoredProcedure` and -`SetDbStatementForText` are not available. Instead, a single `SetDbStatement` -property should be used to control whether this instrumentation should set the +On .NET Framework, the `SetDbStatementForText` property controls whether or not +this instrumentation will set the [`db.statement`](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/database.md#call-level-attributes) -attribute to the text of the `SqlCommand` being executed. This could either be a -name of a stored procedure or a full text of a `CommandType.Text` query. - -On .NET Framework, unlike .NET Core, the instrumentation capabilities for both -[`Microsoft.Data.SqlClient`](https://www.nuget.org/packages/Microsoft.Data.SqlClient/) -and `System.Data.SqlClient` are limited: - -* [`Microsoft.Data.SqlClient`](https://www.nuget.org/packages/Microsoft.Data.SqlClient/) - always exposes both the stored procedure name and the full query text but - doesn't allow for more granular control to turn either on/off depending on - `CommandType`. -* `System.Data.SqlClient` only exposes stored procedure names and not the full - query text. +attribute to the text of the `SqlCommand` being executed. This could either be +the name of a stored procedure (when `CommandType.StoredProcedure` is used) or +the full text of a `CommandType.Text` query. `SetDbStatementForStoredProcedure` +is ignored because on .NET Framework there is no way to determine the type of +command being executed. Since `CommandType.Text` might contain sensitive data, all SQL capturing is _disabled_ by default to protect against accidentally sending full query text to @@ -144,12 +137,14 @@ using the options like below: ```csharp using var tracerProvider = Sdk.CreateTracerProviderBuilder() .AddSqlClientInstrumentation( - options => options.SetDbStatement = true) + options => options.SetDbStatementForText = true) .AddConsoleExporter() .Build(); ``` -## EnableConnectionLevelAttributes +### EnableConnectionLevelAttributes + +**Note:** EnableConnectionLevelAttributes is supported on all runtimes. By default, `EnabledConnectionLevelAttributes` is disabled and this instrumentation sets the `peer.service` attribute to the @@ -170,13 +165,14 @@ using var tracerProvider = Sdk.CreateTracerProviderBuilder() .Build(); ``` -## Enrich +### Enrich -This option, available on .NET Core only, allows one to enrich the activity with -additional information from the raw `SqlCommand` object. The `Enrich` action is -called only when `activity.IsAllDataRequested` is `true`. It contains the -activity itself (which can be enriched), the name of the event, and the actual -raw object. +**Note:** Enrich is supported on .NET and .NET Core runtimes only. + +This option can be used to enrich the activity with additional information from +the raw `SqlCommand` object. The `Enrich` action is called only when +`activity.IsAllDataRequested` is `true`. It contains the activity itself (which +can be enriched), the name of the event, and the actual raw object. Currently there is only one event name reported, "OnCustom". The actual object is `Microsoft.Data.SqlClient.SqlCommand` for `Microsoft.Data.SqlClient` and @@ -207,8 +203,10 @@ access to `SqlCommand` object. ### RecordException -This option, available on .NET Core only, can be set to instruct the -instrumentation to record SqlExceptions as Activity +**Note:** RecordException is supported on .NET and .NET Core runtimes only. + +This option can be set to instruct the instrumentation to record SqlExceptions +as Activity [events](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/exceptions.md). The default value is `false` and can be changed by the code like below. @@ -221,16 +219,18 @@ using var tracerProvider = Sdk.CreateTracerProviderBuilder() .Build(); ``` -## Filter +### Filter + +**Note:** Filter is supported on .NET and .NET Core runtimes only. -This option allows to filter out activities based on the properties of the -`SqlCommand` object being instrumented using a `Func`. -The function receives an instance of the raw `SqlCommand` and should return -`true` if the telemetry is to be collected, and `false` if it should not. -The parameter of the Func delegate is of type `object` and needs to -be cast to the appropriate type of `SqlCommand`, either -`Microsoft.Data.SqlClient.SqlCommand` or `System.Data.SqlClient.SqlCommand`. -The example below filters out all commands that are not stored procedures. +This option can be used to filter out activities based on the properties of the +`SqlCommand` object being instrumented using a `Func`. The +function receives an instance of the raw `SqlCommand` and should return `true` +if the telemetry is to be collected, and `false` if it should not. The parameter +of the Func delegate is of type `object` and needs to be cast to the appropriate +type of `SqlCommand`, either `Microsoft.Data.SqlClient.SqlCommand` or +`System.Data.SqlClient.SqlCommand`. The example below filters out all commands +that are not stored procedures. ```csharp using var traceProvider = Sdk.CreateTracerProviderBuilder() diff --git a/src/OpenTelemetry.Instrumentation.SqlClient/SqlClientInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.SqlClient/SqlClientInstrumentationOptions.cs index b413952e6cf..6cfb81a9587 100644 --- a/src/OpenTelemetry.Instrumentation.SqlClient/SqlClientInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.SqlClient/SqlClientInstrumentationOptions.cs @@ -26,6 +26,9 @@ namespace OpenTelemetry.Instrumentation.SqlClient /// /// Options for . /// + /// + /// For help and examples see: . + /// public class SqlClientInstrumentationOptions { /* @@ -61,95 +64,121 @@ public class SqlClientInstrumentationOptions private static readonly ConcurrentDictionary ConnectionDetailCache = new(StringComparer.OrdinalIgnoreCase); - // .NET Framework implementation uses SqlEventSource from which we can't reliably distinguish - // StoredProcedures from regular Text sql commands. -#if NETFRAMEWORK - /// - /// Gets or sets a value indicating whether or not the should - /// add the text of the executed Sql commands as the tag. - /// Default value: False. + /// Gets or sets a value indicating whether or not the should add the names of commands as the tag. Default + /// value: . /// /// - /// - /// WARNING: potential sensitive data capture! If you use Microsoft.Data.SqlClient, the instrumentation will capture sqlCommand.CommandText - /// for and . Make sure your CommandText property never contains - /// any sensitive data for commands. - /// - /// - /// When using System.Data.SqlClient, the instrumentation will only capture sqlCommand.CommandText for commands. - /// + /// SetDbStatementForStoredProcedure is only supported on .NET + /// and .NET Core runtimes. /// - public bool SetDbStatement { get; set; } -#else - /// - /// Gets or sets a value indicating whether or not the should add the names of commands as the tag. Default value: True. - /// public bool SetDbStatementForStoredProcedure { get; set; } = true; /// - /// Gets or sets a value indicating whether or not the should add the text of commands as the tag. Default value: False. + /// Gets or sets a value indicating whether or not the should add the text of commands as + /// the tag. + /// Default value: . /// + /// + /// + /// WARNING: SetDbStatementForText will capture the raw + /// CommandText. Make sure your CommandText property never + /// contains any sensitive data. + /// + /// SetDbStatementForText is supported on all runtimes. + /// + /// On .NET and .NET Core SetDbStatementForText only applies to + /// SqlCommands with . + /// On .NET Framework SetDbStatementForText applies to all + /// SqlCommands regardless of . Use + /// SetDbStatementForText to capture Text, StoredProcedure, and all + /// other command text. + /// + /// + /// public bool SetDbStatementForText { get; set; } -#endif /// - /// Gets or sets a value indicating whether or not the should parse the DataSource on a SqlConnection into server name, instance name, and/or port connection-level attribute tags. Default value: False. + /// Gets or sets a value indicating whether or not the should parse the DataSource on a + /// SqlConnection into server name, instance name, and/or port + /// connection-level attribute tags. Default value: . /// /// - /// The default behavior is to set the SqlConnection DataSource as the tag. If enabled, SqlConnection DataSource will be parsed and the server name will be sent as the or tag, the instance name will be sent as the tag, and the port will be sent as the tag if it is not 1433 (the default port). + /// EnableConnectionLevelAttributes is supported on all + /// runtimes. + /// The default behavior is to set the SqlConnection DataSource as + /// the tag. If + /// enabled, SqlConnection DataSource will be parsed and the server name + /// will be sent as the or tag, the instance + /// name will be sent as the tag, and + /// the port will be sent as the tag if it is not + /// 1433 (the default port). /// public bool EnableConnectionLevelAttributes { get; set; } /// - /// Gets or sets an action to enrich an Activity. + /// Gets or sets an action to enrich an with the + /// raw SqlCommand object. /// /// - /// : the activity being enriched. - /// string: the name of the event. - /// object: the raw SqlCommand object from which additional information can be extracted to enrich the activity. - /// See also: example. + /// Enrich is only executed on .NET and .NET Core + /// runtimes. + /// The parameters passed to the enrich action are: + /// + /// The being enriched. + /// The name of the event. Currently only "OnCustom" is + /// used but more events may be added in the future. + /// The raw SqlCommand object from which additional + /// information can be extracted to enrich the . + /// /// - /// - /// - /// using var tracerProvider = Sdk.CreateTracerProviderBuilder() - /// .AddSqlClientInstrumentation(opt => opt.Enrich - /// = (activity, eventName, rawObject) => - /// { - /// if (eventName.Equals("OnCustom")) - /// { - /// if (rawObject is SqlCommand cmd) - /// { - /// activity.SetTag("db.commandTimeout", cmd.CommandTimeout); - /// } - /// } - /// }) - /// .Build(); - /// - /// public Action Enrich { get; set; } -#if !NETFRAMEWORK /// - /// Gets or sets a Filter function that determines whether or not to collect telemetry about a command - /// The Filter gets the SqlCommand, and should return a boolean. - /// If Filter returns true, the request is collected. - /// If Filter returns false or throw exception, the request is filtered out. + /// Gets or sets a filter function that determines whether or not to + /// collect telemetry about a command. /// /// - /// object: the raw SqlCommand object to interrogate for a decision on whether to trace or not. + /// Filter is only executed on .NET and .NET Core + /// runtimes. + /// Notes: + /// + /// The first parameter passed to the filter function is the raw + /// SqlCommand object for the command being executed. + /// The return value for the filter function is interpreted as: + /// + /// If filter returns , the command is + /// collected. + /// If filter returns or throws an + /// exception the command is NOT collected. + /// + /// /// - /// true to collect request, false to filter out. public Func Filter { get; set; } /// - /// Gets or sets a value indicating whether the exception will be recorded as ActivityEvent or not. Default value: False. + /// Gets or sets a value indicating whether the exception will be + /// recorded as or not. Default value: . /// /// - /// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/exceptions.md. + /// RecordException is only supported on .NET and .NET Core + /// runtimes. + /// For specification details see: . /// public bool RecordException { get; set; } -#endif internal static SqlConnectionDetails ParseDataSource(string dataSource) { diff --git a/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md b/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md index 4e7fceee7c8..fb2b7bbe875 100644 --- a/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md +++ b/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.0.0-rc9.9 + +Released 2022-Nov-07 + ## 1.0.0-rc9.8 Released 2022-Oct-17 diff --git a/src/OpenTelemetry.Shims.OpenTracing/README.md b/src/OpenTelemetry.Shims.OpenTracing/README.md index 7ed1e58cdc1..8c3fb6db367 100644 --- a/src/OpenTelemetry.Shims.OpenTracing/README.md +++ b/src/OpenTelemetry.Shims.OpenTracing/README.md @@ -13,7 +13,7 @@ OpenTracing Tracer providing a compatible shim on top of the OpenTelemetry API. ## Installation ```shell -dotnet add package OpenTelemetry.Shims.OpenTracing +dotnet add package --prerelease OpenTelemetry.Shims.OpenTracing ``` See diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index 206a7f2aa98..a5968754802 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -16,31 +16,18 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! -OpenTelemetry.Trace.BatchExportActivityProcessorOptions.BatchExportActivityProcessorOptions(Microsoft.Extensions.Configuration.IConfiguration! configuration) -> void static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter, string? name, System.Action? configure) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, string? name, System.Action? configure) -> OpenTelemetry.Trace.TracerProviderBuilder! OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string? OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string! traceStateString) -> void OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable>? attributes, string? traceStateString) -> void *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! -OpenTelemetry.Trace.ExportActivityProcessorOptions -OpenTelemetry.Trace.ExportActivityProcessorOptions.BatchExportProcessorOptions.get -> OpenTelemetry.Trace.BatchExportActivityProcessorOptions! -OpenTelemetry.Trace.ExportActivityProcessorOptions.BatchExportProcessorOptions.set -> void -OpenTelemetry.Trace.ExportActivityProcessorOptions.ExportActivityProcessorOptions() -> void -OpenTelemetry.Trace.ExportActivityProcessorOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType -OpenTelemetry.Trace.ExportActivityProcessorOptions.ExportProcessorType.set -> void static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index 206a7f2aa98..a5968754802 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -16,31 +16,18 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! -OpenTelemetry.Trace.BatchExportActivityProcessorOptions.BatchExportActivityProcessorOptions(Microsoft.Extensions.Configuration.IConfiguration! configuration) -> void static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter, string? name, System.Action? configure) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, string? name, System.Action? configure) -> OpenTelemetry.Trace.TracerProviderBuilder! OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string? OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string! traceStateString) -> void OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable>? attributes, string? traceStateString) -> void *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! -OpenTelemetry.Trace.ExportActivityProcessorOptions -OpenTelemetry.Trace.ExportActivityProcessorOptions.BatchExportProcessorOptions.get -> OpenTelemetry.Trace.BatchExportActivityProcessorOptions! -OpenTelemetry.Trace.ExportActivityProcessorOptions.BatchExportProcessorOptions.set -> void -OpenTelemetry.Trace.ExportActivityProcessorOptions.ExportActivityProcessorOptions() -> void -OpenTelemetry.Trace.ExportActivityProcessorOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType -OpenTelemetry.Trace.ExportActivityProcessorOptions.ExportProcessorType.set -> void static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 206a7f2aa98..a5968754802 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -16,31 +16,18 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! -OpenTelemetry.Trace.BatchExportActivityProcessorOptions.BatchExportActivityProcessorOptions(Microsoft.Extensions.Configuration.IConfiguration! configuration) -> void static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter, string? name, System.Action? configure) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, string? name, System.Action? configure) -> OpenTelemetry.Trace.TracerProviderBuilder! OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string? OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string! traceStateString) -> void OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable>? attributes, string? traceStateString) -> void *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! -OpenTelemetry.Trace.ExportActivityProcessorOptions -OpenTelemetry.Trace.ExportActivityProcessorOptions.BatchExportProcessorOptions.get -> OpenTelemetry.Trace.BatchExportActivityProcessorOptions! -OpenTelemetry.Trace.ExportActivityProcessorOptions.BatchExportProcessorOptions.set -> void -OpenTelemetry.Trace.ExportActivityProcessorOptions.ExportActivityProcessorOptions() -> void -OpenTelemetry.Trace.ExportActivityProcessorOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType -OpenTelemetry.Trace.ExportActivityProcessorOptions.ExportProcessorType.set -> void static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index 206a7f2aa98..a5968754802 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -16,31 +16,18 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! -OpenTelemetry.Trace.BatchExportActivityProcessorOptions.BatchExportActivityProcessorOptions(Microsoft.Extensions.Configuration.IConfiguration! configuration) -> void static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter, string? name, System.Action? configure) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, string? name, System.Action? configure) -> OpenTelemetry.Trace.TracerProviderBuilder! OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string? OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string! traceStateString) -> void OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable>? attributes, string? traceStateString) -> void *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! -OpenTelemetry.Trace.ExportActivityProcessorOptions -OpenTelemetry.Trace.ExportActivityProcessorOptions.BatchExportProcessorOptions.get -> OpenTelemetry.Trace.BatchExportActivityProcessorOptions! -OpenTelemetry.Trace.ExportActivityProcessorOptions.BatchExportProcessorOptions.set -> void -OpenTelemetry.Trace.ExportActivityProcessorOptions.ExportActivityProcessorOptions() -> void -OpenTelemetry.Trace.ExportActivityProcessorOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType -OpenTelemetry.Trace.ExportActivityProcessorOptions.ExportProcessorType.set -> void static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddExporter(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.ExportProcessorType exportProcessorType, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index d2b7d2a1047..f9a7f3013e4 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -2,6 +2,15 @@ ## Unreleased +* Added dependency injection support in the `ResourceBuilder` class and added + support for loading environment variables from `IConfiguration` for the + `AddEnvironmentVariableDetector` extension (Logs) + ([#3889](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3889)) + +## 1.4.0-beta.3 + +Released 2022-Nov-07 + * Fix instrument naming enforcement implementation to match the spec. ([#3821](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3821)) @@ -13,7 +22,7 @@ * Added dependency injection support in the `ResourceBuilder` class and added support for loading environment variables from `IConfiguration` for the - `AddEnvironmentVariableDetector` extension + `AddEnvironmentVariableDetector` extension (Traces & Metrics) ([#3782](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3782), [#3798](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3798)) diff --git a/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs b/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs index 8ae5bd26e48..fb2a3c06301 100644 --- a/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs +++ b/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs @@ -42,7 +42,7 @@ public static IServiceCollection AddOpenTelemetryTracerProviderBuilderServices(t services.AddOpenTelemetryProviderBuilderServices(); services.TryAddSingleton(); - services.RegisterOptionsFactory(configuration => new ExportActivityProcessorOptions(configuration)); + services.RegisterOptionsFactory(configuration => new BatchExportActivityProcessorOptions(configuration)); return services; } diff --git a/src/OpenTelemetry/Internal/ConfigurationExtensions.cs b/src/OpenTelemetry/Internal/ConfigurationExtensions.cs index dc22bbf673c..ecaba0dfc22 100644 --- a/src/OpenTelemetry/Internal/ConfigurationExtensions.cs +++ b/src/OpenTelemetry/Internal/ConfigurationExtensions.cs @@ -137,6 +137,27 @@ public static IServiceCollection RegisterOptionsFactory( return services!; } + public static IServiceCollection RegisterOptionsFactory( + this IServiceCollection services, + Func optionsFactoryFunc) + where T : class + { + Debug.Assert(services != null, "services was null"); + Debug.Assert(optionsFactoryFunc != null, "optionsFactoryFunc was null"); + + services!.TryAddSingleton>(sp => + { + return new DelegatingOptionsFactory( + c => optionsFactoryFunc!(sp, c), + sp.GetRequiredService(), + sp.GetServices>(), + sp.GetServices>(), + sp.GetServices>()); + }); + + return services!; + } + private sealed class DelegatingOptionsFactory : OptionsFactory where T : class { diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs b/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs index 2d52d20399f..af48d1ab528 100644 --- a/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs +++ b/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs @@ -20,6 +20,7 @@ using System.Collections; using System.Text; using System.Threading; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using OpenTelemetry.Internal; @@ -58,6 +59,13 @@ public OpenTelemetryLoggerProvider(IOptionsMonitor o { } + internal OpenTelemetryLoggerProvider(IServiceProvider serviceProvider) + : this( + serviceProvider: serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)), + options: serviceProvider?.GetRequiredService>().CurrentValue!) + { + } + internal OpenTelemetryLoggerProvider() : this(new OpenTelemetryLoggerOptions()) { @@ -68,7 +76,7 @@ internal OpenTelemetryLoggerProvider(Action configur { } - internal OpenTelemetryLoggerProvider(OpenTelemetryLoggerOptions options) + internal OpenTelemetryLoggerProvider(OpenTelemetryLoggerOptions options, IServiceProvider? serviceProvider = null) { OpenTelemetrySdkEventSource.Log.OpenTelemetryLoggerProviderEvent("Building OpenTelemetryLoggerProvider."); @@ -78,7 +86,9 @@ internal OpenTelemetryLoggerProvider(OpenTelemetryLoggerOptions options) this.IncludeFormattedMessage = options.IncludeFormattedMessage; this.ParseStateValues = options.ParseStateValues; - this.Resource = options.ResourceBuilder.Build(); + var resourceBuilder = options.ResourceBuilder; + resourceBuilder.ServiceProvider = serviceProvider; + this.Resource = resourceBuilder.Build(); foreach (var processor in options.Processors) { diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs b/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs index 9a2f8607749..844a744dd2d 100644 --- a/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs +++ b/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs @@ -57,7 +57,9 @@ public static ILoggingBuilder AddOpenTelemetry(this ILoggingBuilder builder, Act builder.AddConfiguration(); - builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); + builder.Services.TryAddEnumerable( + ServiceDescriptor.Singleton( + sp => new OpenTelemetryLoggerProvider(sp))); // Note: This will bind logger options element (eg "Logging:OpenTelemetry") to OpenTelemetryLoggerOptions LoggerProviderOptions.RegisterProviderOptions(builder.Services); diff --git a/src/OpenTelemetry/Trace/BatchExportActivityProcessorOptions.cs b/src/OpenTelemetry/Trace/BatchExportActivityProcessorOptions.cs index 8ea8890e8ba..0dd3fc39bcb 100644 --- a/src/OpenTelemetry/Trace/BatchExportActivityProcessorOptions.cs +++ b/src/OpenTelemetry/Trace/BatchExportActivityProcessorOptions.cs @@ -50,11 +50,7 @@ public BatchExportActivityProcessorOptions() { } - /// - /// Initializes a new instance of the class. - /// - /// . - public BatchExportActivityProcessorOptions(IConfiguration configuration) + internal BatchExportActivityProcessorOptions(IConfiguration configuration) { if (configuration.TryGetIntValue(ExporterTimeoutEnvVarKey, out int value)) { diff --git a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs index 372b411fc5b..b5cf048d16b 100644 --- a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs +++ b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs @@ -20,7 +20,6 @@ using System.Diagnostics; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Options; using OpenTelemetry.Internal; using OpenTelemetry.Resources; @@ -123,28 +122,6 @@ TracerProviderBuilder IDeferredTracerProviderBuilder.Configure( return this; } - internal TracerProviderBuilder AddExporter(ExportProcessorType exportProcessorType, string? name, Action? configure) - where T : BaseExporter - { - this.TryAddSingleton(); - this.ConfigureState((sp, state) - => state.AddProcessor( - BuildExportProcessor(state.ServiceProvider, exportProcessorType, sp.GetRequiredService(), name, configure))); - - return this; - } - - internal TracerProviderBuilder AddExporter(ExportProcessorType exportProcessorType, BaseExporter exporter, string? name, Action? configure) - { - Guard.ThrowIfNull(exporter); - - this.ConfigureState((sp, state) - => state.AddProcessor( - BuildExportProcessor(state.ServiceProvider, exportProcessorType, exporter, name, configure))); - - return this; - } - internal TracerProviderBuilder AddInstrumentation() where T : class { @@ -277,39 +254,6 @@ protected TracerProvider Build() return new TracerProviderSdk(serviceProvider, ownsServiceProvider: true); } - private static BaseProcessor BuildExportProcessor( - IServiceProvider serviceProvider, - ExportProcessorType exportProcessorType, - BaseExporter exporter, - string? name, - Action? configure) - { - name ??= Options.DefaultName; - - switch (exportProcessorType) - { - case ExportProcessorType.Simple: - return new SimpleActivityExportProcessor(exporter); - case ExportProcessorType.Batch: - var options = serviceProvider.GetRequiredService>().Get(name); - - options.ExportProcessorType = ExportProcessorType.Batch; - - configure?.Invoke(options); - - var batchOptions = options.BatchExportProcessorOptions; - - return new BatchActivityExportProcessor( - exporter, - batchOptions.MaxQueueSize, - batchOptions.ScheduledDelayMilliseconds, - batchOptions.ExporterTimeoutMilliseconds, - batchOptions.MaxExportBatchSize); - default: - throw new NotSupportedException($"ExportProcessorType '{exportProcessorType}' is not supported."); - } - } - private TracerProviderBuilder AddInstrumentation(Func instrumentationFactory) where T : class { diff --git a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderExtensions.cs index 94caf0e16da..29e0e2512d3 100644 --- a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderExtensions.cs @@ -155,119 +155,6 @@ public static TracerProviderBuilder AddProcessor(this TracerProviderBuilder t return tracerProviderBuilder; } - /// - /// Adds an exporter to the provider. - /// - /// . - /// . - /// Activity exporter to add. - /// Returns for chaining. - public static TracerProviderBuilder AddExporter( - this TracerProviderBuilder tracerProviderBuilder, - ExportProcessorType exportProcessorType, - BaseExporter exporter) - => AddExporter(tracerProviderBuilder, exportProcessorType, exporter, name: null, configure: null); - - /// - /// Adds an exporter to the provider. - /// - /// . - /// . - /// Activity exporter to add. - /// - /// Returns for chaining. - public static TracerProviderBuilder AddExporter( - this TracerProviderBuilder tracerProviderBuilder, - ExportProcessorType exportProcessorType, - BaseExporter exporter, - Action configure) - => AddExporter(tracerProviderBuilder, exportProcessorType, exporter, name: null, configure); - - /// - /// Adds an exporter to the provider. - /// - /// . - /// . - /// Activity exporter to add. - /// Name which is used when retrieving options. - /// - /// Returns for chaining. - public static TracerProviderBuilder AddExporter( - this TracerProviderBuilder tracerProviderBuilder, - ExportProcessorType exportProcessorType, - BaseExporter exporter, - string? name, - Action? configure) - { - if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) - { - tracerProviderBuilderBase.AddExporter(exportProcessorType, exporter, name, configure); - } - - return tracerProviderBuilder; - } - - /// - /// Adds an exporter to the provider which will be retrieved using dependency injection. - /// - /// - /// Exporter type. - /// . - /// . - /// The supplied for chaining. - public static TracerProviderBuilder AddExporter( - this TracerProviderBuilder tracerProviderBuilder, - ExportProcessorType exportProcessorType) - where T : BaseExporter - => AddExporter(tracerProviderBuilder, exportProcessorType, name: null, configure: null); - - /// - /// Adds an exporter to the provider which will be retrieved using dependency injection. - /// - /// - /// Exporter type. - /// . - /// . - /// - /// The supplied for chaining. - public static TracerProviderBuilder AddExporter( - this TracerProviderBuilder tracerProviderBuilder, - ExportProcessorType exportProcessorType, - Action configure) - where T : BaseExporter - => AddExporter(tracerProviderBuilder, exportProcessorType, name: null, configure); - - /// - /// Adds an exporter to the provider which will be retrieved using dependency injection. - /// - /// - /// Note: The type specified by will be - /// registered as a singleton service into application services. - /// - /// Exporter type. - /// . - /// . - /// Name which is used when retrieving options. - /// Callback action to configure . Only invoked when is . - /// The supplied for chaining. - public static TracerProviderBuilder AddExporter( - this TracerProviderBuilder tracerProviderBuilder, - ExportProcessorType exportProcessorType, - string? name, - Action? configure) - where T : BaseExporter - { - if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) - { - tracerProviderBuilderBase.AddExporter(exportProcessorType, name, configure); - } - - return tracerProviderBuilder; - } - /// /// Adds instrumentation to the provider. /// diff --git a/src/OpenTelemetry/Trace/ExportActivityProcessorOptions.cs b/src/OpenTelemetry/Trace/ExportActivityProcessorOptions.cs deleted file mode 100644 index 173dc960a26..00000000000 --- a/src/OpenTelemetry/Trace/ExportActivityProcessorOptions.cs +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#nullable enable - -using Microsoft.Extensions.Configuration; -using OpenTelemetry.Internal; - -namespace OpenTelemetry.Trace; - -/// -/// Options for configuring either a or . -/// -public class ExportActivityProcessorOptions -{ - private BatchExportActivityProcessorOptions batchExportProcessorOptions; - - /// - /// Initializes a new instance of the class. - /// - public ExportActivityProcessorOptions() - : this(new ConfigurationBuilder().AddEnvironmentVariables().Build()) - { - } - - internal ExportActivityProcessorOptions(IConfiguration configuration) - { - this.batchExportProcessorOptions = new BatchExportActivityProcessorOptions(configuration); - } - - /// - /// Gets or sets the export processor type to be used. The default value is . - /// - public ExportProcessorType ExportProcessorType { get; set; } - - /// - /// Gets or sets the batch export options. Ignored unless is . - /// - public BatchExportActivityProcessorOptions BatchExportProcessorOptions - { - get => this.batchExportProcessorOptions; - set - { - Guard.ThrowIfNull(value); - - this.batchExportProcessorOptions = value; - } - } -} diff --git a/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterOptionsTests.cs b/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterOptionsTests.cs index 42b0548be66..851c68fc921 100644 --- a/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterOptionsTests.cs +++ b/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterOptionsTests.cs @@ -17,6 +17,9 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using OpenTelemetry.Trace; using Xunit; namespace OpenTelemetry.Exporter.Jaeger.Tests @@ -104,18 +107,43 @@ public void JaegerExporterOptions_FromConfigurationTest() [JaegerExporterOptions.OTelAgentHostEnvVarKey] = "jaeger-host", [JaegerExporterOptions.OTelAgentPortEnvVarKey] = "123", [JaegerExporterOptions.OTelEndpointEnvVarKey] = "http://custom-endpoint:12345", + ["OTEL_BSP_MAX_QUEUE_SIZE"] = "18", + ["OTEL_BSP_MAX_EXPORT_BATCH_SIZE"] = "2", + ["Jaeger:BatchExportProcessorOptions:MaxExportBatchSize"] = "5", }; var configuration = new ConfigurationBuilder() .AddInMemoryCollection(values) .Build(); - var options = new JaegerExporterOptions(configuration); + IServiceCollection services = null; + + using var provider = Sdk.CreateTracerProviderBuilder() + .ConfigureServices(s => + { + services = s; + services.AddSingleton(configuration); + services.Configure(configuration.GetSection("Jaeger")); + }) + .AddJaegerExporter() + .Build(); + + Assert.NotNull(services); + + using var serviceProvider = services.BuildServiceProvider(); + + var options = serviceProvider.GetRequiredService>().CurrentValue; Assert.Equal("jaeger-host", options.AgentHost); Assert.Equal(123, options.AgentPort); Assert.Equal(JaegerExportProtocol.HttpBinaryThrift, options.Protocol); Assert.Equal(new Uri("http://custom-endpoint:12345"), options.Endpoint); + Assert.Equal(18, options.BatchExportProcessorOptions.MaxQueueSize); + + // Note: + // 1. OTEL_BSP_MAX_EXPORT_BATCH_SIZE is processed in BatchExportActivityProcessorOptions ctor and sets MaxExportBatchSize to 2. + // 2. Jaeger:BatchExportProcessorOptions:MaxExportBatchSize is processed by options binder after ctor and sets MaxExportBatchSize to 5. + Assert.Equal(5, options.BatchExportProcessorOptions.MaxExportBatchSize); } private static void ClearEnvVars() diff --git a/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterTests.cs b/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterTests.cs index 2998ce78fc0..10f1f9b3324 100644 --- a/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterTests.cs +++ b/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterTests.cs @@ -267,7 +267,7 @@ public void JaegerTraceExporter_SetResource_UpdatesServiceNameFromIConfiguration var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions()); - tracerProviderBuilder.AddExporter(ExportProcessorType.Batch, jaegerTraceExporter); + tracerProviderBuilder.AddProcessor(new BatchActivityExportProcessor(jaegerTraceExporter)); using var provider = tracerProviderBuilder.Build(); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj index 474bc4ca723..5f58fd8ed8e 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj @@ -26,7 +26,7 @@ - + diff --git a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj index ef892fc6bf1..16b75375aa9 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj +++ b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj @@ -24,7 +24,7 @@ - + diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs index b5710a1d1e3..19b901d5769 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs @@ -31,10 +31,10 @@ public class PrometheusHttpListenerTests private readonly string meterName = Utils.GetCurrentMethodName(); [Theory] - [InlineData("http://+:9184")] - [InlineData("http://*:9184")] - [InlineData("http://+:9184/")] - [InlineData("http://*:9184/")] + [InlineData("http://+:9464")] + [InlineData("http://*:9464")] + [InlineData("http://+:9464/")] + [InlineData("http://*:9464/")] [InlineData("https://example.com")] [InlineData("http://127.0.0.1")] [InlineData("http://example.com", "https://example.com", "http://127.0.0.1")] diff --git a/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs b/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs index 2eb3ca9e213..683089e9479 100644 --- a/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs +++ b/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs @@ -220,7 +220,7 @@ public void EndpointConfigurationUsingIConfiguration() .AddInMemoryCollection(values) .Build(); - var options = new ZipkinExporterOptions(configuration); + var options = new ZipkinExporterOptions(configuration, new()); Assert.Equal(new Uri("http://custom-endpoint:12345"), options.Endpoint); } @@ -319,7 +319,7 @@ public void UpdatesServiceNameFromIConfiguration() var zipkinExporter = new ZipkinExporter(new ZipkinExporterOptions()); - tracerProviderBuilder.AddExporter(ExportProcessorType.Batch, zipkinExporter); + tracerProviderBuilder.AddProcessor(new BatchActivityExportProcessor(zipkinExporter)); using var provider = tracerProviderBuilder.Build(); diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/OpenTelemetry.Extensions.Hosting.Tests.csproj b/test/OpenTelemetry.Extensions.Hosting.Tests/OpenTelemetry.Extensions.Hosting.Tests.csproj index 2ba56391e4e..ec1a483e1be 100644 --- a/test/OpenTelemetry.Extensions.Hosting.Tests/OpenTelemetry.Extensions.Hosting.Tests.csproj +++ b/test/OpenTelemetry.Extensions.Hosting.Tests/OpenTelemetry.Extensions.Hosting.Tests.csproj @@ -28,7 +28,7 @@ - + diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs index fe623375a6a..5c1e9548fad 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs @@ -23,10 +23,12 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Moq; using OpenTelemetry.Context.Propagation; using OpenTelemetry.Instrumentation.AspNetCore.Implementation; @@ -57,8 +59,10 @@ public void AddAspNetCoreInstrumentation_BadArgs() Assert.Throws(() => builder.AddAspNetCoreInstrumentation()); } - [Fact] - public async Task StatusIsUnsetOn200Response() + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task StatusIsUnsetOn200Response(bool disableLogging) { var exportedItems = new List(); void ConfigureTestServices(IServiceCollection services) @@ -72,7 +76,13 @@ void ConfigureTestServices(IServiceCollection services) // Arrange using (var client = this.factory .WithWebHostBuilder(builder => - builder.ConfigureTestServices(ConfigureTestServices)) + { + builder.ConfigureTestServices(ConfigureTestServices); + if (disableLogging) + { + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + } + }) .CreateClient()) { // Act @@ -116,7 +126,10 @@ void ConfigureTestServices(IServiceCollection services) // Arrange using (var client = this.factory .WithWebHostBuilder(builder => - builder.ConfigureTestServices(ConfigureTestServices)) + { + builder.ConfigureTestServices(ConfigureTestServices); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }) .CreateClient()) { // Act @@ -150,12 +163,17 @@ public async Task SuccessfulTemplateControllerCallUsesParentContext() // Arrange using (var testFactory = this.factory .WithWebHostBuilder(builder => + { builder.ConfigureTestServices(services => { - this.tracerProvider = Sdk.CreateTracerProviderBuilder().AddAspNetCoreInstrumentation() + this.tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddAspNetCoreInstrumentation() .AddInMemoryExporter(exportedItems) .Build(); - }))) + }); + + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + })) { using var client = testFactory.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, "/api/values/2"); @@ -203,14 +221,14 @@ public async Task CustomPropagator() // Arrange using (var testFactory = this.factory .WithWebHostBuilder(builder => - builder.ConfigureTestServices(services => { - Sdk.SetDefaultTextMapPropagator(propagator.Object); - this.tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddAspNetCoreInstrumentation() - .AddInMemoryExporter(exportedItems) - .Build(); - }))) + builder.ConfigureTestServices(services => + { + Sdk.SetDefaultTextMapPropagator(propagator.Object); + this.tracerProvider = Sdk.CreateTracerProviderBuilder().AddAspNetCoreInstrumentation().AddInMemoryExporter(exportedItems).Build(); + }); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + })) { using var client = testFactory.CreateClient(); var response = await client.GetAsync("/api/values/2"); @@ -256,7 +274,10 @@ void ConfigureTestServices(IServiceCollection services) // Arrange using (var testFactory = this.factory .WithWebHostBuilder(builder => - builder.ConfigureTestServices(ConfigureTestServices))) + { + builder.ConfigureTestServices(ConfigureTestServices); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + })) { using var client = testFactory.CreateClient(); @@ -303,7 +324,10 @@ void ConfigureTestServices(IServiceCollection services) // Arrange using (var testFactory = this.factory .WithWebHostBuilder(builder => - builder.ConfigureTestServices(ConfigureTestServices))) + { + builder.ConfigureTestServices(ConfigureTestServices); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + })) { using var client = testFactory.CreateClient(); @@ -347,13 +371,10 @@ public async Task ExtractContextIrrespectiveOfSamplingDecision(SamplingDecision // Arrange using var testFactory = this.factory .WithWebHostBuilder(builder => - builder.ConfigureTestServices(services => { - this.tracerProvider = Sdk.CreateTracerProviderBuilder() - .SetSampler(new TestSampler(samplingDecision)) - .AddAspNetCoreInstrumentation() - .Build(); - })); + builder.ConfigureTestServices(services => { this.tracerProvider = Sdk.CreateTracerProviderBuilder().SetSampler(new TestSampler(samplingDecision)).AddAspNetCoreInstrumentation().Build(); }); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }); using var client = testFactory.CreateClient(); // Test TraceContext Propagation @@ -404,6 +425,7 @@ public async Task ExtractContextIrrespectiveOfTheFilterApplied() bool isFilterCalled = false; using var testFactory = this.factory .WithWebHostBuilder(builder => + { builder.ConfigureTestServices(services => { this.tracerProvider = Sdk.CreateTracerProviderBuilder() @@ -416,7 +438,9 @@ public async Task ExtractContextIrrespectiveOfTheFilterApplied() }; }) .Build(); - })); + }); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }); using var client = testFactory.CreateClient(); // Test TraceContext Propagation @@ -494,7 +518,10 @@ void ConfigureTestServices(IServiceCollection services) // Arrange using (var client = this.factory .WithWebHostBuilder(builder => - builder.ConfigureTestServices(ConfigureTestServices)) + { + builder.ConfigureTestServices(ConfigureTestServices); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }) .CreateClient()) { using var request = new HttpRequestMessage(HttpMethod.Get, "/api/values"); @@ -549,7 +576,10 @@ void ConfigureTestServices(IServiceCollection services) // Arrange using var client = this.factory .WithWebHostBuilder(builder => - builder.ConfigureTestServices(ConfigureTestServices)) + { + builder.ConfigureTestServices(ConfigureTestServices); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }) .CreateClient(); // Act @@ -582,7 +612,10 @@ void ConfigureTestServices(IServiceCollection services) // Arrange using (var client = this.factory .WithWebHostBuilder(builder => - builder.ConfigureTestServices(ConfigureTestServices)) + { + builder.ConfigureTestServices(ConfigureTestServices); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }) .CreateClient()) { var response = await client.GetAsync("/api/values/2"); @@ -618,13 +651,16 @@ public async Task ActivitiesStartedInMiddlewareBySettingHostActivityToNullShould // Arrange using (var client = this.factory .WithWebHostBuilder(builder => + { builder.ConfigureTestServices((IServiceCollection services) => { services.AddSingleton(new TestNullHostActivityMiddlewareImpl(activitySourceName, activityName)); services.AddOpenTelemetryTracing((builder) => builder.AddAspNetCoreInstrumentation() .AddSource(activitySourceName) .AddInMemoryExporter(exportedItems)); - })) + }); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }) .CreateClient()) { var response = await client.GetAsync("/api/values/2"); @@ -671,7 +707,10 @@ void ConfigureTestServices(IServiceCollection services) // Arrange using (var client = this.factory .WithWebHostBuilder(builder => - builder.ConfigureTestServices(ConfigureTestServices)) + { + builder.ConfigureTestServices(ConfigureTestServices); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }) .CreateClient()) { // Act @@ -699,8 +738,12 @@ public async Task ShouldExportActivityWithOneOrMoreExceptionFilters(int mode) // Arrange using (var client = this.factory - .WithWebHostBuilder(builder => builder.ConfigureTestServices( - (s) => this.ConfigureExceptionFilters(s, mode, ref exportedItems))) + .WithWebHostBuilder(builder => + { + builder.ConfigureTestServices( + (s) => this.ConfigureExceptionFilters(s, mode, ref exportedItems)); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }) .CreateClient()) { // Act @@ -714,11 +757,10 @@ public async Task ShouldExportActivityWithOneOrMoreExceptionFilters(int mode) } [Fact] - public async Task DiagnosticSourceCustomCallbacksAreReceivedOnlyForSubscribedEvents() + public async Task DiagnosticSourceCallbacksAreReceivedOnlyForSubscribedEvents() { - int numberOfCustomCallbacks = 0; - string expectedCustomEventName = "Microsoft.AspNetCore.Mvc.BeforeAction"; - string actualCustomEventName = null; + int numberOfUnSubscribedEvents = 0; + int numberofSubscribedEvents = 0; void ConfigureTestServices(IServiceCollection services) { this.tracerProvider = Sdk.CreateTracerProviderBuilder() @@ -729,10 +771,27 @@ void ConfigureTestServices(IServiceCollection services) { switch (name) { + case HttpInListener.OnStartEvent: + { + numberofSubscribedEvents++; + } + + break; + case HttpInListener.OnStopEvent: + { + numberofSubscribedEvents++; + } + + break; case HttpInListener.OnMvcBeforeActionEvent: { - actualCustomEventName = name; - numberOfCustomCallbacks++; + numberofSubscribedEvents++; + } + + break; + default: + { + numberOfUnSubscribedEvents++; } break; @@ -745,7 +804,10 @@ void ConfigureTestServices(IServiceCollection services) // Arrange using (var client = this.factory .WithWebHostBuilder(builder => - builder.ConfigureTestServices(ConfigureTestServices)) + { + builder.ConfigureTestServices(ConfigureTestServices); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }) .CreateClient()) { using var request = new HttpRequestMessage(HttpMethod.Get, "/api/values"); @@ -754,13 +816,15 @@ void ConfigureTestServices(IServiceCollection services) using var response = await client.SendAsync(request); } - Assert.Equal(1, numberOfCustomCallbacks); - Assert.Equal(expectedCustomEventName, actualCustomEventName); + Assert.Equal(0, numberOfUnSubscribedEvents); + Assert.Equal(3, numberofSubscribedEvents); } [Fact] public async Task DiagnosticSourceExceptionCallbackIsReceivedForUnHandledException() { + int numberOfUnSubscribedEvents = 0; + int numberofSubscribedEvents = 0; int numberOfExceptionCallbacks = 0; void ConfigureTestServices(IServiceCollection services) { @@ -772,14 +836,40 @@ void ConfigureTestServices(IServiceCollection services) { switch (name) { + case HttpInListener.OnStartEvent: + { + numberofSubscribedEvents++; + } + + break; + case HttpInListener.OnStopEvent: + { + numberofSubscribedEvents++; + } + + break; + case HttpInListener.OnMvcBeforeActionEvent: + { + numberofSubscribedEvents++; + } + + break; + // TODO: Add test case for validating name for both the types // of exception event. case HttpInListener.OnUnhandledHostingExceptionEvent: case HttpInListener.OnUnHandledDiagnosticsExceptionEvent: { + numberofSubscribedEvents++; numberOfExceptionCallbacks++; } + break; + default: + { + numberOfUnSubscribedEvents++; + } + break; } }, @@ -790,7 +880,10 @@ void ConfigureTestServices(IServiceCollection services) // Arrange using (var client = this.factory .WithWebHostBuilder(builder => - builder.ConfigureTestServices(ConfigureTestServices)) + { + builder.ConfigureTestServices(ConfigureTestServices); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }) .CreateClient()) { try @@ -807,11 +900,15 @@ void ConfigureTestServices(IServiceCollection services) } Assert.Equal(1, numberOfExceptionCallbacks); + Assert.Equal(0, numberOfUnSubscribedEvents); + Assert.Equal(4, numberofSubscribedEvents); } [Fact] public async Task DiagnosticSourceExceptionCallBackIsNotReceivedForExceptionsHandledInMiddleware() { + int numberOfUnSubscribedEvents = 0; + int numberofSubscribedEvents = 0; int numberOfExceptionCallbacks = 0; // configure SDK @@ -823,12 +920,34 @@ public async Task DiagnosticSourceExceptionCallBackIsNotReceivedForExceptionsHan { switch (name) { + case HttpInListener.OnStartEvent: + { + numberofSubscribedEvents++; + } + + break; + case HttpInListener.OnStopEvent: + { + numberofSubscribedEvents++; + } + + break; + + // TODO: Add test case for validating name for both the types + // of exception event. case HttpInListener.OnUnhandledHostingExceptionEvent: case HttpInListener.OnUnHandledDiagnosticsExceptionEvent: { + numberofSubscribedEvents++; numberOfExceptionCallbacks++; } + break; + default: + { + numberOfUnSubscribedEvents++; + } + break; } }, @@ -836,6 +955,7 @@ public async Task DiagnosticSourceExceptionCallBackIsNotReceivedForExceptionsHan .Build(); var builder = WebApplication.CreateBuilder(); + builder.Logging.ClearProviders(); var app = builder.Build(); app.UseExceptionHandler(handler => @@ -869,6 +989,8 @@ static void ThrowException(IApplicationBuilder app) } Assert.Equal(0, numberOfExceptionCallbacks); + Assert.Equal(0, numberOfUnSubscribedEvents); + Assert.Equal(2, numberofSubscribedEvents); await app.DisposeAsync(); } @@ -905,26 +1027,6 @@ private static void ValidateAspNetCoreActivity(Activity activityToValidate, stri Assert.Equal(expectedHttpPath, activityToValidate.GetTagValue(SemanticConventions.AttributeHttpTarget) as string); } - private static void ActivityEnrichment(Activity activity, string method, object obj) - { - Assert.True(activity.IsAllDataRequested); - switch (method) - { - case "OnStartActivity": - Assert.True(obj is HttpRequest); - break; - - case "OnStopActivity": - Assert.True(obj is HttpResponse); - break; - - default: - break; - } - - activity.SetTag("enriched", "yes"); - } - private static void AssertException(List exportedItems) { Assert.Single(exportedItems); diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/InProcServerTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/InProcServerTests.cs index 9f39e9c2035..d01e170a385 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/InProcServerTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/InProcServerTests.cs @@ -21,6 +21,7 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Logging; using OpenTelemetry.Trace; using Xunit; @@ -37,6 +38,7 @@ public InProcServerTests() { this.exportedItems = new List(); var builder = WebApplication.CreateBuilder(); + builder.Logging.ClearProviders(); var app = builder.Build(); this.tracerProvider = Sdk.CreateTracerProviderBuilder() @@ -71,7 +73,8 @@ public async void ExampleTest() var activity = this.exportedItems[0]; Assert.Equal(ActivityKind.Server, activity.Kind); - Assert.Equal("localhost:5000", activity.GetTagValue(SemanticConventions.AttributeHttpHost)); + Assert.Equal("localhost", activity.GetTagValue(SemanticConventions.AttributeNetHostName)); + Assert.Equal(5000, activity.GetTagValue(SemanticConventions.AttributeNetHostPort)); Assert.Equal("GET", activity.GetTagValue(SemanticConventions.AttributeHttpMethod)); Assert.Equal("1.1", activity.GetTagValue(SemanticConventions.AttributeHttpFlavor)); Assert.Equal(200, activity.GetTagValue(SemanticConventions.AttributeHttpStatusCode)); diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs index fd946019d8d..930bbcd0eb6 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs @@ -19,11 +19,13 @@ using System.Diagnostics; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using OpenTelemetry.Trace; using TestApp.AspNetCore; using Xunit; @@ -58,12 +60,15 @@ public async Task SuccessfulTemplateControllerCallGeneratesASpan( // Arrange using (var client = this.factory .WithWebHostBuilder(builder => + { builder.ConfigureTestServices((IServiceCollection services) => { services.AddSingleton(new TestCallbackMiddlewareImpl(statusCode, reasonPhrase)); services.AddOpenTelemetryTracing((builder) => builder.AddAspNetCoreInstrumentation(options => options.RecordException = recordException) .AddInMemoryExporter(exportedItems)); - })) + }); + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }) .CreateClient()) { try @@ -105,7 +110,7 @@ public async Task SuccessfulTemplateControllerCallGeneratesASpan( var activity = exportedItems[0]; Assert.Equal(ActivityKind.Server, activity.Kind); - Assert.Equal("localhost", activity.GetTagValue(SemanticConventions.AttributeHttpHost)); + Assert.Equal("localhost", activity.GetTagValue(SemanticConventions.AttributeNetHostName)); Assert.Equal("GET", activity.GetTagValue(SemanticConventions.AttributeHttpMethod)); Assert.Equal("1.1", activity.GetTagValue(SemanticConventions.AttributeHttpFlavor)); Assert.Equal("http", activity.GetTagValue(SemanticConventions.AttributeHttpScheme)); diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs index 2b597048008..8cef78f445d 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs @@ -18,7 +18,9 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.Logging; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; using Xunit; @@ -53,7 +55,12 @@ public async Task RequestMetricIsCaptured() .AddInMemoryExporter(metricItems) .Build(); - using (var client = this.factory.CreateClient()) + using (var client = this.factory + .WithWebHostBuilder(builder => + { + builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); + }) + .CreateClient()) { var response = await client.GetAsync("/api/values"); response.EnsureSuccessStatusCode(); diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/OpenTelemetry.Instrumentation.AspNetCore.Tests.csproj b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/OpenTelemetry.Instrumentation.AspNetCore.Tests.csproj index 8e218b535d7..25de7e186df 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/OpenTelemetry.Instrumentation.AspNetCore.Tests.csproj +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/OpenTelemetry.Instrumentation.AspNetCore.Tests.csproj @@ -29,7 +29,7 @@ - + diff --git a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs index 91db02187a9..95751e75e7e 100644 --- a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs +++ b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs @@ -106,7 +106,8 @@ public void GrpcAspNetCoreInstrumentationAddsCorrectAttributes(bool? enableGrpcA Assert.Equal(Status.Unset, activity.GetStatus()); // The following are http.* attributes that are also included on the span for the gRPC invocation. - Assert.Equal($"localhost:{this.server.Port}", activity.GetTagValue(SemanticConventions.AttributeHttpHost)); + Assert.Equal("localhost", activity.GetTagValue(SemanticConventions.AttributeNetHostName)); + Assert.Equal(this.server.Port, activity.GetTagValue(SemanticConventions.AttributeNetHostPort)); Assert.Equal("POST", activity.GetTagValue(SemanticConventions.AttributeHttpMethod)); Assert.Equal("/greet.Greeter/SayHello", activity.GetTagValue(SemanticConventions.AttributeHttpTarget)); Assert.Equal($"http://localhost:{this.server.Port}/greet.Greeter/SayHello", activity.GetTagValue(SemanticConventions.AttributeHttpUrl)); @@ -184,7 +185,8 @@ public void GrpcAspNetCoreInstrumentationAddsCorrectAttributesWhenItCreatesNewAc Assert.Equal(Status.Unset, activity.GetStatus()); // The following are http.* attributes that are also included on the span for the gRPC invocation. - Assert.Equal($"localhost:{this.server.Port}", activity.GetTagValue(SemanticConventions.AttributeHttpHost)); + Assert.Equal("localhost", activity.GetTagValue(SemanticConventions.AttributeNetHostName)); + Assert.Equal(this.server.Port, activity.GetTagValue(SemanticConventions.AttributeNetHostPort)); Assert.Equal("POST", activity.GetTagValue(SemanticConventions.AttributeHttpMethod)); Assert.Equal("/greet.Greeter/SayHello", activity.GetTagValue(SemanticConventions.AttributeHttpTarget)); Assert.Equal($"http://localhost:{this.server.Port}/greet.Greeter/SayHello", activity.GetTagValue(SemanticConventions.AttributeHttpUrl)); diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs index 3798b48328f..d7efa83efe4 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs @@ -200,11 +200,15 @@ public async Task HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOut var scheme = new KeyValuePair(SemanticConventions.AttributeHttpScheme, "http"); var statusCode = new KeyValuePair(SemanticConventions.AttributeHttpStatusCode, tc.ResponseCode == 0 ? 200 : tc.ResponseCode); var flavor = new KeyValuePair(SemanticConventions.AttributeHttpFlavor, "2.0"); + var hostName = new KeyValuePair(SemanticConventions.AttributeNetPeerName, host); + var portNumber = new KeyValuePair(SemanticConventions.AttributeNetPeerPort, port); Assert.Contains(method, attributes); Assert.Contains(scheme, attributes); Assert.Contains(statusCode, attributes); Assert.Contains(flavor, attributes); - Assert.Equal(4, attributes.Length); + Assert.Contains(hostName, attributes); + Assert.Contains(portNumber, attributes); + Assert.Equal(6, attributes.Length); #endif } else @@ -231,7 +235,8 @@ public async Task DebugIndividualTestAsync() ""spanAttributes"": { ""http.scheme"": ""http"", ""http.method"": ""GET"", - ""http.host"": ""{host}:{port}"", + ""net.peer.name"": ""{host}"", + ""net.peer.port"": ""{port}"", ""http.status_code"": ""399"", ""http.flavor"": ""{flavor}"", ""http.url"": ""http://{host}:{port}/"" diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestActivitySourceTests.netfx.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestActivitySourceTests.netfx.cs index f03709ea7ad..42eabb95b8b 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestActivitySourceTests.netfx.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestActivitySourceTests.netfx.cs @@ -39,6 +39,8 @@ public class HttpWebRequestActivitySourceTests : IDisposable private readonly string testServerHost; private readonly int testServerPort; private readonly string hostNameAndPort; + private readonly string netPeerName; + private readonly int netPeerPort; static HttpWebRequestActivitySourceTests() { @@ -74,6 +76,8 @@ public HttpWebRequestActivitySourceTests() out this.testServerPort); this.hostNameAndPort = $"{this.testServerHost}:{this.testServerPort}"; + this.netPeerName = this.testServerHost; + this.netPeerPort = this.testServerPort; void ProcessServerRequest(HttpListenerContext context) { @@ -198,7 +202,7 @@ public async Task TestBasicReceiveAndResponseEvents(string method, string queryS // Check to make sure: The first record must be a request, the next record must be a response. Activity activity = AssertFirstEventWasStart(eventRecords); - VerifyActivityStartTags(this.hostNameAndPort, method, url, activity); + VerifyActivityStartTags(this.netPeerName, this.netPeerPort, method, url, activity); Assert.True(eventRecords.Records.TryDequeue(out var stopEvent)); Assert.Equal("Stop", stopEvent.Key); @@ -378,7 +382,7 @@ public async Task TestBasicReceiveAndResponseWebRequestEvents(string method, int // Check to make sure: The first record must be a request, the next record must be a response. Activity activity = AssertFirstEventWasStart(eventRecords); - VerifyActivityStartTags(this.hostNameAndPort, method, url, activity); + VerifyActivityStartTags(this.netPeerName, this.netPeerPort, method, url, activity); Assert.True(eventRecords.Records.TryDequeue(out var stopEvent)); Assert.Equal("Stop", stopEvent.Key); @@ -484,7 +488,7 @@ public async Task TestResponseWithoutContentEvents(string method) // Check to make sure: The first record must be a request, the next record must be a response. Activity activity = AssertFirstEventWasStart(eventRecords); - VerifyActivityStartTags(this.hostNameAndPort, method, url, activity); + VerifyActivityStartTags(this.netPeerName, this.netPeerPort, method, url, activity); Assert.True(eventRecords.Records.TryDequeue(out var stopEvent)); Assert.Equal("Stop", stopEvent.Key); @@ -523,9 +527,10 @@ public async Task TestRedirectedRequest(string method) [InlineData("POST")] public async Task TestRequestWithException(string method) { + string host = Guid.NewGuid().ToString() + ".com"; string url = method == "GET" - ? $"http://{Guid.NewGuid()}.com" - : $"http://{Guid.NewGuid()}.com"; + ? $"http://{host}" + : $"http://{host}"; using var eventRecords = new ActivitySourceRecorder(); @@ -548,7 +553,7 @@ public async Task TestRequestWithException(string method) // Check to make sure: The first record must be a request, the next record must be an exception. Activity activity = AssertFirstEventWasStart(eventRecords); - VerifyActivityStartTags(null, method, url, activity); + VerifyActivityStartTags(host, null, method, url, activity); Assert.True(eventRecords.Records.TryDequeue(out KeyValuePair exceptionEvent)); Assert.Equal("Stop", exceptionEvent.Key); @@ -587,7 +592,7 @@ public async Task TestCanceledRequest(string method) Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key == "Stop")); Activity activity = AssertFirstEventWasStart(eventRecords); - VerifyActivityStartTags(this.hostNameAndPort, method, url, activity); + VerifyActivityStartTags(this.netPeerName, this.netPeerPort, method, url, activity); Assert.True(eventRecords.Records.TryDequeue(out KeyValuePair exceptionEvent)); Assert.Equal("Stop", exceptionEvent.Key); @@ -626,7 +631,7 @@ public async Task TestSecureTransportFailureRequest(string method) Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key == "Stop")); Activity activity = AssertFirstEventWasStart(eventRecords); - VerifyActivityStartTags(null, method, url, activity); + VerifyActivityStartTags("expired.badssl.com", null, method, url, activity); Assert.True(eventRecords.Records.TryDequeue(out KeyValuePair exceptionEvent)); Assert.Equal("Stop", exceptionEvent.Key); @@ -668,7 +673,7 @@ public async Task TestSecureTransportRetryFailureRequest(string method) Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key == "Stop")); Activity activity = AssertFirstEventWasStart(eventRecords); - VerifyActivityStartTags(this.hostNameAndPort, method, url, activity); + VerifyActivityStartTags(this.netPeerName, this.netPeerPort, method, url, activity); Assert.True(eventRecords.Records.TryDequeue(out KeyValuePair exceptionEvent)); Assert.Equal("Stop", exceptionEvent.Key); @@ -778,15 +783,17 @@ private static void VerifyHeaders(HttpWebRequest startRequest) Assert.Matches("^[0-9a-f]{2}-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$", traceparent); } - private static void VerifyActivityStartTags(string hostNameAndPort, string method, string url, Activity activity) + private static void VerifyActivityStartTags(string netPeerName, int? netPeerPort, string method, string url, Activity activity) { Assert.NotNull(activity.TagObjects); Assert.Equal(method, activity.GetTagValue(SemanticConventions.AttributeHttpMethod)); - if (hostNameAndPort != null) + if (netPeerPort != null) { - Assert.Equal(hostNameAndPort, activity.GetTagValue(SemanticConventions.AttributeHttpHost)); + Assert.Equal(netPeerPort, activity.GetTagValue(SemanticConventions.AttributeNetPeerPort)); } + Assert.Equal(netPeerName, activity.GetTagValue(SemanticConventions.AttributeNetPeerName)); + Assert.Equal(url, activity.GetTagValue(SemanticConventions.AttributeHttpUrl)); } diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.cs index 61f11102d7b..d447606a47e 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.cs @@ -182,7 +182,8 @@ public void DebugIndividualTest() ""spanAttributes"": { ""http.scheme"": ""http"", ""http.method"": ""GET"", - ""http.host"": ""{host}:{port}"", + ""net.peer.name"": ""{host}"", + ""net.peer.port"": ""{port}"", ""http.flavor"": ""1.1"", ""http.status_code"": ""200"", ""http.url"": ""http://{host}:{port}/"" diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/http-out-test-cases.json b/test/OpenTelemetry.Instrumentation.Http.Tests/http-out-test-cases.json index f389d393422..c9f68f4698b 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/http-out-test-cases.json +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/http-out-test-cases.json @@ -9,7 +9,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "200", "http.url": "http://{host}:{port}/" @@ -25,7 +26,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "POST", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "200", "http.url": "http://{host}:{port}/" @@ -42,7 +44,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "200", "http.url": "http://{host}:{port}/path/to/resource/" @@ -59,7 +62,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "200", "http.url": "http://{host}:{port}/path/to/resource#fragment" @@ -76,7 +80,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "200", "http.url": "http://{host}:{port}/path/to/resource#fragment" @@ -94,7 +99,7 @@ "spanAttributes": { "http.scheme": "https", "http.method": "GET", - "http.host": "sdlfaldfjalkdfjlkajdflkajlsdjf.sdlkjafsdjfalfadslkf.com", + "net.peer.name": "sdlfaldfjalkdfjlkajdflkajlsdjf.sdlkjafsdjfalfadslkf.com", "http.flavor": "{flavor}", "http.url": "https://sdlfaldfjalkdfjlkajdflkajlsdjf.sdlkjafsdjfalfadslkf.com/" } @@ -111,7 +116,7 @@ "spanAttributes": { "http.scheme": "https", "http.method": "GET", - "http.host": "sdlfaldfjalkdfjlkajdflkajlsdjf.sdlkjafsdjfalfadslkf.com", + "net.peer.name": "sdlfaldfjalkdfjlkajdflkajlsdjf.sdlkjafsdjfalfadslkf.com", "http.flavor": "{flavor}", "http.url": "https://sdlfaldfjalkdfjlkajdflkajlsdjf.sdlkjafsdjfalfadslkf.com/" } @@ -127,7 +132,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "200", "http.url": "http://{host}:{port}/" @@ -144,7 +150,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "200", "http.url": "http://{host}:{port}/" @@ -161,7 +168,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "399", "http.url": "http://{host}:{port}/" @@ -178,7 +186,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "400", "http.url": "http://{host}:{port}/" @@ -195,7 +204,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "401", "http.url": "http://{host}:{port}/" @@ -212,7 +222,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "403", "http.url": "http://{host}:{port}/" @@ -229,7 +240,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "404", "http.url": "http://{host}:{port}/" @@ -246,7 +258,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "429", "http.url": "http://{host}:{port}/" @@ -263,7 +276,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "501", "http.url": "http://{host}:{port}/" @@ -280,7 +294,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "503", "http.url": "http://{host}:{port}/" @@ -297,7 +312,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "504", "http.url": "http://{host}:{port}/" @@ -314,7 +330,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "600", "http.url": "http://{host}:{port}/" @@ -331,7 +348,8 @@ "spanAttributes": { "http.scheme": "http", "http.method": "GET", - "http.host": "{host}:{port}", + "net.peer.name": "{host}", + "net.peer.port": "{port}", "http.flavor": "{flavor}", "http.status_code": "200", "http.url": "http://{host}:{port}/" diff --git a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/OpenTelemetry.Instrumentation.SqlClient.Tests.csproj b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/OpenTelemetry.Instrumentation.SqlClient.Tests.csproj index 0b465099147..7e8ff7edac4 100644 --- a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/OpenTelemetry.Instrumentation.SqlClient.Tests.csproj +++ b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/OpenTelemetry.Instrumentation.SqlClient.Tests.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlClientTests.cs b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlClientTests.cs index 7164ba8d18e..bf054001459 100644 --- a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlClientTests.cs +++ b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlClientTests.cs @@ -15,13 +15,11 @@ // using System; -using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Linq; using Microsoft.Data.SqlClient; -using Moq; using OpenTelemetry.Instrumentation.SqlClient.Implementation; using OpenTelemetry.Tests; using OpenTelemetry.Trace; @@ -67,9 +65,7 @@ public void SqlClient_BadArgs() [Trait("CategoryName", "SqlIntegrationTests")] [SkipUnlessEnvVarFoundTheory(SqlConnectionStringEnvVarName)] [InlineData(CommandType.Text, "select 1/1", false)] -#if !NETFRAMEWORK [InlineData(CommandType.Text, "select 1/1", false, true)] -#endif [InlineData(CommandType.Text, "select 1/0", false, false, true)] [InlineData(CommandType.Text, "select 1/0", false, false, true, false, false)] [InlineData(CommandType.Text, "select 1/0", false, false, true, true, false)] @@ -84,6 +80,12 @@ public void SuccessfulCommandTest( bool recordException = false, bool shouldEnrich = true) { +#if NETFRAMEWORK + // Disable things not available on netfx + recordException = false; + shouldEnrich = false; +#endif + var sampler = new TestSampler(); var activities = new List(); using var tracerProvider = Sdk.CreateTracerProviderBuilder() @@ -94,10 +96,10 @@ public void SuccessfulCommandTest( #if !NETFRAMEWORK options.SetDbStatementForStoredProcedure = captureStoredProcedureCommandName; options.SetDbStatementForText = captureTextCommandContent; - options.RecordException = recordException; #else - options.SetDbStatement = captureStoredProcedureCommandName; + options.SetDbStatementForText = captureStoredProcedureCommandName || captureTextCommandContent; #endif + options.RecordException = recordException; if (shouldEnrich) { options.Enrich = ActivityEnrichment; @@ -105,11 +107,6 @@ public void SuccessfulCommandTest( }) .Build(); -#if NETFRAMEWORK - // RecordException not available on netfx - recordException = false; -#endif - using SqlConnection sqlConnection = new SqlConnection(SqlConnectionString); sqlConnection.Open(); diff --git a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlEventSourceTests.netfx.cs b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlEventSourceTests.netfx.cs index 0db32cfdd4e..007b42c2340 100644 --- a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlEventSourceTests.netfx.cs +++ b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlEventSourceTests.netfx.cs @@ -13,13 +13,13 @@ // See the License for the specific language governing permissions and // limitations under the License. // + #if NETFRAMEWORK using System; using System.Data; using System.Data.SqlClient; using System.Diagnostics; using System.Diagnostics.Tracing; -using System.Linq; using System.Threading.Tasks; using Moq; using OpenTelemetry.Instrumentation.SqlClient.Implementation; @@ -55,7 +55,7 @@ public async Task SuccessfulCommandTest(CommandType commandType, string commandT .AddProcessor(activityProcessor.Object) .AddSqlClientInstrumentation(options => { - options.SetDbStatement = captureText; + options.SetDbStatementForText = captureText; }) .Build(); @@ -112,7 +112,7 @@ public void EventSourceFakeTests( .AddProcessor(activityProcessor.Object) .AddSqlClientInstrumentation(options => { - options.SetDbStatement = captureText; + options.SetDbStatementForText = captureText; options.EnableConnectionLevelAttributes = enableConnectionLevelAttributes; }) .Build(); diff --git a/test/OpenTelemetry.Tests.Stress.Logs/Program.cs b/test/OpenTelemetry.Tests.Stress.Logs/Program.cs index 1239e08432c..00a51da2ab2 100644 --- a/test/OpenTelemetry.Tests.Stress.Logs/Program.cs +++ b/test/OpenTelemetry.Tests.Stress.Logs/Program.cs @@ -37,7 +37,7 @@ public static void Main() logger = loggerFactory.CreateLogger(); - Stress(prometheusPort: 9184); + Stress(prometheusPort: 9464); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs index da3215aee79..c0788e0b17e 100644 --- a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs +++ b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs @@ -50,7 +50,7 @@ public static void Main() options => options.UriPrefixes = new string[] { $"http://localhost:9185/" }) .Build(); - Stress(prometheusPort: 9184); + Stress(prometheusPort: 9464); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/test/OpenTelemetry.Tests.Stress.Metrics/README.md b/test/OpenTelemetry.Tests.Stress.Metrics/README.md index 88a7168ed79..ec8eba4c3cc 100644 --- a/test/OpenTelemetry.Tests.Stress.Metrics/README.md +++ b/test/OpenTelemetry.Tests.Stress.Metrics/README.md @@ -5,7 +5,7 @@ This stress test is specifically for Metrics SDK, and is based on the * [Running the stress test](#running-the-stress-test) -**NOTE:** To run the stress tests for Histogram, comment out the `Run` method +**Note:** To run the stress tests for Histogram, comment out the `Run` method for `Counter` and uncomment everything related to `Histogram` in the [Program.cs](../OpenTelemetry.Tests.Stress.Metrics/Program.cs). diff --git a/test/OpenTelemetry.Tests.Stress.Traces/Program.cs b/test/OpenTelemetry.Tests.Stress.Traces/Program.cs index 3449c14b124..2d4087b74cb 100644 --- a/test/OpenTelemetry.Tests.Stress.Traces/Program.cs +++ b/test/OpenTelemetry.Tests.Stress.Traces/Program.cs @@ -31,7 +31,7 @@ public static void Main() .AddSource(ActivitySource.Name) .Build(); - Stress(prometheusPort: 9184); + Stress(prometheusPort: 9464); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/test/OpenTelemetry.Tests.Stress/Meat.cs b/test/OpenTelemetry.Tests.Stress/Meat.cs index 6959c8259f1..287090db0b3 100644 --- a/test/OpenTelemetry.Tests.Stress/Meat.cs +++ b/test/OpenTelemetry.Tests.Stress/Meat.cs @@ -22,7 +22,7 @@ public partial class Program { public static void Main() { - Stress(concurrency: 1, prometheusPort: 9184); + Stress(concurrency: 1, prometheusPort: 9464); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/test/OpenTelemetry.Tests.Stress/README.md b/test/OpenTelemetry.Tests.Stress/README.md index 0013c573ad6..890b1d0cc9b 100644 --- a/test/OpenTelemetry.Tests.Stress/README.md +++ b/test/OpenTelemetry.Tests.Stress/README.md @@ -43,7 +43,7 @@ Running (concurrency = 1), press to stop... The stress test metrics are exposed via [Prometheus HttpListener](../../src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md), which can be accessed via -[http://localhost:9184/metrics/](http://localhost:9184/metrics/). +[http://localhost:9464/metrics/](http://localhost:9464/metrics/). Following shows a section of the metrics exposed in prometheus format: @@ -82,7 +82,7 @@ public partial class Program { public static void Main() { - Stress(concurrency: 10, prometheusPort: 9184); + Stress(concurrency: 10, prometheusPort: 9464); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs index 6ddd5d7caa4..c42729af674 100644 --- a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs +++ b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs @@ -15,6 +15,8 @@ // using System.Collections.Generic; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using OpenTelemetry.Exporter; using OpenTelemetry.Resources; @@ -38,6 +40,23 @@ public void DefaultCtorTests() Assert.NotNull(provider.Resource); } + [Fact] + public void ResourceDetectionUsingIConfigurationTest() + { + var services = new ServiceCollection(); + + services.AddOptions(); + + services.AddSingleton( + new ConfigurationBuilder().AddInMemoryCollection(new Dictionary { ["OTEL_SERVICE_NAME"] = "TestServiceName" }).Build()); + + using var serviceProvider = services.BuildServiceProvider(); + + using var loggerProvider = new OpenTelemetryLoggerProvider(serviceProvider); + + Assert.Contains(loggerProvider.Resource.Attributes, kvp => kvp.Key == "service.name" && (string)kvp.Value == "TestServiceName"); + } + [Fact] public void ConfigureCtorTests() { diff --git a/test/OpenTelemetry.Tests/Trace/BatchExportActivityProcessorOptionsTest.cs b/test/OpenTelemetry.Tests/Trace/BatchExportActivityProcessorOptionsTest.cs index 15ecbd6babd..e74263fe3de 100644 --- a/test/OpenTelemetry.Tests/Trace/BatchExportActivityProcessorOptionsTest.cs +++ b/test/OpenTelemetry.Tests/Trace/BatchExportActivityProcessorOptionsTest.cs @@ -62,7 +62,7 @@ public void BatchExportProcessorOptions_EnvironmentVariableOverride() } [Fact] - public void ExportActivityProcessorOptions_UsingIConfiguration() + public void BatchExportProcessorOptions_UsingIConfiguration() { var values = new Dictionary() { @@ -76,13 +76,6 @@ public void ExportActivityProcessorOptions_UsingIConfiguration() .AddInMemoryCollection(values) .Build(); - var parentOptions = new ExportActivityProcessorOptions(configuration); - - Assert.Equal(1, parentOptions.BatchExportProcessorOptions.MaxQueueSize); - Assert.Equal(2, parentOptions.BatchExportProcessorOptions.MaxExportBatchSize); - Assert.Equal(3, parentOptions.BatchExportProcessorOptions.ExporterTimeoutMilliseconds); - Assert.Equal(4, parentOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds); - var options = new BatchExportActivityProcessorOptions(configuration); Assert.Equal(1, options.MaxQueueSize); diff --git a/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs b/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs index 6c94a0da77c..f7b5149c1d6 100644 --- a/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs +++ b/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs @@ -293,114 +293,6 @@ public void SetAndConfigureResourceTest() Assert.Contains(provider.Resource.Attributes, kvp => kvp.Key == "key2" && (string)kvp.Value == "value2"); } - [Fact] - public void AddExporterTest() - { - var builder = Sdk.CreateTracerProviderBuilder(); - - builder.AddExporter(ExportProcessorType.Simple, new MyExporter()); - builder.AddExporter(ExportProcessorType.Batch); - - using var provider = builder.Build() as TracerProviderSdk; - - Assert.NotNull(provider); - - var processor = provider.Processor as CompositeProcessor; - - Assert.NotNull(processor); - - var firstProcessor = processor.Head.Value; - var secondProcessor = processor.Head.Next?.Value; - - Assert.True(firstProcessor is SimpleActivityExportProcessor simpleProcessor && simpleProcessor.Exporter is MyExporter); - Assert.True(secondProcessor is BatchActivityExportProcessor batchProcessor && batchProcessor.Exporter is MyExporter); - } - - [Fact] - public void AddExporterWithOptionsTest() - { - int optionsInvocations = 0; - - var builder = Sdk.CreateTracerProviderBuilder(); - - builder.ConfigureServices(services => - { - services.Configure(options => - { - // Note: This is testing options integration - - optionsInvocations++; - - options.BatchExportProcessorOptions.MaxExportBatchSize = 18; - }); - }); - - builder.AddExporter( - ExportProcessorType.Simple, - new MyExporter(), - options => - { - // Note: Options delegate isn't invoked for simple processor type - Assert.True(false); - }); - builder.AddExporter( - ExportProcessorType.Batch, - options => - { - optionsInvocations++; - - Assert.Equal(18, options.BatchExportProcessorOptions.MaxExportBatchSize); - - options.BatchExportProcessorOptions.MaxExportBatchSize = 100; - }); - - using var provider = builder.Build() as TracerProviderSdk; - - Assert.NotNull(provider); - - Assert.Equal(2, optionsInvocations); - - var processor = provider.Processor as CompositeProcessor; - - Assert.NotNull(processor); - - var firstProcessor = processor.Head.Value; - var secondProcessor = processor.Head.Next?.Value; - - Assert.True(firstProcessor is SimpleActivityExportProcessor simpleProcessor && simpleProcessor.Exporter is MyExporter); - Assert.True(secondProcessor is BatchActivityExportProcessor batchProcessor - && batchProcessor.Exporter is MyExporter - && batchProcessor.MaxExportBatchSize == 100); - } - - [Fact] - public void AddExporterNamedOptionsTest() - { - var builder = Sdk.CreateTracerProviderBuilder(); - - int defaultOptionsConfigureInvocations = 0; - int namedOptionsConfigureInvocations = 0; - - builder.ConfigureServices(services => - { - services.Configure(o => defaultOptionsConfigureInvocations++); - - services.Configure("Exporter2", o => namedOptionsConfigureInvocations++); - }); - - builder.AddExporter(ExportProcessorType.Batch, new MyExporter()); - builder.AddExporter(ExportProcessorType.Batch, new MyExporter(), name: "Exporter2", configure: null); - builder.AddExporter(ExportProcessorType.Batch); - builder.AddExporter(ExportProcessorType.Batch, name: "Exporter2", configure: null); - - using var provider = builder.Build() as TracerProviderSdk; - - Assert.NotNull(provider); - - Assert.Equal(1, defaultOptionsConfigureInvocations); - Assert.Equal(1, namedOptionsConfigureInvocations); - } - [Fact] public void ConfigureBuilderIConfigurationAvailableTest() {