From d3b7aa8936fbfac13daa1ff7875ab5f786024e15 Mon Sep 17 00:00:00 2001 From: aasulyan Date: Sun, 24 May 2026 18:36:59 +0400 Subject: [PATCH 01/20] MinVer and Microsoft.SourceLink.GitHub are always restored as build-only dependencies. MinVerSkip is enabled for local AllowPackWithoutGit=true smoke packs. local non-git pack fallback still produces 1.0.0, not 0.0.0-alpha.0. --- src/OpenTelemetry/OpenTelemetry.csproj | 7 ++++--- src/OpenTelemetry/packages.lock.json | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry/OpenTelemetry.csproj b/src/OpenTelemetry/OpenTelemetry.csproj index 2799f1c..93b1d66 100644 --- a/src/OpenTelemetry/OpenTelemetry.csproj +++ b/src/OpenTelemetry/OpenTelemetry.csproj @@ -8,8 +8,9 @@ v alpha.0 + true - 1.0.0 + 1.0.0 $(NoWarn);NU5104 @@ -22,8 +23,8 @@ - - + + diff --git a/src/OpenTelemetry/packages.lock.json b/src/OpenTelemetry/packages.lock.json index 94ed890..7cfd29e 100644 --- a/src/OpenTelemetry/packages.lock.json +++ b/src/OpenTelemetry/packages.lock.json @@ -64,6 +64,22 @@ "Microsoft.Extensions.Primitives": "10.0.8" } }, + "Microsoft.SourceLink.GitHub": { + "type": "Direct", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "8.0.0", + "Microsoft.SourceLink.Common": "8.0.0" + } + }, + "MinVer": { + "type": "Direct", + "requested": "[6.0.0, )", + "resolved": "6.0.0", + "contentHash": "+/SsmiySsXJlvQLCGBqaZKNVt3s/Y/HbAdwtop7Km2CnuZbaScoqkWJEBQ5Cy9ebkn6kCYKrHsXgwrFdTgcb3g==" + }, "OpenTelemetry": { "type": "Direct", "requested": "[1.15.3, )", @@ -184,6 +200,11 @@ "Microsoft.Extensions.Options": "10.0.8" } }, + "Microsoft.Build.Tasks.Git": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" + }, "Microsoft.Extensions.Configuration": { "type": "Transitive", "resolved": "10.0.8", @@ -215,6 +236,11 @@ "resolved": "10.0.8", "contentHash": "OBPo4nYhMyIbtueoC10CBm6AGAbo/A9IV8QQ/6ryZS7VvmqpGT7hunazeHLxFawRzn3oLOq4jhqhpBX4tfswWQ==" }, + "Microsoft.SourceLink.Common": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" + }, "OpenTelemetry.Api": { "type": "Transitive", "resolved": "1.15.3", From 261c7eb9aef498e57fca1158901da898ac199641 Mon Sep 17 00:00:00 2001 From: Arsen Asulyan Date: Sun, 24 May 2026 18:54:37 +0400 Subject: [PATCH 02/20] Fix coverage report input format (#9) --- .github/workflows/ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37d8181..1d67f7f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,9 +96,7 @@ jobs: if: matrix.os == 'ubuntu-latest' uses: danielpalme/ReportGenerator-GitHub-Action@5.5.0 with: - reports: | - artifacts/test-results/**/coverage.cobertura.xml - artifacts/coverage/coverage.cobertura.xml + reports: artifacts/test-results/**/coverage.cobertura.xml;artifacts/coverage/coverage.cobertura.xml targetdir: artifacts/coverage-report reporttypes: HtmlInline;MarkdownSummaryGithub;Cobertura From 780084e21b2f8649de93a483268344360014f890 Mon Sep 17 00:00:00 2001 From: Arsen Asulyan Date: Sun, 24 May 2026 19:08:40 +0400 Subject: [PATCH 03/20] Fix coverage report input format (#10) From 6a2df4b7b33286b6581089b326aa82322fdad1e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 May 2026 19:09:26 +0400 Subject: [PATCH 04/20] chore(actions)(deps): bump softprops/action-gh-release from 2 to 3 (#5) Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/publish-nuget.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml index 5951a88..4e82473 100644 --- a/.github/workflows/publish-nuget.yml +++ b/.github/workflows/publish-nuget.yml @@ -246,7 +246,7 @@ jobs: git push origin "v$env:PACKAGE_VERSION" - name: Create GitHub Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 with: tag_name: v${{ steps.version.outputs.version }} name: v${{ steps.version.outputs.version }} From c68768f1675714301ef2f5215a532fda28d384fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 May 2026 19:09:58 +0400 Subject: [PATCH 05/20] chore(actions)(deps): bump actions/setup-dotnet from 4 to 5 (#4) Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4 to 5. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/publish-nuget.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d67f7f..17c131a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: global-json-file: global.json diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml index 4e82473..cee596e 100644 --- a/.github/workflows/publish-nuget.yml +++ b/.github/workflows/publish-nuget.yml @@ -111,7 +111,7 @@ jobs: Write-Host "Package version: $version" - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: global-json-file: global.json From 8510491497395d533996e717f485f5f96fe27de6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 May 2026 19:10:11 +0400 Subject: [PATCH 06/20] chore(actions)(deps): bump actions/checkout from 4 to 6 (#3) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/publish-nuget.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 17c131a..c971b6f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml index cee596e..74df0d8 100644 --- a/.github/workflows/publish-nuget.yml +++ b/.github/workflows/publish-nuget.yml @@ -37,7 +37,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 From 330cce74937497849d8a0742a50a4be4cec89031 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 May 2026 19:10:25 +0400 Subject: [PATCH 07/20] chore(actions)(deps): bump danielpalme/ReportGenerator-GitHub-Action (#2) Bumps [danielpalme/ReportGenerator-GitHub-Action](https://github.com/danielpalme/reportgenerator-github-action) from 5.5.0 to 5.5.10. - [Release notes](https://github.com/danielpalme/reportgenerator-github-action/releases) - [Commits](https://github.com/danielpalme/reportgenerator-github-action/compare/5.5.0...5.5.10) --- updated-dependencies: - dependency-name: danielpalme/ReportGenerator-GitHub-Action dependency-version: 5.5.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c971b6f..ed3849d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,7 +94,7 @@ jobs: - name: Generate coverage report if: matrix.os == 'ubuntu-latest' - uses: danielpalme/ReportGenerator-GitHub-Action@5.5.0 + uses: danielpalme/ReportGenerator-GitHub-Action@5.5.10 with: reports: artifacts/test-results/**/coverage.cobertura.xml;artifacts/coverage/coverage.cobertura.xml targetdir: artifacts/coverage-report From 0567efab980d0b8add292e02fc498da81c5b9986 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 May 2026 19:10:37 +0400 Subject: [PATCH 08/20] chore(actions)(deps): bump actions/attest-build-provenance from 2 to 4 (#1) Bumps [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) from 2 to 4. - [Release notes](https://github.com/actions/attest-build-provenance/releases) - [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md) - [Commits](https://github.com/actions/attest-build-provenance/compare/v2...v4) --- updated-dependencies: - dependency-name: actions/attest-build-provenance dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/publish-nuget.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml index 74df0d8..90a28e2 100644 --- a/.github/workflows/publish-nuget.yml +++ b/.github/workflows/publish-nuget.yml @@ -211,7 +211,7 @@ jobs: if-no-files-found: error - name: Attest package artifacts - uses: actions/attest-build-provenance@v2 + uses: actions/attest-build-provenance@v4 with: subject-path: | artifacts/packages/*.nupkg From 565edc40ee65ec993b6b87916cf05584bdfbd2aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 May 2026 19:15:46 +0400 Subject: [PATCH 09/20] chore(deps): Bump MinVer from 6.0.0 to 7.0.0 (#7) --- updated-dependencies: - dependency-name: MinVer dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Arsen Asulyan --- Directory.Packages.props | 108 +++++++++++++-------------- src/OpenTelemetry/packages.lock.json | 6 +- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index a7e6c74..36663a4 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,54 +1,54 @@ - - - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/OpenTelemetry/packages.lock.json b/src/OpenTelemetry/packages.lock.json index 7cfd29e..4647b8f 100644 --- a/src/OpenTelemetry/packages.lock.json +++ b/src/OpenTelemetry/packages.lock.json @@ -76,9 +76,9 @@ }, "MinVer": { "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+/SsmiySsXJlvQLCGBqaZKNVt3s/Y/HbAdwtop7Km2CnuZbaScoqkWJEBQ5Cy9ebkn6kCYKrHsXgwrFdTgcb3g==" + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "2lMTCQl5bGP4iv0JNkockPnyllC6eHLz+CoK2ICvalvHod+exXSxueu9hq+zNkU7bZBJf8wMfeRC/Edn8AGmEg==" }, "OpenTelemetry": { "type": "Direct", From f767d434a3e89bb5ea2aee298fe3fd3323971cb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 May 2026 19:21:00 +0400 Subject: [PATCH 10/20] chore(deps): Bump Microsoft.SourceLink.GitHub from 8.0.0 to 10.0.300 (#6) --- updated-dependencies: - dependency-name: Microsoft.SourceLink.GitHub dependency-version: 10.0.300 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Arsen Asulyan --- src/OpenTelemetry/packages.lock.json | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/OpenTelemetry/packages.lock.json b/src/OpenTelemetry/packages.lock.json index 4647b8f..8e7da1d 100644 --- a/src/OpenTelemetry/packages.lock.json +++ b/src/OpenTelemetry/packages.lock.json @@ -66,12 +66,13 @@ }, "Microsoft.SourceLink.GitHub": { "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==", + "requested": "[10.0.300, )", + "resolved": "10.0.300", + "contentHash": "QzCtLkXVb3l4IxcpvJCbzUwMLihAmLN6vVLjQGSzYSF8d2dvXxqJAZk83RV3gYnp2egz8jRMgSR2woY3vOahTA==", "dependencies": { - "Microsoft.Build.Tasks.Git": "8.0.0", - "Microsoft.SourceLink.Common": "8.0.0" + "Microsoft.Build.Tasks.Git": "10.0.300", + "Microsoft.SourceLink.Common": "10.0.300", + "System.IO.Hashing": "10.0.8" } }, "MinVer": { @@ -202,8 +203,11 @@ }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" + "resolved": "10.0.300", + "contentHash": "P0kaQwVZx4xIUe2FtrLyBadYNXuAljttJUPvjBYRuHhPE8L77L42KakLDkaADRiUrGspoLcMwayjrbQhYTr0zA==", + "dependencies": { + "System.IO.Hashing": "10.0.8" + } }, "Microsoft.Extensions.Configuration": { "type": "Transitive", @@ -238,8 +242,8 @@ }, "Microsoft.SourceLink.Common": { "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" + "resolved": "10.0.300", + "contentHash": "0jlkXaUGjYlWTIVPve5MftjKHnT3SlAtq9BCLV4J9IjdPrxV/+4rMlBSjfr1khG8/GC6KGojjola8E1VvWF0qQ==" }, "OpenTelemetry.Api": { "type": "Transitive", @@ -255,6 +259,11 @@ "OpenTelemetry.Api": "1.15.3" } }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "+dJsbPJ3FyUbTZNplFj0RCKePFizmv6ewDV46JE9q/IVH4c3xTCftHfHelLsAKf0jryIPqgMb5GpS0x7TAY3mg==" + }, "Microsoft.Extensions.DependencyInjection": { "type": "CentralTransitive", "requested": "[10.0.8, )", From dd596f4a451d28a4cb4dcbebeb96e35d57f76b12 Mon Sep 17 00:00:00 2001 From: Arsen Asulyan Date: Sun, 24 May 2026 19:24:56 +0400 Subject: [PATCH 11/20] Fix coverage report input format (#12) From 766e047319846a6219c494f619d8e495331004ff Mon Sep 17 00:00:00 2001 From: Arsen Asulyan Date: Sun, 24 May 2026 21:26:49 +0400 Subject: [PATCH 12/20] Fix SourceLink lock file version mismatch (#13) --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 36663a4..07aab63 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,7 +5,7 @@ - + From bd63ea5661015ee82748fc73c504fdfa4fa085ed Mon Sep 17 00:00:00 2001 From: Arsen Asulyan Date: Sun, 24 May 2026 22:06:16 +0400 Subject: [PATCH 13/20] Development (#11) (#14) * MinVer and Microsoft.SourceLink.GitHub are always restored as build-only dependencies. MinVerSkip is enabled for local AllowPackWithoutGit=true smoke packs. local non-git pack fallback still produces 1.0.0, not 0.0.0-alpha.0. * Fix coverage report input format (#9) * Fix coverage report input format (#10) * chore(actions)(deps): bump softprops/action-gh-release from 2 to 3 (#5) Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... * chore(actions)(deps): bump actions/setup-dotnet from 4 to 5 (#4) Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4 to 5. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... * chore(actions)(deps): bump actions/checkout from 4 to 6 (#3) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... * chore(actions)(deps): bump danielpalme/ReportGenerator-GitHub-Action (#2) Bumps [danielpalme/ReportGenerator-GitHub-Action](https://github.com/danielpalme/reportgenerator-github-action) from 5.5.0 to 5.5.10. - [Release notes](https://github.com/danielpalme/reportgenerator-github-action/releases) - [Commits](https://github.com/danielpalme/reportgenerator-github-action/compare/5.5.0...5.5.10) --- updated-dependencies: - dependency-name: danielpalme/ReportGenerator-GitHub-Action dependency-version: 5.5.10 dependency-type: direct:production update-type: version-update:semver-patch ... * chore(actions)(deps): bump actions/attest-build-provenance from 2 to 4 (#1) Bumps [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) from 2 to 4. - [Release notes](https://github.com/actions/attest-build-provenance/releases) - [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md) - [Commits](https://github.com/actions/attest-build-provenance/compare/v2...v4) --- updated-dependencies: - dependency-name: actions/attest-build-provenance dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... * chore(deps): Bump MinVer from 6.0.0 to 7.0.0 (#7) --- updated-dependencies: - dependency-name: MinVer dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... * chore(deps): Bump Microsoft.SourceLink.GitHub from 8.0.0 to 10.0.300 (#6) --- updated-dependencies: - dependency-name: Microsoft.SourceLink.GitHub dependency-version: 10.0.300 dependency-type: direct:production update-type: version-update:semver-major ... * Fix coverage report input format (#12) * Fix SourceLink lock file version mismatch (#13) --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 2a1b19ccb06482b493251e8f489651e7a26a5636 Mon Sep 17 00:00:00 2001 From: Arsen Asulyan Date: Sun, 24 May 2026 22:11:59 +0400 Subject: [PATCH 14/20] Tmp (#15) * Fix coverage report input format * tmp --- Directory.Packages.props | 108 +++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 07aab63..f99fb08 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,54 +1,54 @@ - - - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From db5eedfda03397ca641002166fd8dfa71ca9c7a3 Mon Sep 17 00:00:00 2001 From: Arsen Asulyan Date: Sun, 24 May 2026 23:55:38 +0400 Subject: [PATCH 15/20] Use OtlpExportProtocol for OTLP options (#16) * Development (#11) * MinVer and Microsoft.SourceLink.GitHub are always restored as build-only dependencies. MinVerSkip is enabled for local AllowPackWithoutGit=true smoke packs. local non-git pack fallback still produces 1.0.0, not 0.0.0-alpha.0. * Fix coverage report input format (#9) * Fix coverage report input format (#10) * chore(actions)(deps): bump softprops/action-gh-release from 2 to 3 (#5) Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(actions)(deps): bump actions/setup-dotnet from 4 to 5 (#4) Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4 to 5. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(actions)(deps): bump actions/checkout from 4 to 6 (#3) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(actions)(deps): bump danielpalme/ReportGenerator-GitHub-Action (#2) Bumps [danielpalme/ReportGenerator-GitHub-Action](https://github.com/danielpalme/reportgenerator-github-action) from 5.5.0 to 5.5.10. - [Release notes](https://github.com/danielpalme/reportgenerator-github-action/releases) - [Commits](https://github.com/danielpalme/reportgenerator-github-action/compare/5.5.0...5.5.10) --- updated-dependencies: - dependency-name: danielpalme/ReportGenerator-GitHub-Action dependency-version: 5.5.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(actions)(deps): bump actions/attest-build-provenance from 2 to 4 (#1) Bumps [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) from 2 to 4. - [Release notes](https://github.com/actions/attest-build-provenance/releases) - [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md) - [Commits](https://github.com/actions/attest-build-provenance/compare/v2...v4) --- updated-dependencies: - dependency-name: actions/attest-build-provenance dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): Bump MinVer from 6.0.0 to 7.0.0 (#7) --- updated-dependencies: - dependency-name: MinVer dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Arsen Asulyan * chore(deps): Bump Microsoft.SourceLink.GitHub from 8.0.0 to 10.0.300 (#6) --- updated-dependencies: - dependency-name: Microsoft.SourceLink.GitHub dependency-version: 10.0.300 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Arsen Asulyan * Fix coverage report input format (#12) * Fix SourceLink lock file version mismatch (#13) --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Use OtlpExportProtocol for OTLP options --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- CHANGELOG.md | 2 +- Directory.Packages.props | 112 +++++++++--------- .../OpenTelemetry.Benchmarks/Program.cs | 3 +- .../Internal/OpenTelemetryOptionsValidator.cs | 6 +- .../Internal/OtlpExporterConfigurator.cs | 41 ++----- src/OpenTelemetry/Options/OtlpOptions.cs | 6 +- src/OpenTelemetry/PublicAPI.Shipped.txt | 2 +- src/OpenTelemetry/PublicAPI.Unshipped.txt | 1 + src/OpenTelemetry/README.md | 7 +- ...lemetryServiceCollectionExtensionsTests.cs | 9 +- .../Internal/OpenTelemetryInternalTests.cs | 36 ++---- 11 files changed, 100 insertions(+), 125 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7b1bdf..56b462c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ This project follows semantic versioning. Release tags use `vMAJOR.MINOR.PATCH`. ## [Unreleased] -No unreleased changes. +- Changed `OtlpOptions.Protocol` from a string to the nullable OpenTelemetry `OtlpExportProtocol` enum. ## [1.0.0] - 2026-05-24 diff --git a/Directory.Packages.props b/Directory.Packages.props index f99fb08..8ee9859 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,54 +1,58 @@ - - - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/benchmarks/OpenTelemetry.Benchmarks/Program.cs b/benchmarks/OpenTelemetry.Benchmarks/Program.cs index 073c0f7..046896f 100644 --- a/benchmarks/OpenTelemetry.Benchmarks/Program.cs +++ b/benchmarks/OpenTelemetry.Benchmarks/Program.cs @@ -4,6 +4,7 @@ using BenchmarkDotNet.Order; using BenchmarkDotNet.Running; using Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Exporter; namespace OpenTelemetry.Benchmarks; @@ -88,7 +89,7 @@ private static void ConfigureFull(OpenTelemetryOptions options) options.Instrumentations.Runtime.Enabled = true; options.Exporters.Otlp.Enabled = true; options.Exporters.Otlp.Endpoint = "http://localhost:4317"; - options.Exporters.Otlp.Protocol = "grpc"; + options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc; options.Exporters.Otlp.Headers["x-benchmark"] = "opentelemetry"; } } diff --git a/src/OpenTelemetry/Internal/OpenTelemetryOptionsValidator.cs b/src/OpenTelemetry/Internal/OpenTelemetryOptionsValidator.cs index 470b1e5..5f9907f 100644 --- a/src/OpenTelemetry/Internal/OpenTelemetryOptionsValidator.cs +++ b/src/OpenTelemetry/Internal/OpenTelemetryOptionsValidator.cs @@ -4,6 +4,7 @@ using Atya.Diagnostics.OpenTelemetry.Options; using Atya.Foundation.Guards; using Microsoft.Extensions.Options; +using OpenTelemetry.Exporter; namespace Atya.Diagnostics.OpenTelemetry.Internal; @@ -43,10 +44,11 @@ public ValidateOptionsResult Validate(string? name, OpenTelemetryOptions options $"OpenTelemetryOptions.Exporters.Otlp.Endpoint '{options.Exporters.Otlp.Endpoint}' is not a valid absolute URI."); } - if (!OtlpExporterConfigurator.IsSupportedProtocol(options.Exporters.Otlp.Protocol)) + if (options.Exporters.Otlp.Protocol is { } protocol && + !Enum.IsDefined(typeof(OtlpExportProtocol), protocol)) { return ValidateOptionsResult.Fail( - "OpenTelemetryOptions.Exporters.Otlp.Protocol must be either 'grpc' or 'http/protobuf'."); + "OpenTelemetryOptions.Exporters.Otlp.Protocol must be a defined OtlpExportProtocol value."); } foreach (var header in options.Exporters.Otlp.Headers) diff --git a/src/OpenTelemetry/Internal/OtlpExporterConfigurator.cs b/src/OpenTelemetry/Internal/OtlpExporterConfigurator.cs index e802017..4ebce3b 100644 --- a/src/OpenTelemetry/Internal/OtlpExporterConfigurator.cs +++ b/src/OpenTelemetry/Internal/OtlpExporterConfigurator.cs @@ -23,9 +23,17 @@ public static void Apply(OtlpExporterOptions otlp, OtlpOptions options) otlp.Endpoint = new Uri(options.Endpoint); } - if (!string.IsNullOrWhiteSpace(options.Protocol)) + if (options.Protocol is { } protocol) { - otlp.Protocol = ParseProtocol(options.Protocol); + if (!Enum.IsDefined(typeof(OtlpExportProtocol), protocol)) + { + throw new ArgumentOutOfRangeException( + nameof(options), + protocol, + "OTLP protocol must be a defined OtlpExportProtocol value."); + } + + otlp.Protocol = protocol; } if (options.Headers.Count > 0) @@ -34,33 +42,4 @@ public static void Apply(OtlpExporterOptions otlp, OtlpOptions options) } } - public static bool IsSupportedProtocol(string? protocol) - { - if (string.IsNullOrWhiteSpace(protocol)) - { - return true; - } - - return protocol.Equals("grpc", StringComparison.OrdinalIgnoreCase) || - protocol.Equals("http/protobuf", StringComparison.OrdinalIgnoreCase); - } - - private static OtlpExportProtocol ParseProtocol(string protocol) - { - var normalizedProtocol = Guard.AgainstNullOrWhiteSpace(protocol).Trim(); - - if (normalizedProtocol.Equals("grpc", StringComparison.OrdinalIgnoreCase)) - { - return OtlpExportProtocol.Grpc; - } - - if (normalizedProtocol.Equals("http/protobuf", StringComparison.OrdinalIgnoreCase)) - { - return OtlpExportProtocol.HttpProtobuf; - } - - throw new ArgumentException( - "OTLP protocol must be either 'grpc' or 'http/protobuf'.", - nameof(protocol)); - } } diff --git a/src/OpenTelemetry/Options/OtlpOptions.cs b/src/OpenTelemetry/Options/OtlpOptions.cs index 5e0ab3f..2e757f8 100644 --- a/src/OpenTelemetry/Options/OtlpOptions.cs +++ b/src/OpenTelemetry/Options/OtlpOptions.cs @@ -1,6 +1,8 @@ // // Copyright (c) Atya. All rights reserved. // +using OpenTelemetry.Exporter; + namespace Atya.Diagnostics.OpenTelemetry.Options; /// @@ -20,10 +22,10 @@ public sealed class OtlpOptions public string? Endpoint { get; set; } /// - /// Gets or sets the OTLP transport protocol. Supported values: "grpc", "http/protobuf". + /// Gets or sets the OTLP transport protocol. /// When null, the OpenTelemetry SDK default is used. /// - public string? Protocol { get; set; } + public OtlpExportProtocol? Protocol { get; set; } /// /// Gets additional headers to include in OTLP export requests. diff --git a/src/OpenTelemetry/PublicAPI.Shipped.txt b/src/OpenTelemetry/PublicAPI.Shipped.txt index af2bfe2..96eec18 100644 --- a/src/OpenTelemetry/PublicAPI.Shipped.txt +++ b/src/OpenTelemetry/PublicAPI.Shipped.txt @@ -58,7 +58,7 @@ Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Endpoint.get -> string? Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Endpoint.set -> void Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Headers.get -> System.Collections.Generic.IDictionary! Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.OtlpOptions() -> void -Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Protocol.get -> string? +*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Protocol.get -> string? Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Protocol.set -> void static Microsoft.Extensions.DependencyInjection.OpenTelemetryServiceCollectionExtensions.AddAtyaOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, Microsoft.Extensions.Configuration.IConfiguration! configuration, string! sectionName = "OpenTelemetry") -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.OpenTelemetryServiceCollectionExtensions.AddAtyaOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action? configure = null) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! diff --git a/src/OpenTelemetry/PublicAPI.Unshipped.txt b/src/OpenTelemetry/PublicAPI.Unshipped.txt index 7dc5c58..5b19d31 100644 --- a/src/OpenTelemetry/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/PublicAPI.Unshipped.txt @@ -1 +1,2 @@ #nullable enable +Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Protocol.get -> OpenTelemetry.Exporter.OtlpExportProtocol? diff --git a/src/OpenTelemetry/README.md b/src/OpenTelemetry/README.md index aa7202f..2dbdc48 100644 --- a/src/OpenTelemetry/README.md +++ b/src/OpenTelemetry/README.md @@ -16,6 +16,7 @@ dotnet add package Atya.Diagnostics.OpenTelemetry ```csharp using Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Exporter; services.AddAtyaOpenTelemetry(options => { @@ -38,7 +39,7 @@ services.AddAtyaOpenTelemetry(options => options.Exporters.Otlp.Enabled = true; options.Exporters.Otlp.Endpoint = "http://otel-collector:4317"; - options.Exporters.Otlp.Protocol = "grpc"; + options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc; }); ``` @@ -81,7 +82,7 @@ Bind from the default `OpenTelemetry` configuration section: "Otlp": { "Enabled": true, "Endpoint": "http://otel-collector:4317", - "Protocol": "grpc", + "Protocol": "Grpc", "Headers": { "x-service": "orders" } @@ -124,7 +125,7 @@ Options are validated through `Microsoft.Extensions.Options`. Invalid options fa - `ServiceName` cannot be null, empty, or whitespace. - `ActivitySources` and `Meters` cannot contain null, empty, or whitespace names. - OTLP `Endpoint`, when set, must be an absolute URI. -- OTLP `Protocol`, when set, must be `grpc` or `http/protobuf`. +- OTLP `Protocol`, when set, must be a defined `OtlpExportProtocol` value such as `Grpc` or `HttpProtobuf`. - OTLP header names cannot be empty and cannot contain `,` or `=`. - OTLP header values cannot be null and cannot contain `,`. diff --git a/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs b/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs index 0d51081..775352d 100644 --- a/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs +++ b/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using OpenTelemetry.Exporter; namespace OpenTelemetry.UnitTests.DependencyInjection; @@ -195,7 +196,7 @@ public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetryOptions() options.Meters.Add("Orders.Business"); options.Exporters.Otlp.Enabled = true; options.Exporters.Otlp.Endpoint = "http://localhost:4317"; - options.Exporters.Otlp.Protocol = "grpc"; + options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc; options.Exporters.Otlp.Headers["authorization"] = "Bearer token"; options.Instrumentations.AspNetCore.Enabled = true; options.Instrumentations.HttpClient.Enabled = true; @@ -218,7 +219,7 @@ public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetryOptions() _ = resolvedOptions.Meters.Should().ContainSingle("Orders.Business"); _ = resolvedOptions.Exporters.Otlp.Enabled.Should().BeTrue(); _ = resolvedOptions.Exporters.Otlp.Endpoint.Should().Be("http://localhost:4317"); - _ = resolvedOptions.Exporters.Otlp.Protocol.Should().Be("grpc"); + _ = resolvedOptions.Exporters.Otlp.Protocol.Should().Be(OtlpExportProtocol.Grpc); _ = resolvedOptions.Exporters.Otlp.Headers.Should().ContainKey("authorization"); _ = resolvedOptions.Instrumentations.AspNetCore.Enabled.Should().BeTrue(); _ = resolvedOptions.Instrumentations.HttpClient.Enabled.Should().BeTrue(); @@ -249,7 +250,7 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_ ["OpenTelemetry:Instrumentations:GrpcClient:Enabled"] = "true", ["OpenTelemetry:Exporters:Otlp:Enabled"] = "true", ["OpenTelemetry:Exporters:Otlp:Endpoint"] = "http://collector:4317", - ["OpenTelemetry:Exporters:Otlp:Protocol"] = "http/protobuf", + ["OpenTelemetry:Exporters:Otlp:Protocol"] = "HttpProtobuf", ["OpenTelemetry:Exporters:Otlp:Headers:tenant"] = "billing", }) .Build(); @@ -273,7 +274,7 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_ _ = resolvedOptions.Instrumentations.GrpcClient.Enabled.Should().BeTrue(); _ = resolvedOptions.Exporters.Otlp.Enabled.Should().BeTrue(); _ = resolvedOptions.Exporters.Otlp.Endpoint.Should().Be("http://collector:4317"); - _ = resolvedOptions.Exporters.Otlp.Protocol.Should().Be("http/protobuf"); + _ = resolvedOptions.Exporters.Otlp.Protocol.Should().Be(OtlpExportProtocol.HttpProtobuf); _ = resolvedOptions.Exporters.Otlp.Headers.Should().Contain("tenant", "billing"); } diff --git a/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs b/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs index 238c0c9..b8b0e07 100644 --- a/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs +++ b/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs @@ -24,7 +24,7 @@ public void OtlpExporterConfigurator_Should_Apply_Endpoint_Grpc_And_Headers() var options = new OtlpOptions { Endpoint = "http://localhost:4317", - Protocol = "grpc", + Protocol = OtlpExportProtocol.Grpc, }; options.Headers["authorization"] = "Bearer token"; options.Headers["tenant"] = "orders"; @@ -42,7 +42,7 @@ public void OtlpExporterConfigurator_Should_Apply_HttpProtobuf_Protocol() var otlp = new OtlpExporterOptions(); var options = new OtlpOptions { - Protocol = " http/protobuf ", + Protocol = OtlpExportProtocol.HttpProtobuf, }; OtlpExporterConfigurator.Apply(otlp, options); @@ -66,34 +66,18 @@ public void OtlpExporterConfigurator_Should_Leave_Defaults_When_Optional_Values_ } [Fact] - public void OtlpExporterConfigurator_Should_Throw_For_Invalid_Protocol() + public void OtlpExporterConfigurator_Should_Throw_For_Undefined_Protocol() { var otlp = new OtlpExporterOptions(); var options = new OtlpOptions { - Protocol = "json", + Protocol = (OtlpExportProtocol)42, }; var act = () => OtlpExporterConfigurator.Apply(otlp, options); - _ = act.Should().Throw() - .WithParameterName("protocol"); - } - - [Theory] - [InlineData(null, true)] - [InlineData("", true)] - [InlineData(" ", true)] - [InlineData("grpc", true)] - [InlineData("GRPC", true)] - [InlineData("http/protobuf", true)] - [InlineData("HTTP/PROTOBUF", true)] - [InlineData("http/json", false)] - public void OtlpExporterConfigurator_Should_Report_Supported_Protocols(string? protocol, bool expected) - { - var supported = OtlpExporterConfigurator.IsSupportedProtocol(protocol); - - _ = supported.Should().Be(expected); + _ = act.Should().Throw() + .WithParameterName("options"); } [Fact] @@ -114,7 +98,7 @@ public void OpenTelemetryOptionsValidator_Should_Return_Success_For_Valid_Option var options = CreateValidOptions(); options.Exporters.Otlp.Enabled = true; options.Exporters.Otlp.Endpoint = "http://localhost:4317"; - options.Exporters.Otlp.Protocol = "grpc"; + options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc; options.Exporters.Otlp.Headers["authorization"] = "Bearer token"; var result = new OpenTelemetryOptionsValidator().Validate(null, options); @@ -127,7 +111,7 @@ public void OpenTelemetryOptionsValidator_Should_Ignore_Disabled_Otlp_Details() { var options = CreateValidOptions(); options.Exporters.Otlp.Endpoint = "not a uri"; - options.Exporters.Otlp.Protocol = "json"; + options.Exporters.Otlp.Protocol = (OtlpExportProtocol)42; options.Exporters.Otlp.Headers["bad,key"] = "bad,value"; var result = new OpenTelemetryOptionsValidator().Validate(null, options); @@ -190,7 +174,7 @@ public void OpenTelemetryOptionsValidator_Should_Fail_When_Enabled_Otlp_Protocol { var options = CreateValidOptions(); options.Exporters.Otlp.Enabled = true; - options.Exporters.Otlp.Protocol = "json"; + options.Exporters.Otlp.Protocol = (OtlpExportProtocol)42; var result = new OpenTelemetryOptionsValidator().Validate(null, options); @@ -507,7 +491,7 @@ private static OpenTelemetryOptions CreateFullOptions() options.Instrumentations.Runtime.Enabled = true; options.Exporters.Otlp.Enabled = true; options.Exporters.Otlp.Endpoint = "http://localhost:4317"; - options.Exporters.Otlp.Protocol = "grpc"; + options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc; return options; } } From 8a367e7c6a2b4806d6ec3a60a02f1d7baeee59b3 Mon Sep 17 00:00:00 2001 From: Arsen Asulyan Date: Mon, 25 May 2026 00:32:13 +0400 Subject: [PATCH 16/20] Add console exporter configuration (#17) --- CHANGELOG.md | 1 + Directory.Packages.props | 1 + .../OpenTelemetry.Benchmarks/Program.cs | 1 + .../packages.lock.json | 10 ++ .../OpenTelemetry.Samples.Console.csproj | 1 + .../OpenTelemetry.Samples.Console/Program.cs | 47 ++++-- .../packages.lock.json | 156 ++++++++++++++++++ .../Metrics/MeterProviderBuilderExtensions.cs | 5 + src/OpenTelemetry/OpenTelemetry.csproj | 1 + src/OpenTelemetry/Options/ConsoleOptions.cs | 15 ++ .../Options/OpenTelemetryExporterOptions.cs | 5 + src/OpenTelemetry/PublicAPI.Unshipped.txt | 5 + src/OpenTelemetry/README.md | 7 +- .../TracerProviderBuilderExtensions.cs | 5 + src/OpenTelemetry/packages.lock.json | 9 + ...lemetryServiceCollectionExtensionsTests.cs | 5 + .../Internal/OpenTelemetryInternalTests.cs | 1 + .../packages.lock.json | 10 ++ 18 files changed, 267 insertions(+), 18 deletions(-) create mode 100644 src/OpenTelemetry/Options/ConsoleOptions.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 56b462c..cf82aa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project follows semantic versioning. Release tags use `vMAJOR.MINOR.PATCH`. ## [Unreleased] - Changed `OtlpOptions.Protocol` from a string to the nullable OpenTelemetry `OtlpExportProtocol` enum. +- Added opt-in console exporter configuration for local tracing and metrics debugging. ## [1.0.0] - 2026-05-24 diff --git a/Directory.Packages.props b/Directory.Packages.props index 8ee9859..05b7b3e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -46,6 +46,7 @@ + diff --git a/benchmarks/OpenTelemetry.Benchmarks/Program.cs b/benchmarks/OpenTelemetry.Benchmarks/Program.cs index 046896f..92d06b9 100644 --- a/benchmarks/OpenTelemetry.Benchmarks/Program.cs +++ b/benchmarks/OpenTelemetry.Benchmarks/Program.cs @@ -87,6 +87,7 @@ private static void ConfigureFull(OpenTelemetryOptions options) options.Instrumentations.AspNetCore.Enabled = true; options.Instrumentations.HttpClient.Enabled = true; options.Instrumentations.Runtime.Enabled = true; + options.Exporters.Console.Enabled = true; options.Exporters.Otlp.Enabled = true; options.Exporters.Otlp.Endpoint = "http://localhost:4317"; options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc; diff --git a/benchmarks/OpenTelemetry.Benchmarks/packages.lock.json b/benchmarks/OpenTelemetry.Benchmarks/packages.lock.json index d27a0f2..3f35464 100644 --- a/benchmarks/OpenTelemetry.Benchmarks/packages.lock.json +++ b/benchmarks/OpenTelemetry.Benchmarks/packages.lock.json @@ -217,6 +217,7 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "[10.0.8, )", "Microsoft.Extensions.Options": "[10.0.8, )", "OpenTelemetry": "[1.15.3, )", + "OpenTelemetry.Exporter.Console": "[1.15.3, )", "OpenTelemetry.Exporter.OpenTelemetryProtocol": "[1.15.3, )", "OpenTelemetry.Extensions.Hosting": "[1.15.3, )", "OpenTelemetry.Instrumentation.AspNetCore": "[1.15.2, )", @@ -366,6 +367,15 @@ "OpenTelemetry.Api.ProviderBuilderExtensions": "1.15.3" } }, + "OpenTelemetry.Exporter.Console": { + "type": "CentralTransitive", + "requested": "[1.15.3, )", + "resolved": "1.15.3", + "contentHash": "QBGOoPwLHDXX+hXeUpspOjsqEn4vMkLw672QN+MzVWFBzjf625DdxLxhzowS1J/dRtW93U34rRbJec+4808fkg==", + "dependencies": { + "OpenTelemetry": "1.15.3" + } + }, "OpenTelemetry.Exporter.OpenTelemetryProtocol": { "type": "CentralTransitive", "requested": "[1.15.3, )", diff --git a/samples/OpenTelemetry.Samples.Console/OpenTelemetry.Samples.Console.csproj b/samples/OpenTelemetry.Samples.Console/OpenTelemetry.Samples.Console.csproj index bf54fc6..3abf333 100644 --- a/samples/OpenTelemetry.Samples.Console/OpenTelemetry.Samples.Console.csproj +++ b/samples/OpenTelemetry.Samples.Console/OpenTelemetry.Samples.Console.csproj @@ -13,6 +13,7 @@ + diff --git a/samples/OpenTelemetry.Samples.Console/Program.cs b/samples/OpenTelemetry.Samples.Console/Program.cs index d4c81f1..c451f43 100644 --- a/samples/OpenTelemetry.Samples.Console/Program.cs +++ b/samples/OpenTelemetry.Samples.Console/Program.cs @@ -3,6 +3,7 @@ using Atya.Diagnostics.Tracing.Abstractions; using Atya.Diagnostics.Tracing.Extensions; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; // ------------------------------------------------------------------------ @@ -10,18 +11,19 @@ // // Demonstrates the full OpenTelemetry telemetry pipeline: // - Resource metadata configuration -// - Tracing + Metrics pipelines with OTLP export +// - Tracing + Metrics pipelines with console and OTLP export // - ASP.NET Core / HttpClient / Runtime instrumentations // - Using generic Tracing + Metrics building blocks inside the pipeline // ------------------------------------------------------------------------ -var services = new ServiceCollection(); +var builder = Host.CreateApplicationBuilder(args); // Register console logging so we can see log output. -services.AddLogging(logging => logging.AddConsole()); +_ = builder.Logging.ClearProviders(); +_ = builder.Logging.AddConsole(); // Register the full telemetry pipeline. -services.AddAtyaOpenTelemetry(options => +_ = builder.Services.AddAtyaOpenTelemetry(options => { // Service identity (required). options.ServiceName = "Samples.OrderProcessor"; @@ -42,27 +44,38 @@ options.Instrumentations.AspNetCore.Enabled = true; options.Instrumentations.Runtime.Enabled = true; - // OTLP exporter (point to your collector). - options.Exporters.Otlp.Enabled = true; + // Console exporter is handy while developing locally. + options.Exporters.Console.Enabled = true; + + // OTLP exporter (enable when a collector is available). + options.Exporters.Otlp.Enabled = false; options.Exporters.Otlp.Endpoint = "http://localhost:4317"; }); -using var provider = services.BuildServiceProvider(); +using var host = builder.Build(); +await host.StartAsync(); -// Resolve the generic building blocks that OpenTelemetry registered for us. -var logger = provider.GetRequiredService>(); -var activitySourceAccessor = provider.GetRequiredService(); -var meterAccessor = provider.GetRequiredService(); +try +{ + // Resolve the generic building blocks that OpenTelemetry registered for us. + var logger = host.Services.GetRequiredService>(); + var activitySourceAccessor = host.Services.GetRequiredService(); + var meterAccessor = host.Services.GetRequiredService(); -var processor = new OrderProcessor(logger, activitySourceAccessor, meterAccessor); + var processor = new OrderProcessor(logger, activitySourceAccessor, meterAccessor); -// Simulate processing some orders. -processor.ProcessOrder("ORD-001", "tenant-acme"); -processor.ProcessOrder("ORD-002", "tenant-globex"); + // Simulate processing some orders. + processor.ProcessOrder("ORD-001", "tenant-acme"); + processor.ProcessOrder("ORD-002", "tenant-globex"); +} +finally +{ + await host.StopAsync(); +} Console.WriteLine(); -Console.WriteLine("Sample completed. In a real setup with OTLP enabled,"); -Console.WriteLine("traces and metrics would be exported to your collector."); +Console.WriteLine("Sample completed. Console exporter output is written while the host stops."); +Console.WriteLine("With OTLP enabled, traces and metrics are also exported to your collector."); // ------------------------------------------------------------------------ // Sample service that uses all three diagnostics building blocks. diff --git a/samples/OpenTelemetry.Samples.Console/packages.lock.json b/samples/OpenTelemetry.Samples.Console/packages.lock.json index 72d5baf..b091977 100644 --- a/samples/OpenTelemetry.Samples.Console/packages.lock.json +++ b/samples/OpenTelemetry.Samples.Console/packages.lock.json @@ -11,6 +11,36 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8" } }, + "Microsoft.Extensions.Hosting": { + "type": "Direct", + "requested": "[10.0.8, )", + "resolved": "10.0.8", + "contentHash": "VfEyM2BipThcSd0GG/FS2ZPCVCTiosVq2zLKEDsfeMIg78sOVZPEmS7CgWlb+dqTlgXvLSL4OG2q6sM4xRhHNg==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", + "Microsoft.Extensions.Configuration.Binder": "10.0.8", + "Microsoft.Extensions.Configuration.CommandLine": "10.0.8", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "10.0.8", + "Microsoft.Extensions.Configuration.FileExtensions": "10.0.8", + "Microsoft.Extensions.Configuration.Json": "10.0.8", + "Microsoft.Extensions.Configuration.UserSecrets": "10.0.8", + "Microsoft.Extensions.DependencyInjection": "10.0.8", + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", + "Microsoft.Extensions.Diagnostics": "10.0.8", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8", + "Microsoft.Extensions.FileProviders.Physical": "10.0.8", + "Microsoft.Extensions.Hosting.Abstractions": "10.0.8", + "Microsoft.Extensions.Logging": "10.0.8", + "Microsoft.Extensions.Logging.Abstractions": "10.0.8", + "Microsoft.Extensions.Logging.Configuration": "10.0.8", + "Microsoft.Extensions.Logging.Console": "10.0.8", + "Microsoft.Extensions.Logging.Debug": "10.0.8", + "Microsoft.Extensions.Logging.EventLog": "10.0.8", + "Microsoft.Extensions.Logging.EventSource": "10.0.8", + "Microsoft.Extensions.Options": "10.0.8" + } + }, "Microsoft.Extensions.Logging.Console": { "type": "Direct", "requested": "[10.0.8, )", @@ -63,6 +93,83 @@ "Microsoft.Extensions.Primitives": "10.0.8" } }, + "Microsoft.Extensions.Configuration.CommandLine": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "nQXq1a4MiInYh+0VF9fguxAl06q2ftmOyYQ+5e933s4rk57xjgkbTjUdFUySzjrcrvDeWsSqlZB+TE8+TbM2HA==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8" + } + }, + "Microsoft.Extensions.Configuration.EnvironmentVariables": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "bVGqctAfPGfTxJvNp8pMshtvpsUj6r6JkeiCNVIGVYO5gBxuxdN0Lbr25kEvE/zXdctkEc44g8HssnPgDnFGVA==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8" + } + }, + "Microsoft.Extensions.Configuration.FileExtensions": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "1g9mzuu8gIHkjYb0jLxOTQVl/QDG5nn0b0JzgT/gbgNKr6gXZzxOHRAsdYRc1eDApB7LdHR8uK5vQrNjIQdRrQ==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8", + "Microsoft.Extensions.FileProviders.Physical": "10.0.8", + "Microsoft.Extensions.Primitives": "10.0.8" + } + }, + "Microsoft.Extensions.Configuration.Json": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "KLtAZ6A38s1pIfCO2ns6aG14NNGMYNZ4PBYfFK4M+R4A+xuSc6oklhqDcpHZxvDpyBWeFtR5C8iQBw2ng8tUHQ==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", + "Microsoft.Extensions.Configuration.FileExtensions": "10.0.8", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8" + } + }, + "Microsoft.Extensions.Configuration.UserSecrets": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "6XTfFOnf27WY8kEeZkTZ4YNn0t+imgvdQ0YaAdR4vgURKATo9bCaVJ1KB71IOJAQtJP7Elb53VHlTNXg2CtSsA==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", + "Microsoft.Extensions.Configuration.Json": "10.0.8", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8", + "Microsoft.Extensions.FileProviders.Physical": "10.0.8" + } + }, + "Microsoft.Extensions.Diagnostics": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "uduyw9d3Fi+sbredO5drA1S44AQS2FRNFyn72UmB2vmQIO1qaXprpp1U/2lYhYi8yFdVERfY9sy/pxw/qPOU9w==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Diagnostics.Abstractions": "10.0.8", + "Microsoft.Extensions.Options.ConfigurationExtensions": "10.0.8" + } + }, + "Microsoft.Extensions.FileProviders.Physical": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "GkPvQe6IdidLu6Q3Lw6+B8NJpW8feW8czZ5mBKt5rXM/x8MvZfEp5WvAsjznzDGd23chIDrW0b2mmt+ScnEgiw==", + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8", + "Microsoft.Extensions.FileSystemGlobbing": "10.0.8", + "Microsoft.Extensions.Primitives": "10.0.8" + } + }, + "Microsoft.Extensions.FileSystemGlobbing": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "IUQet3SY51xIFcFZKtAB6a54/Zdxs7T3SQ84kJtOD6yeXfZgiOMksACWD5qtTmXGQGFH4QYGBOT0KIO8Uy/dJw==" + }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", "resolved": "10.0.8", @@ -71,6 +178,40 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8" } }, + "Microsoft.Extensions.Logging.Debug": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "4HW3M1lGHHDwEYcDZHRNptBQ48LCI2yW+XV4vuxdfQUqafTpVT8j9RqAsez08krZKhIiaArWu8iQq5uRKZ9Ffg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", + "Microsoft.Extensions.Logging": "10.0.8", + "Microsoft.Extensions.Logging.Abstractions": "10.0.8" + } + }, + "Microsoft.Extensions.Logging.EventLog": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "kK/C3SLIoGrcZvddYQw4eMm6YaROiSYBO7YgUR5Hdv5l+GIjBmbvQK5cST2FqjeubiAOPqFEimBT2N/8wVI+3A==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", + "Microsoft.Extensions.Logging": "10.0.8", + "Microsoft.Extensions.Logging.Abstractions": "10.0.8", + "Microsoft.Extensions.Options": "10.0.8", + "System.Diagnostics.EventLog": "10.0.8" + } + }, + "Microsoft.Extensions.Logging.EventSource": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "HX2M0MgzwQM8jpLe3AYAEMd0YsUfOP5RgGrDuk+Ki9n7HSuMbvLm9TEV3qRI3Pg9aqxc56GfgK/KdMRBhfWwKw==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", + "Microsoft.Extensions.Logging": "10.0.8", + "Microsoft.Extensions.Logging.Abstractions": "10.0.8", + "Microsoft.Extensions.Options": "10.0.8", + "Microsoft.Extensions.Primitives": "10.0.8" + } + }, "Microsoft.Extensions.Options.DataAnnotations": { "type": "Transitive", "resolved": "10.0.8", @@ -99,6 +240,11 @@ "OpenTelemetry.Api": "1.15.3" } }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "+Ro7WgIom+BDNH+YhTuZKL6QJ0ctfOpTyfUG/h3aU5KwXt3OaNf0wYWrTvoBUj+34Dy5V8dN9yCco1hAJQ4txw==" + }, "Atya.Diagnostics.OpenTelemetry": { "type": "Project", "dependencies": { @@ -109,6 +255,7 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "[10.0.8, )", "Microsoft.Extensions.Options": "[10.0.8, )", "OpenTelemetry": "[1.15.3, )", + "OpenTelemetry.Exporter.Console": "[1.15.3, )", "OpenTelemetry.Exporter.OpenTelemetryProtocol": "[1.15.3, )", "OpenTelemetry.Extensions.Hosting": "[1.15.3, )", "OpenTelemetry.Instrumentation.AspNetCore": "[1.15.2, )", @@ -258,6 +405,15 @@ "OpenTelemetry.Api.ProviderBuilderExtensions": "1.15.3" } }, + "OpenTelemetry.Exporter.Console": { + "type": "CentralTransitive", + "requested": "[1.15.3, )", + "resolved": "1.15.3", + "contentHash": "QBGOoPwLHDXX+hXeUpspOjsqEn4vMkLw672QN+MzVWFBzjf625DdxLxhzowS1J/dRtW93U34rRbJec+4808fkg==", + "dependencies": { + "OpenTelemetry": "1.15.3" + } + }, "OpenTelemetry.Exporter.OpenTelemetryProtocol": { "type": "CentralTransitive", "requested": "[1.15.3, )", diff --git a/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs index 7b68638..4570ba8 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs @@ -74,6 +74,11 @@ private static MeterProviderBuilder AddConfiguredExporters( this MeterProviderBuilder builder, OpenTelemetryExporterOptions exporters) { + if (exporters.Console.Enabled) + { + _ = builder.AddConsoleExporter(); + } + if (exporters.Otlp.Enabled) { _ = builder.AddOtlpExporter(otlp => OtlpExporterConfigurator.Apply(otlp, exporters.Otlp)); diff --git a/src/OpenTelemetry/OpenTelemetry.csproj b/src/OpenTelemetry/OpenTelemetry.csproj index 93b1d66..f1fa356 100644 --- a/src/OpenTelemetry/OpenTelemetry.csproj +++ b/src/OpenTelemetry/OpenTelemetry.csproj @@ -35,6 +35,7 @@ + diff --git a/src/OpenTelemetry/Options/ConsoleOptions.cs b/src/OpenTelemetry/Options/ConsoleOptions.cs new file mode 100644 index 0000000..36236e4 --- /dev/null +++ b/src/OpenTelemetry/Options/ConsoleOptions.cs @@ -0,0 +1,15 @@ +// +// Copyright (c) Atya. All rights reserved. +// +namespace Atya.Diagnostics.OpenTelemetry.Options; + +/// +/// Options for configuring the console exporter. +/// +public sealed class ConsoleOptions +{ + /// + /// Gets or sets a value indicating whether the console exporter is enabled. Default is false. + /// + public bool Enabled { get; set; } +} diff --git a/src/OpenTelemetry/Options/OpenTelemetryExporterOptions.cs b/src/OpenTelemetry/Options/OpenTelemetryExporterOptions.cs index 4bd0d4b..4b0c8db 100644 --- a/src/OpenTelemetry/Options/OpenTelemetryExporterOptions.cs +++ b/src/OpenTelemetry/Options/OpenTelemetryExporterOptions.cs @@ -8,6 +8,11 @@ namespace Atya.Diagnostics.OpenTelemetry.Options; /// public sealed class OpenTelemetryExporterOptions { + /// + /// Gets console exporter configuration. + /// + public ConsoleOptions Console { get; } = new(); + /// /// Gets OTLP exporter configuration. /// diff --git a/src/OpenTelemetry/PublicAPI.Unshipped.txt b/src/OpenTelemetry/PublicAPI.Unshipped.txt index 5b19d31..c040684 100644 --- a/src/OpenTelemetry/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/PublicAPI.Unshipped.txt @@ -1,2 +1,7 @@ #nullable enable +Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions +Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions.ConsoleOptions() -> void +Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions.Enabled.get -> bool +Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions.Enabled.set -> void +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryExporterOptions.Console.get -> Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions! Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Protocol.get -> OpenTelemetry.Exporter.OtlpExportProtocol? diff --git a/src/OpenTelemetry/README.md b/src/OpenTelemetry/README.md index 2dbdc48..7887f9d 100644 --- a/src/OpenTelemetry/README.md +++ b/src/OpenTelemetry/README.md @@ -37,6 +37,7 @@ services.AddAtyaOpenTelemetry(options => options.Instrumentations.GrpcClient.Enabled = true; options.Instrumentations.Runtime.Enabled = true; + options.Exporters.Console.Enabled = true; options.Exporters.Otlp.Enabled = true; options.Exporters.Otlp.Endpoint = "http://otel-collector:4317"; options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc; @@ -79,6 +80,9 @@ Bind from the default `OpenTelemetry` configuration section: "Runtime": { "Enabled": true } }, "Exporters": { + "Console": { + "Enabled": true + }, "Otlp": { "Enabled": true, "Endpoint": "http://otel-collector:4317", @@ -113,7 +117,7 @@ services.AddAtyaOpenTelemetry(configuration, "Diagnostics:OpenTelemetry"); - Configure the package through the delegate or configuration section passed to `AddAtyaOpenTelemetry`; later `services.Configure(...)` calls do not rebuild the OpenTelemetry tracing or metrics providers. - Tracing and metrics are enabled by default. - Observation-layer logging is disabled by default. -- ASP.NET Core, HttpClient, Runtime, and OTLP exporter registrations are opt-in. +- ASP.NET Core, HttpClient, Runtime, console exporter, and OTLP exporter registrations are opt-in. - SqlClient, Entity Framework Core, and gRPC client instrumentations are opt-in. - SQL command text capture is disabled by default because command text can contain sensitive data. - The package composes `Atya.Diagnostics.Observation`; it does not define business metrics, activity names, or log catalogs. @@ -153,6 +157,7 @@ Leave SQL text capture disabled unless queries are known not to contain secrets | Exporter | Toggle | Configuration | | -------- | ------ | ------------- | +| Console | `Exporters.Console.Enabled` | `Enabled` | | OTLP | `Exporters.Otlp.Enabled` | `Endpoint`, `Protocol`, `Headers` | ## Package Boundaries diff --git a/src/OpenTelemetry/Tracing/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry/Tracing/TracerProviderBuilderExtensions.cs index 309cf7c..4462cde 100644 --- a/src/OpenTelemetry/Tracing/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry/Tracing/TracerProviderBuilderExtensions.cs @@ -92,6 +92,11 @@ private static TracerProviderBuilder AddConfiguredExporters( this TracerProviderBuilder builder, OpenTelemetryExporterOptions exporters) { + if (exporters.Console.Enabled) + { + _ = builder.AddConsoleExporter(); + } + if (exporters.Otlp.Enabled) { _ = builder.AddOtlpExporter(otlp => OtlpExporterConfigurator.Apply(otlp, exporters.Otlp)); diff --git a/src/OpenTelemetry/packages.lock.json b/src/OpenTelemetry/packages.lock.json index 8e7da1d..5f91665 100644 --- a/src/OpenTelemetry/packages.lock.json +++ b/src/OpenTelemetry/packages.lock.json @@ -92,6 +92,15 @@ "OpenTelemetry.Api.ProviderBuilderExtensions": "1.15.3" } }, + "OpenTelemetry.Exporter.Console": { + "type": "Direct", + "requested": "[1.15.3, )", + "resolved": "1.15.3", + "contentHash": "QBGOoPwLHDXX+hXeUpspOjsqEn4vMkLw672QN+MzVWFBzjf625DdxLxhzowS1J/dRtW93U34rRbJec+4808fkg==", + "dependencies": { + "OpenTelemetry": "1.15.3" + } + }, "OpenTelemetry.Exporter.OpenTelemetryProtocol": { "type": "Direct", "requested": "[1.15.3, )", diff --git a/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs b/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs index 775352d..a2e1690 100644 --- a/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs +++ b/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs @@ -194,6 +194,7 @@ public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetryOptions() options.EnableObservationLogging = true; options.ActivitySources.Add("Orders.Workflows"); options.Meters.Add("Orders.Business"); + options.Exporters.Console.Enabled = true; options.Exporters.Otlp.Enabled = true; options.Exporters.Otlp.Endpoint = "http://localhost:4317"; options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc; @@ -217,6 +218,7 @@ public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetryOptions() _ = resolvedOptions.EnableObservationLogging.Should().BeTrue(); _ = resolvedOptions.ActivitySources.Should().ContainSingle("Orders.Workflows"); _ = resolvedOptions.Meters.Should().ContainSingle("Orders.Business"); + _ = resolvedOptions.Exporters.Console.Enabled.Should().BeTrue(); _ = resolvedOptions.Exporters.Otlp.Enabled.Should().BeTrue(); _ = resolvedOptions.Exporters.Otlp.Endpoint.Should().Be("http://localhost:4317"); _ = resolvedOptions.Exporters.Otlp.Protocol.Should().Be(OtlpExportProtocol.Grpc); @@ -248,6 +250,7 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_ ["OpenTelemetry:Instrumentations:EntityFrameworkCore:Enabled"] = "true", ["OpenTelemetry:Instrumentations:EntityFrameworkCore:CaptureSqlText"] = "true", ["OpenTelemetry:Instrumentations:GrpcClient:Enabled"] = "true", + ["OpenTelemetry:Exporters:Console:Enabled"] = "true", ["OpenTelemetry:Exporters:Otlp:Enabled"] = "true", ["OpenTelemetry:Exporters:Otlp:Endpoint"] = "http://collector:4317", ["OpenTelemetry:Exporters:Otlp:Protocol"] = "HttpProtobuf", @@ -272,6 +275,7 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_ _ = resolvedOptions.Instrumentations.EntityFrameworkCore.Enabled.Should().BeTrue(); _ = resolvedOptions.Instrumentations.EntityFrameworkCore.CaptureSqlText.Should().BeTrue(); _ = resolvedOptions.Instrumentations.GrpcClient.Enabled.Should().BeTrue(); + _ = resolvedOptions.Exporters.Console.Enabled.Should().BeTrue(); _ = resolvedOptions.Exporters.Otlp.Enabled.Should().BeTrue(); _ = resolvedOptions.Exporters.Otlp.Endpoint.Should().Be("http://collector:4317"); _ = resolvedOptions.Exporters.Otlp.Protocol.Should().Be(OtlpExportProtocol.HttpProtobuf); @@ -323,6 +327,7 @@ public void OpenTelemetryOptions_Defaults_Should_Be_Production_Safe() _ = options.Instrumentations.EntityFrameworkCore.CaptureSqlText.Should().BeFalse(); _ = options.Instrumentations.GrpcClient.Enabled.Should().BeFalse(); _ = options.Instrumentations.Runtime.Enabled.Should().BeFalse(); + _ = options.Exporters.Console.Enabled.Should().BeFalse(); _ = options.Exporters.Otlp.Enabled.Should().BeFalse(); _ = options.Exporters.Otlp.Endpoint.Should().BeNull(); _ = options.Exporters.Otlp.Protocol.Should().BeNull(); diff --git a/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs b/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs index b8b0e07..de15e9e 100644 --- a/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs +++ b/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs @@ -489,6 +489,7 @@ private static OpenTelemetryOptions CreateFullOptions() options.Instrumentations.EntityFrameworkCore.CaptureSqlText = true; options.Instrumentations.GrpcClient.Enabled = true; options.Instrumentations.Runtime.Enabled = true; + options.Exporters.Console.Enabled = true; options.Exporters.Otlp.Enabled = true; options.Exporters.Otlp.Endpoint = "http://localhost:4317"; options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc; diff --git a/tests/OpenTelemetry.UnitTests/packages.lock.json b/tests/OpenTelemetry.UnitTests/packages.lock.json index 9949df7..6ca47b1 100644 --- a/tests/OpenTelemetry.UnitTests/packages.lock.json +++ b/tests/OpenTelemetry.UnitTests/packages.lock.json @@ -373,6 +373,7 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "[10.0.8, )", "Microsoft.Extensions.Options": "[10.0.8, )", "OpenTelemetry": "[1.15.3, )", + "OpenTelemetry.Exporter.Console": "[1.15.3, )", "OpenTelemetry.Exporter.OpenTelemetryProtocol": "[1.15.3, )", "OpenTelemetry.Extensions.Hosting": "[1.15.3, )", "OpenTelemetry.Instrumentation.AspNetCore": "[1.15.2, )", @@ -540,6 +541,15 @@ "OpenTelemetry.Api.ProviderBuilderExtensions": "1.15.3" } }, + "OpenTelemetry.Exporter.Console": { + "type": "CentralTransitive", + "requested": "[1.15.3, )", + "resolved": "1.15.3", + "contentHash": "QBGOoPwLHDXX+hXeUpspOjsqEn4vMkLw672QN+MzVWFBzjf625DdxLxhzowS1J/dRtW93U34rRbJec+4808fkg==", + "dependencies": { + "OpenTelemetry": "1.15.3" + } + }, "OpenTelemetry.Exporter.OpenTelemetryProtocol": { "type": "CentralTransitive", "requested": "[1.15.3, )", From bf44a9fbbb9429378c20cf35a3002d7f44eab114 Mon Sep 17 00:00:00 2001 From: Arsen Asulyan Date: Mon, 25 May 2026 22:58:43 +0400 Subject: [PATCH 17/20] Add OpenTelemetry logging pipeline (#18) --- CHANGELOG.md | 3 +- .../OpenTelemetry.Samples.Console/Program.cs | 7 +- ...penTelemetryServiceCollectionExtensions.cs | 8 +++ .../Internal/OtlpExporterConfigurator.cs | 2 +- .../LoggerProviderBuilderExtensions.cs | 54 ++++++++++++++ .../OpenTelemetryLoggerOptionsExtensions.cs | 32 +++++++++ .../Options/OpenTelemetryLoggingOptions.cs | 28 ++++++++ .../Options/OpenTelemetryOptions.cs | 10 +++ src/OpenTelemetry/PublicAPI.Unshipped.txt | 11 +++ src/OpenTelemetry/README.md | 15 +++- ...lemetryServiceCollectionExtensionsTests.cs | 43 ++++++++++- .../OpenTelemetryHostIntegrationTests.cs | 4 ++ .../Internal/OpenTelemetryInternalTests.cs | 72 +++++++++++++++++++ 13 files changed, 278 insertions(+), 11 deletions(-) create mode 100644 src/OpenTelemetry/Logging/LoggerProviderBuilderExtensions.cs create mode 100644 src/OpenTelemetry/Logging/OpenTelemetryLoggerOptionsExtensions.cs create mode 100644 src/OpenTelemetry/Options/OpenTelemetryLoggingOptions.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index cf82aa2..434c6fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ This project follows semantic versioning. Release tags use `vMAJOR.MINOR.PATCH`. ## [Unreleased] - Changed `OtlpOptions.Protocol` from a string to the nullable OpenTelemetry `OtlpExportProtocol` enum. -- Added opt-in console exporter configuration for local tracing and metrics debugging. +- Added opt-in console exporter configuration for local logging, tracing, and metrics debugging. +- Added opt-in OpenTelemetry logging pipeline registration with OTLP log export support. ## [1.0.0] - 2026-05-24 diff --git a/samples/OpenTelemetry.Samples.Console/Program.cs b/samples/OpenTelemetry.Samples.Console/Program.cs index c451f43..6fbc3ae 100644 --- a/samples/OpenTelemetry.Samples.Console/Program.cs +++ b/samples/OpenTelemetry.Samples.Console/Program.cs @@ -11,9 +11,9 @@ // // Demonstrates the full OpenTelemetry telemetry pipeline: // - Resource metadata configuration -// - Tracing + Metrics pipelines with console and OTLP export +// - Logging + Tracing + Metrics pipelines with console and OTLP export // - ASP.NET Core / HttpClient / Runtime instrumentations -// - Using generic Tracing + Metrics building blocks inside the pipeline +// - Using generic Logging + Tracing + Metrics building blocks inside the pipeline // ------------------------------------------------------------------------ var builder = Host.CreateApplicationBuilder(args); @@ -30,6 +30,7 @@ options.ServiceVersion = "1.0.0"; // Pipeline toggles. + options.EnableLogging = true; options.EnableTracing = true; options.EnableMetrics = true; options.EnableObservationLogging = true; @@ -75,7 +76,7 @@ Console.WriteLine(); Console.WriteLine("Sample completed. Console exporter output is written while the host stops."); -Console.WriteLine("With OTLP enabled, traces and metrics are also exported to your collector."); +Console.WriteLine("logs, traces, and metrics would be exported to your collector."); // ------------------------------------------------------------------------ // Sample service that uses all three diagnostics building blocks. diff --git a/src/OpenTelemetry/DependencyInjection/OpenTelemetryServiceCollectionExtensions.cs b/src/OpenTelemetry/DependencyInjection/OpenTelemetryServiceCollectionExtensions.cs index e8b4928..5f32026 100644 --- a/src/OpenTelemetry/DependencyInjection/OpenTelemetryServiceCollectionExtensions.cs +++ b/src/OpenTelemetry/DependencyInjection/OpenTelemetryServiceCollectionExtensions.cs @@ -2,6 +2,7 @@ // Copyright (c) Atya. All rights reserved. // using Atya.Diagnostics.OpenTelemetry.Internal; +using Atya.Diagnostics.OpenTelemetry.Logging; using Atya.Diagnostics.OpenTelemetry.Metrics; using Atya.Diagnostics.OpenTelemetry.Options; using Atya.Diagnostics.OpenTelemetry.Tracing; @@ -72,6 +73,13 @@ public static IServiceCollection AddAtyaOpenTelemetry( // Delegate pipeline configuration to folder-based configurators. var otelBuilder = services.AddOpenTelemetry(); + if (bootstrapOptions.EnableLogging) + { + _ = otelBuilder.WithLogging( + logging => logging.ConfigureAtyaLogging(bootstrapOptions, resourceBuilder), + loggingOptions => loggingOptions.ConfigureAtyaLogging(bootstrapOptions.Logging)); + } + if (bootstrapOptions.EnableTracing) { _ = otelBuilder.WithTracing(tracing => diff --git a/src/OpenTelemetry/Internal/OtlpExporterConfigurator.cs b/src/OpenTelemetry/Internal/OtlpExporterConfigurator.cs index 4ebce3b..40d3281 100644 --- a/src/OpenTelemetry/Internal/OtlpExporterConfigurator.cs +++ b/src/OpenTelemetry/Internal/OtlpExporterConfigurator.cs @@ -9,7 +9,7 @@ namespace Atya.Diagnostics.OpenTelemetry.Internal; /// /// Applies configuration to the underlying OpenTelemetry . -/// Shared between tracing and metrics pipelines. +/// Shared between logging, tracing, and metrics pipelines. /// internal static class OtlpExporterConfigurator { diff --git a/src/OpenTelemetry/Logging/LoggerProviderBuilderExtensions.cs b/src/OpenTelemetry/Logging/LoggerProviderBuilderExtensions.cs new file mode 100644 index 0000000..c780a7d --- /dev/null +++ b/src/OpenTelemetry/Logging/LoggerProviderBuilderExtensions.cs @@ -0,0 +1,54 @@ +// +// Copyright (c) Atya. All rights reserved. +// +using Atya.Diagnostics.OpenTelemetry.Internal; +using Atya.Diagnostics.OpenTelemetry.Options; +using Atya.Foundation.Guards; +using OpenTelemetry.Logs; +using OpenTelemetry.Resources; + +namespace Atya.Diagnostics.OpenTelemetry.Logging; + +/// +/// Provides fluent extension methods for configuring the Atya +/// OpenTelemetry logging pipeline on a . +/// +internal static class LoggerProviderBuilderExtensions +{ + /// + /// Configures the logging pipeline with the Atya telemetry + /// resource and exporters. + /// + /// The same instance. + public static LoggerProviderBuilder ConfigureAtyaLogging( + this LoggerProviderBuilder builder, + OpenTelemetryOptions options, + ResourceBuilder resourceBuilder) + { + _ = Guard.AgainstNull(builder); + _ = Guard.AgainstNull(options); + _ = Guard.AgainstNull(resourceBuilder); + + _ = builder.SetResourceBuilder(resourceBuilder); + _ = builder.AddConfiguredExporters(options.Exporters); + + return builder; + } + + private static LoggerProviderBuilder AddConfiguredExporters( + this LoggerProviderBuilder builder, + OpenTelemetryExporterOptions exporters) + { + if (exporters.Console.Enabled) + { + _ = builder.AddConsoleExporter(); + } + + if (exporters.Otlp.Enabled) + { + _ = builder.AddOtlpExporter(otlp => OtlpExporterConfigurator.Apply(otlp, exporters.Otlp)); + } + + return builder; + } +} diff --git a/src/OpenTelemetry/Logging/OpenTelemetryLoggerOptionsExtensions.cs b/src/OpenTelemetry/Logging/OpenTelemetryLoggerOptionsExtensions.cs new file mode 100644 index 0000000..8234da7 --- /dev/null +++ b/src/OpenTelemetry/Logging/OpenTelemetryLoggerOptionsExtensions.cs @@ -0,0 +1,32 @@ +// +// Copyright (c) Atya. All rights reserved. +// +using Atya.Diagnostics.OpenTelemetry.Options; +using Atya.Foundation.Guards; +using OpenTelemetry.Logs; + +namespace Atya.Diagnostics.OpenTelemetry.Logging; + +/// +/// Provides fluent extension methods for configuring OpenTelemetry logger options. +/// +internal static class OpenTelemetryLoggerOptionsExtensions +{ + /// + /// Applies Atya log record options to the OpenTelemetry logging provider. + /// + /// The same instance. + public static OpenTelemetryLoggerOptions ConfigureAtyaLogging( + this OpenTelemetryLoggerOptions loggerOptions, + OpenTelemetryLoggingOptions options) + { + _ = Guard.AgainstNull(loggerOptions); + _ = Guard.AgainstNull(options); + + loggerOptions.IncludeFormattedMessage = options.IncludeFormattedMessage; + loggerOptions.IncludeScopes = options.IncludeScopes; + loggerOptions.ParseStateValues = options.ParseStateValues; + + return loggerOptions; + } +} diff --git a/src/OpenTelemetry/Options/OpenTelemetryLoggingOptions.cs b/src/OpenTelemetry/Options/OpenTelemetryLoggingOptions.cs new file mode 100644 index 0000000..d83007a --- /dev/null +++ b/src/OpenTelemetry/Options/OpenTelemetryLoggingOptions.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) Atya. All rights reserved. +// +namespace Atya.Diagnostics.OpenTelemetry.Options; + +/// +/// Options for configuring OpenTelemetry log records. +/// +public sealed class OpenTelemetryLoggingOptions +{ + /// + /// Gets or sets a value indicating whether formatted log messages are included on exported log records. + /// Default is true. + /// + public bool IncludeFormattedMessage { get; set; } = true; + + /// + /// Gets or sets a value indicating whether logging scopes are included on exported log records. + /// Default is true. + /// + public bool IncludeScopes { get; set; } = true; + + /// + /// Gets or sets a value indicating whether structured log state values are parsed into log record attributes. + /// Default is true. + /// + public bool ParseStateValues { get; set; } = true; +} diff --git a/src/OpenTelemetry/Options/OpenTelemetryOptions.cs b/src/OpenTelemetry/Options/OpenTelemetryOptions.cs index 5aabe3d..7545a4b 100644 --- a/src/OpenTelemetry/Options/OpenTelemetryOptions.cs +++ b/src/OpenTelemetry/Options/OpenTelemetryOptions.cs @@ -29,6 +29,11 @@ public sealed class OpenTelemetryOptions /// public bool EnableMetrics { get; set; } = true; + /// + /// Gets or sets a value indicating whether the OpenTelemetry logging pipeline is enabled. Default is false. + /// + public bool EnableLogging { get; set; } + /// /// Gets or sets a value indicating whether the Atya Observation logging layer is enabled. Default is false. /// @@ -64,6 +69,11 @@ public sealed class OpenTelemetryOptions /// public OpenTelemetryInstrumentationOptions Instrumentations { get; } = new(); + /// + /// Gets OpenTelemetry logging options. + /// + public OpenTelemetryLoggingOptions Logging { get; } = new(); + /// /// Gets exporter configuration options. /// diff --git a/src/OpenTelemetry/PublicAPI.Unshipped.txt b/src/OpenTelemetry/PublicAPI.Unshipped.txt index c040684..d6159de 100644 --- a/src/OpenTelemetry/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/PublicAPI.Unshipped.txt @@ -4,4 +4,15 @@ Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions.ConsoleOptions() -> void Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions.Enabled.get -> bool Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions.Enabled.set -> void Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryExporterOptions.Console.get -> Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions! +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.IncludeFormattedMessage.get -> bool +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.IncludeFormattedMessage.set -> void +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.IncludeScopes.get -> bool +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.IncludeScopes.set -> void +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.OpenTelemetryLoggingOptions() -> void +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.ParseStateValues.get -> bool +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.ParseStateValues.set -> void +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableLogging.get -> bool +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableLogging.set -> void +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Logging.get -> Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions! Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Protocol.get -> OpenTelemetry.Exporter.OtlpExportProtocol? diff --git a/src/OpenTelemetry/README.md b/src/OpenTelemetry/README.md index 7887f9d..1c3fcd4 100644 --- a/src/OpenTelemetry/README.md +++ b/src/OpenTelemetry/README.md @@ -1,6 +1,6 @@ # Atya.Diagnostics.OpenTelemetry -`Atya.Diagnostics.OpenTelemetry` is the host-facing OpenTelemetry integration package for Atya diagnostics libraries. It wires OpenTelemetry tracing and metrics, Atya service identity, resource metadata, optional instrumentations, and OTLP export through one dependency-injection entry point. +`Atya.Diagnostics.OpenTelemetry` is the host-facing OpenTelemetry integration package for Atya diagnostics libraries. It wires OpenTelemetry logging, tracing, and metrics, Atya service identity, resource metadata, optional instrumentations, and OTLP export through one dependency-injection entry point. ## Supported Framework @@ -22,6 +22,7 @@ services.AddAtyaOpenTelemetry(options => { options.ServiceName = "Orders.Service"; options.ServiceVersion = "1.0.0"; + options.EnableLogging = true; options.ActivitySources.Add("Orders.Workflows"); options.Meters.Add("Orders.Business"); @@ -53,6 +54,7 @@ Bind from the default `OpenTelemetry` configuration section: "OpenTelemetry": { "ServiceName": "Orders.Service", "ServiceVersion": "1.0.0", + "EnableLogging": true, "EnableTracing": true, "EnableMetrics": true, "EnableObservationLogging": false, @@ -65,6 +67,11 @@ Bind from the default `OpenTelemetry` configuration section: "team": "platform" } }, + "Logging": { + "IncludeFormattedMessage": true, + "IncludeScopes": true, + "ParseStateValues": true + }, "Instrumentations": { "AspNetCore": { "Enabled": true }, "HttpClient": { "Enabled": true }, @@ -114,9 +121,11 @@ services.AddAtyaOpenTelemetry(configuration, "Diagnostics:OpenTelemetry"); - `ActivitySources` adds extra application `ActivitySource` names beyond the package default. - `Meters` adds extra application `Meter` names beyond the package default. - Options passed to `AddAtyaOpenTelemetry` are validated immediately because the OpenTelemetry providers are configured during service registration. -- Configure the package through the delegate or configuration section passed to `AddAtyaOpenTelemetry`; later `services.Configure(...)` calls do not rebuild the OpenTelemetry tracing or metrics providers. +- Configure the package through the delegate or configuration section passed to `AddAtyaOpenTelemetry`; later `services.Configure(...)` calls do not rebuild the OpenTelemetry logging, tracing, or metrics providers. - Tracing and metrics are enabled by default. +- OpenTelemetry logging is disabled by default. Set `EnableLogging` to `true` to register the OpenTelemetry logging provider and export logs through configured exporters. - Observation-layer logging is disabled by default. +- `EnableObservationLogging` registers Atya Observation logging services; it does not by itself register the OpenTelemetry logging provider. - ASP.NET Core, HttpClient, Runtime, console exporter, and OTLP exporter registrations are opt-in. - SqlClient, Entity Framework Core, and gRPC client instrumentations are opt-in. - SQL command text capture is disabled by default because command text can contain sensitive data. @@ -158,7 +167,7 @@ Leave SQL text capture disabled unless queries are known not to contain secrets | Exporter | Toggle | Configuration | | -------- | ------ | ------------- | | Console | `Exporters.Console.Enabled` | `Enabled` | -| OTLP | `Exporters.Otlp.Enabled` | `Endpoint`, `Protocol`, `Headers` | +| OTLP | `Exporters.Otlp.Enabled` | `Endpoint`, `Protocol`, `Headers` for enabled logging, tracing, and metrics pipelines | ## Package Boundaries diff --git a/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs b/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs index a2e1690..058cbd4 100644 --- a/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs +++ b/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs @@ -6,8 +6,10 @@ using Atya.Diagnostics.Tracing.Options; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using OpenTelemetry.Exporter; +using OpenTelemetry.Logs; namespace OpenTelemetry.UnitTests.DependencyInjection; @@ -143,20 +145,35 @@ public void AddAtyaOpenTelemetry_Should_Allow_Disabling_Metrics() } [Fact] - public void AddAtyaOpenTelemetry_Should_Register_Logging_When_Enabled() + public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetry_Logging_When_Enabled() { var services = new ServiceCollection(); _ = services.AddAtyaOpenTelemetry(options => { options.ServiceName = "Orders.Service"; - options.EnableObservationLogging = true; + options.EnableLogging = true; }); using var provider = services.BuildServiceProvider(); var resolvedOptions = provider.GetRequiredService>().Value; + var loggerProviders = provider.GetServices(); - _ = resolvedOptions.EnableObservationLogging.Should().BeTrue(); + _ = resolvedOptions.EnableLogging.Should().BeTrue(); + _ = loggerProviders.Should().Contain(provider => provider is OpenTelemetryLoggerProvider); + } + + [Fact] + public void AddAtyaOpenTelemetry_Should_Not_Register_OpenTelemetry_Logging_By_Default() + { + var services = new ServiceCollection(); + + _ = services.AddAtyaOpenTelemetry(options => options.ServiceName = "Orders.Service"); + + using var provider = services.BuildServiceProvider(); + var loggerProviders = provider.GetServices(); + + _ = loggerProviders.Should().NotContain(provider => provider is OpenTelemetryLoggerProvider); } [Fact] @@ -191,7 +208,11 @@ public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetryOptions() { options.ServiceName = "Orders.Service"; options.ServiceVersion = "2.0.0"; + options.EnableLogging = true; options.EnableObservationLogging = true; + options.Logging.IncludeFormattedMessage = false; + options.Logging.IncludeScopes = false; + options.Logging.ParseStateValues = false; options.ActivitySources.Add("Orders.Workflows"); options.Meters.Add("Orders.Business"); options.Exporters.Console.Enabled = true; @@ -215,7 +236,11 @@ public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetryOptions() _ = resolvedOptions.ServiceName.Should().Be("Orders.Service"); _ = resolvedOptions.ServiceVersion.Should().Be("2.0.0"); + _ = resolvedOptions.EnableLogging.Should().BeTrue(); _ = resolvedOptions.EnableObservationLogging.Should().BeTrue(); + _ = resolvedOptions.Logging.IncludeFormattedMessage.Should().BeFalse(); + _ = resolvedOptions.Logging.IncludeScopes.Should().BeFalse(); + _ = resolvedOptions.Logging.ParseStateValues.Should().BeFalse(); _ = resolvedOptions.ActivitySources.Should().ContainSingle("Orders.Workflows"); _ = resolvedOptions.Meters.Should().ContainSingle("Orders.Business"); _ = resolvedOptions.Exporters.Console.Enabled.Should().BeTrue(); @@ -241,7 +266,11 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_ { ["OpenTelemetry:ServiceName"] = "Billing.Service", ["OpenTelemetry:ServiceVersion"] = "3.1.4", + ["OpenTelemetry:EnableLogging"] = "true", ["OpenTelemetry:EnableObservationLogging"] = "true", + ["OpenTelemetry:Logging:IncludeFormattedMessage"] = "false", + ["OpenTelemetry:Logging:IncludeScopes"] = "false", + ["OpenTelemetry:Logging:ParseStateValues"] = "false", ["OpenTelemetry:ActivitySources:0"] = "Billing.Workflows", ["OpenTelemetry:Meters:0"] = "Billing.Business", ["OpenTelemetry:Instrumentations:HttpClient:Enabled"] = "true", @@ -266,7 +295,11 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_ _ = resolvedOptions.ServiceName.Should().Be("Billing.Service"); _ = resolvedOptions.ServiceVersion.Should().Be("3.1.4"); + _ = resolvedOptions.EnableLogging.Should().BeTrue(); _ = resolvedOptions.EnableObservationLogging.Should().BeTrue(); + _ = resolvedOptions.Logging.IncludeFormattedMessage.Should().BeFalse(); + _ = resolvedOptions.Logging.IncludeScopes.Should().BeFalse(); + _ = resolvedOptions.Logging.ParseStateValues.Should().BeFalse(); _ = resolvedOptions.ActivitySources.Should().ContainSingle("Billing.Workflows"); _ = resolvedOptions.Meters.Should().ContainSingle("Billing.Business"); _ = resolvedOptions.Instrumentations.HttpClient.Enabled.Should().BeTrue(); @@ -316,9 +349,13 @@ public void OpenTelemetryOptions_Defaults_Should_Be_Production_Safe() _ = options.MeterName.Should().BeNull(); _ = options.ActivitySources.Should().BeEmpty(); _ = options.Meters.Should().BeEmpty(); + _ = options.EnableLogging.Should().BeFalse(); _ = options.EnableTracing.Should().BeTrue(); _ = options.EnableMetrics.Should().BeTrue(); _ = options.EnableObservationLogging.Should().BeFalse(); + _ = options.Logging.IncludeFormattedMessage.Should().BeTrue(); + _ = options.Logging.IncludeScopes.Should().BeTrue(); + _ = options.Logging.ParseStateValues.Should().BeTrue(); _ = options.Instrumentations.AspNetCore.Enabled.Should().BeFalse(); _ = options.Instrumentations.HttpClient.Enabled.Should().BeFalse(); _ = options.Instrumentations.SqlClient.Enabled.Should().BeFalse(); diff --git a/tests/OpenTelemetry.UnitTests/Integration/OpenTelemetryHostIntegrationTests.cs b/tests/OpenTelemetry.UnitTests/Integration/OpenTelemetryHostIntegrationTests.cs index 4e96484..2b713b1 100644 --- a/tests/OpenTelemetry.UnitTests/Integration/OpenTelemetryHostIntegrationTests.cs +++ b/tests/OpenTelemetry.UnitTests/Integration/OpenTelemetryHostIntegrationTests.cs @@ -19,6 +19,7 @@ public async Task AddAtyaOpenTelemetry_Should_Start_And_Stop_OpenTelemetry_Hoste options.Resource.ServiceNamespace = "orders"; options.Resource.DeploymentEnvironment = "test"; options.Resource.Attributes["team"] = "platform"; + options.EnableLogging = true; options.Instrumentations.HttpClient.Enabled = true; options.Instrumentations.Runtime.Enabled = true; }); @@ -29,6 +30,9 @@ public async Task AddAtyaOpenTelemetry_Should_Start_And_Stop_OpenTelemetry_Hoste try { var hostedServices = host.Services.GetServices().ToArray(); + var logger = host.Services.GetRequiredService>(); + + logger.LogInformation("OpenTelemetry logging pipeline started."); _ = hostedServices.Should().NotBeEmpty(); } diff --git a/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs b/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs index de15e9e..d05e1c8 100644 --- a/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs +++ b/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs @@ -1,16 +1,21 @@ using System.Data; using System.Diagnostics; using Atya.Diagnostics.OpenTelemetry.Internal; +using Atya.Diagnostics.OpenTelemetry.Logging; using Atya.Diagnostics.OpenTelemetry.Metrics; using Atya.Diagnostics.OpenTelemetry.Options; using Atya.Diagnostics.OpenTelemetry.Tracing; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using NSubstitute; using OpenTelemetry; using OpenTelemetry.Exporter; +using OpenTelemetry.Logs; using OpenTelemetry.Resources; using OpenTelemetry.Trace; +using AtyaLoggerProviderBuilderExtensions = Atya.Diagnostics.OpenTelemetry.Logging.LoggerProviderBuilderExtensions; +using AtyaOpenTelemetryLoggerOptionsExtensions = Atya.Diagnostics.OpenTelemetry.Logging.OpenTelemetryLoggerOptionsExtensions; using AtyaTracerProviderBuilderExtensions = Atya.Diagnostics.OpenTelemetry.Tracing.TracerProviderBuilderExtensions; namespace OpenTelemetry.UnitTests.Internal; @@ -401,6 +406,73 @@ public void MeterProviderBuilderExtensions_Should_Throw_When_Arguments_Are_Inval .WithParameterName("meterName"); } + [Fact] + public void LoggerProviderBuilderExtensions_Should_Configure_Through_OpenTelemetry_Builder() + { + var options = CreateFullOptions(); + var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics"); + var services = new ServiceCollection(); + var configured = false; + + _ = services.AddOpenTelemetry() + .WithLogging(logging => + { + var result = logging.ConfigureAtyaLogging(options, resourceBuilder); + configured = ReferenceEquals(result, logging); + }); + + using var provider = services.BuildServiceProvider(); + var loggerProviders = provider.GetServices(); + + _ = loggerProviders.Should().Contain(loggerProvider => loggerProvider is OpenTelemetryLoggerProvider); + _ = configured.Should().BeTrue(); + } + + [Fact] + public void LoggerProviderBuilderExtensions_Should_Throw_When_Builder_Is_Null() + { + var options = CreateValidOptions(); + var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics"); + + var actForNullBuilder = () => AtyaLoggerProviderBuilderExtensions.ConfigureAtyaLogging(null!, options, resourceBuilder); + + _ = actForNullBuilder.Should().Throw() + .WithParameterName("builder"); + } + + [Fact] + public void OpenTelemetryLoggerOptionsExtensions_Should_Apply_Log_Record_Options() + { + var loggerOptions = new OpenTelemetryLoggerOptions(); + var options = new OpenTelemetryLoggingOptions + { + IncludeFormattedMessage = false, + IncludeScopes = false, + ParseStateValues = false, + }; + + var result = loggerOptions.ConfigureAtyaLogging(options); + + _ = result.Should().BeSameAs(loggerOptions); + _ = loggerOptions.IncludeFormattedMessage.Should().BeFalse(); + _ = loggerOptions.IncludeScopes.Should().BeFalse(); + _ = loggerOptions.ParseStateValues.Should().BeFalse(); + } + + [Fact] + public void OpenTelemetryLoggerOptionsExtensions_Should_Throw_When_Arguments_Are_Null() + { + var loggerOptions = new OpenTelemetryLoggerOptions(); + + var actForNullOptions = () => loggerOptions.ConfigureAtyaLogging(null!); + var actForNullLoggerOptions = () => AtyaOpenTelemetryLoggerOptionsExtensions.ConfigureAtyaLogging(null!, new OpenTelemetryLoggingOptions()); + + _ = actForNullOptions.Should().Throw() + .WithParameterName("options"); + _ = actForNullLoggerOptions.Should().Throw() + .WithParameterName("loggerOptions"); + } + [Fact] public void DatabaseInstrumentationEnricher_Should_Add_Query_Text_Tags_From_Database_Command() { From e627360357b4057cbb061fb9d16161301fc8a6ce Mon Sep 17 00:00:00 2001 From: Arsen Asulyan Date: Tue, 26 May 2026 09:07:36 +0400 Subject: [PATCH 18/20] Compose OpenTelemetry observation options (#19) * Development (#11) * MinVer and Microsoft.SourceLink.GitHub are always restored as build-only dependencies. MinVerSkip is enabled for local AllowPackWithoutGit=true smoke packs. local non-git pack fallback still produces 1.0.0, not 0.0.0-alpha.0. * Fix coverage report input format (#9) * Fix coverage report input format (#10) * chore(actions)(deps): bump softprops/action-gh-release from 2 to 3 (#5) Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(actions)(deps): bump actions/setup-dotnet from 4 to 5 (#4) Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4 to 5. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(actions)(deps): bump actions/checkout from 4 to 6 (#3) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(actions)(deps): bump danielpalme/ReportGenerator-GitHub-Action (#2) Bumps [danielpalme/ReportGenerator-GitHub-Action](https://github.com/danielpalme/reportgenerator-github-action) from 5.5.0 to 5.5.10. - [Release notes](https://github.com/danielpalme/reportgenerator-github-action/releases) - [Commits](https://github.com/danielpalme/reportgenerator-github-action/compare/5.5.0...5.5.10) --- updated-dependencies: - dependency-name: danielpalme/ReportGenerator-GitHub-Action dependency-version: 5.5.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(actions)(deps): bump actions/attest-build-provenance from 2 to 4 (#1) Bumps [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) from 2 to 4. - [Release notes](https://github.com/actions/attest-build-provenance/releases) - [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md) - [Commits](https://github.com/actions/attest-build-provenance/compare/v2...v4) --- updated-dependencies: - dependency-name: actions/attest-build-provenance dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): Bump MinVer from 6.0.0 to 7.0.0 (#7) --- updated-dependencies: - dependency-name: MinVer dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Arsen Asulyan * chore(deps): Bump Microsoft.SourceLink.GitHub from 8.0.0 to 10.0.300 (#6) --- updated-dependencies: - dependency-name: Microsoft.SourceLink.GitHub dependency-version: 10.0.300 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Arsen Asulyan * Fix coverage report input format (#12) * Fix SourceLink lock file version mismatch (#13) --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Compose OpenTelemetry observation options * Refresh Metrics package lock hash --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Packages.props | 119 ++++++++--------- .../OpenTelemetry.Benchmarks/Program.cs | 8 +- .../packages.lock.json | 38 ++---- .../OpenTelemetry.Samples.Console/Program.cs | 4 +- .../packages.lock.json | 61 ++++----- ...penTelemetryServiceCollectionExtensions.cs | 27 ++-- .../Internal/OpenTelemetryOptionsValidator.cs | 89 ++++++------- .../Internal/ResourceBuilderFactory.cs | 27 ++-- .../Options/OpenTelemetryOptions.cs | 43 +++--- src/OpenTelemetry/PublicAPI.Shipped.txt | 16 +-- src/OpenTelemetry/PublicAPI.Unshipped.txt | 1 + src/OpenTelemetry/README.md | 18 +-- src/OpenTelemetry/packages.lock.json | 36 ++--- ...lemetryServiceCollectionExtensionsTests.cs | 124 ++++++++++++++---- .../OpenTelemetryHostIntegrationTests.cs | 4 +- .../Internal/OpenTelemetryInternalTests.cs | 92 +++++++++---- .../OpenTelemetry.UnitTests.csproj | 1 + .../packages.lock.json | 61 ++++----- 18 files changed, 422 insertions(+), 347 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 05b7b3e..b449a9c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,59 +1,60 @@ - - - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/benchmarks/OpenTelemetry.Benchmarks/Program.cs b/benchmarks/OpenTelemetry.Benchmarks/Program.cs index 92d06b9..7ef961e 100644 --- a/benchmarks/OpenTelemetry.Benchmarks/Program.cs +++ b/benchmarks/OpenTelemetry.Benchmarks/Program.cs @@ -69,7 +69,7 @@ public static int BuildMinimalServiceProvider() private static void ConfigureMinimal(OpenTelemetryOptions options) { - options.ServiceName = ServiceName; + options.Observation.ServiceName = ServiceName; options.EnableObservationLogging = false; options.EnableTracing = true; options.EnableMetrics = true; @@ -78,9 +78,9 @@ private static void ConfigureMinimal(OpenTelemetryOptions options) private static void ConfigureFull(OpenTelemetryOptions options) { ConfigureMinimal(options); - options.ServiceVersion = "1.0.0"; - options.ActivitySourceName = "Benchmarks.Orders.Tracing"; - options.MeterName = "Benchmarks.Orders.Metrics"; + options.Observation.ServiceVersion = "1.0.0"; + options.Observation.ActivitySourceName = "Benchmarks.Orders.Tracing"; + options.Observation.MeterName = "Benchmarks.Orders.Metrics"; options.Resource.ServiceNamespace = "benchmarks"; options.Resource.DeploymentEnvironment = "production"; options.Resource.Attributes["team"] = "platform"; diff --git a/benchmarks/OpenTelemetry.Benchmarks/packages.lock.json b/benchmarks/OpenTelemetry.Benchmarks/packages.lock.json index 3f35464..5acbc78 100644 --- a/benchmarks/OpenTelemetry.Benchmarks/packages.lock.json +++ b/benchmarks/OpenTelemetry.Benchmarks/packages.lock.json @@ -31,8 +31,8 @@ }, "Atya.Diagnostics.Logging": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "JXgn5jimNlnYA94WynXTdcp6ayybTveqTCcfxN/60fqO3ucaQ9YGf3JDVRzo0en5D6lYKwZKNZXWzo3/wnO9ew==", + "resolved": "1.0.1", + "contentHash": "PlrizTJNeGkV0jTc4iw5ceswuGqH2wV3dDfo+LUcrYCjYtgbtT8ycFfNWV4ZuPoZR5vSj4b0LGQu5dGK/B98LA==", "dependencies": { "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", @@ -41,8 +41,8 @@ }, "Atya.Diagnostics.Metrics": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "2iT9yJeBSFnPpkszq+i9/Bp3adrqp1q85x9EgTLfsvi+FWms3e48rgvIO6zeer8Jtehe0Whur1Njn5AB4/usHQ==", + "resolved": "1.0.1", + "contentHash": "1H70t3SEcoxIPI1bD/i9Y7+NnOnAMM3YqwuK1DpHoqH+aqX5RIbDOarACJ60oyhz6HjIIGTiypN4GqhgDzRmtg==", "dependencies": { "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", @@ -51,8 +51,8 @@ }, "Atya.Diagnostics.Tracing": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "Er7R3/oL8s1XrzrVy4h1QKEVLsNo8vFYEZ93kfl/XURyAUOapajK9UUI5azQOMDtsUK3yNtMjCqVi8V97wmEhA==", + "resolved": "1.0.1", + "contentHash": "8lGM/J451JmkWZJRDYtxJuKXcSs0P18igKB9S3EhAwUM5X4v59SIkb0Lg9eRYTae7+vQcPJvOVQNqfwXQvh/Hg==", "dependencies": { "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", @@ -148,15 +148,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8" } }, - "Microsoft.Extensions.Options.DataAnnotations": { - "type": "Transitive", - "resolved": "10.0.8", - "contentHash": "HhxwIGECGGJ8ox2kvm6/hkN/w1ZyKrO5uu/rLAL51V0ypPdahoNf+dHS6Er/DJs2aeUmH38ZTTzACfLy1O6w3Q==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", - "Microsoft.Extensions.Options": "10.0.8" - } - }, "Microsoft.Extensions.Primitives": { "type": "Transitive", "resolved": "10.0.8", @@ -210,7 +201,7 @@ "Atya.Diagnostics.OpenTelemetry": { "type": "Project", "dependencies": { - "Atya.Diagnostics.Observation": "[1.0.0, )", + "Atya.Diagnostics.Observation": "[1.0.1, )", "Atya.Foundation.Guards": "[1.0.0, )", "Microsoft.Extensions.Configuration.Abstractions": "[10.0.8, )", "Microsoft.Extensions.Configuration.Binder": "[10.0.8, )", @@ -230,17 +221,16 @@ }, "Atya.Diagnostics.Observation": { "type": "CentralTransitive", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "85nmR5rEEEzwg8n76NHLv+j8sGMWx1EdfMADlhZqBvS8oPSe70N1mZ9iBFfYtMz27jN8+9YVHyIf5GI+r9nFHg==", + "requested": "[1.0.1, )", + "resolved": "1.0.1", + "contentHash": "Rx7dLfRsqN2eLCnHr5Yswa2w8yQUxXNgVcAvjifrULEPDWHx5ZUY4Morb/0uf2FKKn2WLtEGTh9uA2nEdEyZbg==", "dependencies": { - "Atya.Diagnostics.Logging": "1.0.0", - "Atya.Diagnostics.Metrics": "1.0.0", - "Atya.Diagnostics.Tracing": "1.0.0", + "Atya.Diagnostics.Logging": "1.0.1", + "Atya.Diagnostics.Metrics": "1.0.1", + "Atya.Diagnostics.Tracing": "1.0.1", "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", - "Microsoft.Extensions.Options": "10.0.8", - "Microsoft.Extensions.Options.DataAnnotations": "10.0.8" + "Microsoft.Extensions.Options": "10.0.8" } }, "Atya.Foundation.Guards": { diff --git a/samples/OpenTelemetry.Samples.Console/Program.cs b/samples/OpenTelemetry.Samples.Console/Program.cs index 6fbc3ae..8f8358b 100644 --- a/samples/OpenTelemetry.Samples.Console/Program.cs +++ b/samples/OpenTelemetry.Samples.Console/Program.cs @@ -26,8 +26,8 @@ _ = builder.Services.AddAtyaOpenTelemetry(options => { // Service identity (required). - options.ServiceName = "Samples.OrderProcessor"; - options.ServiceVersion = "1.0.0"; + options.Observation.ServiceName = "Samples.OrderProcessor"; + options.Observation.ServiceVersion = "1.0.0"; // Pipeline toggles. options.EnableLogging = true; diff --git a/samples/OpenTelemetry.Samples.Console/packages.lock.json b/samples/OpenTelemetry.Samples.Console/packages.lock.json index b091977..d6730b2 100644 --- a/samples/OpenTelemetry.Samples.Console/packages.lock.json +++ b/samples/OpenTelemetry.Samples.Console/packages.lock.json @@ -56,8 +56,8 @@ }, "Atya.Diagnostics.Logging": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "JXgn5jimNlnYA94WynXTdcp6ayybTveqTCcfxN/60fqO3ucaQ9YGf3JDVRzo0en5D6lYKwZKNZXWzo3/wnO9ew==", + "resolved": "1.0.1", + "contentHash": "PlrizTJNeGkV0jTc4iw5ceswuGqH2wV3dDfo+LUcrYCjYtgbtT8ycFfNWV4ZuPoZR5vSj4b0LGQu5dGK/B98LA==", "dependencies": { "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", @@ -66,8 +66,8 @@ }, "Atya.Diagnostics.Metrics": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "2iT9yJeBSFnPpkszq+i9/Bp3adrqp1q85x9EgTLfsvi+FWms3e48rgvIO6zeer8Jtehe0Whur1Njn5AB4/usHQ==", + "resolved": "1.0.1", + "contentHash": "1H70t3SEcoxIPI1bD/i9Y7+NnOnAMM3YqwuK1DpHoqH+aqX5RIbDOarACJ60oyhz6HjIIGTiypN4GqhgDzRmtg==", "dependencies": { "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", @@ -76,8 +76,8 @@ }, "Atya.Diagnostics.Tracing": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "Er7R3/oL8s1XrzrVy4h1QKEVLsNo8vFYEZ93kfl/XURyAUOapajK9UUI5azQOMDtsUK3yNtMjCqVi8V97wmEhA==", + "resolved": "1.0.1", + "contentHash": "8lGM/J451JmkWZJRDYtxJuKXcSs0P18igKB9S3EhAwUM5X4v59SIkb0Lg9eRYTae7+vQcPJvOVQNqfwXQvh/Hg==", "dependencies": { "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", @@ -123,17 +123,6 @@ "Microsoft.Extensions.Primitives": "10.0.8" } }, - "Microsoft.Extensions.Configuration.Json": { - "type": "Transitive", - "resolved": "10.0.8", - "contentHash": "KLtAZ6A38s1pIfCO2ns6aG14NNGMYNZ4PBYfFK4M+R4A+xuSc6oklhqDcpHZxvDpyBWeFtR5C8iQBw2ng8tUHQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "10.0.8", - "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", - "Microsoft.Extensions.Configuration.FileExtensions": "10.0.8", - "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8" - } - }, "Microsoft.Extensions.Configuration.UserSecrets": { "type": "Transitive", "resolved": "10.0.8", @@ -212,15 +201,6 @@ "Microsoft.Extensions.Primitives": "10.0.8" } }, - "Microsoft.Extensions.Options.DataAnnotations": { - "type": "Transitive", - "resolved": "10.0.8", - "contentHash": "HhxwIGECGGJ8ox2kvm6/hkN/w1ZyKrO5uu/rLAL51V0ypPdahoNf+dHS6Er/DJs2aeUmH38ZTTzACfLy1O6w3Q==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", - "Microsoft.Extensions.Options": "10.0.8" - } - }, "Microsoft.Extensions.Primitives": { "type": "Transitive", "resolved": "10.0.8", @@ -248,7 +228,7 @@ "Atya.Diagnostics.OpenTelemetry": { "type": "Project", "dependencies": { - "Atya.Diagnostics.Observation": "[1.0.0, )", + "Atya.Diagnostics.Observation": "[1.0.1, )", "Atya.Foundation.Guards": "[1.0.0, )", "Microsoft.Extensions.Configuration.Abstractions": "[10.0.8, )", "Microsoft.Extensions.Configuration.Binder": "[10.0.8, )", @@ -268,17 +248,16 @@ }, "Atya.Diagnostics.Observation": { "type": "CentralTransitive", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "85nmR5rEEEzwg8n76NHLv+j8sGMWx1EdfMADlhZqBvS8oPSe70N1mZ9iBFfYtMz27jN8+9YVHyIf5GI+r9nFHg==", + "requested": "[1.0.1, )", + "resolved": "1.0.1", + "contentHash": "Rx7dLfRsqN2eLCnHr5Yswa2w8yQUxXNgVcAvjifrULEPDWHx5ZUY4Morb/0uf2FKKn2WLtEGTh9uA2nEdEyZbg==", "dependencies": { - "Atya.Diagnostics.Logging": "1.0.0", - "Atya.Diagnostics.Metrics": "1.0.0", - "Atya.Diagnostics.Tracing": "1.0.0", + "Atya.Diagnostics.Logging": "1.0.1", + "Atya.Diagnostics.Metrics": "1.0.1", + "Atya.Diagnostics.Tracing": "1.0.1", "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", - "Microsoft.Extensions.Options": "10.0.8", - "Microsoft.Extensions.Options.DataAnnotations": "10.0.8" + "Microsoft.Extensions.Options": "10.0.8" } }, "Atya.Foundation.Guards": { @@ -306,6 +285,18 @@ "Microsoft.Extensions.Configuration.Abstractions": "10.0.8" } }, + "Microsoft.Extensions.Configuration.Json": { + "type": "CentralTransitive", + "requested": "[10.0.8, )", + "resolved": "10.0.8", + "contentHash": "KLtAZ6A38s1pIfCO2ns6aG14NNGMYNZ4PBYfFK4M+R4A+xuSc6oklhqDcpHZxvDpyBWeFtR5C8iQBw2ng8tUHQ==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", + "Microsoft.Extensions.Configuration.FileExtensions": "10.0.8", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8" + } + }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "CentralTransitive", "requested": "[10.0.8, )", diff --git a/src/OpenTelemetry/DependencyInjection/OpenTelemetryServiceCollectionExtensions.cs b/src/OpenTelemetry/DependencyInjection/OpenTelemetryServiceCollectionExtensions.cs index 5f32026..b79febc 100644 --- a/src/OpenTelemetry/DependencyInjection/OpenTelemetryServiceCollectionExtensions.cs +++ b/src/OpenTelemetry/DependencyInjection/OpenTelemetryServiceCollectionExtensions.cs @@ -6,7 +6,7 @@ using Atya.Diagnostics.OpenTelemetry.Metrics; using Atya.Diagnostics.OpenTelemetry.Options; using Atya.Diagnostics.OpenTelemetry.Tracing; -using Atya.Diagnostics.Observation.DependencyInjection; +using Atya.Diagnostics.Observation.Models; using Atya.Foundation.Guards; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -45,30 +45,25 @@ public static IServiceCollection AddAtyaOpenTelemetry( .Configure(configureOptions) .ValidateOnStart(); - services.TryAddSingleton, OpenTelemetryOptionsValidator>(); + services.TryAddEnumerable( + ServiceDescriptor.Singleton, OpenTelemetryOptionsValidator>()); - var serviceName = bootstrapOptions.ServiceName.Trim(); - var activitySourceName = string.IsNullOrWhiteSpace(bootstrapOptions.ActivitySourceName) - ? serviceName - : bootstrapOptions.ActivitySourceName.Trim(); - var meterName = string.IsNullOrWhiteSpace(bootstrapOptions.MeterName) - ? serviceName - : bootstrapOptions.MeterName.Trim(); + var identity = ObservationIdentityResolver.Resolve(bootstrapOptions.Observation); // Compose the generic Observation layer (Logging + Tracing + Metrics registration). _ = services.AddAtyaObservation(observationOptions => { - observationOptions.ServiceName = serviceName; - observationOptions.ServiceVersion = bootstrapOptions.ServiceVersion; - observationOptions.ActivitySourceName = activitySourceName; - observationOptions.MeterName = meterName; + observationOptions.ServiceName = bootstrapOptions.Observation.ServiceName; + observationOptions.ServiceVersion = bootstrapOptions.Observation.ServiceVersion; + observationOptions.ActivitySourceName = bootstrapOptions.Observation.ActivitySourceName; + observationOptions.MeterName = bootstrapOptions.Observation.MeterName; observationOptions.ConfigureLogging = bootstrapOptions.EnableObservationLogging; observationOptions.ConfigureTracing = bootstrapOptions.EnableTracing; observationOptions.ConfigureMetrics = bootstrapOptions.EnableMetrics; }); // Build the OpenTelemetry resource. - var resourceBuilder = ResourceBuilderFactory.Create(bootstrapOptions, activitySourceName, meterName); + var resourceBuilder = ResourceBuilderFactory.Create(identity, bootstrapOptions.Resource); // Delegate pipeline configuration to folder-based configurators. var otelBuilder = services.AddOpenTelemetry(); @@ -83,13 +78,13 @@ public static IServiceCollection AddAtyaOpenTelemetry( if (bootstrapOptions.EnableTracing) { _ = otelBuilder.WithTracing(tracing => - tracing.ConfigureAtyaTracing(bootstrapOptions, resourceBuilder, activitySourceName)); + tracing.ConfigureAtyaTracing(bootstrapOptions, resourceBuilder, identity.ActivitySourceName)); } if (bootstrapOptions.EnableMetrics) { _ = otelBuilder.WithMetrics(metrics => - metrics.ConfigureAtyaMetrics(bootstrapOptions, resourceBuilder, meterName)); + metrics.ConfigureAtyaMetrics(bootstrapOptions, resourceBuilder, identity.MeterName)); } return services; diff --git a/src/OpenTelemetry/Internal/OpenTelemetryOptionsValidator.cs b/src/OpenTelemetry/Internal/OpenTelemetryOptionsValidator.cs index 5f9907f..772a27e 100644 --- a/src/OpenTelemetry/Internal/OpenTelemetryOptionsValidator.cs +++ b/src/OpenTelemetry/Internal/OpenTelemetryOptionsValidator.cs @@ -15,80 +15,71 @@ public ValidateOptionsResult Validate(string? name, OpenTelemetryOptions options _ = name; _ = Guard.AgainstNull(options); - if (string.IsNullOrWhiteSpace(options.ServiceName)) - { - return ValidateOptionsResult.Fail("OpenTelemetryOptions.ServiceName cannot be null or whitespace."); - } + var failures = new List(); - var activitySourceValidation = ValidateTelemetryNames(options.ActivitySources, nameof(options.ActivitySources)); - if (activitySourceValidation is not null) + if (string.IsNullOrWhiteSpace(options.Observation.ServiceName)) { - return activitySourceValidation; + failures.Add("OpenTelemetryOptions.Observation.ServiceName cannot be null or whitespace."); } - var meterValidation = ValidateTelemetryNames(options.Meters, nameof(options.Meters)); - if (meterValidation is not null) - { - return meterValidation; - } + AddTelemetryNameFailures(options.ActivitySources, nameof(options.ActivitySources), failures); + AddTelemetryNameFailures(options.Meters, nameof(options.Meters), failures); - if (!options.Exporters.Otlp.Enabled) + if (options.Exporters.Otlp.Enabled) { - return ValidateOptionsResult.Success; - } - - if (options.Exporters.Otlp.Endpoint is not null && - !Uri.TryCreate(options.Exporters.Otlp.Endpoint, UriKind.Absolute, out _)) - { - return ValidateOptionsResult.Fail( - $"OpenTelemetryOptions.Exporters.Otlp.Endpoint '{options.Exporters.Otlp.Endpoint}' is not a valid absolute URI."); - } - - if (options.Exporters.Otlp.Protocol is { } protocol && - !Enum.IsDefined(typeof(OtlpExportProtocol), protocol)) - { - return ValidateOptionsResult.Fail( - "OpenTelemetryOptions.Exporters.Otlp.Protocol must be a defined OtlpExportProtocol value."); - } - - foreach (var header in options.Exporters.Otlp.Headers) - { - if (string.IsNullOrWhiteSpace(header.Key)) + if (options.Exporters.Otlp.Endpoint is not null && + !Uri.TryCreate(options.Exporters.Otlp.Endpoint, UriKind.Absolute, out _)) { - return ValidateOptionsResult.Fail("OpenTelemetryOptions.Exporters.Otlp.Headers cannot contain a null or whitespace header name."); + failures.Add( + $"OpenTelemetryOptions.Exporters.Otlp.Endpoint '{options.Exporters.Otlp.Endpoint}' is not a valid absolute URI."); } - if (header.Key.Contains(',', StringComparison.Ordinal) || - header.Key.Contains('=', StringComparison.Ordinal)) + if (options.Exporters.Otlp.Protocol is { } protocol && + !Enum.IsDefined(typeof(OtlpExportProtocol), protocol)) { - return ValidateOptionsResult.Fail("OpenTelemetryOptions.Exporters.Otlp.Headers header names cannot contain ',' or '='."); + failures.Add("OpenTelemetryOptions.Exporters.Otlp.Protocol must be a defined OtlpExportProtocol value."); } - if (header.Value is null) + foreach (var header in options.Exporters.Otlp.Headers) { - return ValidateOptionsResult.Fail("OpenTelemetryOptions.Exporters.Otlp.Headers cannot contain a null header value."); - } + if (string.IsNullOrWhiteSpace(header.Key)) + { + failures.Add("OpenTelemetryOptions.Exporters.Otlp.Headers cannot contain a null or whitespace header name."); + } - if (header.Value.Contains(',', StringComparison.Ordinal)) - { - return ValidateOptionsResult.Fail("OpenTelemetryOptions.Exporters.Otlp.Headers header values cannot contain ','."); + if (header.Key.Contains(',', StringComparison.Ordinal) || + header.Key.Contains('=', StringComparison.Ordinal)) + { + failures.Add("OpenTelemetryOptions.Exporters.Otlp.Headers header names cannot contain ',' or '='."); + } + + if (header.Value is null) + { + failures.Add("OpenTelemetryOptions.Exporters.Otlp.Headers cannot contain a null header value."); + } + else if (header.Value.Contains(',', StringComparison.Ordinal)) + { + failures.Add("OpenTelemetryOptions.Exporters.Otlp.Headers header values cannot contain ','."); + } } } - return ValidateOptionsResult.Success; + return failures.Count == 0 + ? ValidateOptionsResult.Success + : ValidateOptionsResult.Fail(failures); } - private static ValidateOptionsResult? ValidateTelemetryNames(IEnumerable names, string optionName) + private static void AddTelemetryNameFailures( + IEnumerable names, + string optionName, + List failures) { foreach (var name in names) { if (string.IsNullOrWhiteSpace(name)) { - return ValidateOptionsResult.Fail( - $"OpenTelemetryOptions.{optionName} cannot contain a null or whitespace name."); + failures.Add($"OpenTelemetryOptions.{optionName} cannot contain a null or whitespace name."); } } - - return null; } } diff --git a/src/OpenTelemetry/Internal/ResourceBuilderFactory.cs b/src/OpenTelemetry/Internal/ResourceBuilderFactory.cs index cc3953e..f164d6a 100644 --- a/src/OpenTelemetry/Internal/ResourceBuilderFactory.cs +++ b/src/OpenTelemetry/Internal/ResourceBuilderFactory.cs @@ -2,6 +2,7 @@ // Copyright (c) Atya. All rights reserved. // using Atya.Diagnostics.OpenTelemetry.Options; +using Atya.Diagnostics.Observation.Models; using Atya.Foundation.Guards; using OpenTelemetry.Resources; @@ -9,30 +10,32 @@ namespace Atya.Diagnostics.OpenTelemetry.Internal; internal static class ResourceBuilderFactory { - public static ResourceBuilder Create(OpenTelemetryOptions options, string activitySourceName, string meterName) + public static ResourceBuilder Create( + ObservationIdentity identity, + OpenTelemetryResourceOptions resourceOptions) { - _ = Guard.AgainstNull(options); - _ = Guard.AgainstNullOrWhiteSpace(activitySourceName); - _ = Guard.AgainstNullOrWhiteSpace(meterName); + _ = Guard.AgainstNull(identity); + _ = Guard.AgainstNull(resourceOptions); var resourceBuilder = ResourceBuilder.CreateDefault() .AddService( - serviceName: options.ServiceName.Trim(), - serviceVersion: string.IsNullOrWhiteSpace(options.ServiceVersion) ? null : options.ServiceVersion.Trim(), - serviceNamespace: options.Resource.ServiceNamespace, - serviceInstanceId: options.Resource.ServiceInstanceId); + serviceName: identity.ServiceName.Trim(), + serviceVersion: string.IsNullOrWhiteSpace(identity.ServiceVersion) ? null : identity.ServiceVersion.Trim(), + serviceNamespace: resourceOptions.ServiceNamespace, + serviceInstanceId: resourceOptions.ServiceInstanceId); - if (!string.IsNullOrWhiteSpace(options.Resource.DeploymentEnvironment)) + if (!string.IsNullOrWhiteSpace(resourceOptions.DeploymentEnvironment)) { _ = resourceBuilder.AddAttributes(new KeyValuePair[] { - new ("deployment.environment", options.Resource.DeploymentEnvironment), + new ("deployment.environment.name", resourceOptions.DeploymentEnvironment), + new ("deployment.environment", resourceOptions.DeploymentEnvironment), }); } - if (options.Resource.Attributes.Count > 0) + if (resourceOptions.Attributes.Count > 0) { - _ = resourceBuilder.AddAttributes(options.Resource.Attributes); + _ = resourceBuilder.AddAttributes(resourceOptions.Attributes); } return resourceBuilder; diff --git a/src/OpenTelemetry/Options/OpenTelemetryOptions.cs b/src/OpenTelemetry/Options/OpenTelemetryOptions.cs index 7545a4b..86962be 100644 --- a/src/OpenTelemetry/Options/OpenTelemetryOptions.cs +++ b/src/OpenTelemetry/Options/OpenTelemetryOptions.cs @@ -1,6 +1,8 @@ // // Copyright (c) Atya. All rights reserved. // +using Atya.Diagnostics.Observation.Options; + namespace Atya.Diagnostics.OpenTelemetry.Options; /// @@ -10,14 +12,17 @@ namespace Atya.Diagnostics.OpenTelemetry.Options; public sealed class OpenTelemetryOptions { /// - /// Gets or sets the logical service name used for resource metadata, tracing, and metrics. + /// Gets the shared observation identity (service name, version, + /// activity source name, meter name) used across the Atya + /// diagnostics layers. Single source of truth for identity. /// - public string ServiceName { get; set; } = string.Empty; - - /// - /// Gets or sets the service version used for resource metadata and instrument versioning. - /// - public string? ServiceVersion { get; set; } + /// + /// Setting Observation.ConfigureLogging / ConfigureTracing / + /// ConfigureMetrics directly is IGNORED. The OpenTelemetry-layer + /// toggles EnableObservationLogging / EnableTracing / EnableMetrics + /// take precedence and overwrite them at registration time. + /// + public ObservationOptions Observation { get; } = new(); /// /// Gets or sets a value indicating whether the OpenTelemetry tracing pipeline is enabled. Default is true. @@ -32,23 +37,27 @@ public sealed class OpenTelemetryOptions /// /// Gets or sets a value indicating whether the OpenTelemetry logging pipeline is enabled. Default is false. /// + /// + /// Independent of , which only + /// registers the in-process Atya.Diagnostics.Logging helpers (scope + /// factories, structured property helpers) and does NOT export logs + /// anywhere. EnableLogging controls the OpenTelemetry SDK LoggerProvider + /// pipeline (OTLP / Console export). + /// public bool EnableLogging { get; set; } /// /// Gets or sets a value indicating whether the Atya Observation logging layer is enabled. Default is false. /// + /// + /// Independent of , which controls the + /// OpenTelemetry SDK LoggerProvider pipeline (OTLP / Console export). + /// EnableObservationLogging only registers the in-process + /// Atya.Diagnostics.Logging helpers (scope factories, structured property + /// helpers) and does NOT export logs anywhere. + /// public bool EnableObservationLogging { get; set; } - /// - /// Gets or sets the ActivitySource name override. When null, defaults to . - /// - public string? ActivitySourceName { get; set; } - - /// - /// Gets or sets the Meter name override. When null, defaults to . - /// - public string? MeterName { get; set; } - /// /// Gets additional application names to subscribe to. /// diff --git a/src/OpenTelemetry/PublicAPI.Shipped.txt b/src/OpenTelemetry/PublicAPI.Shipped.txt index 96eec18..135fcf6 100644 --- a/src/OpenTelemetry/PublicAPI.Shipped.txt +++ b/src/OpenTelemetry/PublicAPI.Shipped.txt @@ -22,8 +22,8 @@ Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryInstrumentationOptions.OpenT Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryInstrumentationOptions.Runtime.get -> Atya.Diagnostics.OpenTelemetry.Options.InstrumentationToggle! Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryInstrumentationOptions.SqlClient.get -> Atya.Diagnostics.OpenTelemetry.Options.DatabaseInstrumentationOptions! Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions -Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ActivitySourceName.get -> string? -Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ActivitySourceName.set -> void +*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ActivitySourceName.get -> string? +*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ActivitySourceName.set -> void Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ActivitySources.get -> System.Collections.Generic.IList! Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableMetrics.get -> bool Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableMetrics.set -> void @@ -33,15 +33,15 @@ Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableTracing.get -> Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableTracing.set -> void Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Exporters.get -> Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryExporterOptions! Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Instrumentations.get -> Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryInstrumentationOptions! -Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.MeterName.get -> string? -Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.MeterName.set -> void +*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.MeterName.get -> string? +*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.MeterName.set -> void Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Meters.get -> System.Collections.Generic.IList! Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.OpenTelemetryOptions() -> void Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Resource.get -> Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryResourceOptions! -Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceName.get -> string! -Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceName.set -> void -Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceVersion.get -> string? -Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceVersion.set -> void +*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceName.get -> string! +*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceName.set -> void +*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceVersion.get -> string? +*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceVersion.set -> void Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryResourceOptions Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryResourceOptions.Attributes.get -> System.Collections.Generic.IDictionary! Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryResourceOptions.DeploymentEnvironment.get -> string? diff --git a/src/OpenTelemetry/PublicAPI.Unshipped.txt b/src/OpenTelemetry/PublicAPI.Unshipped.txt index d6159de..5a01198 100644 --- a/src/OpenTelemetry/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/PublicAPI.Unshipped.txt @@ -15,4 +15,5 @@ Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.ParseStateVal Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableLogging.get -> bool Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableLogging.set -> void Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Logging.get -> Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions! +Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Observation.get -> Atya.Diagnostics.Observation.Options.ObservationOptions! Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Protocol.get -> OpenTelemetry.Exporter.OtlpExportProtocol? diff --git a/src/OpenTelemetry/README.md b/src/OpenTelemetry/README.md index 1c3fcd4..007dda1 100644 --- a/src/OpenTelemetry/README.md +++ b/src/OpenTelemetry/README.md @@ -20,8 +20,8 @@ using OpenTelemetry.Exporter; services.AddAtyaOpenTelemetry(options => { - options.ServiceName = "Orders.Service"; - options.ServiceVersion = "1.0.0"; + options.Observation.ServiceName = "Orders.Service"; + options.Observation.ServiceVersion = "1.0.0"; options.EnableLogging = true; options.ActivitySources.Add("Orders.Workflows"); options.Meters.Add("Orders.Business"); @@ -52,8 +52,10 @@ Bind from the default `OpenTelemetry` configuration section: ```json { "OpenTelemetry": { - "ServiceName": "Orders.Service", - "ServiceVersion": "1.0.0", + "Observation": { + "ServiceName": "Orders.Service", + "ServiceVersion": "1.0.0" + }, "EnableLogging": true, "EnableTracing": true, "EnableMetrics": true, @@ -115,9 +117,9 @@ services.AddAtyaOpenTelemetry(configuration, "Diagnostics:OpenTelemetry"); ## Behavior -- `ServiceName` is required and is trimmed before registration. -- `ActivitySourceName` defaults to `ServiceName` when omitted. -- `MeterName` defaults to `ServiceName` when omitted. +- `Observation.ServiceName` is required and is trimmed before registration. +- `Observation.ActivitySourceName` defaults to `Observation.ServiceName` when omitted. +- `Observation.MeterName` defaults to `Observation.ServiceName` when omitted. - `ActivitySources` adds extra application `ActivitySource` names beyond the package default. - `Meters` adds extra application `Meter` names beyond the package default. - Options passed to `AddAtyaOpenTelemetry` are validated immediately because the OpenTelemetry providers are configured during service registration. @@ -135,7 +137,7 @@ services.AddAtyaOpenTelemetry(configuration, "Diagnostics:OpenTelemetry"); Options are validated through `Microsoft.Extensions.Options`. Invalid options fail when options are resolved or when host startup validation runs. -- `ServiceName` cannot be null, empty, or whitespace. +- `Observation.ServiceName` cannot be null, empty, or whitespace. - `ActivitySources` and `Meters` cannot contain null, empty, or whitespace names. - OTLP `Endpoint`, when set, must be an absolute URI. - OTLP `Protocol`, when set, must be a defined `OtlpExportProtocol` value such as `Grpc` or `HttpProtobuf`. diff --git a/src/OpenTelemetry/packages.lock.json b/src/OpenTelemetry/packages.lock.json index 5f91665..6d89887 100644 --- a/src/OpenTelemetry/packages.lock.json +++ b/src/OpenTelemetry/packages.lock.json @@ -4,17 +4,16 @@ "net10.0": { "Atya.Diagnostics.Observation": { "type": "Direct", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "85nmR5rEEEzwg8n76NHLv+j8sGMWx1EdfMADlhZqBvS8oPSe70N1mZ9iBFfYtMz27jN8+9YVHyIf5GI+r9nFHg==", + "requested": "[1.0.1, )", + "resolved": "1.0.1", + "contentHash": "Rx7dLfRsqN2eLCnHr5Yswa2w8yQUxXNgVcAvjifrULEPDWHx5ZUY4Morb/0uf2FKKn2WLtEGTh9uA2nEdEyZbg==", "dependencies": { - "Atya.Diagnostics.Logging": "1.0.0", - "Atya.Diagnostics.Metrics": "1.0.0", - "Atya.Diagnostics.Tracing": "1.0.0", + "Atya.Diagnostics.Logging": "1.0.1", + "Atya.Diagnostics.Metrics": "1.0.1", + "Atya.Diagnostics.Tracing": "1.0.1", "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", - "Microsoft.Extensions.Options": "10.0.8", - "Microsoft.Extensions.Options.DataAnnotations": "10.0.8" + "Microsoft.Extensions.Options": "10.0.8" } }, "Atya.Foundation.Guards": { @@ -182,8 +181,8 @@ }, "Atya.Diagnostics.Logging": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "JXgn5jimNlnYA94WynXTdcp6ayybTveqTCcfxN/60fqO3ucaQ9YGf3JDVRzo0en5D6lYKwZKNZXWzo3/wnO9ew==", + "resolved": "1.0.1", + "contentHash": "PlrizTJNeGkV0jTc4iw5ceswuGqH2wV3dDfo+LUcrYCjYtgbtT8ycFfNWV4ZuPoZR5vSj4b0LGQu5dGK/B98LA==", "dependencies": { "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", @@ -192,8 +191,8 @@ }, "Atya.Diagnostics.Metrics": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "2iT9yJeBSFnPpkszq+i9/Bp3adrqp1q85x9EgTLfsvi+FWms3e48rgvIO6zeer8Jtehe0Whur1Njn5AB4/usHQ==", + "resolved": "1.0.1", + "contentHash": "1H70t3SEcoxIPI1bD/i9Y7+NnOnAMM3YqwuK1DpHoqH+aqX5RIbDOarACJ60oyhz6HjIIGTiypN4GqhgDzRmtg==", "dependencies": { "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", @@ -202,8 +201,8 @@ }, "Atya.Diagnostics.Tracing": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "Er7R3/oL8s1XrzrVy4h1QKEVLsNo8vFYEZ93kfl/XURyAUOapajK9UUI5azQOMDtsUK3yNtMjCqVi8V97wmEhA==", + "resolved": "1.0.1", + "contentHash": "8lGM/J451JmkWZJRDYtxJuKXcSs0P18igKB9S3EhAwUM5X4v59SIkb0Lg9eRYTae7+vQcPJvOVQNqfwXQvh/Hg==", "dependencies": { "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", @@ -235,15 +234,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8" } }, - "Microsoft.Extensions.Options.DataAnnotations": { - "type": "Transitive", - "resolved": "10.0.8", - "contentHash": "HhxwIGECGGJ8ox2kvm6/hkN/w1ZyKrO5uu/rLAL51V0ypPdahoNf+dHS6Er/DJs2aeUmH38ZTTzACfLy1O6w3Q==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", - "Microsoft.Extensions.Options": "10.0.8" - } - }, "Microsoft.Extensions.Primitives": { "type": "Transitive", "resolved": "10.0.8", diff --git a/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs b/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs index 058cbd4..7e9ec4e 100644 --- a/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs +++ b/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs @@ -1,7 +1,9 @@ +using System.Text; using Atya.Diagnostics.Metrics.Abstractions; using Atya.Diagnostics.Metrics.Options; -using Atya.Diagnostics.Observation.Models; +using Atya.Diagnostics.OpenTelemetry.Internal; using Atya.Diagnostics.OpenTelemetry.Options; +using Atya.Diagnostics.Observation.Models; using Atya.Diagnostics.Tracing.Abstractions; using Atya.Diagnostics.Tracing.Options; using Microsoft.Extensions.Configuration; @@ -57,8 +59,8 @@ public void AddAtyaOpenTelemetry_Should_Register_ObservationIdentity_And_Map_Def _ = services.AddAtyaOpenTelemetry(options => { - options.ServiceName = "Orders.Service"; - options.ServiceVersion = "1.0.0"; + options.Observation.ServiceName = "Orders.Service"; + options.Observation.ServiceVersion = "1.0.0"; }); using var provider = services.BuildServiceProvider(); @@ -84,9 +86,9 @@ public void AddAtyaOpenTelemetry_Should_Trim_Service_And_Use_Explicit_ActivitySo _ = services.AddAtyaOpenTelemetry(options => { - options.ServiceName = " Orders.Service "; - options.ActivitySourceName = " Orders.Tracing "; - options.MeterName = " Orders.Metrics "; + options.Observation.ServiceName = " Orders.Service "; + options.Observation.ActivitySourceName = " Orders.Tracing "; + options.Observation.MeterName = " Orders.Metrics "; }); using var provider = services.BuildServiceProvider(); @@ -102,7 +104,7 @@ public void AddAtyaOpenTelemetry_Should_Register_Tracing_And_Metrics_By_Default( { var services = new ServiceCollection(); - _ = services.AddAtyaOpenTelemetry(options => options.ServiceName = "Orders.Service"); + _ = services.AddAtyaOpenTelemetry(options => options.Observation.ServiceName = "Orders.Service"); using var provider = services.BuildServiceProvider(); @@ -110,6 +112,23 @@ public void AddAtyaOpenTelemetry_Should_Register_Tracing_And_Metrics_By_Default( _ = provider.GetService().Should().NotBeNull(); } + [Fact] + public void AddAtyaOpenTelemetry_Should_Let_OpenTelemetry_Toggles_Override_Observation_Toggles() + { + var services = new ServiceCollection(); + + _ = services.AddAtyaOpenTelemetry(options => + { + options.Observation.ServiceName = "Orders.Service"; + options.Observation.ConfigureTracing = false; + options.EnableTracing = true; + }); + + using var provider = services.BuildServiceProvider(); + + _ = provider.GetService().Should().NotBeNull(); + } + [Fact] public void AddAtyaOpenTelemetry_Should_Allow_Disabling_Tracing() { @@ -117,7 +136,7 @@ public void AddAtyaOpenTelemetry_Should_Allow_Disabling_Tracing() _ = services.AddAtyaOpenTelemetry(options => { - options.ServiceName = "Orders.Service"; + options.Observation.ServiceName = "Orders.Service"; options.EnableTracing = false; }); @@ -134,7 +153,7 @@ public void AddAtyaOpenTelemetry_Should_Allow_Disabling_Metrics() _ = services.AddAtyaOpenTelemetry(options => { - options.ServiceName = "Orders.Service"; + options.Observation.ServiceName = "Orders.Service"; options.EnableMetrics = false; }); @@ -151,7 +170,7 @@ public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetry_Logging_When_Enab _ = services.AddAtyaOpenTelemetry(options => { - options.ServiceName = "Orders.Service"; + options.Observation.ServiceName = "Orders.Service"; options.EnableLogging = true; }); @@ -168,7 +187,7 @@ public void AddAtyaOpenTelemetry_Should_Not_Register_OpenTelemetry_Logging_By_De { var services = new ServiceCollection(); - _ = services.AddAtyaOpenTelemetry(options => options.ServiceName = "Orders.Service"); + _ = services.AddAtyaOpenTelemetry(options => options.Observation.ServiceName = "Orders.Service"); using var provider = services.BuildServiceProvider(); var loggerProviders = provider.GetServices(); @@ -193,12 +212,27 @@ public void AddAtyaOpenTelemetry_Should_Be_Idempotent_For_Core_Identity_Service( { var services = new ServiceCollection(); - _ = services.AddAtyaOpenTelemetry(options => options.ServiceName = "Orders.Service"); - _ = services.AddAtyaOpenTelemetry(options => options.ServiceName = "Orders.Service"); + _ = services.AddAtyaOpenTelemetry(options => options.Observation.ServiceName = "Orders.Service"); + _ = services.AddAtyaOpenTelemetry(options => options.Observation.ServiceName = "Orders.Service"); _ = services.Count(d => d.ServiceType == typeof(ObservationIdentity)).Should().Be(1); } + [Fact] + public void AddAtyaOpenTelemetry_Should_Register_Validator_Through_Enumerable() + { + var services = new ServiceCollection(); + services.AddSingleton, TestOpenTelemetryOptionsValidator>(); + + _ = services.AddAtyaOpenTelemetry(options => options.Observation.ServiceName = "Orders.Service"); + + using var provider = services.BuildServiceProvider(); + var validators = provider.GetServices>().ToArray(); + + _ = validators.Should().ContainSingle(validator => validator is TestOpenTelemetryOptionsValidator); + _ = validators.Should().ContainSingle(validator => validator is OpenTelemetryOptionsValidator); + } + [Fact] public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetryOptions() { @@ -206,8 +240,8 @@ public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetryOptions() _ = services.AddAtyaOpenTelemetry(options => { - options.ServiceName = "Orders.Service"; - options.ServiceVersion = "2.0.0"; + options.Observation.ServiceName = "Orders.Service"; + options.Observation.ServiceVersion = "2.0.0"; options.EnableLogging = true; options.EnableObservationLogging = true; options.Logging.IncludeFormattedMessage = false; @@ -234,8 +268,8 @@ public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetryOptions() var resolvedOptions = provider.GetRequiredService>().Value; - _ = resolvedOptions.ServiceName.Should().Be("Orders.Service"); - _ = resolvedOptions.ServiceVersion.Should().Be("2.0.0"); + _ = resolvedOptions.Observation.ServiceName.Should().Be("Orders.Service"); + _ = resolvedOptions.Observation.ServiceVersion.Should().Be("2.0.0"); _ = resolvedOptions.EnableLogging.Should().BeTrue(); _ = resolvedOptions.EnableObservationLogging.Should().BeTrue(); _ = resolvedOptions.Logging.IncludeFormattedMessage.Should().BeFalse(); @@ -264,8 +298,8 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_ var configuration = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { - ["OpenTelemetry:ServiceName"] = "Billing.Service", - ["OpenTelemetry:ServiceVersion"] = "3.1.4", + ["OpenTelemetry:Observation:ServiceName"] = "Billing.Service", + ["OpenTelemetry:Observation:ServiceVersion"] = "3.1.4", ["OpenTelemetry:EnableLogging"] = "true", ["OpenTelemetry:EnableObservationLogging"] = "true", ["OpenTelemetry:Logging:IncludeFormattedMessage"] = "false", @@ -293,8 +327,8 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_ using var provider = services.BuildServiceProvider(); var resolvedOptions = provider.GetRequiredService>().Value; - _ = resolvedOptions.ServiceName.Should().Be("Billing.Service"); - _ = resolvedOptions.ServiceVersion.Should().Be("3.1.4"); + _ = resolvedOptions.Observation.ServiceName.Should().Be("Billing.Service"); + _ = resolvedOptions.Observation.ServiceVersion.Should().Be("3.1.4"); _ = resolvedOptions.EnableLogging.Should().BeTrue(); _ = resolvedOptions.EnableObservationLogging.Should().BeTrue(); _ = resolvedOptions.Logging.IncludeFormattedMessage.Should().BeFalse(); @@ -315,15 +349,39 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_ _ = resolvedOptions.Exporters.Otlp.Headers.Should().Contain("tenant", "billing"); } + [Fact] + public void OpenTelemetryOptions_Should_Bind_Nested_Observation_From_Json() + { + const string Json = """ + { + "OpenTelemetry": { + "Observation": { + "ServiceName": "Catalog.Service" + } + } + } + """; + + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(Json)); + var configuration = new ConfigurationBuilder() + .AddJsonStream(stream) + .Build(); + var options = new OpenTelemetryOptions(); + + configuration.GetSection("OpenTelemetry").Bind(options); + + _ = options.Observation.ServiceName.Should().Be("Catalog.Service"); + } + [Fact] public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Custom_Configuration_Section() { var configuration = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { - ["Diagnostics:ServiceName"] = "Shipping.Service", - ["Diagnostics:ActivitySourceName"] = "Shipping.Tracing", - ["Diagnostics:MeterName"] = "Shipping.Metrics", + ["Diagnostics:Observation:ServiceName"] = "Shipping.Service", + ["Diagnostics:Observation:ActivitySourceName"] = "Shipping.Tracing", + ["Diagnostics:Observation:MeterName"] = "Shipping.Metrics", }) .Build(); var services = new ServiceCollection(); @@ -343,10 +401,10 @@ public void OpenTelemetryOptions_Defaults_Should_Be_Production_Safe() { var options = new OpenTelemetryOptions(); - _ = options.ServiceName.Should().BeEmpty(); - _ = options.ServiceVersion.Should().BeNull(); - _ = options.ActivitySourceName.Should().BeNull(); - _ = options.MeterName.Should().BeNull(); + _ = options.Observation.ServiceName.Should().BeEmpty(); + _ = options.Observation.ServiceVersion.Should().BeNull(); + _ = options.Observation.ActivitySourceName.Should().BeNull(); + _ = options.Observation.MeterName.Should().BeNull(); _ = options.ActivitySources.Should().BeEmpty(); _ = options.Meters.Should().BeEmpty(); _ = options.EnableLogging.Should().BeFalse(); @@ -374,4 +432,14 @@ public void OpenTelemetryOptions_Defaults_Should_Be_Production_Safe() _ = options.Resource.DeploymentEnvironment.Should().BeNull(); _ = options.Resource.Attributes.Should().BeEmpty(); } + + private sealed class TestOpenTelemetryOptionsValidator : IValidateOptions + { + public ValidateOptionsResult Validate(string? name, OpenTelemetryOptions options) + { + _ = name; + _ = options; + return ValidateOptionsResult.Success; + } + } } diff --git a/tests/OpenTelemetry.UnitTests/Integration/OpenTelemetryHostIntegrationTests.cs b/tests/OpenTelemetry.UnitTests/Integration/OpenTelemetryHostIntegrationTests.cs index 2b713b1..438cba2 100644 --- a/tests/OpenTelemetry.UnitTests/Integration/OpenTelemetryHostIntegrationTests.cs +++ b/tests/OpenTelemetry.UnitTests/Integration/OpenTelemetryHostIntegrationTests.cs @@ -14,8 +14,8 @@ public async Task AddAtyaOpenTelemetry_Should_Start_And_Stop_OpenTelemetry_Hoste _ = builder.Logging.ClearProviders(); _ = builder.Services.AddAtyaOpenTelemetry(options => { - options.ServiceName = "Orders.Service"; - options.ServiceVersion = "1.0.0"; + options.Observation.ServiceName = "Orders.Service"; + options.Observation.ServiceVersion = "1.0.0"; options.Resource.ServiceNamespace = "orders"; options.Resource.DeploymentEnvironment = "test"; options.Resource.Attributes["team"] = "platform"; diff --git a/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs b/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs index d05e1c8..2676abc 100644 --- a/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs +++ b/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs @@ -5,6 +5,7 @@ using Atya.Diagnostics.OpenTelemetry.Metrics; using Atya.Diagnostics.OpenTelemetry.Options; using Atya.Diagnostics.OpenTelemetry.Tracing; +using Atya.Diagnostics.Observation.Models; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -131,12 +132,38 @@ public void OpenTelemetryOptionsValidator_Should_Ignore_Disabled_Otlp_Details() public void OpenTelemetryOptionsValidator_Should_Fail_When_ServiceName_Is_Missing(string? serviceName) { var options = CreateValidOptions(); - options.ServiceName = serviceName!; + options.Observation.ServiceName = serviceName!; var result = new OpenTelemetryOptionsValidator().Validate("named", options); _ = result.Failed.Should().BeTrue(); - _ = result.FailureMessage.Should().Contain("ServiceName"); + _ = result.Failures.Should().Contain("OpenTelemetryOptions.Observation.ServiceName cannot be null or whitespace."); + } + + [Fact] + public void OpenTelemetryOptionsValidator_Should_Collect_All_Failures() + { + var options = CreateValidOptions(); + options.Observation.ServiceName = string.Empty; + options.ActivitySources.Add(" "); + options.Meters.Add(""); + options.Exporters.Otlp.Enabled = true; + options.Exporters.Otlp.Endpoint = "not a uri"; + options.Exporters.Otlp.Protocol = (OtlpExportProtocol)42; + options.Exporters.Otlp.Headers["bad,key"] = "bad,value"; + options.Exporters.Otlp.Headers["missing-value"] = null!; + + var result = new OpenTelemetryOptionsValidator().Validate(null, options); + + _ = result.Failed.Should().BeTrue(); + _ = result.Failures.Should().Contain("OpenTelemetryOptions.Observation.ServiceName cannot be null or whitespace."); + _ = result.Failures.Should().Contain("OpenTelemetryOptions.ActivitySources cannot contain a null or whitespace name."); + _ = result.Failures.Should().Contain("OpenTelemetryOptions.Meters cannot contain a null or whitespace name."); + _ = result.Failures.Should().Contain(failure => failure.Contains("OpenTelemetryOptions.Exporters.Otlp.Endpoint", StringComparison.Ordinal)); + _ = result.Failures.Should().Contain("OpenTelemetryOptions.Exporters.Otlp.Protocol must be a defined OtlpExportProtocol value."); + _ = result.Failures.Should().Contain("OpenTelemetryOptions.Exporters.Otlp.Headers header names cannot contain ',' or '='."); + _ = result.Failures.Should().Contain("OpenTelemetryOptions.Exporters.Otlp.Headers header values cannot contain ','."); + _ = result.Failures.Should().Contain("OpenTelemetryOptions.Exporters.Otlp.Headers cannot contain a null header value."); } [Theory] @@ -221,20 +248,23 @@ public void OpenTelemetryOptionsValidator_Should_Throw_When_Options_Are_Null() public void ResourceBuilderFactory_Should_Create_Resource_With_Service_Metadata_And_Custom_Attributes() { var options = CreateValidOptions(); - options.ServiceName = " Orders.Service "; - options.ServiceVersion = " 1.2.3 "; + options.Observation.ServiceName = " Orders.Service "; + options.Observation.ServiceVersion = " 1.2.3 "; options.Resource.ServiceNamespace = "orders"; options.Resource.ServiceInstanceId = "pod-123"; options.Resource.DeploymentEnvironment = "production"; options.Resource.Attributes["team"] = "platform"; - var resource = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics").Build(); + var resource = ResourceBuilderFactory.Create( + ObservationIdentityResolver.Resolve(options.Observation), + options.Resource).Build(); var attributes = resource.Attributes.ToDictionary(attribute => attribute.Key, attribute => attribute.Value); _ = attributes.Should().Contain("service.name", "Orders.Service"); _ = attributes.Should().Contain("service.version", "1.2.3"); _ = attributes.Should().Contain("service.namespace", "orders"); _ = attributes.Should().Contain("service.instance.id", "pod-123"); + _ = attributes.Should().Contain("deployment.environment.name", "production"); _ = attributes.Should().Contain("deployment.environment", "production"); _ = attributes.Should().Contain("team", "platform"); } @@ -242,10 +272,14 @@ public void ResourceBuilderFactory_Should_Create_Resource_With_Service_Metadata_ [Fact] public void ResourceBuilderFactory_Should_Create_Minimal_Resource() { - var resource = ResourceBuilderFactory.Create(CreateValidOptions(), "Orders.Tracing", "Orders.Metrics").Build(); + var options = CreateValidOptions(); + var resource = ResourceBuilderFactory.Create( + ObservationIdentityResolver.Resolve(options.Observation), + options.Resource).Build(); var attributes = resource.Attributes.ToDictionary(attribute => attribute.Key, attribute => attribute.Value); _ = attributes.Should().Contain("service.name", "Orders.Service"); + _ = attributes.Should().NotContainKey("deployment.environment.name"); _ = attributes.Should().NotContainKey("deployment.environment"); } @@ -253,16 +287,14 @@ public void ResourceBuilderFactory_Should_Create_Minimal_Resource() public void ResourceBuilderFactory_Should_Throw_When_Arguments_Are_Invalid() { var validOptions = CreateValidOptions(); - var actForNullOptions = () => ResourceBuilderFactory.Create(null!, "source", "meter"); - var actForInvalidSource = () => ResourceBuilderFactory.Create(validOptions, " ", "meter"); - var actForInvalidMeter = () => ResourceBuilderFactory.Create(validOptions, "source", ""); + var validIdentity = ObservationIdentityResolver.Resolve(validOptions.Observation); + var actForNullIdentity = () => ResourceBuilderFactory.Create(null!, validOptions.Resource); + var actForNullResource = () => ResourceBuilderFactory.Create(validIdentity, null!); - _ = actForNullOptions.Should().Throw() - .WithParameterName("options"); - _ = actForInvalidSource.Should().Throw() - .WithParameterName("activitySourceName"); - _ = actForInvalidMeter.Should().Throw() - .WithParameterName("meterName"); + _ = actForNullIdentity.Should().Throw() + .WithParameterName("identity"); + _ = actForNullResource.Should().Throw() + .WithParameterName("resourceOptions"); } [Fact] @@ -300,7 +332,7 @@ public void TelemetryNameNormalizer_Should_Throw_When_Arguments_Are_Invalid() public void TracerProviderBuilderExtensions_Should_Configure_All_Tracing_Branches() { var options = CreateFullOptions(); - var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics"); + var resourceBuilder = CreateResourceBuilder(options); var builder = Sdk.CreateTracerProviderBuilder(); var result = builder.ConfigureAtyaTracing(options, resourceBuilder, "Orders.Tracing"); @@ -314,7 +346,7 @@ public void TracerProviderBuilderExtensions_Should_Configure_All_Tracing_Branche public void TracerProviderBuilderExtensions_Should_Configure_Minimal_Tracing_Branches() { var options = CreateValidOptions(); - var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics"); + var resourceBuilder = CreateResourceBuilder(options); var builder = Sdk.CreateTracerProviderBuilder(); var result = builder.ConfigureAtyaTracing(options, resourceBuilder, "Orders.Tracing"); @@ -328,7 +360,7 @@ public void TracerProviderBuilderExtensions_Should_Configure_Database_Instrument var options = CreateValidOptions(); options.Instrumentations.SqlClient.Enabled = true; options.Instrumentations.EntityFrameworkCore.Enabled = true; - var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics"); + var resourceBuilder = CreateResourceBuilder(options); var builder = Sdk.CreateTracerProviderBuilder(); var result = builder.ConfigureAtyaTracing(options, resourceBuilder, "Orders.Tracing"); @@ -342,7 +374,7 @@ public void TracerProviderBuilderExtensions_Should_Configure_Database_Instrument public void TracerProviderBuilderExtensions_Should_Throw_When_Arguments_Are_Invalid() { var options = CreateValidOptions(); - var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics"); + var resourceBuilder = CreateResourceBuilder(options); var builder = Sdk.CreateTracerProviderBuilder(); var actForNullBuilder = () => AtyaTracerProviderBuilderExtensions.ConfigureAtyaTracing(null!, options, resourceBuilder, "source"); @@ -364,7 +396,7 @@ public void TracerProviderBuilderExtensions_Should_Throw_When_Arguments_Are_Inva public void MeterProviderBuilderExtensions_Should_Configure_All_Metrics_Branches() { var options = CreateFullOptions(); - var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics"); + var resourceBuilder = CreateResourceBuilder(options); var builder = Sdk.CreateMeterProviderBuilder(); var result = builder.ConfigureAtyaMetrics(options, resourceBuilder, "Orders.Metrics"); @@ -376,7 +408,7 @@ public void MeterProviderBuilderExtensions_Should_Configure_All_Metrics_Branches public void MeterProviderBuilderExtensions_Should_Configure_Minimal_Metrics_Branches() { var options = CreateValidOptions(); - var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics"); + var resourceBuilder = CreateResourceBuilder(options); var builder = Sdk.CreateMeterProviderBuilder(); var result = builder.ConfigureAtyaMetrics(options, resourceBuilder, "Orders.Metrics"); @@ -388,7 +420,7 @@ public void MeterProviderBuilderExtensions_Should_Configure_Minimal_Metrics_Bran public void MeterProviderBuilderExtensions_Should_Throw_When_Arguments_Are_Invalid() { var options = CreateValidOptions(); - var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics"); + var resourceBuilder = CreateResourceBuilder(options); var builder = Sdk.CreateMeterProviderBuilder(); var actForNullBuilder = () => MeterProviderBuilderExtensions.ConfigureAtyaMetrics(null!, options, resourceBuilder, "meter"); @@ -410,7 +442,7 @@ public void MeterProviderBuilderExtensions_Should_Throw_When_Arguments_Are_Inval public void LoggerProviderBuilderExtensions_Should_Configure_Through_OpenTelemetry_Builder() { var options = CreateFullOptions(); - var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics"); + var resourceBuilder = CreateResourceBuilder(options); var services = new ServiceCollection(); var configured = false; @@ -432,7 +464,7 @@ public void LoggerProviderBuilderExtensions_Should_Configure_Through_OpenTelemet public void LoggerProviderBuilderExtensions_Should_Throw_When_Builder_Is_Null() { var options = CreateValidOptions(); - var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics"); + var resourceBuilder = CreateResourceBuilder(options); var actForNullBuilder = () => AtyaLoggerProviderBuilderExtensions.ConfigureAtyaLogging(null!, options, resourceBuilder); @@ -544,10 +576,20 @@ private static OpenTelemetryOptions CreateValidOptions() { return new OpenTelemetryOptions { - ServiceName = "Orders.Service", + Observation = + { + ServiceName = "Orders.Service", + }, }; } + private static ResourceBuilder CreateResourceBuilder(OpenTelemetryOptions options) + { + return ResourceBuilderFactory.Create( + ObservationIdentityResolver.Resolve(options.Observation), + options.Resource); + } + private static OpenTelemetryOptions CreateFullOptions() { var options = CreateValidOptions(); diff --git a/tests/OpenTelemetry.UnitTests/OpenTelemetry.UnitTests.csproj b/tests/OpenTelemetry.UnitTests/OpenTelemetry.UnitTests.csproj index 14351e6..39792a3 100644 --- a/tests/OpenTelemetry.UnitTests/OpenTelemetry.UnitTests.csproj +++ b/tests/OpenTelemetry.UnitTests/OpenTelemetry.UnitTests.csproj @@ -5,6 +5,7 @@ + diff --git a/tests/OpenTelemetry.UnitTests/packages.lock.json b/tests/OpenTelemetry.UnitTests/packages.lock.json index 6ca47b1..aa17d80 100644 --- a/tests/OpenTelemetry.UnitTests/packages.lock.json +++ b/tests/OpenTelemetry.UnitTests/packages.lock.json @@ -36,6 +36,18 @@ "Microsoft.Extensions.Primitives": "10.0.8" } }, + "Microsoft.Extensions.Configuration.Json": { + "type": "Direct", + "requested": "[10.0.8, )", + "resolved": "10.0.8", + "contentHash": "KLtAZ6A38s1pIfCO2ns6aG14NNGMYNZ4PBYfFK4M+R4A+xuSc6oklhqDcpHZxvDpyBWeFtR5C8iQBw2ng8tUHQ==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", + "Microsoft.Extensions.Configuration.FileExtensions": "10.0.8", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8" + } + }, "Microsoft.Extensions.DependencyInjection": { "type": "Direct", "requested": "[10.0.8, )", @@ -129,8 +141,8 @@ }, "Atya.Diagnostics.Logging": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "JXgn5jimNlnYA94WynXTdcp6ayybTveqTCcfxN/60fqO3ucaQ9YGf3JDVRzo0en5D6lYKwZKNZXWzo3/wnO9ew==", + "resolved": "1.0.1", + "contentHash": "PlrizTJNeGkV0jTc4iw5ceswuGqH2wV3dDfo+LUcrYCjYtgbtT8ycFfNWV4ZuPoZR5vSj4b0LGQu5dGK/B98LA==", "dependencies": { "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", @@ -139,8 +151,8 @@ }, "Atya.Diagnostics.Metrics": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "2iT9yJeBSFnPpkszq+i9/Bp3adrqp1q85x9EgTLfsvi+FWms3e48rgvIO6zeer8Jtehe0Whur1Njn5AB4/usHQ==", + "resolved": "1.0.1", + "contentHash": "1H70t3SEcoxIPI1bD/i9Y7+NnOnAMM3YqwuK1DpHoqH+aqX5RIbDOarACJ60oyhz6HjIIGTiypN4GqhgDzRmtg==", "dependencies": { "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", @@ -149,8 +161,8 @@ }, "Atya.Diagnostics.Tracing": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "Er7R3/oL8s1XrzrVy4h1QKEVLsNo8vFYEZ93kfl/XURyAUOapajK9UUI5azQOMDtsUK3yNtMjCqVi8V97wmEhA==", + "resolved": "1.0.1", + "contentHash": "8lGM/J451JmkWZJRDYtxJuKXcSs0P18igKB9S3EhAwUM5X4v59SIkb0Lg9eRYTae7+vQcPJvOVQNqfwXQvh/Hg==", "dependencies": { "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", @@ -192,17 +204,6 @@ "Microsoft.Extensions.Primitives": "10.0.8" } }, - "Microsoft.Extensions.Configuration.Json": { - "type": "Transitive", - "resolved": "10.0.8", - "contentHash": "KLtAZ6A38s1pIfCO2ns6aG14NNGMYNZ4PBYfFK4M+R4A+xuSc6oklhqDcpHZxvDpyBWeFtR5C8iQBw2ng8tUHQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "10.0.8", - "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", - "Microsoft.Extensions.Configuration.FileExtensions": "10.0.8", - "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8" - } - }, "Microsoft.Extensions.Configuration.UserSecrets": { "type": "Transitive", "resolved": "10.0.8", @@ -281,15 +282,6 @@ "Microsoft.Extensions.Primitives": "10.0.8" } }, - "Microsoft.Extensions.Options.DataAnnotations": { - "type": "Transitive", - "resolved": "10.0.8", - "contentHash": "HhxwIGECGGJ8ox2kvm6/hkN/w1ZyKrO5uu/rLAL51V0ypPdahoNf+dHS6Er/DJs2aeUmH38ZTTzACfLy1O6w3Q==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", - "Microsoft.Extensions.Options": "10.0.8" - } - }, "Microsoft.Extensions.Primitives": { "type": "Transitive", "resolved": "10.0.8", @@ -366,7 +358,7 @@ "Atya.Diagnostics.OpenTelemetry": { "type": "Project", "dependencies": { - "Atya.Diagnostics.Observation": "[1.0.0, )", + "Atya.Diagnostics.Observation": "[1.0.1, )", "Atya.Foundation.Guards": "[1.0.0, )", "Microsoft.Extensions.Configuration.Abstractions": "[10.0.8, )", "Microsoft.Extensions.Configuration.Binder": "[10.0.8, )", @@ -386,17 +378,16 @@ }, "Atya.Diagnostics.Observation": { "type": "CentralTransitive", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "85nmR5rEEEzwg8n76NHLv+j8sGMWx1EdfMADlhZqBvS8oPSe70N1mZ9iBFfYtMz27jN8+9YVHyIf5GI+r9nFHg==", + "requested": "[1.0.1, )", + "resolved": "1.0.1", + "contentHash": "Rx7dLfRsqN2eLCnHr5Yswa2w8yQUxXNgVcAvjifrULEPDWHx5ZUY4Morb/0uf2FKKn2WLtEGTh9uA2nEdEyZbg==", "dependencies": { - "Atya.Diagnostics.Logging": "1.0.0", - "Atya.Diagnostics.Metrics": "1.0.0", - "Atya.Diagnostics.Tracing": "1.0.0", + "Atya.Diagnostics.Logging": "1.0.1", + "Atya.Diagnostics.Metrics": "1.0.1", + "Atya.Diagnostics.Tracing": "1.0.1", "Atya.Foundation.Guards": "1.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", - "Microsoft.Extensions.Options": "10.0.8", - "Microsoft.Extensions.Options.DataAnnotations": "10.0.8" + "Microsoft.Extensions.Options": "10.0.8" } }, "Atya.Foundation.Guards": { From 1ef2209cccb538bac2d3d0f8ba2bbb5642d0a7e9 Mon Sep 17 00:00:00 2001 From: Arsen Asulyan Date: Tue, 26 May 2026 09:19:41 +0400 Subject: [PATCH 19/20] Development (#11) (#21) * MinVer and Microsoft.SourceLink.GitHub are always restored as build-only dependencies. MinVerSkip is enabled for local AllowPackWithoutGit=true smoke packs. local non-git pack fallback still produces 1.0.0, not 0.0.0-alpha.0. * Fix coverage report input format (#9) * Fix coverage report input format (#10) * chore(actions)(deps): bump softprops/action-gh-release from 2 to 3 (#5) Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... * chore(actions)(deps): bump actions/setup-dotnet from 4 to 5 (#4) Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4 to 5. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... * chore(actions)(deps): bump actions/checkout from 4 to 6 (#3) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... * chore(actions)(deps): bump danielpalme/ReportGenerator-GitHub-Action (#2) Bumps [danielpalme/ReportGenerator-GitHub-Action](https://github.com/danielpalme/reportgenerator-github-action) from 5.5.0 to 5.5.10. - [Release notes](https://github.com/danielpalme/reportgenerator-github-action/releases) - [Commits](https://github.com/danielpalme/reportgenerator-github-action/compare/5.5.0...5.5.10) --- updated-dependencies: - dependency-name: danielpalme/ReportGenerator-GitHub-Action dependency-version: 5.5.10 dependency-type: direct:production update-type: version-update:semver-patch ... * chore(actions)(deps): bump actions/attest-build-provenance from 2 to 4 (#1) Bumps [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) from 2 to 4. - [Release notes](https://github.com/actions/attest-build-provenance/releases) - [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md) - [Commits](https://github.com/actions/attest-build-provenance/compare/v2...v4) --- updated-dependencies: - dependency-name: actions/attest-build-provenance dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... * chore(deps): Bump MinVer from 6.0.0 to 7.0.0 (#7) --- updated-dependencies: - dependency-name: MinVer dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... * chore(deps): Bump Microsoft.SourceLink.GitHub from 8.0.0 to 10.0.300 (#6) --- updated-dependencies: - dependency-name: Microsoft.SourceLink.GitHub dependency-version: 10.0.300 dependency-type: direct:production update-type: version-update:semver-major ... * Fix coverage report input format (#12) * Fix SourceLink lock file version mismatch (#13) --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 690632bf5119e3780e4616d76577553737a98c5d Mon Sep 17 00:00:00 2001 From: Arsen Asulyan Date: Tue, 26 May 2026 20:56:39 +0400 Subject: [PATCH 20/20] Development (#11) (#22) * MinVer and Microsoft.SourceLink.GitHub are always restored as build-only dependencies. MinVerSkip is enabled for local AllowPackWithoutGit=true smoke packs. local non-git pack fallback still produces 1.0.0, not 0.0.0-alpha.0. * Fix coverage report input format (#9) * Fix coverage report input format (#10) * chore(actions)(deps): bump softprops/action-gh-release from 2 to 3 (#5) Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... * chore(actions)(deps): bump actions/setup-dotnet from 4 to 5 (#4) Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4 to 5. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... * chore(actions)(deps): bump actions/checkout from 4 to 6 (#3) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... * chore(actions)(deps): bump danielpalme/ReportGenerator-GitHub-Action (#2) Bumps [danielpalme/ReportGenerator-GitHub-Action](https://github.com/danielpalme/reportgenerator-github-action) from 5.5.0 to 5.5.10. - [Release notes](https://github.com/danielpalme/reportgenerator-github-action/releases) - [Commits](https://github.com/danielpalme/reportgenerator-github-action/compare/5.5.0...5.5.10) --- updated-dependencies: - dependency-name: danielpalme/ReportGenerator-GitHub-Action dependency-version: 5.5.10 dependency-type: direct:production update-type: version-update:semver-patch ... * chore(actions)(deps): bump actions/attest-build-provenance from 2 to 4 (#1) Bumps [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) from 2 to 4. - [Release notes](https://github.com/actions/attest-build-provenance/releases) - [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md) - [Commits](https://github.com/actions/attest-build-provenance/compare/v2...v4) --- updated-dependencies: - dependency-name: actions/attest-build-provenance dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... * chore(deps): Bump MinVer from 6.0.0 to 7.0.0 (#7) --- updated-dependencies: - dependency-name: MinVer dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... * chore(deps): Bump Microsoft.SourceLink.GitHub from 8.0.0 to 10.0.300 (#6) --- updated-dependencies: - dependency-name: Microsoft.SourceLink.GitHub dependency-version: 10.0.300 dependency-type: direct:production update-type: version-update:semver-major ... * Fix coverage report input format (#12) * Fix SourceLink lock file version mismatch (#13) --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>