diff --git a/.editorconfig b/.editorconfig
index 5bc89604c7..45d0806a20 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -41,7 +41,7 @@ csharp_indent_labels = flush_left
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:suggestion
-dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
# this. preferences
dotnet_style_qualification_for_field = true:suggestion
@@ -53,8 +53,8 @@ dotnet_style_qualification_for_event = true:suggestion
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = true:silent
-dotnet_style_predefined_type_for_locals_parameters_members = true:silent
-dotnet_style_predefined_type_for_member_access = true:silent
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
# name all constant fields using PascalCase
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
@@ -75,6 +75,7 @@ dotnet_style_readonly_field = true:suggestion
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
dotnet_style_prefer_simplified_interpolation = true:suggestion
dotnet_style_object_initializer = true:suggestion
+csharp_style_prefer_primary_constructors = false:none
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
@@ -82,21 +83,23 @@ dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
-dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
-dotnet_style_prefer_auto_properties = true:silent
-dotnet_style_prefer_conditional_expression_over_assignment = true:silent
-dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_prefer_auto_properties = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
+dotnet_style_prefer_conditional_expression_over_return = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_unused_value_expression_statement_preference = discard_variable:none
# Expression-bodied members
-csharp_style_expression_bodied_methods = false:silent
-csharp_style_expression_bodied_constructors = false:silent
-csharp_style_expression_bodied_operators = false:silent
-csharp_style_expression_bodied_properties = true:silent
-csharp_style_expression_bodied_indexers = true:silent
-csharp_style_expression_bodied_accessors = true:silent
+csharp_style_expression_bodied_methods = true:suggestion
+dotnet_diagnostic.IDE0022.severity = suggestion # dotnet format doesn't respect the suggestion in the line above
+csharp_style_expression_bodied_constructors = false:warning
+csharp_style_expression_bodied_operators = true:suggestion
+csharp_style_expression_bodied_properties = true:suggestion
+csharp_style_expression_bodied_indexers = true:suggestion
+csharp_style_expression_bodied_accessors = true:suggestion
# Pattern matching
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
@@ -113,6 +116,7 @@ csharp_style_prefer_range_operator = false:none
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_style_namespace_declarations = file_scoped:warning
+dotnet_style_namespace_match_folder = false:none
# Space preferences
csharp_space_after_cast = false
@@ -128,10 +132,10 @@ csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
# Parentheses preferences
-dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
-dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
-dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
-dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
# Code analyzers
# CA1031: Do not catch general exception types
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 3bad5b876a..d503e982d1 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -1,6 +1,7 @@
name: Bug report
+title: "[bug] "
description: Create a report to help us improve
-labels: ["bug"]
+labels: [bug,needs-triage]
body:
- type: markdown
attributes:
@@ -47,7 +48,7 @@ body:
- type: input
attributes:
label: Runtime Version
- description: What .NET runtime version did you use? (e.g. `net462`, `net48`, `netcoreapp3.1`, `net6.0` etc. You can find this information from the `*.csproj` file)
+ description: What .NET runtime version did you use? (e.g. `net462`, `net48`, `net8.0`, etc. You can find this information from the `*.csproj` file)
validations:
required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000..3104c7c976
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,7 @@
+# https://docs.github.com/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
+
+blank_issues_enabled: false
+contact_links:
+ - name: Question
+ url: https://github.com/open-telemetry/opentelemetry-dotnet/discussions/new?category=q-a
+ about: Ask a question to help us improve our knowledge base and documentation.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index 7fd9b2f4ed..ab95873173 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -1,6 +1,7 @@
name: Feature request
+title: "[feature request] "
description: Suggest an idea for this project
-labels: ["enhancement"]
+labels: [enhancement,needs-triage]
body:
- type: markdown
attributes:
diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml
deleted file mode 100644
index 76eea55351..0000000000
--- a/.github/ISSUE_TEMPLATE/question.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-name: Question
-description: Ask a question to help us improve our knowledge base and documentation
-labels: ["question"]
-body:
- - type: markdown
- attributes:
- value: |
- > [!NOTE]
- > Please ask questions using [GitHub Discussions](https://github.com/open-telemetry/opentelemetry-dotnet/discussions/new) instead of GitHub Issues.
-
- - type: textarea
- attributes:
- label: What is the question?
- description: Describe the question you have.
- validations:
- required: true
-
- - type: textarea
- attributes:
- label: Additional context
- description: Any additional information you think may be relevant to this question.
diff --git a/.github/codecov.yml b/.github/codecov.yml
index b20bf1b297..c381869ce7 100644
--- a/.github/codecov.yml
+++ b/.github/codecov.yml
@@ -33,22 +33,22 @@ ignore:
- "test"
flags:
- unittests-Solution-Stable:
+ unittests-Solution:
carryforward: true
paths:
- src
- unittests-Solution-Experimental:
+ unittests-Project-Stable:
carryforward: true
paths:
- src
- unittests-Instrumentation-Stable:
+ unittests-Project-Experimental:
carryforward: true
paths:
- src
- unittests-Instrumentation-Experimental:
+ unittests-UnstableCoreLibraries-Experimental:
carryforward: true
paths:
- src
diff --git a/.github/workflows/Component.BuildTest.yml b/.github/workflows/Component.BuildTest.yml
index f97c8b94f9..de7ebb3fc4 100644
--- a/.github/workflows/Component.BuildTest.yml
+++ b/.github/workflows/Component.BuildTest.yml
@@ -20,11 +20,11 @@ on:
required: false
type: string
os-list:
- default: '[ "windows-latest", "ubuntu-latest" ]'
+ default: '[ "windows-latest", "ubuntu-latest", "otel-linux-arm64" ]'
required: false
type: string
tfm-list:
- default: '[ "net462", "net6.0", "net7.0", "net8.0" ]'
+ default: '[ "net462", "net8.0", "net9.0" ]'
required: false
type: string
@@ -39,6 +39,10 @@ jobs:
exclude:
- os: ubuntu-latest
version: net462
+ - os: otel-linux-arm64
+ version: net462
+ - os: otel-linux-arm64
+ version: net8.0
runs-on: ${{ matrix.os }}
steps:
@@ -65,7 +69,7 @@ jobs:
run: dotnet tool install -g dotnet-coverage
- name: Merging test results
- run: dotnet-coverage merge -r -f cobertura -o ./TestResults/Cobertura.xml ./TestResults/*.coverage
+ run: dotnet-coverage merge -f cobertura -o ./TestResults/Cobertura.xml ./TestResults/**/*.coverage
- name: Upload code coverage ${{ inputs.code-cov-prefix }}-${{ inputs.code-cov-name }}
uses: codecov/codecov-action@v4
diff --git a/.github/workflows/add-labels.yml b/.github/workflows/add-labels.yml
index 3566af9ec8..cae26b876b 100644
--- a/.github/workflows/add-labels.yml
+++ b/.github/workflows/add-labels.yml
@@ -1,25 +1,55 @@
-name: 'Add labels for area found in bug issue descriptions'
+name: 'Add labels to issues and pull requests'
on:
issues:
- types: [opened]
+ types: [ opened ]
+
+ pull_request_target:
+ branches: [ 'main*' ]
permissions:
issues: write
+ pull-requests: write
jobs:
- add-labels:
- if: ${{ !github.event.issue.pull_request }}
+ add-labels-on-issues:
+ if: github.event_name == 'issues' && !github.event.issue.pull_request
runs-on: ubuntu-latest
+
steps:
- name: check out code
uses: actions/checkout@v4
- - name: Add labels for areas found in bug issue descriptions
+ - name: Add labels for package found in bug issue descriptions
shell: pwsh
run: |
- .\build\scripts\add-labels.ps1 -issueNumber $env:ISSUE_NUMBER -issueBody $env:ISSUE_BODY
+ Import-Module .\build\scripts\add-labels.psm1
+
+ AddLabelsOnIssuesForPackageFoundInBody `
+ -issueNumber ${{ github.event.issue.number }} `
+ -issueBody $env:ISSUE_BODY
env:
GH_TOKEN: ${{ github.token }}
- ISSUE_NUMBER: ${{ github.event.issue.number }}
ISSUE_BODY: ${{ github.event.issue.body }}
+
+ add-labels-on-pull-requests:
+ if: github.event_name == 'pull_request_target'
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: check out code
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.repository.default_branch }} # Note: Do not run on the PR branch we want to execute add-labels.psm1 from main on the base repo only because pull_request_target can see secrets
+
+ - name: Add labels for files changed on pull requests
+ shell: pwsh
+ run: |
+ Import-Module .\build\scripts\add-labels.psm1
+
+ AddLabelsOnPullRequestsBasedOnFilesChanged `
+ -pullRequestNumber ${{ github.event.pull_request.number }} `
+ -labelPackagePrefix 'pkg:'
+ env:
+ GH_TOKEN: ${{ github.token }}
diff --git a/.github/workflows/automation.yml b/.github/workflows/automation.yml
new file mode 100644
index 0000000000..1385474892
--- /dev/null
+++ b/.github/workflows/automation.yml
@@ -0,0 +1,34 @@
+name: Resolve automation settings
+
+on:
+ workflow_call:
+ outputs:
+ enabled:
+ value: ${{ jobs.resolve-automation.outputs.enabled == 'true' }}
+ token-secret-name:
+ value: ${{ jobs.resolve-automation.outputs.token-secret-name }}
+ username:
+ value: ${{ vars.AUTOMATION_USERNAME }}
+ email:
+ value: ${{ vars.AUTOMATION_EMAIL }}
+ secrets:
+ OPENTELEMETRYBOT_GITHUB_TOKEN:
+ required: false
+
+jobs:
+ resolve-automation:
+
+ runs-on: ubuntu-latest
+
+ outputs:
+ enabled: ${{ steps.evaluate.outputs.enabled }}
+ token-secret-name: ${{ steps.evaluate.outputs.token-secret-name }}
+
+ env:
+ OPENTELEMETRYBOT_GITHUB_TOKEN_EXISTS: ${{ secrets.OPENTELEMETRYBOT_GITHUB_TOKEN != '' }}
+
+ steps:
+ - id: evaluate
+ run: |
+ echo "enabled=${{ env.OPENTELEMETRYBOT_GITHUB_TOKEN_EXISTS == 'true' }}" >> "$GITHUB_OUTPUT"
+ echo "token-secret-name=OPENTELEMETRYBOT_GITHUB_TOKEN" >> "$GITHUB_OUTPUT"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b1a0d80bac..73ecbd165e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -27,6 +27,7 @@ jobs:
build: ['build/**', '.github/**/*.yml', '**/*.targets', '**/*.props']
shared: ['src/Shared/**']
code: ['**.cs', '**.csproj', '.editorconfig']
+ solution: ['OpenTelemetry.sln']
packaged-code: ['src/**', '!**/*.md']
api-code: ['*/OpenTelemetry.Api*/**', '!**/*.md']
api-packages: ['src/OpenTelemetry.Api*/**', '!**/*.md']
@@ -50,19 +51,30 @@ jobs:
|| contains(needs.detect-changes.outputs.changes, 'build')
uses: ./.github/workflows/dotnet-format.yml
- build-test-solution-stable:
+ build-test-solution:
needs: detect-changes
if: |
- contains(needs.detect-changes.outputs.changes, 'code')
+ contains(needs.detect-changes.outputs.changes, 'solution')
|| contains(needs.detect-changes.outputs.changes, 'build')
|| contains(needs.detect-changes.outputs.changes, 'shared')
uses: ./.github/workflows/Component.BuildTest.yml
with:
project-name: 'OpenTelemetry.sln'
+ code-cov-name: 'Solution'
+
+ build-test-project-stable:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'code')
+ || contains(needs.detect-changes.outputs.changes, 'build')
+ || contains(needs.detect-changes.outputs.changes, 'shared')
+ uses: ./.github/workflows/Component.BuildTest.yml
+ with:
+ project-name: './build/OpenTelemetry.proj'
project-build-commands: '-p:ExposeExperimentalFeatures=false'
- code-cov-name: 'Solution-Stable'
+ code-cov-name: 'Project-Stable'
- build-test-solution-experimental:
+ build-test-project-experimental:
needs: detect-changes
if: |
contains(needs.detect-changes.outputs.changes, 'code')
@@ -70,9 +82,9 @@ jobs:
|| contains(needs.detect-changes.outputs.changes, 'shared')
uses: ./.github/workflows/Component.BuildTest.yml
with:
- project-name: 'OpenTelemetry.sln'
+ project-name: './build/OpenTelemetry.proj'
project-build-commands: '-p:ExposeExperimentalFeatures=true'
- code-cov-name: 'Solution-Experimental'
+ code-cov-name: 'Project-Experimental'
# Build unstable core libraries using stable packages released to NuGet
build-test-unstable-core:
@@ -85,7 +97,7 @@ jobs:
with:
project-name: './build/UnstableCoreLibraries.proj'
project-build-commands: '-p:RunningDotNetPack=true -p:ExposeExperimentalFeatures=true'
- code-cov-name: 'Unstable-Core'
+ code-cov-name: 'UnstableCoreLibraries-Experimental'
otlp-integration-test:
needs: detect-changes
@@ -99,7 +111,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- version: [ net6.0, net7.0, net8.0 ]
+ version: [ net8.0, net9.0 ]
steps:
- uses: actions/checkout@v4
- name: Run OTLP Exporter docker compose
@@ -117,7 +129,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- version: [ net6.0, net7.0 ]
+ version: [ net8.0, net9.0 ]
steps:
- uses: actions/checkout@v4
- name: Run W3C Trace Context docker compose
@@ -159,12 +171,13 @@ jobs:
build-test:
needs: [
- lint-misspell-sanitycheck,
detect-changes,
+ lint-misspell-sanitycheck,
lint-md,
lint-dotnet-format,
- build-test-solution-stable,
- build-test-solution-experimental,
+ build-test-solution,
+ build-test-project-stable,
+ build-test-project-experimental,
build-test-unstable-core,
otlp-integration-test,
w3c-trace-context-integration-test,
@@ -173,7 +186,8 @@ jobs:
verify-aot-compat,
concurrency-tests
]
- if: always() && !cancelled() && !contains(needs.*.result, 'failure')
- runs-on: windows-latest
+ if: always() && !cancelled()
+ runs-on: ubuntu-latest
steps:
- - run: echo 'build complete'
+ - run: |
+ if ( ${{ contains(needs.*.result, 'failure') }} == true ); then echo 'build failed'; exit 1; else echo 'build complete'; fi
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index c091dc8518..3cdd6a57b6 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -39,8 +39,8 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v4
- - name: dotnet pack OpenTelemetry.proj
- run: dotnet pack OpenTelemetry.proj --configuration Release
+ - name: dotnet pack
+ run: dotnet pack ./build/OpenTelemetry.proj --configuration Release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
diff --git a/.github/workflows/docfx.yml b/.github/workflows/docfx.yml
index 4c2031c930..76ab4f2e1e 100644
--- a/.github/workflows/docfx.yml
+++ b/.github/workflows/docfx.yml
@@ -13,6 +13,9 @@ jobs:
- name: check out code
uses: actions/checkout@v4
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v4
+
- name: install docfx
run: dotnet tool install -g docfx
diff --git a/.github/workflows/dotnet-format.yml b/.github/workflows/dotnet-format.yml
index b6baf18aab..2ea4834570 100644
--- a/.github/workflows/dotnet-format.yml
+++ b/.github/workflows/dotnet-format.yml
@@ -17,10 +17,10 @@ jobs:
uses: actions/setup-dotnet@v4
- name: dotnet restore
- run: dotnet restore
+ run: dotnet restore OpenTelemetry.sln
- name: dotnet format
- run: dotnet format OpenTelemetry.sln --no-restore --verify-no-changes
+ run: dotnet format OpenTelemetry.sln --no-restore --verify-no-changes # Note: .proj files are currently not supported by dotnet format
env:
ExposeExperimentalFeatures: false
@@ -35,9 +35,9 @@ jobs:
uses: actions/setup-dotnet@v4
- name: dotnet restore
- run: dotnet restore
+ run: dotnet restore OpenTelemetry.sln
- name: dotnet format
- run: dotnet format OpenTelemetry.sln --no-restore --verify-no-changes
+ run: dotnet format OpenTelemetry.sln --no-restore --verify-no-changes # Note: .proj files are currently not supported by dotnet format
env:
ExposeExperimentalFeatures: true
diff --git a/.github/workflows/package-validation.yml b/.github/workflows/package-validation.yml
index 757b38c18a..d1f7658ee2 100644
--- a/.github/workflows/package-validation.yml
+++ b/.github/workflows/package-validation.yml
@@ -20,8 +20,8 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v4
- - name: Pack
- run: dotnet pack OpenTelemetry.proj --configuration Release /p:EnablePackageValidation=true /p:ExposeExperimentalFeatures=false /p:RunningDotNetPack=true
+ - name: dotnet pack
+ run: dotnet pack ./build/OpenTelemetry.proj --configuration Release /p:EnablePackageValidation=true /p:ExposeExperimentalFeatures=false /p:RunningDotNetPack=true
run-package-validation-experimental:
runs-on: windows-latest
@@ -37,5 +37,5 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v4
- - name: Pack
- run: dotnet pack OpenTelemetry.proj --configuration Release /p:EnablePackageValidation=true /p:ExposeExperimentalFeatures=true /p:RunningDotNetPack=true
+ - name: dotnet pack
+ run: dotnet pack ./build/OpenTelemetry.proj --configuration Release /p:EnablePackageValidation=true /p:ExposeExperimentalFeatures=true /p:RunningDotNetPack=true
diff --git a/.github/workflows/post-release.yml b/.github/workflows/post-release.yml
new file mode 100644
index 0000000000..249fd360da
--- /dev/null
+++ b/.github/workflows/post-release.yml
@@ -0,0 +1,122 @@
+name: Complete release
+
+on:
+ workflow_dispatch:
+ inputs:
+ tag:
+ required: true
+ description: 'Release tag'
+ type: string
+
+ release:
+ types:
+ - published
+
+ issue_comment:
+ types:
+ - created
+
+jobs:
+ automation:
+ uses: ./.github/workflows/automation.yml
+ secrets: inherit
+
+ push-packages-and-publish-release:
+ runs-on: ubuntu-latest
+
+ needs: automation
+
+ if: |
+ github.event_name == 'issue_comment'
+ && github.event.issue.pull_request
+ && github.event.issue.locked == true
+ && github.event.comment.user.login != needs.automation.outputs.username
+ && contains(github.event.comment.body, '/PushPackages')
+ && startsWith(github.event.issue.title, '[release] Prepare release ')
+ && github.event.issue.pull_request.merged_at
+ && needs.automation.outputs.enabled
+
+ env:
+ GH_TOKEN: ${{ secrets[needs.automation.outputs.token-secret-name] }}
+
+ steps:
+ - name: check out code
+ uses: actions/checkout@v4
+ with:
+ token: ${{ secrets[needs.automation.outputs.token-secret-name] }}
+ ref: ${{ github.event.repository.default_branch }}
+
+ - name: Push packages and publish release
+ shell: pwsh
+ env:
+ NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
+ run: |
+ Import-Module .\build\scripts\post-release.psm1
+
+ PushPackagesPublishReleaseUnlockAndPostNoticeOnPrepareReleasePullRequest `
+ -gitRepository '${{ github.repository }}' `
+ -pullRequestNumber '${{ github.event.issue.number }}' `
+ -botUserName '${{ needs.automation.outputs.username }}' `
+ -commentUserName '${{ github.event.comment.user.login }}' `
+ -artifactDownloadPath '${{ github.workspace }}/artifacts' `
+ -pushToNuget '${{ secrets.NUGET_TOKEN != '' }}'
+
+ post-release-published:
+ runs-on: ubuntu-latest
+
+ needs:
+ - automation
+
+ if: |
+ needs.automation.outputs.enabled
+ && (github.event_name == 'release' || github.event_name == 'workflow_dispatch')
+
+ env:
+ GH_TOKEN: ${{ secrets[needs.automation.outputs.token-secret-name] }}
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ # Note: By default GitHub only fetches 1 commit. We need all the tags
+ # for this work.
+ fetch-depth: 0
+ ref: ${{ github.event.repository.default_branch }}
+ token: ${{ secrets[needs.automation.outputs.token-secret-name] }}
+
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v4
+
+ - name: Create GitHub Pull Request to update stable build version in props
+ if: |
+ (github.ref_type == 'tag' && startsWith(github.ref_name, 'core-') && !contains(github.ref_name, '-alpha') && !contains(github.ref_name, '-beta') && !contains(github.ref_name, '-rc'))
+ || (inputs.tag && startsWith(inputs.tag, 'core-') && !contains(inputs.tag, '-alpha') && !contains(inputs.tag, '-beta') && !contains(inputs.tag, '-rc'))
+ shell: pwsh
+ run: |
+ Import-Module .\build\scripts\post-release.psm1
+
+ CreateStableVersionUpdatePullRequest `
+ -gitRepository '${{ github.repository }}' `
+ -tag '${{ inputs.tag || github.ref_name }}' `
+ -targetBranch '${{ github.event.repository.default_branch }}' `
+ -gitUserName '${{ needs.automation.outputs.username }}' `
+ -gitUserEmail '${{ needs.automation.outputs.email }}'
+
+ - name: Invoke core version update workflow in opentelemetry-dotnet-contrib repository
+ if: vars.CONTRIB_REPO
+ shell: pwsh
+ run: |
+ Import-Module .\build\scripts\post-release.psm1
+
+ InvokeCoreVersionUpdateWorkflowInRemoteRepository `
+ -remoteGitRepository '${{ vars.CONTRIB_REPO }}' `
+ -tag '${{ inputs.tag || github.ref_name }}'
+
+ - name: Post notice when release is published
+ shell: pwsh
+ run: |
+ Import-Module .\build\scripts\post-release.psm1
+
+ TryPostReleasePublishedNoticeOnPrepareReleasePullRequest `
+ -gitRepository '${{ github.repository }}' `
+ -botUserName '${{ needs.automation.outputs.username }}' `
+ -tag '${{ inputs.tag || github.ref_name }}'
diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml
index fb54dfd04f..a731bbd405 100644
--- a/.github/workflows/prepare-release.yml
+++ b/.github/workflows/prepare-release.yml
@@ -23,19 +23,26 @@ on:
types:
- created
-permissions:
- contents: write
- pull-requests: write
-
jobs:
+ automation:
+ uses: ./.github/workflows/automation.yml
+ secrets: inherit
+
prepare-release-pr:
- if: github.event_name == 'workflow_dispatch'
+ runs-on: ubuntu-latest
+
+ needs: automation
+
+ if: github.event_name == 'workflow_dispatch' && needs.automation.outputs.enabled
- runs-on: windows-latest
+ env:
+ GH_TOKEN: ${{ secrets[needs.automation.outputs.token-secret-name] }}
steps:
- name: check out code
uses: actions/checkout@v4
+ with:
+ token: ${{ secrets[needs.automation.outputs.token-secret-name] }}
- name: Create GitHub Pull Request to prepare release
shell: pwsh
@@ -43,25 +50,35 @@ jobs:
Import-Module .\build\scripts\prepare-release.psm1
CreatePullRequestToUpdateChangelogsAndPublicApis `
+ -gitRepository '${{ github.repository }}' `
-minVerTagPrefix '${{ inputs.tag-prefix }}' `
-version '${{ inputs.version }}' `
- -targetBranch '${{ github.ref_name }}'
- env:
- GH_TOKEN: ${{ github.token }}
+ -requestedByUserName '${{ github.event.sender.login }}' `
+ -targetBranch '${{ github.ref_name }}' `
+ -gitUserName '${{ needs.automation.outputs.username }}' `
+ -gitUserEmail '${{ needs.automation.outputs.email }}'
lock-pr-and-post-notice-to-create-release-tag:
+ runs-on: ubuntu-latest
+
+ needs: automation
+
if: |
github.event_name == 'pull_request'
&& github.event.action == 'closed'
- && github.event.pull_request.user.login == 'github-actions[bot]'
+ && github.event.pull_request.user.login == needs.automation.outputs.username
&& github.event.pull_request.merged == true
- && startsWith(github.event.pull_request.title, '[repo] Prepare release ')
+ && startsWith(github.event.pull_request.title, '[release] Prepare release ')
+ && needs.automation.outputs.enabled
- runs-on: windows-latest
+ env:
+ GH_TOKEN: ${{ secrets[needs.automation.outputs.token-secret-name] }}
steps:
- name: check out code
uses: actions/checkout@v4
+ with:
+ token: ${{ secrets[needs.automation.outputs.token-secret-name] }}
- name: Lock GitHub Pull Request to prepare release
shell: pwsh
@@ -69,23 +86,27 @@ jobs:
Import-Module .\build\scripts\prepare-release.psm1
LockPullRequestAndPostNoticeToCreateReleaseTag `
- -pullRequestNumber '${{ github.event.pull_request.number }}'
- env:
- GH_TOKEN: ${{ github.token }}
+ -gitRepository '${{ github.repository }}' `
+ -pullRequestNumber '${{ github.event.pull_request.number }}' `
+ -botUserName '${{ needs.automation.outputs.username }}'
+
+ create-release-tag-pr-post-notice:
+ runs-on: ubuntu-latest
+
+ needs: automation
- create-release-tag-unlock-pr-post-notice:
if: |
github.event_name == 'issue_comment'
&& github.event.issue.pull_request
&& github.event.issue.locked == true
+ && github.event.comment.user.login != needs.automation.outputs.username
&& contains(github.event.comment.body, '/CreateReleaseTag')
- && startsWith(github.event.issue.title, '[repo] Prepare release ')
+ && startsWith(github.event.issue.title, '[release] Prepare release ')
&& github.event.issue.pull_request.merged_at
+ && needs.automation.outputs.enabled
- runs-on: windows-latest
-
- outputs:
- tag: ${{ steps.create-tag.outputs.tag }}
+ env:
+ GH_TOKEN: ${{ secrets[needs.automation.outputs.token-secret-name] }}
steps:
- name: check out code
@@ -93,6 +114,7 @@ jobs:
with:
# Note: By default GitHub only fetches 1 commit which fails the git tag operation below
fetch-depth: 0
+ token: ${{ secrets[needs.automation.outputs.token-secret-name] }}
- name: Create release tag
id: create-tag
@@ -100,40 +122,50 @@ jobs:
run: |
Import-Module .\build\scripts\prepare-release.psm1
- $tag = ''
-
- CreateReleaseTag `
+ CreateReleaseTagAndPostNoticeOnPullRequest `
+ -gitRepository '${{ github.repository }}' `
-pullRequestNumber '${{ github.event.issue.number }}' `
- -actionRunId '${{ github.run_id }}' `
- -tag ([ref]$tag)
-
- echo "tag=$tag" >> $env:GITHUB_OUTPUT
- env:
- GH_TOKEN: ${{ github.token }}
-
- invoke-package-workflow:
- needs: create-release-tag-unlock-pr-post-notice
- uses: ./.github/workflows/publish-packages-1.0.yml
- with:
- tag: ${{ needs.create-release-tag-unlock-pr-post-notice.outputs.tag }}
-
- post-packages-ready-notice:
- needs:
- - create-release-tag-unlock-pr-post-notice
- - invoke-package-workflow
- runs-on: windows-latest
+ -botUserName '${{ needs.automation.outputs.username }}' `
+ -gitUserName '${{ needs.automation.outputs.username }}' `
+ -gitUserEmail '${{ needs.automation.outputs.email }}'
+
+ update-changelog-release-dates-on-prepare-pr-post-notice:
+ runs-on: ubuntu-latest
+
+ needs: automation
+
+ if: |
+ github.event_name == 'issue_comment'
+ && github.event.issue.pull_request
+ && github.event.issue.state == 'open'
+ && github.event.comment.user.login != needs.automation.outputs.username
+ && contains(github.event.comment.body, '/UpdateReleaseDates')
+ && startsWith(github.event.issue.title, '[release] Prepare release ')
+ && github.event.issue.pull_request.merged_at == null
+ && needs.automation.outputs.enabled
+
+ env:
+ GH_TOKEN: ${{ secrets[needs.automation.outputs.token-secret-name] }}
+
steps:
- name: check out code
uses: actions/checkout@v4
+ with:
+ # Note: By default GitHub only fetches 1 commit which fails the git tag operation below
+ fetch-depth: 0
+ token: ${{ secrets[needs.automation.outputs.token-secret-name] }}
- - name: Post notice when packages are ready
+ - name: Update release date
+ id: create-tag
shell: pwsh
run: |
Import-Module .\build\scripts\prepare-release.psm1
- PostPackagesReadyNotice `
+ UpdateChangelogReleaseDatesAndPostNoticeOnPullRequest `
+ -gitRepository '${{ github.repository }}' `
-pullRequestNumber '${{ github.event.issue.number }}' `
- -tag '${{ needs.create-release-tag-unlock-pr-post-notice.outputs.tag }}' `
- -packagesUrl '${{ needs.invoke-package-workflow.outputs.artifact-url }}'
- env:
- GH_TOKEN: ${{ github.token }}
+ -botUserName '${{ needs.automation.outputs.username }}' `
+ -commentUserName '${{ github.event.comment.user.login }}' `
+ -gitUserName '${{ needs.automation.outputs.username }}' `
+ -gitUserEmail '${{ needs.automation.outputs.email }}'
+
diff --git a/.github/workflows/publish-packages-1.0.yml b/.github/workflows/publish-packages-1.0.yml
index dd2e568f2d..df29e3af55 100644
--- a/.github/workflows/publish-packages-1.0.yml
+++ b/.github/workflows/publish-packages-1.0.yml
@@ -13,30 +13,26 @@ on:
tags:
- 'core-*'
- 'coreunstable-*'
- workflow_call:
- inputs:
- tag:
- required: true
- type: string
- outputs:
- artifact-id:
- value: ${{ jobs.build-pack-publish.outputs.artifact-id }}
- artifact-url:
- value: ${{ jobs.build-pack-publish.outputs.artifact-url }}
schedule:
- cron: '0 0 * * *' # once in a day at 00:00
-permissions:
- contents: write
- pull-requests: write
-
jobs:
+ automation:
+ uses: ./.github/workflows/automation.yml
+ secrets: inherit
+
build-pack-publish:
runs-on: windows-latest
+ permissions:
+ contents: read
+ id-token: write
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ COSIGN_YES: "yes"
outputs:
- artifact-id: ${{ steps.upload-artifacts.outputs.artifact-id }}
artifact-url: ${{ steps.upload-artifacts.outputs.artifact-url }}
+ artifact-id: ${{ steps.upload-artifacts.outputs.artifact-id }}
steps:
- uses: actions/checkout@v4
@@ -45,26 +41,46 @@ jobs:
# the version tag which is typically NOT on the first commit so we
# retrieve them all.
fetch-depth: 0
- ref: ${{ inputs.tag || github.ref || 'main' }}
- name: Setup dotnet
uses: actions/setup-dotnet@v4
+ - name: Install Cosign
+ uses: sigstore/cosign-installer@v3
+ with:
+ cosign-release: v2.4.0
+
- name: dotnet restore
- run: dotnet restore OpenTelemetry.proj -p:RunningDotNetPack=true
+ run: dotnet restore ./build/OpenTelemetry.proj -p:RunningDotNetPack=true
- name: dotnet build
- run: dotnet build OpenTelemetry.proj --configuration Release --no-restore -p:Deterministic=true -p:BuildNumber=${{ github.run_number }} -p:RunningDotNetPack=true
+ run: dotnet build ./build/OpenTelemetry.proj --configuration Release --no-restore -p:Deterministic=true -p:BuildNumber=${{ github.run_number }} -p:RunningDotNetPack=true
+
+ - name: Sign DLLs with Cosign Keyless
+ shell: pwsh
+ run: |
+ $projectFiles = Get-ChildItem -Path src/*/*.csproj -File
+
+ foreach ($projectFile in $projectFiles) {
+ $projectName = [System.IO.Path]::GetFileNameWithoutExtension($projectFile)
+
+ Get-ChildItem -Path src/$projectName/bin/Release/*/$projectName.dll -File | ForEach-Object {
+ $fileFullPath = $_.FullName
+ Write-Host "Signing $fileFullPath"
+
+ cosign.exe sign-blob $fileFullPath --yes --output-signature $fileFullPath-keyless.sig --output-certificate $fileFullPath-keyless.pem
+ }
+ }
- name: dotnet pack
- run: dotnet pack OpenTelemetry.proj --configuration Release --no-restore --no-build -p:PackTag=${{ github.ref_type == 'tag' && github.ref_name || inputs.tag || '' }}
+ run: dotnet pack ./build/OpenTelemetry.proj --configuration Release --no-restore --no-build -p:PackTag=${{ github.ref_type == 'tag' && github.ref_name || '' }}
- name: Publish Artifacts
id: upload-artifacts
uses: actions/upload-artifact@v4
with:
- name: ${{ inputs.tag || github.ref_name }}-packages
- path: '**/bin/**/*.*nupkg'
+ name: ${{ github.ref_name }}-packages
+ path: 'src/**/*.*nupkg'
- name: Publish MyGet
env:
@@ -72,28 +88,56 @@ jobs:
if: env.MYGET_TOKEN_EXISTS == 'true' # Skip MyGet publish if run on a fork without the secret
run: |
nuget setApiKey ${{ secrets.MYGET_TOKEN }} -Source https://www.myget.org/F/opentelemetry/api/v2/package
- nuget push **/bin/**/*.nupkg -Source https://www.myget.org/F/opentelemetry/api/v2/package
+ nuget push src/**/*.nupkg -Source https://www.myget.org/F/opentelemetry/api/v2/package
+
+ post-build:
+ runs-on: ubuntu-latest
+
+ needs:
+ - automation
+ - build-pack-publish
+
+ if: needs.automation.outputs.enabled && github.event_name == 'push'
+
+ env:
+ GH_TOKEN: ${{ secrets[needs.automation.outputs.token-secret-name] }}
+
+ steps:
+ - name: check out code
+ uses: actions/checkout@v4
+ with:
+ token: ${{ secrets[needs.automation.outputs.token-secret-name] }}
+
+ - name: Download Artifacts
+ run: |
+ curl \
+ -H "Accept: application/vnd.github+json" \
+ -H "Authorization: token ${{ github.token }}" \
+ -L \
+ -o '${{ github.workspace }}/artifacts/${{ github.ref_name }}-packages.zip' \
+ --create-dirs \
+ "https://api.github.com/repos/${{ github.repository }}/actions/artifacts/${{ needs.build-pack-publish.outputs.artifact-id }}/zip"
- name: Create GitHub Release draft
- if: github.ref_type == 'tag' || inputs.tag
shell: pwsh
run: |
Import-Module .\build\scripts\post-release.psm1
CreateDraftRelease `
- -tag '${{ inputs.tag || github.ref_name }}'
- env:
- GH_TOKEN: ${{ github.token }}
+ -gitRepository '${{ github.repository }}' `
+ -tag '${{ github.ref_name }}' `
+ -releaseFiles '${{ github.workspace }}/artifacts/${{ github.ref_name }}-packages.zip#Packages'
- - name: Create GitHub draft Pull Request to update stable build version in props
- if: |
- (github.ref_type == 'tag' && startsWith(github.ref_name, 'core-') && !contains(github.ref_name, '-alpha') && !contains(github.ref_name, '-beta') && !contains(github.ref_name, '-rc'))
- || (inputs.tag && startsWith(inputs.tag, 'core-') && !contains(inputs.tag, '-alpha') && !contains(inputs.tag, '-beta') && !contains(inputs.tag, '-rc'))
+ - name: Post notice when packages are ready
shell: pwsh
run: |
Import-Module .\build\scripts\post-release.psm1
- CreateStableVersionUpdatePullRequest `
- -tag '${{ inputs.tag || github.ref_name }}'
- env:
- GH_TOKEN: ${{ github.token }}
+ TryPostPackagesReadyNoticeOnPrepareReleasePullRequest `
+ -gitRepository '${{ github.repository }}' `
+ -tag '${{ github.ref_name }}' `
+ -tagSha '${{ github.sha }}' `
+ -packagesUrl '${{ needs.build-pack-publish.outputs.artifact-url }}' `
+ -botUserName '${{ needs.automation.outputs.username }}'
+
+
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index f5657aa9f5..9be0713edb 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -1,7 +1,7 @@
# Syntax: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
# Github Actions Stale: https://github.com/actions/stale
-name: "Close stale pull requests"
+name: "Manage stale issues and pull requests"
on:
schedule:
- cron: "12 3 * * *" # arbitrary time not to DDOS GitHub
@@ -12,10 +12,14 @@ jobs:
steps:
- uses: actions/stale@v9
with:
- stale-pr-message: 'This PR was marked stale due to lack of activity and will be closed in 7 days. Commenting or Pushing will instruct the bot to automatically remove the label. This bot runs once per day.'
+ stale-issue-message: 'This issue was marked stale due to lack of activity and will be closed in 7 days. Commenting will instruct the bot to automatically remove the label. This bot runs once per day.'
+ close-issue-message: 'Closed as inactive. Feel free to reopen if this issue is still a concern.'
+ stale-pr-message: 'This PR was marked stale due to lack of activity and will be closed in 7 days. Commenting or pushing will instruct the bot to automatically remove the label. This bot runs once per day.'
close-pr-message: 'Closed as inactive. Feel free to reopen if this PR is still being worked on.'
operations-per-run: 400
days-before-pr-stale: 7
- days-before-issue-stale: -1
+ days-before-issue-stale: 300
days-before-pr-close: 7
- days-before-issue-close: -1
+ days-before-issue-close: 7
+ exempt-all-issue-milestones: true
+ exempt-issue-labels: needs-triage
diff --git a/.github/workflows/verifyaotcompat.yml b/.github/workflows/verifyaotcompat.yml
index 24991b9fe3..3bdc42e3e7 100644
--- a/.github/workflows/verifyaotcompat.yml
+++ b/.github/workflows/verifyaotcompat.yml
@@ -12,7 +12,7 @@ jobs:
fail-fast: false # ensures the entire test matrix is run, even if one permutation fails
matrix:
os: [ ubuntu-latest, windows-latest ]
- version: [ net8.0 ]
+ version: [ net8.0, net9.0 ]
runs-on: ${{ matrix.os }}
steps:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7a9590b068..02f8d2dd57 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -10,8 +10,8 @@ for a summary description of past meetings. To request edit access, join the
meeting or get in touch on
[Slack](https://cloud-native.slack.com/archives/C01N3BC2W7Q).
-Even though, anybody can contribute, there are benefits of being a member of our
-community. See to the [community membership
+Anyone may contribute but there are benefits of being a member of our community.
+See the [community membership
document](https://github.com/open-telemetry/community/blob/main/community-membership.md)
on how to become a
[**Member**](https://github.com/open-telemetry/community/blob/main/community-membership.md#member),
@@ -19,7 +19,7 @@ on how to become a
and
[**Maintainer**](https://github.com/open-telemetry/community/blob/main/community-membership.md#maintainer).
-## Find a Buddy and Get Started Quickly
+## Find a buddy and get started quickly
If you are looking for someone to help you find a starting point and be a
resource for your first contribution, join our Slack channel and find a buddy!
@@ -34,17 +34,24 @@ resource for your first contribution, join our Slack channel and find a buddy!
Your OpenTelemetry buddy is your resource to talk to directly on all aspects of
contributing to OpenTelemetry: providing context, reviewing PRs, and helping
-those get merged. Buddies will not be available 24/7, but is committed to
-responding during their normal contribution hours.
+those get merged. Buddies will not be available 24/7, but are committed to
+responding during their normal working hours.
## Development Environment
-You can contribute to this project from a Windows, macOS or Linux machine.
+You can contribute to this project from a Windows, macOS, or Linux machine.
On all platforms, the minimum requirements are:
-* Git client and command line tools.
-* .NET 8.0
+* Git client and command line tools
+
+* [.NET SDK (latest stable version)](https://dotnet.microsoft.com/download)
+
+ > [!NOTE]
+ > At times a pre-release version of the .NET SDK may be required to build code
+ in this repository. Check
+ [global.json](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/global.json)
+ to verify the current required version.
### Linux or MacOS
@@ -59,42 +66,97 @@ of Windows.
* Visual Studio 2022+ or Visual Studio Code
* .NET Framework 4.6.2+
-### Public API
-
-It is critical to keep public API surface small and clean. This repository is
-using `Microsoft.CodeAnalysis.PublicApiAnalyzers` to validate the public APIs.
-This analyzer will check if you changed a public property/method so the change
-will be easily spotted in pull request. It will also ensure that OpenTelemetry
-doesn't expose APIs outside of the library primary concerns like a generic
-helper methods.
-
-#### How to enable and configure
-
-* Create a folder in your project called `.publicApi` with the frameworks that
- as folders you target.
-* Create two files called `PublicAPI.Shipped.txt` and `PublicAPI.Unshipped.txt`
- in each framework that you target.
-* Add the following lines to your csproj:
-
-```xml
-
-
-
-
-```
-
-* Use
- [IntelliSense](https://docs.microsoft.com/visualstudio/ide/using-intellisense)
- to update the publicApi files.
+## Public API validation
+
+It is critical to **NOT** make breaking changes to public APIs which have been
+released in stable builds. We also strive to keep a minimal public API surface.
+This repository is using
+[Microsoft.CodeAnalysis.PublicApiAnalyzers](https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
+and [Package
+validation](https://learn.microsoft.com/dotnet/fundamentals/apicompat/package-validation/overview)
+to validate public APIs.
+
+* `Microsoft.CodeAnalysis.PublicApiAnalyzers` will validate public API
+ changes/additions against a set of "public API files" which capture the
+ shipped/unshipped public APIs. These files must be maintained manually (not
+ recommended) or by using tooling/code fixes built into the package (see below
+ for details).
+
+ Public API files are also used to perform public API reviews by repo
+ approvers/maintainers before releasing stable builds.
+
+* `Package validation` will validate public API changes/additions against
+ previously released NuGet packages.
+
+ This is performed automatically by the build/CI
+ [package-validation](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/.github/workflows/package-validation.yml)
+ workflow.
+
+ By default package validation is **NOT** run for local builds. To enable
+ package validation in local builds set the `EnablePackageValidation` property
+ to `true` in
+ [Common.prod.props](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/build/Common.prod.props)
+ (please do not check in this change).
+
+### Working with Microsoft.CodeAnalysis.PublicApiAnalyzers
+
+#### Update public API files when writing code
+
+[IntelliSense](https://docs.microsoft.com/visualstudio/ide/using-intellisense)
+will [suggest
+modifications](https://github.com/dotnet/roslyn-analyzers/issues/3322#issuecomment-591031429)
+to the `PublicAPI.Unshipped.txt` file when you make changes. After reviewing
+these changes, ensure they are reflected across all targeted frameworks. You can
+do this by:
+
+* Using the "Fix all occurrences in Project" feature in Visual Studio.
+
+* Manually cycling through each framework using Visual Studio's target framework
+ dropdown (in the upper right corner) and applying the IntelliSense
+ suggestions.
+
+> [!IMPORTANT]
+> Do **NOT** modify `PublicAPI.Shipped.txt` files. New features and bug fixes
+ **SHOULD** only require changes to `PublicAPI.Unshipped.txt` files. If you
+ have to modify a "shipped" file it likely means you made a mistake and broke a
+ stable API. Typically only maintainers modify the `PublicAPI.Shipped.txt` file
+ while performing stable releases. If you need help reach out to an approver or
+ maintainer on Slack or open a draft PR.
+
+#### Enable public API validation in new projects
+
+1. If you are **NOT** using experimental APIs:
+ * If your API is the same across all target frameworks:
+ * You only need two files: `.publicApi/PublicAPI.Shipped.txt` and
+ `.publicApi/PublicAPI.Unshipped.txt`.
+ * If your APIs differ between target frameworks:
+ * Place the shared APIs in `.publicApi/PublicAPI.Shipped.txt` and
+ `.publicApi/PublicAPI.Unshipped.txt`.
+ * Create framework-specific files for API differences (e.g.,
+ `.publicApi/net462/PublicAPI.Shipped.txt` and
+ `.publicApi/net462/PublicAPI.Unshipped.txt`).
+
+2. If you are using experimental APIs:
+ * Follow the rules above, but create an additional layer in your folder
+ structure:
+ * For stable APIs: `.publicApi/Stable/*`.
+ * For experimental APIs: `.publicApi/Experimental/*`.
+ * The `Experimental` folder should contain APIs that are public only in
+ pre-release builds. Typically the `Experimental` folder only contains
+ `PublicAPI.Unshipped.txt` files as experimental APIs are never shipped
+ stable.
+
+ Example folder structure can be found
+ [here](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry.Api/.publicApi).
## Pull Requests
-### How to Send Pull Requests
+### How to create pull requests
Everyone is welcome to contribute code to `opentelemetry-dotnet` via GitHub pull
requests (PRs).
-To create a new PR, fork the project in GitHub and clone the upstream repo:
+To create a new PR, fork the project on GitHub and clone the upstream repo:
```sh
git clone https://github.com/open-telemetry/opentelemetry-dotnet.git
@@ -125,7 +187,7 @@ If you made changes to the Markdown documents (`*.md` files), install the latest
markdownlint .
```
-Check out a new branch, make modifications and push the branch to your fork:
+Check out a new branch, make modifications, and push the branch to your fork:
```sh
$ git checkout -b feature
@@ -136,20 +198,26 @@ $ git push fork feature
Open a pull request against the main `opentelemetry-dotnet` repo.
-### How to Receive Comments
+#### Tips and best practices for pull requests
* If the PR is not ready for review, please mark it as
[`draft`](https://github.blog/2019-02-14-introducing-draft-pull-requests/).
* Make sure CLA is signed and all required CI checks are clear.
-* Submit small, focused PRs addressing a single
- concern/issue.
+* Submit small, focused PRs addressing a single concern/issue.
* Make sure the PR title reflects the contribution.
* Write a summary that helps understand the change.
* Include usage examples in the summary, where applicable.
* Include benchmarks (before/after) in the summary, for contributions that are
performance enhancements.
+* We are open to bot generated PRs or AI/LLM assisted PRs. Actually, we are
+ using
+ [dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates)
+ to automate the security updates. However, if you use bots to generate spam
+ PRs (e.g. incorrect, noisy, non-improvements, unintelligible, trying to sell
+ your product, etc.), we might close the PR right away with a warning, and if
+ you keep doing so, we might block your user account.
-### How to Get PRs Merged
+### How to get pull requests merged
A PR is considered to be **ready to merge** when:
@@ -157,18 +225,21 @@ A PR is considered to be **ready to merge** when:
[Approvers](https://github.com/open-telemetry/community/blob/main/community-membership.md#approver).
/
[Maintainers](https://github.com/open-telemetry/community/blob/main/community-membership.md#maintainer).
-* Major feedbacks are resolved.
+* Major feedback/comments are resolved.
* It has been open for review for at least one working day. This gives people
reasonable time to review.
-* Trivial change (typo, cosmetic, doc, etc.) doesn't have to wait for one day.
-* Urgent fix can take exception as long as it has been actively communicated.
+ * Trivial change (typo, cosmetic, doc, etc.) doesn't have to wait for one day.
+ * Urgent fix can take exception as long as it has been actively communicated.
-Any Maintainer can merge the PR once it is **ready to merge**. Note, that some
-PRs may not be merged immediately if the repo is in the process of a release and
-the maintainers decided to defer the PR to the next release train.
+Any maintainer can merge PRs once they are **ready to merge** however
+maintainers might decide to wait on merging changes until there are more
+approvals and/or dicussion, or based on other factors such as release timing and
+risk to users. For example if a stable release is planned and a new change is
+introduced adding public API(s) or behavioral changes it might be held until the
+next alpha/beta release.
-If a PR has been stuck (e.g. there are lots of debates and people couldn't agree
-on each other), the owner should try to get people aligned by:
+If a PR has become stuck (e.g. there is a lot of debate and people couldn't
+agree on the direction), the owner should try to get people aligned by:
* Consolidating the perspectives and putting a summary in the PR. It is
recommended to add a link into the PR description, which points to a comment
@@ -183,7 +254,7 @@ on each other), the owner should try to get people aligned by:
the owner should bring it to the OpenTelemetry .NET SIG
[meeting](README.md#contributing).
-## Design Choices
+## Design choices
As with other OpenTelemetry clients, opentelemetry-dotnet follows the
[opentelemetry-specification](https://github.com/open-telemetry/opentelemetry-specification).
@@ -191,7 +262,7 @@ As with other OpenTelemetry clients, opentelemetry-dotnet follows the
It's especially valuable to read through the [library
guidelines](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/library-guidelines.md).
-### Focus on Capabilities, Not Structure Compliance
+### Focus on capabilities not structural compliance
OpenTelemetry is an evolving specification, one where the desires and use cases
are clear, but the method to satisfy those uses cases are not.
@@ -205,10 +276,10 @@ than conform to specific API names or argument patterns in the spec.
For a deeper discussion, see [this spec
issue](https://github.com/open-telemetry/opentelemetry-specification/issues/165).
-## Style Guide
+## Style guide
This project includes a [`.editorconfig`](./.editorconfig) file which is
-supported by all the IDEs/editor mentioned above. It works with the IDE/editor
+supported by all the IDEs/editors mentioned above. It works with the IDE/editor
only and does not affect the actual build of the project.
This repository also includes StyleCop ruleset files under the `./build` folder.
@@ -237,23 +308,6 @@ analysis](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/overview
[Common.props](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/build/Common.props)
new projects must NOT manually override these settings.
-## New code
-
-New code files MUST enable [nullable reference
-types](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/nullable-reference-types)
-manually in projects where it is not automatically enabled project-wide. This is
-done by specifying `#nullable enable` towards the top of the file (usually after
-the copyright header). We are currently working towards enabling nullable
-context in every project by updating code as it is worked on, this requirement
-is to make sure the surface area of code needing updates is shrinking and not
-expanding.
-
-> [!NOTE]
-> The first time a project is updated to use nullable context in public APIs
-some housekeeping needs to be done in public API definitions (`.publicApi`
-folder). This can be done automatically via a code fix offered by the public API
-analyzer.
-
## License requirements
OpenTelemetry .NET is licensed under the [Apache License, Version
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 6469f47b89..7678397d0e 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,7 +1,19 @@
+
true
- 1.8.1
+ 1.9.0
+
+
+ 9.0.0-rc.1.24431.7
+
+
+ 8.0.0
+ 8.0.5
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
-
+
+
+
+
+
+
+
+
-
+
+
-
-
+
+
+
-
-
+
-
-
-
-
-
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln
index 5150016a12..1b3928c116 100644
--- a/OpenTelemetry.sln
+++ b/OpenTelemetry.sln
@@ -17,8 +17,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
global.json = global.json
LICENSE.TXT = LICENSE.TXT
NuGet.config = NuGet.config
- OpenTelemetry.proj = OpenTelemetry.proj
README.md = README.md
+ RELEASENOTES.md = RELEASENOTES.md
THIRD-PARTY-NOTICES.TXT = THIRD-PARTY-NOTICES.TXT
VERSIONING.md = VERSIONING.md
EndProjectSection
@@ -28,16 +28,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{7CB2F02E
build\Common.nonprod.props = build\Common.nonprod.props
build\Common.prod.props = build\Common.prod.props
build\Common.props = build\Common.props
+ build\Common.targets = build\Common.targets
build\debug.snk = build\debug.snk
Directory.Packages.props = Directory.Packages.props
build\docfx.cmd = build\docfx.cmd
- build\docker-compose.net6.0.yml = build\docker-compose.net6.0.yml
- build\docker-compose.net7.0.yml = build\docker-compose.net7.0.yml
build\docker-compose.net8.0.yml = build\docker-compose.net8.0.yml
+ build\docker-compose.net9.0.yml = build\docker-compose.net9.0.yml
build\GlobalAttrExclusions.txt = build\GlobalAttrExclusions.txt
build\opentelemetry-icon-color.png = build\opentelemetry-icon-color.png
build\OpenTelemetry.prod.loose.ruleset = build\OpenTelemetry.prod.loose.ruleset
build\OpenTelemetry.prod.ruleset = build\OpenTelemetry.prod.ruleset
+ build\OpenTelemetry.proj = build\OpenTelemetry.proj
build\OpenTelemetry.test.ruleset = build\OpenTelemetry.test.ruleset
build\RELEASING.md = build\RELEASING.md
build\stylecop.json = build\stylecop.json
@@ -80,12 +81,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEM
ProjectSection(SolutionItems) = preProject
.github\ISSUE_TEMPLATE\bug_report.yml = .github\ISSUE_TEMPLATE\bug_report.yml
.github\ISSUE_TEMPLATE\feature_request.yml = .github\ISSUE_TEMPLATE\feature_request.yml
- .github\ISSUE_TEMPLATE\question.yml = .github\ISSUE_TEMPLATE\question.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{E69578EB-B456-4062-A645-877CD964528B}"
ProjectSection(SolutionItems) = preProject
.github\workflows\add-labels.yml = .github\workflows\add-labels.yml
+ .github\workflows\automation.yml = .github\workflows\automation.yml
.github\workflows\ci.yml = .github\workflows\ci.yml
.github\workflows\codeql-analysis.yml = .github\workflows\codeql-analysis.yml
.github\workflows\Component.BuildTest.yml = .github\workflows\Component.BuildTest.yml
@@ -94,6 +95,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
.github\workflows\dotnet-format.yml = .github\workflows\dotnet-format.yml
.github\workflows\markdownlint.yml = .github\workflows\markdownlint.yml
.github\workflows\package-validation.yml = .github\workflows\package-validation.yml
+ .github\workflows\post-release.yml = .github\workflows\post-release.yml
.github\workflows\prepare-release.yml = .github\workflows\prepare-release.yml
.github\workflows\publish-packages-1.0.yml = .github\workflows\publish-packages-1.0.yml
.github\workflows\sanitycheck.yml = .github\workflows\sanitycheck.yml
@@ -111,7 +113,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D2E73927-5
ProjectSection(SolutionItems) = preProject
test\Directory.Build.props = test\Directory.Build.props
test\Directory.Build.targets = test\Directory.Build.targets
- test\Directory.Packages.props = test\Directory.Packages.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Examples.Console", "examples\Console\Examples.Console.csproj", "{FF3E6E08-E8E4-4523-B526-847CD989279F}"
@@ -121,14 +122,20 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "test\Benchmarks\Benchmarks.csproj", "{DE9130A4-F30A-49D7-8834-41DE3021218B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{7C87CAF9-79D7-4C26-9FFB-F3F1FB6911F1}"
+ ProjectSection(SolutionItems) = preProject
+ docs\README.md = docs\README.md
+ EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{2C7DD1DA-C229-4D9E-9AF0-BCD5CD3E4948}"
ProjectSection(SolutionItems) = preProject
examples\Directory.Build.props = examples\Directory.Build.props
- examples\Directory.Packages.props = examples\Directory.Packages.props
+ examples\Directory.Build.targets = examples\Directory.Build.targets
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "trace", "trace", "{5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}"
+ ProjectSection(SolutionItems) = preProject
+ docs\trace\README.md = docs\trace\README.md
+ EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "metrics", "metrics", "{3277B1C0-BDFE-4460-9B0D-D9A661FB48DB}"
ProjectSection(SolutionItems) = preProject
@@ -274,6 +281,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shims", "Shims", "{A0CB9A10-F22D-4E66-A449-74B3D0361A9C}"
ProjectSection(SolutionItems) = preProject
src\Shared\Shims\IsExternalInit.cs = src\Shared\Shims\IsExternalInit.cs
+ src\Shared\Shims\Lock.cs = src\Shared\Shims\Lock.cs
src\Shared\Shims\NullableAttributes.cs = src\Shared\Shims\NullableAttributes.cs
EndProjectSection
EndProject
@@ -297,7 +305,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "experimental-apis", "experi
ProjectSection(SolutionItems) = preProject
docs\diagnostics\experimental-apis\OTEL1000.md = docs\diagnostics\experimental-apis\OTEL1000.md
docs\diagnostics\experimental-apis\OTEL1001.md = docs\diagnostics\experimental-apis\OTEL1001.md
- docs\diagnostics\experimental-apis\OTEL1003.md = docs\diagnostics\experimental-apis\OTEL1003.md
docs\diagnostics\experimental-apis\OTEL1004.md = docs\diagnostics\experimental-apis\OTEL1004.md
docs\diagnostics\experimental-apis\README.md = docs\diagnostics\experimental-apis\README.md
EndProjectSection
@@ -326,7 +333,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TagWriter", "TagWriter", "{
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{44982E0D-C8C6-42DC-9F8F-714981F27CE6}"
ProjectSection(SolutionItems) = preProject
- build\scripts\add-labels.ps1 = build\scripts\add-labels.ps1
+ build\scripts\add-labels.psm1 = build\scripts\add-labels.psm1
build\scripts\finalize-publicapi.ps1 = build\scripts\finalize-publicapi.ps1
build\scripts\post-release.psm1 = build\scripts\post-release.psm1
build\scripts\prepare-release.psm1 = build\scripts\prepare-release.psm1
@@ -336,6 +343,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{4498
build\scripts\update-changelogs.ps1 = build\scripts\update-changelogs.ps1
EndProjectSection
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "exemplars", "docs\metrics\exemplars\exemplars.csproj", "{79C12C80-B27B-41FB-AE79-A3BB74CFA782}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -590,6 +599,10 @@ Global
{19545B37-8518-4BDD-AD49-00C031FB3C2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{19545B37-8518-4BDD-AD49-00C031FB3C2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19545B37-8518-4BDD-AD49-00C031FB3C2A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {79C12C80-B27B-41FB-AE79-A3BB74CFA782}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {79C12C80-B27B-41FB-AE79-A3BB74CFA782}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {79C12C80-B27B-41FB-AE79-A3BB74CFA782}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {79C12C80-B27B-41FB-AE79-A3BB74CFA782}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -647,6 +660,7 @@ Global
{87A20A76-D524-4AAC-AF92-8725BFED0415} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
{993E65E5-E71B-40FD-871C-60A9EBD59724} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
{44982E0D-C8C6-42DC-9F8F-714981F27CE6} = {7CB2F02E-03FA-4FFF-89A5-C51F107623FD}
+ {79C12C80-B27B-41FB-AE79-A3BB74CFA782} = {3277B1C0-BDFE-4460-9B0D-D9A661FB48DB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521}
diff --git a/README.md b/README.md
index 8a2695da6d..f0c69d1e1e 100644
--- a/README.md
+++ b/README.md
@@ -6,9 +6,27 @@
[![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.svg)](https://www.nuget.org/profiles/OpenTelemetry)
[![Build](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/ci.yml)
-The .NET [OpenTelemetry](https://opentelemetry.io/) client.
+The .NET [OpenTelemetry](https://opentelemetry.io/) implementation.
-## Supported .NET Versions
+
+Table of Contents
+
+* [Supported .NET versions](#supported-net-versions)
+* [Project status](#project-status)
+* [Getting started](#getting-started)
+ * [Getting started with Logging](#getting-started-with-logging)
+ * [Getting started with Metrics](#getting-started-with-metrics)
+ * [Getting started with Tracing](#getting-started-with-tracing)
+* [Repository structure](#repository-structure)
+* [Troubleshooting](#troubleshooting)
+* [Extensibility](#extensibility)
+* [Releases](#releases)
+* [Contributing](#contributing)
+* [References](#references)
+
+
+
+## Supported .NET versions
Packages shipped from this repository generally support all the officially
supported versions of [.NET](https://dotnet.microsoft.com/download/dotnet) and
@@ -17,36 +35,88 @@ older Windows-based .NET implementation), except `.NET Framework 3.5`.
Any exceptions to this are noted in the individual `README.md`
files.
-## Project Status
+## Project status
+
+**Stable** across all 3 signals (`Logs`, `Metrics`, and `Traces`).
-**Stable** across all 3 signals i.e. `Logs`, `Metrics`, and `Traces`.
+> [!CAUTION]
+> Certain components, marked as
+[pre-release](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/VERSIONING.md#pre-releases),
+are still work in progress and can undergo breaking changes before stable
+release. Check the individual `README.md` file for each component to understand its
+current state.
-See [Spec Compliance
-Matrix](https://github.com/open-telemetry/opentelemetry-specification/blob/main/spec-compliance-matrix.md)
-to understand which portions of the specification has been implemented in this
-repo.
+To understand which portions of the [OpenTelemetry
+Specification](https://github.com/open-telemetry/opentelemetry-specification)
+have been implemented in OpenTelemetry .NET see: [Spec Compliance
+Matrix](https://github.com/open-telemetry/opentelemetry-specification/blob/main/spec-compliance-matrix.md).
-## Getting Started
+## Getting started
If you are new here, please read the getting started docs:
-* [Logs](./docs/logs/README.md)
-* [Metrics](./docs/metrics/README.md)
-* [Traces](./docs/trace/README.md)
-
-This repository includes multiple installable components, available on
-[NuGet](https://www.nuget.org/profiles/OpenTelemetry). Each component has its
-individual `README.md` file, which covers the instruction on how to install and
-how to get started. To find all the available components, please take a look at
-the `src` folder.
+### Getting started with Logging
+
+If you are new to
+[logging](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/README.md),
+it is recommended to first follow the [getting started in 5 minutes - ASP.NET
+Core Application](./docs/logs/getting-started-aspnetcore/README.md) guide or
+the [getting started in 5 minutes - Console
+Application](./docs/logs/getting-started-console/README.md) guide to get up
+and running.
+
+For general information and best practices see: [OpenTelemetry .NET
+Logs](./docs/logs/README.md). For a more detailed explanation of SDK logging
+features see: [Customizing OpenTelemetry .NET SDK for
+Logs](./docs/logs/customizing-the-sdk/README.md).
+
+### Getting started with Metrics
+
+If you are new to
+[metrics](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/README.md),
+it is recommended to first follow the [getting started in 5 minutes - ASP.NET
+Core Application](./docs/metrics/getting-started-aspnetcore/README.md) guide
+or the [getting started in 5 minutes - Console
+Application](./docs/metrics/getting-started-console/README.md) guide to get
+up and running.
+
+For general information and best practices see: [OpenTelemetry .NET
+Metrics](./docs/metrics/README.md). For a more detailed explanation of SDK
+metric features see: [Customizing OpenTelemetry .NET SDK for
+Metrics](./docs/metrics/customizing-the-sdk/README.md).
+
+### Getting started with Tracing
+
+If you are new to
+[traces](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/README.md),
+it is recommended to first follow the [getting started in 5 minutes - ASP.NET
+Core Application](./docs/trace/getting-started-aspnetcore/README.md) guide
+or the [getting started in 5 minutes - Console
+Application](./docs/trace/getting-started-console/README.md) guide to get up
+and running.
+
+For general information and best practices see: [OpenTelemetry .NET
+Traces](./docs/trace/README.md). For a more detailed explanation of SDK tracing
+features see: [Customizing OpenTelemetry .NET SDK for
+Tracing](./docs/trace/customizing-the-sdk/README.md).
+
+## Repository structure
+
+This repository includes only what is defined in the [OpenTelemetry
+Specification](https://github.com/open-telemetry/opentelemetry-specification)
+and is shipped as separate packages through
+[NuGet](https://www.nuget.org/profiles/OpenTelemetry). Each component has an
+individual `README.md` and `CHANGELOG.md` file which covers the instructions on
+how to install and get started, and details about the individual changes made
+(respectively). To find all the available components, please take a look at the
+`src` folder.
Here are the most commonly used components:
-* [OpenTelemetry .NET API](./src/OpenTelemetry.Api/README.md)
-* [OpenTelemetry .NET SDK](./src/OpenTelemetry/README.md)
-
-[Instrumentation libraries](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#instrumentation-library)
-can be found in [contrib repository](https://github.com/open-telemetry/opentelemetry-dotnet-contrib).
+* [OpenTelemetry API](./src/OpenTelemetry.Api/README.md)
+* [OpenTelemetry SDK](./src/OpenTelemetry/README.md)
+* [OpenTelemetry Hosting
+ Extensions](./src/OpenTelemetry.Extensions.Hosting/README.md)
Here are the [exporter
libraries](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#exporter-library):
@@ -59,16 +129,19 @@ libraries](https://github.com/open-telemetry/opentelemetry-specification/blob/ma
* [Prometheus HttpListener](./src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md)
* [Zipkin](./src/OpenTelemetry.Exporter.Zipkin/README.md)
-See the [OpenTelemetry
-registry](https://opentelemetry.io/ecosystem/registry/?language=dotnet) and
-[OpenTelemetry .NET Contrib
-repo](https://github.com/open-telemetry/opentelemetry-dotnet-contrib) for more
-components.
+Additional packages including [instrumentation
+libraries](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#instrumentation-library),
+exporters, resource detectors, and extensions can be found in the
+[opentelemetry-dotnet-contrib
+repository](https://github.com/open-telemetry/opentelemetry-dotnet-contrib)
+and/or the [OpenTelemetry
+registry](https://opentelemetry.io/ecosystem/registry/?language=dotnet).
## Troubleshooting
-See [Troubleshooting](./src/OpenTelemetry/README.md#troubleshooting).
-Additionally check readme file for the individual components for any additional
+For general instructions see:
+[Troubleshooting](./src/OpenTelemetry/README.md#troubleshooting). Additionally
+`README.md` files for individual components may contain more detailed
troubleshooting information.
## Extensibility
@@ -80,7 +153,7 @@ extension scenarios:
library](./docs/trace/extending-the-sdk/README.md#instrumentation-library).
* Building a custom exporter for
[logs](./docs/logs/extending-the-sdk/README.md#exporter),
- [metrics](./docs/metrics/extending-the-sdk/README.md#exporter) and
+ [metrics](./docs/metrics/extending-the-sdk/README.md#exporter), and
[traces](./docs/trace/extending-the-sdk/README.md#exporter).
* Building a custom processor for
[logs](./docs/logs/extending-the-sdk/README.md#processor) and
@@ -88,14 +161,33 @@ extension scenarios:
* Building a custom sampler for
[traces](./docs/trace/extending-the-sdk/README.md#sampler).
+## Releases
+
+For details about upcoming planned releases see:
+[Milestones](https://github.com/open-telemetry/opentelemetry-dotnet/milestones).
+The dates and features described in issues and milestones are estimates and
+subject to change.
+
+For highlights and annoucements for stable releases see: [Release
+Notes](./RELEASENOTES.md).
+
+To access packages, source code, and/or view a list of changes for all
+components in a release see:
+[Releases](https://github.com/open-telemetry/opentelemetry-dotnet/releases).
+
+Nightly builds from this repo are published to [MyGet](https://www.myget.org),
+and can be installed using the
+`https://www.myget.org/F/opentelemetry/api/v3/index.json` source.
+
## Contributing
-See [CONTRIBUTING.md](CONTRIBUTING.md)
+For information about contributing to the project see:
+[CONTRIBUTING.md](CONTRIBUTING.md).
We meet weekly on Tuesdays, and the time of the meeting alternates between 9AM
PT and 4PM PT. The meeting is subject to change depending on contributors'
availability. Check the [OpenTelemetry community
-calendar](https://calendar.google.com/calendar/embed?src=google.com_b79e3e90j7bbsa2n2p5an5lf60%40group.calendar.google.com)
+calendar](https://github.com/open-telemetry/community?tab=readme-ov-file#calendar)
for specific dates and for Zoom meeting links.
Meeting notes are available as a public [Google
@@ -108,28 +200,28 @@ regardless of your experience level. Whether you're a seasoned OpenTelemetry
developer, just starting your journey, or simply curious about the work we do,
you're more than welcome to participate!
-[Maintainers](https://github.com/open-telemetry/community/blob/main/community-membership.md#maintainer)
+[Maintainers](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer)
([@open-telemetry/dotnet-maintainers](https://github.com/orgs/open-telemetry/teams/dotnet-maintainers)):
* [Alan West](https://github.com/alanwest), New Relic
* [Mikel Blanchard](https://github.com/CodeBlanch), Microsoft
-[Approvers](https://github.com/open-telemetry/community/blob/main/community-membership.md#approver)
+[Approvers](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver)
([@open-telemetry/dotnet-approvers](https://github.com/orgs/open-telemetry/teams/dotnet-approvers)):
* [Cijo Thomas](https://github.com/cijothomas), Microsoft
+* [Piotr Kiełkowicz](https://github.com/Kielek), Splunk
* [Reiley Yang](https://github.com/reyang), Microsoft
* [Utkarsh Umesan Pillai](https://github.com/utpilla), Microsoft
-* [Vishwesh Bankwar](https://github.com/vishweshbankwar), Microsoft
-[Triagers](https://github.com/open-telemetry/community/blob/main/community-membership.md#triager)
+[Triagers](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#triager)
([@open-telemetry/dotnet-triagers](https://github.com/orgs/open-telemetry/teams/dotnet-triagers)):
* [Martin Thwaites](https://github.com/martinjt), Honeycomb
-* [Piotr Kiełkowicz](https://github.com/Kielek), Splunk
+* [Timothy "Mothra" Lee](https://github.com/TimothyMothra), Microsoft
[Emeritus
-Maintainer/Approver/Triager](https://github.com/open-telemetry/community/blob/main/community-membership.md#emeritus-maintainerapprovertriager):
+Maintainer/Approver/Triager](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager):
* [Bruno Garcia](https://github.com/bruno-garcia)
* [Eddy Nakamura](https://github.com/eddynaka)
@@ -139,28 +231,13 @@ Maintainer/Approver/Triager](https://github.com/open-telemetry/community/blob/ma
* [Robert Pająk](https://github.com/pellared)
* [Sergey Kanzhelev](https://github.com/SergeyKanzhelev)
* [Victor Lu](https://github.com/victlu)
+* [Vishwesh Bankwar](https://github.com/vishweshbankwar)
### Thanks to all the people who have contributed
[![contributors](https://contributors-img.web.app/image?repo=open-telemetry/opentelemetry-dotnet)](https://github.com/open-telemetry/opentelemetry-dotnet/graphs/contributors)
-## Release Schedule
-
-See the [project
-milestones](https://github.com/open-telemetry/opentelemetry-dotnet/milestones)
-for details on upcoming releases. The dates and features described in issues and
-milestones are estimates, and subject to change.
-
-See the [release
-notes](https://github.com/open-telemetry/opentelemetry-dotnet/releases) for
-existing releases.
-
-> [!CAUTION]
-> Certain components, marked as
-[pre-release](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/VERSIONING.md#pre-releases),
-are still work in progress and can undergo breaking changes before stable
-release. Check the individual `README.md` file for each component to understand its
-current state.
+## References
-Daily builds from this repo are published to MyGet, and can be installed from
-[this source](https://www.myget.org/F/opentelemetry/api/v3/index.json).
+* [OpenTelemetry Project](https://opentelemetry.io/)
+* [OpenTelemetry Specification](https://github.com/open-telemetry/opentelemetry-specification)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
new file mode 100644
index 0000000000..365d9dc876
--- /dev/null
+++ b/RELEASENOTES.md
@@ -0,0 +1,88 @@
+# Release Notes
+
+This file contains highlights and announcements covering all components.
+For more details see `CHANGELOG.md` files maintained in the root source
+directory of each individual package.
+
+## 1.10.0
+
+* Bumped the package versions of `System.Diagnostic.DiagnosticSource` and other
+ Microsoft.Extensions.* packages to `9.0.0`.
+
+* Added support for new APIs introduced in `System.Diagnostics.DiagnosticSource`
+ `9.0.0`:
+
+ * [InstrumentAdvice<T>](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.instrumentadvice-1)
+
+ * [Gauge<T>](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.gauge-1)
+
+ * [ActivitySource.Tags](https://learn.microsoft.com/dotnet/api/system.diagnostics.activitysource.tags)
+ (supported in OtlpExporter & ConsoleExporter)
+
+* Experimental features promoted to stable:
+
+ * `CardinalityLimit` can now be managed for individual metrics via the View
+ API. For details see: [Changing cardinality limit for a
+ Metric](./docs/metrics/customizing-the-sdk/README.md#changing-the-cardinality-limit-for-a-metric).
+
+ * The [overflow
+ attribute](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#overflow-attribute)
+ (`otel.metric.overflow`) behavior is now enabled by default. The
+ `OTEL_DOTNET_EXPERIMENTAL_METRICS_EMIT_OVERFLOW_ATTRIBUTE` environment
+ variable is no longer required. For details see: [Cardinality
+ Limits](./docs/metrics/README.md#cardinality-limits).
+
+* Added `OpenTelemetrySdk.Create` API for configuring OpenTelemetry .NET signals
+ (logging, tracing, and metrics) via a single builder. This new API simplifies
+ bootstrap and teardown, and supports cross-cutting extensions targeting
+ `IOpenTelemetryBuilder`.
+
+* Removed out of support `net6.0` target and added `net9.0` target.
+
+## 1.9.0
+
+* `Exemplars` are now part of the stable API! For details see: [customizing
+ exemplars
+ collection](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/docs/metrics/customizing-the-sdk#exemplars).
+
+* `WithLogging` is now part of the stable API! Logging, Metrics, and Tracing can
+ now all be configured using the `With` style and the builders finally have
+ parity in their APIs.
+
+## 1.8.0
+
+* `TracerProvider` sampler can now be configured via the `OTEL_TRACES_SAMPLER` &
+ `OTEL_TRACES_SAMPLER_ARG` envvars.
+
+* A new `UseOtlpExporter` cross-cutting extension has been added to register the
+ `OtlpExporter` and enable all signals in a single call.
+
+* `exception.type`, `exception.message`, `exception.stacktrace` will now
+ automatically be included by the `OtlpLogExporter` when logging exceptions.
+ Previously an experimental environment variable had to be set.
+
+## 1.7.0
+
+* Bumped the package versions of System.Diagnostic.DiagnosticSource and other
+ Microsoft.Extensions.* packages to `8.0.0`.
+
+* Added `net8.0` targets to all the components.
+
+* OTLP Exporter
+ * Updated to use `ILogger` `CategoryName` as the instrumentation scope for
+ logs.
+ * Added named options support for OTLP Log Exporter.
+ * Added support for instrumentation scope attributes in metrics.
+ * Added support under an experimental flag to emit log exception attributes.
+ * Added support under an experimental flag to emit log eventId and eventName.
+ attributes.
+
+* Added support for the
+ [IMetricsBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.diagnostics.metrics.imetricsbuilder)
+ API.
+
+* Added an experimental opt-in metrics feature to reclaim unused MetricPoints
+ which enables a higher number of unique dimension combinations to be emitted.
+ See [reclaim unused metric
+ points](https://github.com/open-telemetry/opentelemetry-dotnet/blob/32c64d04defb5c92d056fd8817638151168b10da/docs/metrics/README.md#cardinality-limits)
+ for more details.
diff --git a/build/Common.nonprod.props b/build/Common.nonprod.props
index 7f617c4549..ce99895ccb 100644
--- a/build/Common.nonprod.props
+++ b/build/Common.nonprod.props
@@ -8,7 +8,7 @@
- net8.0
+ net9.0
@@ -44,4 +44,24 @@
+
+
+
+
+
+
+
+
+
+ $(DefineConstants);@(CompilerConstantsForDependenciesWithExposedExperimentalFeatures)
+
+
diff --git a/build/Common.prod.props b/build/Common.prod.props
index 011f7d9b31..832306e140 100644
--- a/build/Common.prod.props
+++ b/build/Common.prod.props
@@ -3,6 +3,9 @@
$(MSBuildThisFileDirectory)/OpenTelemetry.prod.ruleset
+
+
+
true
false
@@ -22,6 +25,9 @@
true
$(RepoRoot)\LICENSE.TXT
$(RepoRoot)\THIRD-PARTY-NOTICES.TXT
+ README.md
+ CHANGELOG.md
+ $(RepoRoot)\RELEASENOTES.md
@@ -30,6 +36,13 @@
true
+
+
+
+
+
@@ -39,11 +52,28 @@
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ \[([^]]+?)\]\(\.(.+?)\)
+ $(GitOriginConsoleOutput.Replace('.git',''))
+ $(GitHubRepoUrl)/blob/$(PackTag)
+ $(GitHubRepoUrl)/blob/$(GitCommitConsoleOutput)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_PackageReleaseNotesFilePath>$([System.IO.Path]::GetFullPath('$(PackageReleaseNotesFile)').Replace('$(RepoRoot)', '').Replace('\', '/'))
+ <_PackageChangelogFilePath>$([System.IO.Path]::GetFullPath('$(PackageChangelogFile)').Replace('$(RepoRoot)', '').Replace('\', '/'))
+
+ For highlights and announcements see: $(GitHubPermalinkUrl)$(_PackageReleaseNotesFilePath).
+
+ For detailed changes see: $(GitHubPermalinkUrl)$(_PackageChangelogFilePath).
+
+
+
+
+
+
+
+
+
+
diff --git a/build/Common.props b/build/Common.props
index 7c1c5b5a47..c1a4874c57 100644
--- a/build/Common.props
+++ b/build/Common.props
@@ -9,30 +9,38 @@
true
enable
enable
+ true
+ all
+ low
- $(NoWarn);OTEL1000;OTEL1001;OTEL1002;OTEL1003;OTEL1004
+ $(NoWarn);OTEL1000;OTEL1001;OTEL1002;OTEL1004
+
+ false
+
+
net462
net481;net48;net472;net471;net47;net462
- net8.0;net6.0;netstandard2.0;$(NetFrameworkMinimumSupportedVersion)
- net8.0;net6.0;netstandard2.1;netstandard2.0;$(NetFrameworkMinimumSupportedVersion)
- net8.0;net6.0
+ net9.0;net8.0;netstandard2.0;$(NetFrameworkMinimumSupportedVersion)
+ net9.0;net8.0;netstandard2.1;netstandard2.0;$(NetFrameworkMinimumSupportedVersion)
+ net9.0;net8.0
+ net8.0;netstandard2.1;netstandard2.0;$(NetFrameworkMinimumSupportedVersion)
- net8.0;net7.0;net6.0
- net8.0
- net8.0;net7.0;net6.0
+ net9.0;net8.0
+ net9.0;net8.0
+ net9.0;net8.0
$(TargetFrameworksForDocs);$(NetFrameworkSupportedVersions)
- net8.0;net7.0;net6.0
+ net9.0;net8.0
$(TargetFrameworksForTests);$(NetFrameworkMinimumSupportedVersion)
diff --git a/build/Common.targets b/build/Common.targets
new file mode 100644
index 0000000000..63286efffb
--- /dev/null
+++ b/build/Common.targets
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
diff --git a/OpenTelemetry.proj b/build/OpenTelemetry.proj
similarity index 61%
rename from OpenTelemetry.proj
rename to build/OpenTelemetry.proj
index b55859fe01..86987bbbe2 100644
--- a/OpenTelemetry.proj
+++ b/build/OpenTelemetry.proj
@@ -1,16 +1,18 @@
+
+ $([System.IO.Directory]::GetParent($(MSBuildThisFileDirectory)).Parent.FullName)
+
+
-
-
-
+
+
+
-
-
-
+
+
+
diff --git a/build/RELEASING.md b/build/RELEASING.md
index 035aad38d6..28fdc9a078 100644
--- a/build/RELEASING.md
+++ b/build/RELEASING.md
@@ -1,6 +1,7 @@
# Release process
-**Only for Maintainers.**
+**Note: Approvers (collaborators) can perform much of the release process but
+Maintainers (admins) are needed to merge PRs and for the push to NuGet.**
1. Decide the component(s) and tag name (version name) to be released. We use
[MinVer](https://github.com/adamralph/minver) to do versioning, which
@@ -40,15 +41,13 @@
* `OpenTelemetry.Shims.OpenTracing` - Defined by spec (stable but
incomplete implementation)
- * As of the `1.9.0` release cycle instrumentation packages and core
- unstable packages always depend on the stable versions of core
- packages. Before releasing a non-core component ensure the
- `OTelLatestStableVer` property in `Directory.Packages.props` has been
- updated to the latest stable core version.
+ * As of the `1.9.0` release cycle core unstable packages always depend on
+ the stable versions of core packages. Before releasing a non-core
+ component ensure the `OTelLatestStableVer` property in
+ `Directory.Packages.props` has been updated to the latest stable core
+ version.
- 2. Prepare for release
-
- Run the [Prepare for a
+ 2. Run the [Prepare for a
release](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/prepare-release.yml)
workflow. Specify the `tag-prefix` and the `version` for the release. Make
sure to run the workflow on the branch being released. This is typically
@@ -91,11 +90,10 @@
comment and lock the PR. Post a comment with "/CreateReleaseTag" in the
body. This will tell the [Prepare for a
release](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/prepare-release.yml)
- workflow to push the tag for the merge commit of the PR and to call the
- [Build, pack, and publish to
+ workflow to push the tag for the merge commit of the PR which will trigger
+ the [Build, pack, and publish to
MyGet](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/publish-packages-1.0.yml)
- workflow. Once packages are available a comment will be posted on the PR
- opened in step 2 with a link to the artifacts.
+ workflow.
Instructions for pushing tags manually
@@ -127,56 +125,85 @@
5. :stop_sign: Wait for the [Build, pack, and publish to
MyGet](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/publish-packages-1.0.yml)
- workflow to complete.
+ workflow to complete. When complete a trigger will automatically add a
+ comment on the PR opened by [Prepare for a
+ release](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/prepare-release.yml)
+ workflow in step 2. Use MyGet or download the packages using the provided
+ link to validate locally everything works. After validation has been
+ performed have a maintainer post a comment with "/PushPackages" in the body.
+ This will trigger the [Complete
+ release](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/prepare-release.yml)
+ workflow to push the packages to NuGet and publish the draft release created
+ by the [Build, pack, and publish to
+ MyGet](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/publish-packages-1.0.yml)
+ workflow. Comments will automatically be added on the PR opened by [Prepare
+ for a
+ release](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/prepare-release.yml)
+ workflow in step 2 as the process is run and the PR will be unlocked.
- 6. Validate locally everything works using the MyGet packages pushed from the
- release. Basic sanity checks :)
+
+ Instructions for pushing packages to NuGet manually
- 7. Download the artifacts from the drop attached to the workflow run. The
- artifacts archive (`.zip`) contains all the NuGet packages (`.nupkg`) and
- symbols (`.snupkg`) from the build which were pushed to MyGet.
+ 1. The [Build, pack, and publish to
+ MyGet](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/publish-packages-1.0.yml)
+ workflow pushes the packages to MyGet and attaches them as artifacts on
+ the workflow run.
- 8. Extract the artifacts from the archive (`.zip`) into a local folder.
+ 2. Validate locally everything works using the packages pushed to MyGet or
+ downloaded from the drop attached to the workflow run. Basic sanity
+ checks :)
- 9. Download latest [nuget.exe](https://www.nuget.org/downloads) into the same
- folder from Step 8.
+ 3. Download the artifacts from the drop attached to the workflow run. The
+ artifacts archive (`.zip`) contains all the NuGet packages (`.nupkg`) and
+ symbols (`.snupkg`) from the build which were pushed to MyGet.
-10. Create or regenerate an API key from nuget.org (only maintainers have
- access). When creating API keys make sure it is set to expire in 1 day or
- less.
+ 4. Extract the artifacts from the archive (`.zip`) into a local folder.
-11. Run the following commands from PowerShell from local folder used in Step 8:
+ 5. Download latest [nuget.exe](https://www.nuget.org/downloads) into the
+ same folder from step 4.
- ```powershell
- .\nuget.exe setApiKey
+ 6. Create or regenerate an API key from nuget.org (only maintainers have
+ access). When creating API keys make sure it is set to expire in 1 day or
+ less.
- get-childitem -Recurse | where {$_.extension -eq ".nupkg"} | foreach ($_) {.\nuget.exe push $_.fullname -Source https://api.nuget.org/v3/index.json}
- ```
+ 7. Run the following commands from PowerShell from local folder used in step
+ 4:
-12. Validate that the package(s) are uploaded. Packages are available
- immediately to maintainers on nuget.org but aren't publicly visible until
- scanning completes. This process usually takes a few minutes.
+ ```powershell
+ .\nuget.exe setApiKey
-13. Open the
- [Releases](https://github.com/open-telemetry/opentelemetry-dotnet/releases)
- page on the GitHub repository. The [Build, pack, and publish to
- MyGet](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/publish-packages-1.0.yml)
- workflow creates a draft release for the tag which was pushed. Edit the
- draft Release and click `Publish release`.
+ get-childitem -Recurse | where {$_.extension -eq ".nupkg"} | foreach ($_) {.\nuget.exe push $_.fullname -Source https://api.nuget.org/v3/index.json}
+ ```
-14. If a new stable version of the core packages was released, a draft PR should
- have been automatically created by the [Build, pack, and publish to
- MyGet](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/publish-packages-1.0.yml)
+ 8. Validate that the package(s) are uploaded. Packages are available
+ immediately to maintainers on nuget.org but aren't publicly visible until
+ scanning completes. This process usually takes a few minutes.
+
+ 9. Open the
+ [Releases](https://github.com/open-telemetry/opentelemetry-dotnet/releases)
+ page on the GitHub repository. The [Build, pack, and publish to
+ MyGet](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/publish-packages-1.0.yml)
+ workflow creates a draft release for the tag which was pushed. Edit the
+ draft Release and click `Publish release`.
+
+
+ 6. If a new stable version of the core packages was released, a PR should have
+ been automatically created by the [Complete
+ release](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/post-release.yml)
workflow to update the `OTelLatestStableVer` property in
- `Directory.Packages.props` to the just released stable version. Mark that PR
- `Ready for review` and then merge it once the build passes (this requires
- the packages be available on NuGet).
-
-15. If a new stable version of the core packages was released, open an issue in
- the
- [opentelemetry-dotnet-contrib](https://github.com/open-telemetry/opentelemetry-dotnet-contrib)
- repo to notify maintainers to begin upgrading dependencies.
-
-16. Post an announcement in the [Slack
- channel](https://cloud-native.slack.com/archives/C01N3BC2W7Q). Note any big
- or interesting new features as part of the announcement.
+ `Directory.Packages.props` to the just released stable version. Merge that
+ PR once the build passes (this requires the packages be available on NuGet).
+
+ 7. The [Complete
+ release](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/post-release.yml)
+ workflow should have invoked the [Core version
+ update](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/actions/workflows/core-version-update.yml)
+ workflow on the
+ [opentelemetry-dotnet-contrib](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/)
+ repository which opens a PR to update dependencies. Verify this PR was
+ opened successfully.
+
+ 8. For stable releases, update [Release Notes](../RELEASENOTES.md) with any big
+ or interesting new features and then post an announcement in the [Slack
+ channel](https://cloud-native.slack.com/archives/C01N3BC2W7Q) with the same
+ information.
diff --git a/build/UnstableCoreLibraries.proj b/build/UnstableCoreLibraries.proj
index 8d333db2d9..7686376563 100644
--- a/build/UnstableCoreLibraries.proj
+++ b/build/UnstableCoreLibraries.proj
@@ -1,12 +1,16 @@
+
+ $([System.IO.Directory]::GetParent($(MSBuildThisFileDirectory)).Parent.FullName)
+
+
-
-
-
+
+
+
-
-
-
+
+
+
diff --git a/build/docker-compose.net6.0.yml b/build/docker-compose.net6.0.yml
deleted file mode 100644
index 099f100727..0000000000
--- a/build/docker-compose.net6.0.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-version: '3.7'
-
-services:
- tests:
- build:
- args:
- PUBLISH_FRAMEWORK: net6.0
- TEST_SDK_VERSION: "6.0"
- BUILD_SDK_VERSION: "8.0"
diff --git a/build/docker-compose.net7.0.yml b/build/docker-compose.net7.0.yml
deleted file mode 100644
index 48a2589cda..0000000000
--- a/build/docker-compose.net7.0.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-version: '3.7'
-
-services:
- tests:
- build:
- args:
- PUBLISH_FRAMEWORK: net7.0
- TEST_SDK_VERSION: "7.0"
- BUILD_SDK_VERSION: "8.0"
diff --git a/build/docker-compose.net8.0.yml b/build/docker-compose.net8.0.yml
index a5ac999e43..22787bff66 100644
--- a/build/docker-compose.net8.0.yml
+++ b/build/docker-compose.net8.0.yml
@@ -6,4 +6,4 @@ services:
args:
PUBLISH_FRAMEWORK: net8.0
TEST_SDK_VERSION: "8.0"
- BUILD_SDK_VERSION: "8.0"
+ BUILD_SDK_VERSION: "9.0"
diff --git a/build/docker-compose.net9.0.yml b/build/docker-compose.net9.0.yml
new file mode 100644
index 0000000000..29663b3246
--- /dev/null
+++ b/build/docker-compose.net9.0.yml
@@ -0,0 +1,9 @@
+version: '3.7'
+
+services:
+ tests:
+ build:
+ args:
+ PUBLISH_FRAMEWORK: net9.0
+ TEST_SDK_VERSION: "9.0"
+ BUILD_SDK_VERSION: "9.0"
diff --git a/build/scripts/add-labels.ps1 b/build/scripts/add-labels.ps1
deleted file mode 100644
index 9b91ad9df8..0000000000
--- a/build/scripts/add-labels.ps1
+++ /dev/null
@@ -1,12 +0,0 @@
-param(
- [Parameter(Mandatory=$true)][int]$issueNumber,
- [Parameter(Mandatory=$true)][string]$issueBody
-)
-
-$match = [regex]::Match($issueBody, '^[#]+ Package\s*(OpenTelemetry(?:\.\w+)*)')
-if ($match.Success -eq $false)
-{
- Return
-}
-
-gh issue edit $issueNumber --add-label $("pkg:" + $match.Groups[1].Value)
diff --git a/build/scripts/add-labels.psm1 b/build/scripts/add-labels.psm1
new file mode 100644
index 0000000000..1b14854adb
--- /dev/null
+++ b/build/scripts/add-labels.psm1
@@ -0,0 +1,148 @@
+function AddLabelsOnIssuesForPackageFoundInBody {
+ param(
+ [Parameter(Mandatory=$true)][int]$issueNumber,
+ [Parameter(Mandatory=$true)][string]$issueBody
+ )
+
+ $match = [regex]::Match($issueBody, '^[#]+ Package\s*(OpenTelemetry(?:\.\w+)*)')
+ if ($match.Success -eq $false)
+ {
+ Return
+ }
+
+ gh issue edit $issueNumber --add-label $("pkg:" + $match.Groups[1].Value)
+}
+
+Export-ModuleMember -Function AddLabelsOnIssuesForPackageFoundInBody
+
+function AddLabelsOnPullRequestsBasedOnFilesChanged {
+ param(
+ [Parameter(Mandatory=$true)][int]$pullRequestNumber,
+ [Parameter(Mandatory=$true)][string]$labelPackagePrefix # 'pkg:' on main repo, 'comp:' on contrib repo
+ )
+
+ # Note: This function is intended to work on main repo and on contrib. Please
+ # keep them in sync.
+
+ $repoLabels = gh label list --json name,id -L 200 | ConvertFrom-Json
+
+ $filesChangedOnPullRequest = gh pr diff $pullRequestNumber --name-only
+
+ $labelsOnPullRequest = (gh pr view $pullRequestNumber --json labels | ConvertFrom-Json).labels
+
+ $visitedProjects = New-Object System.Collections.Generic.HashSet[string]
+ $labelsToAdd = New-Object System.Collections.Generic.HashSet[string]
+ $labelsToRemove = New-Object System.Collections.Generic.HashSet[string]
+
+ # Note: perf label may be added but it is kind of a guess so we don't remove
+ # it automatically in order to also allow manual inclusion after reviewing files
+ $managedLabels = 'infra', 'documentation', 'dependencies'
+ $rootInfraFiles = 'global.json', 'NuGet.config', 'codeowners'
+ $documentationFiles = 'readme.md', 'contributing.md', 'releasing.md', 'versioning.md', 'releasenotes.md'
+
+ foreach ($fileChanged in $filesChangedOnPullRequest)
+ {
+ $fileChanged = $fileChanged.ToLower()
+ $fullFileName = [System.IO.Path]::GetFileName($fileChanged)
+ $fileName = [System.IO.Path]::GetFileNameWithoutExtension($fileChanged)
+ $fileExtension = [System.IO.Path]::GetExtension($fileChanged)
+
+ if ($fileChanged.StartsWith('src/') -or $fileChanged.StartsWith('test/'))
+ {
+ $match = [regex]::Match($fileChanged, '^(?:(?:src)|(?:test))\/(.*?)\/.+$')
+ if ($match.Success -eq $false)
+ {
+ continue
+ }
+ $rawProjectName = $match.Groups[1].Value
+ if ($rawProjectName.Contains(".benchmarks") -or $rawProjectName.Contains(".stress"))
+ {
+ $added = $labelsToAdd.Add("perf")
+ }
+
+ $projectName = $rawProjectName.Replace(".tests", "").Replace(".benchmarks", "").Replace(".stress", "")
+ if ($visitedProjects.Contains($projectName))
+ {
+ continue
+ }
+
+ $added = $visitedProjects.Add($projectName);
+
+ foreach ($repoLabel in $repoLabels)
+ {
+ if ($repoLabel.name.StartsWith($labelPackagePrefix))
+ {
+ $package = $repoLabel.name.Substring($labelPackagePrefix.Length).ToLower()
+ if ($package.StartsWith('opentelemetry') -eq $false)
+ {
+ # Note: On contrib labels don't have "OpenTelemetry." prefix
+ $package = 'opentelemetry.' + $package
+ }
+ if ($package -eq $projectName)
+ {
+ $added = $labelsToAdd.Add($repoLabel.name)
+ break
+ }
+ }
+ }
+ }
+
+ if ($documentationFiles.Contains($fullFileName) -or
+ $fileChanged.StartsWith('docs/') -or
+ $fileChanged.StartsWith('examples/'))
+ {
+ $added = $labelsToAdd.Add("documentation")
+ }
+
+ if ($fileChanged.StartsWith('build/') -or
+ $fileChanged.StartsWith('.github/') -or
+ $rootInfraFiles.Contains($fullFileName) -or
+ $fileExtension -eq ".props" -or
+ $fileExtension -eq ".targets" -or
+ $fileChanged.StartsWith('test/openTelemetry.aotcompatibility'))
+ {
+ $added = $labelsToAdd.Add("infra")
+ }
+
+ if ($fileChanged.StartsWith('test/benchmarks'))
+ {
+ $added = $labelsToAdd.Add("perf")
+ }
+
+ if ($fullFileName -eq 'directory.packages.props')
+ {
+ $added = $labelsToAdd.Add("dependencies")
+ }
+ }
+
+ foreach ($labelOnPullRequest in $labelsOnPullRequest)
+ {
+ if ($labelsToAdd.Contains($labelOnPullRequest.name))
+ {
+ $removed = $labelsToAdd.Remove($labelOnPullRequest.name)
+ }
+ elseif ($labelOnPullRequest.name.StartsWith($labelPackagePrefix) -or
+ $managedLabels.Contains($labelOnPullRequest.name))
+ {
+ $added = $labelsToRemove.Add($labelOnPullRequest.name)
+ }
+ }
+
+ if ($labelsToAdd.Count -gt 0)
+ {
+ foreach ($label in $labelsToAdd)
+ {
+ gh pr edit $pullRequestNumber --add-label $label
+ }
+ }
+
+ if ($labelsToRemove.Count -gt 0)
+ {
+ foreach ($label in $labelsToRemove)
+ {
+ gh pr edit $pullRequestNumber --remove-label $label
+ }
+ }
+}
+
+Export-ModuleMember -Function AddLabelsOnPullRequestsBasedOnFilesChanged
diff --git a/build/scripts/post-release.psm1 b/build/scripts/post-release.psm1
index 39250d38d1..ae20f939e2 100644
--- a/build/scripts/post-release.psm1
+++ b/build/scripts/post-release.psm1
@@ -1,39 +1,42 @@
-$gitHubBotUserName="github-actions[bot]"
-$gitHubBotEmail="41898282+github-actions[bot]@users.noreply.github.com"
-
-$repoViewResponse = gh repo view --json nameWithOwner | ConvertFrom-Json
-
-$gitRepository = $repoViewResponse.nameWithOwner
-
function CreateDraftRelease {
param(
- [Parameter(Mandatory=$true)][string]$tag
+ [Parameter(Mandatory=$true)][string]$gitRepository,
+ [Parameter(Mandatory=$true)][string]$tag,
+ [Parameter()][string]$releaseFiles
)
- $packages = (Get-ChildItem -Path src/*/bin/Release/*.nupkg).Name
+ $match = [regex]::Match($tag, '^(.*?-)(.*)$')
+ if ($match.Success -eq $false)
+ {
+ throw 'Could not parse prefix or version from tag'
+ }
+
+ $tagPrefix = $match.Groups[1].Value
+ $version = $match.Groups[2].Value
+ $isPrerelease = $version -match '-alpha' -or $version -match '-beta' -or $version -match '-rc'
- $notes = ''
- $firstPackageVersion = ''
+ $projects = @(Get-ChildItem -Path src/**/*.csproj | Select-String "$tagPrefix" -List | Select Path)
- foreach ($package in $packages)
+ if ($projects.Length -eq 0)
{
- $match = [regex]::Match($package, '(.*)\.(\d+\.\d+\.\d+.*?)\.nupkg')
- $packageName = $match.Groups[1].Value
- $packageVersion = $match.Groups[2].Value
+ throw 'No projects found with MinVerTagPrefix matching prefix from tag'
+ }
- if ($firstPackageVersion -eq '')
- {
- $firstPackageVersion = $packageVersion
- }
+ $notes = ''
+ $previousVersion = ''
- $changelogContent = Get-Content -Path "src/$packageName/CHANGELOG.md"
+ foreach ($project in $projects)
+ {
+ $projectName = [System.IO.Path]::GetFileNameWithoutExtension($project.Path)
+
+ $changelogContent = Get-Content -Path "src/$projectName/CHANGELOG.md"
$started = $false
$content = ""
foreach ($line in $changelogContent)
{
- if ($line -like "## $packageVersion" -and $started -ne $true)
+ if ($line -like "## $version" -and $started -ne $true)
{
$started = $true
}
@@ -43,6 +46,11 @@ function CreateDraftRelease {
}
elseif ($line -like "## *" -and $started -eq $true)
{
+ $match = [regex]::Match($line, '^##\s*(.*)$')
+ if ($match.Success -eq $true)
+ {
+ $previousVersion = $match.Groups[1].Value
+ }
break
}
else
@@ -56,25 +64,33 @@ function CreateDraftRelease {
if ([string]::IsNullOrWhitespace($content) -eq $true)
{
- $content = " No notable changes."
+ $content = " No notable changes."
}
$content = $content.trimend()
$notes +=
@"
-* NuGet: [$packageName v$packageVersion](https://www.nuget.org/packages/$packageName/$packageVersion)
+* NuGet: [$projectName v$version](https://www.nuget.org/packages/$projectName/$version)
$content
- See [CHANGELOG](https://github.com/$gitRepository/blob/$tag/src/$packageName/CHANGELOG.md) for details.
+ See [CHANGELOG](https://github.com/$gitRepository/blob/$tag/src/$projectName/CHANGELOG.md) for details.
+
"@
}
- if ($firstPackageVersion -match '-alpha' -or $firstPackageVersion -match '-beta' -or $firstPackageVersion -match '-rc')
+ if ($isPrerelease -eq $true)
{
- gh release create $tag `
+ $notes =
+@"
+The following changes are from the previous release [$previousVersion](https://github.com/$gitRepository/releases/tag/$tagPrefix$previousVersion).
+
+
+"@ + $notes
+
+ gh release create $tag $releaseFiles `
--title $tag `
--verify-tag `
--notes $notes `
@@ -83,7 +99,16 @@ $content
}
else
{
- gh release create $tag `
+ $notes =
+@"
+For highlights and announcements pertaining to this release see: [Release Notes > $version](https://github.com/$gitRepository/blob/main/RELEASENOTES.md#$($version.Replace('.',''))).
+
+The following changes are from the previous release [$previousVersion](https://github.com/$gitRepository/releases/tag/$tagPrefix$previousVersion).
+
+
+"@ + $notes
+
+ gh release create $tag $releaseFiles `
--title $tag `
--verify-tag `
--notes $notes `
@@ -94,12 +119,153 @@ $content
Export-ModuleMember -Function CreateDraftRelease
+function TryPostPackagesReadyNoticeOnPrepareReleasePullRequest {
+ param(
+ [Parameter(Mandatory=$true)][string]$gitRepository,
+ [Parameter(Mandatory=$true)][string]$tag,
+ [Parameter(Mandatory=$true)][string]$tagSha,
+ [Parameter(Mandatory=$true)][string]$packagesUrl,
+ [Parameter(Mandatory=$true)][string]$botUserName
+ )
+
+ $prListResponse = gh pr list --search $tagSha --state merged --json number,author,title,comments | ConvertFrom-Json
+
+ if ($prListResponse.Length -eq 0)
+ {
+ Write-Host 'No prepare release PR found for tag & commit skipping post notice'
+ return
+ }
+
+ foreach ($pr in $prListResponse)
+ {
+ if ($pr.author.login -ne $botUserName -or $pr.title -ne "[release] Prepare release $tag")
+ {
+ continue
+ }
+
+ $foundComment = $false
+ foreach ($comment in $pr.comments)
+ {
+ if ($comment.author.login -eq $botUserName -and $comment.body.StartsWith("I just pushed the [$tag]"))
+ {
+ $foundComment = $true
+ break
+ }
+ }
+
+ if ($foundComment -eq $false)
+ {
+ continue
+ }
+
+ $body =
+@"
+The packages for [$tag](https://github.com/$gitRepository/releases/tag/$tag) are now available: $packagesUrl.
+
+Once these packages have been validated have a maintainer post a comment with "/PushPackages" in the body if you would like me to push to NuGet.
+"@
+
+ $pullRequestNumber = $pr.number
+
+ gh pr comment $pullRequestNumber --body $body
+ return
+ }
+
+ Write-Host 'No prepare release PR found matched author and title with a valid comment'
+}
+
+Export-ModuleMember -Function TryPostPackagesReadyNoticeOnPrepareReleasePullRequest
+
+function PushPackagesPublishReleaseUnlockAndPostNoticeOnPrepareReleasePullRequest {
+ param(
+ [Parameter(Mandatory=$true)][string]$gitRepository,
+ [Parameter(Mandatory=$true)][string]$pullRequestNumber,
+ [Parameter(Mandatory=$true)][string]$botUserName,
+ [Parameter(Mandatory=$true)][string]$commentUserName,
+ [Parameter(Mandatory=$true)][string]$artifactDownloadPath,
+ [Parameter(Mandatory=$true)][string]$pushToNuget
+ )
+
+ $prViewResponse = gh pr view $pullRequestNumber --json author,title,comments | ConvertFrom-Json
+
+ if ($prViewResponse.author.login -ne $botUserName)
+ {
+ throw 'PR author was unexpected'
+ }
+
+ $match = [regex]::Match($prViewResponse.title, '^\[release\] Prepare release (.*)$')
+ if ($match.Success -eq $false)
+ {
+ throw 'Could not parse tag from PR title'
+ }
+
+ $tag = $match.Groups[1].Value
+
+ $commentUserPermission = gh api "repos/$gitRepository/collaborators/$commentUserName/permission" | ConvertFrom-Json
+ if ($commentUserPermission.permission -ne 'admin')
+ {
+ gh pr comment $pullRequestNumber `
+ --body "I'm sorry @$commentUserName but you don't have permission to push packages. Only maintainers can push to NuGet."
+ return
+ }
+
+ $foundComment = $false
+ $packagesUrl = ''
+ foreach ($comment in $prViewResponse.comments)
+ {
+ if ($comment.author.login -eq $botUserName -and $comment.body.StartsWith("The packages for [$tag](https://github.com/$gitRepository/releases/tag/$tag) are now available:"))
+ {
+ $foundComment = $true
+ break
+ }
+ }
+
+ if ($foundComment -eq $false)
+ {
+ throw 'Could not find package push comment on pr'
+ }
+
+ gh release download $tag `
+ -p "$tag-packages.zip" `
+ -D "$artifactDownloadPath"
+
+ Expand-Archive -LiteralPath "$artifactDownloadPath/$tag-packages.zip" -DestinationPath "$artifactDownloadPath\"
+
+ if ($pushToNuget -eq 'true')
+ {
+ gh pr comment $pullRequestNumber `
+ --body "I am uploading the packages for ``$tag`` to NuGet and then I will publish the release."
+
+ nuget push "$artifactDownloadPath/**/*.nupkg" -Source https://api.nuget.org/v3/index.json -ApiKey "$env:NUGET_TOKEN" -SymbolApiKey "$env:NUGET_TOKEN"
+
+ if ($LASTEXITCODE -gt 0)
+ {
+ gh pr comment $pullRequestNumber `
+ --body "Something went wrong uploading the packages for ``$tag`` to NuGet."
+
+ throw 'nuget push failure'
+ }
+ }
+ else {
+ gh pr comment $pullRequestNumber `
+ --body "I am publishing the release without uploading the packages to NuGet because a token wasn't configured."
+ }
+
+ gh release edit $tag --draft=false
+
+ gh pr unlock $pullRequestNumber
+}
+
+Export-ModuleMember -Function PushPackagesPublishReleaseUnlockAndPostNoticeOnPrepareReleasePullRequest
+
function CreateStableVersionUpdatePullRequest {
param(
+ [Parameter(Mandatory=$true)][string]$gitRepository,
[Parameter(Mandatory=$true)][string]$tag,
- [Parameter()][string]$gitUserName=$gitHubBotUserName,
- [Parameter()][string]$gitUserEmail=$gitHubBotEmail,
- [Parameter()][string]$targetBranch="main"
+ [Parameter()][string]$targetBranch="main",
+ [Parameter()][string]$lineEnding="`n",
+ [Parameter()][string]$gitUserName,
+ [Parameter()][string]$gitUserEmail
)
$match = [regex]::Match($tag, '.*?-(.*)')
@@ -108,12 +274,18 @@ function CreateStableVersionUpdatePullRequest {
throw 'Could not parse version from tag'
}
- $packageVersion = $match.Groups[1].Value
+ $version = $match.Groups[1].Value
$branch="release/post-stable-${tag}-update"
- git config user.name $gitUserName
- git config user.email $gitUserEmail
+ if ([string]::IsNullOrEmpty($gitUserName) -eq $false)
+ {
+ git config user.name $gitUserName
+ }
+ if ([string]::IsNullOrEmpty($gitUserEmail) -eq $false)
+ {
+ git config user.email $gitUserEmail
+ }
git switch --create $branch origin/$targetBranch --no-track 2>&1 | % ToString
if ($LASTEXITCODE -gt 0)
@@ -121,17 +293,38 @@ function CreateStableVersionUpdatePullRequest {
throw 'git switch failure'
}
+ $projectsAndDependenciesBefore = GetCoreDependenciesForProjects
+
(Get-Content Directory.Packages.props) `
- -replace '.*<\/OTelLatestStableVer>', "$packageVersion" |
+ -replace '.*<\/OTelLatestStableVer>', "$version" |
Set-Content Directory.Packages.props
+ $projectsAndDependenciesAfter = GetCoreDependenciesForProjects
+
+ $changedProjects = @{}
+
+ $projectsAndDependenciesBefore.GetEnumerator() | ForEach-Object {
+ $projectDir = $_.Key
+ $projectDependenciesBefore = $_.Value
+ $projectDependenciesAfter = $projectsAndDependenciesAfter[$projectDir]
+
+ $projectDependenciesBefore.GetEnumerator() | ForEach-Object {
+ $packageName = $_.Key
+ $packageVersionBefore = $_.Value
+ if ($projectDependenciesAfter[$packageName] -ne $packageVersionBefore)
+ {
+ $changedProjects[$projectDir] = $true
+ }
+ }
+ }
+
git add Directory.Packages.props 2>&1 | % ToString
if ($LASTEXITCODE -gt 0)
{
throw 'git add failure'
}
- git commit -m "Update OTelLatestStableVer in Directory.Packages.props to $packageVersion." 2>&1 | % ToString
+ git commit -m "Update OTelLatestStableVer in Directory.Packages.props to $version." 2>&1 | % ToString
if ($LASTEXITCODE -gt 0)
{
throw 'git commit failure'
@@ -145,22 +338,261 @@ function CreateStableVersionUpdatePullRequest {
$body =
@"
-Note: This PR was opened automatically by the [package workflow](https://github.com/$gitRepository/actions/workflows/publish-packages-1.0.yml).
+Note: This PR was opened automatically by the [post-release workflow](https://github.com/$gitRepository/actions/workflows/post-release.yml).
Merge once packages are available on NuGet and the build passes.
## Changes
-* Sets ``OTelLatestStableVer`` in ``Directory.Packages.props`` to ``$packageVersion``.
+* Sets ``OTelLatestStableVer`` in ``Directory.Packages.props`` to ``$version``.
"@
- gh pr create `
- --title "[repo] Core stable release $packageVersion updates" `
+ $createPullRequestResponse = gh pr create `
+ --title "[release] Core stable release $version updates" `
--body $body `
--base $targetBranch `
--head $branch `
- --label infra `
- --draft
+ --label release
+
+ Write-Host $createPullRequestResponse
+
+ $match = [regex]::Match($createPullRequestResponse, "\/pull\/(.*)$")
+ if ($match.Success -eq $false)
+ {
+ throw 'Could not parse pull request number from gh pr create response'
+ }
+
+ $pullRequestNumber = $match.Groups[1].Value
+
+ if ($changedProjects.Count -eq 0)
+ {
+ Return
+ }
+
+ $entry = @"
+* Updated OpenTelemetry core component version(s) to ``$version``.
+ ([#$pullRequestNumber](https://github.com/$gitRepository/pull/$pullRequestNumber))
+
+
+"@
+
+ $lastLineBlank = $true
+ $changelogFilesUpdated = 0
+
+ foreach ($projectDir in $changedProjects.Keys)
+ {
+ $path = Join-Path -Path $projectDir -ChildPath "CHANGELOG.md"
+
+ if ([System.IO.File]::Exists($path) -eq $false)
+ {
+ Write-Host "No CHANGELOG found in $projectDir"
+ continue
+ }
+
+ $changelogContent = Get-Content -Path $path
+
+ $started = $false
+ $isRemoving = $false
+ $content = ""
+
+ foreach ($line in $changelogContent)
+ {
+ if ($line -like "## Unreleased" -and $started -ne $true)
+ {
+ $started = $true
+ }
+ elseif ($line -like "## *" -and $started -eq $true)
+ {
+ if ($lastLineBlank -eq $false)
+ {
+ $content += $lineEnding
+ }
+ $content += $entry
+ $started = $false
+ $isRemoving = $false
+ }
+ elseif ($started -eq $true -and ($line -like '*Update* OpenTelemetry SDK version to*' -or $line -like '*Updated OpenTelemetry core component version(s) to*'))
+ {
+ $isRemoving = $true
+ continue
+ }
+
+ if ($line.StartsWith('* '))
+ {
+ if ($isRemoving -eq $true)
+ {
+ $isRemoving = $false
+ }
+
+ if ($lastLineBlank -eq $false)
+ {
+ $content += $lineEnding
+ }
+ }
+
+ if ($isRemoving -eq $true)
+ {
+ continue
+ }
+
+ $content += $line + $lineEnding
+
+ $lastLineBlank = [string]::IsNullOrWhitespace($line)
+ }
+
+ if ($started -eq $true)
+ {
+ # Note: If we never wrote the entry it means the file ended in the unreleased section
+ if ($lastLineBlank -eq $false)
+ {
+ $content += $lineEnding
+ }
+ $content += $entry
+ }
+
+ Set-Content -Path $path -Value $content.TrimEnd()
+
+ git add $path 2>&1 | % ToString
+ if ($LASTEXITCODE -gt 0)
+ {
+ throw 'git add failure'
+ }
+
+ $changelogFilesUpdated++
+ }
+
+ if ($changelogFilesUpdated -gt 0)
+ {
+ git commit -m "Update CHANGELOGs for projects using OTelLatestStableVer." 2>&1 | % ToString
+ if ($LASTEXITCODE -gt 0)
+ {
+ throw 'git commit failure'
+ }
+
+ git push -u origin $branch 2>&1 | % ToString
+ if ($LASTEXITCODE -gt 0)
+ {
+ throw 'git push failure'
+ }
+ }
}
Export-ModuleMember -Function CreateStableVersionUpdatePullRequest
+
+function GetCoreDependenciesForProjects {
+ $projects = @(Get-ChildItem -Path 'src/*/*.csproj')
+
+ $projectsAndDependencies = @{}
+
+ foreach ($project in $projects)
+ {
+ # Note: dotnet restore may fail if the core packages aren't available yet but that is fine, we just want to generate project.assets.json for these projects.
+ $output = dotnet restore $project -p:RunningDotNetPack=true
+
+ $projectDir = $project | Split-Path -Parent
+
+ $content = (Get-Content "$projectDir/obj/project.assets.json" -Raw)
+
+ $projectDependencies = @{}
+
+ $matches = [regex]::Matches($content, '"(OpenTelemetry(?:.*))?": {[\S\s]*?"target": "Package",[\S\s]*?"version": "(.*)"[\S\s]*?}')
+ foreach ($match in $matches)
+ {
+ $packageName = $match.Groups[1].Value
+ $packageVersion = $match.Groups[2].Value
+ if ($packageName -eq 'OpenTelemetry' -or
+ $packageName -eq 'OpenTelemetry.Api' -or
+ $packageName -eq 'OpenTelemetry.Api.ProviderBuilderExtensions' -or
+ $packageName -eq 'OpenTelemetry.Extensions.Hosting' -or
+ $packageName -eq 'OpenTelemetry.Extensions.Propagators')
+ {
+ $projectDependencies[$packageName.ToString()] = $packageVersion.ToString()
+ }
+ }
+ $projectsAndDependencies[$projectDir.ToString()] = $projectDependencies
+ }
+
+ return $projectsAndDependencies
+}
+
+function InvokeCoreVersionUpdateWorkflowInRemoteRepository {
+ param(
+ [Parameter(Mandatory=$true)][string]$remoteGitRepository,
+ [Parameter(Mandatory=$true)][string]$tag,
+ [Parameter()][string]$targetBranch="main"
+ )
+
+ $match = [regex]::Match($tag, '^(.*?-)(.*)$')
+ if ($match.Success -eq $false)
+ {
+ throw 'Could not parse prefix or version from tag'
+ }
+
+ gh workflow run "core-version-update.yml" `
+ --repo $remoteGitRepository `
+ --ref $targetBranch `
+ --field "tag=$tag"
+}
+
+Export-ModuleMember -Function InvokeCoreVersionUpdateWorkflowInRemoteRepository
+
+function TryPostReleasePublishedNoticeOnPrepareReleasePullRequest {
+ param(
+ [Parameter(Mandatory=$true)][string]$gitRepository,
+ [Parameter(Mandatory=$true)][string]$botUserName,
+ [Parameter(Mandatory=$true)][string]$tag
+ )
+
+ $tagSha = git rev-list -n 1 $tag 2>&1 | % ToString
+ if ($LASTEXITCODE -gt 0)
+ {
+ throw 'git rev-list failure'
+ }
+
+ $prListResponse = gh pr list --search $tagSha --state merged --json number,author,title,comments | ConvertFrom-Json
+
+ if ($prListResponse.Length -eq 0)
+ {
+ Write-Host 'No prepare release PR found for tag & commit skipping post notice'
+ return
+ }
+
+ foreach ($pr in $prListResponse)
+ {
+ if ($pr.author.login -ne $botUserName -or $pr.title -ne "[release] Prepare release $tag")
+ {
+ continue
+ }
+
+ $foundComment = $false
+ foreach ($comment in $pr.comments)
+ {
+ if ($comment.author.login -eq $botUserName -and $comment.body.StartsWith("The packages for [$tag](https://github.com/$gitRepository/releases/tag/$tag) are now available:"))
+ {
+ $foundComment = $true
+ break
+ }
+ }
+
+ if ($foundComment -eq $false)
+ {
+ continue
+ }
+
+ $body =
+@"
+The release [$tag](https://github.com/$gitRepository/releases/tag/$tag) has been published and packages should be available on NuGet momentarily.
+
+Have a nice day!
+"@
+
+ $pullRequestNumber = $pr.number
+
+ gh pr comment $pullRequestNumber --body $body
+ return
+ }
+
+ Write-Host 'No prepare release PR found matched author and title with a valid comment'
+}
+
+Export-ModuleMember -Function TryPostReleasePublishedNoticeOnPrepareReleasePullRequest
diff --git a/build/scripts/prepare-release.psm1 b/build/scripts/prepare-release.psm1
index ad2b0b53e7..44ba4f4130 100644
--- a/build/scripts/prepare-release.psm1
+++ b/build/scripts/prepare-release.psm1
@@ -1,24 +1,31 @@
-$gitHubBotUserName="github-actions[bot]"
-$gitHubBotEmail="41898282+github-actions[bot]@users.noreply.github.com"
-
-$repoViewResponse = gh repo view --json nameWithOwner | ConvertFrom-Json
-
-$gitRepository = $repoViewResponse.nameWithOwner
-
function CreatePullRequestToUpdateChangelogsAndPublicApis {
param(
+ [Parameter(Mandatory=$true)][string]$gitRepository,
[Parameter(Mandatory=$true)][string]$minVerTagPrefix,
[Parameter(Mandatory=$true)][string]$version,
- [Parameter()][string]$gitUserName=$gitHubBotUserName,
- [Parameter()][string]$gitUserEmail=$gitHubBotEmail,
- [Parameter()][string]$targetBranch="main"
+ [Parameter(Mandatory=$true)][string]$requestedByUserName,
+ [Parameter()][string]$targetBranch="main",
+ [Parameter()][string]$gitUserName,
+ [Parameter()][string]$gitUserEmail
)
+ $match = [regex]::Match($version, '^(\d+\.\d+\.\d+)(?:-((?:alpha)|(?:beta)|(?:rc))\.(\d+))?$')
+ if ($match.Success -eq $false)
+ {
+ throw 'Input version did not match expected format'
+ }
+
$tag="${minVerTagPrefix}${version}"
$branch="release/prepare-${tag}-release"
- git config user.name $gitUserName
- git config user.email $gitUserEmail
+ if ([string]::IsNullOrEmpty($gitUserName) -eq $false)
+ {
+ git config user.name $gitUserName
+ }
+ if ([string]::IsNullOrEmpty($gitUserEmail) -eq $false)
+ {
+ git config user.email $gitUserEmail
+ }
git switch --create $branch 2>&1 | % ToString
if ($LASTEXITCODE -gt 0)
@@ -30,6 +37,8 @@ function CreatePullRequestToUpdateChangelogsAndPublicApis {
@"
Note: This PR was opened automatically by the [prepare release workflow](https://github.com/$gitRepository/actions/workflows/prepare-release.yml).
+Requested by: @$requestedByUserName
+
## Changes
* CHANGELOG files updated for projects being released.
@@ -46,6 +55,16 @@ Note: This PR was opened automatically by the [prepare release workflow](https:/
$body += "`r`n* Public API files updated for projects being released (only performed for stable releases)."
}
+ $body +=
+@"
+
+## Commands
+
+``/UpdateReleaseDates``: Use to update release dates in CHANGELOGs before merging [``approvers``, ``maintainers``]
+``/CreateReleaseTag``: Use after merging to push the release tag and trigger the job to create packages [``approvers``, ``maintainers``]
+``/PushPackages``: Use after the created packages have been validated to push to NuGet [``maintainers``]
+"@
+
git commit -a -m "Prepare repo to release $tag." 2>&1 | % ToString
if ($LASTEXITCODE -gt 0)
{
@@ -59,33 +78,30 @@ Note: This PR was opened automatically by the [prepare release workflow](https:/
}
gh pr create `
- --title "[repo] Prepare release $tag" `
+ --title "[release] Prepare release $tag" `
--body $body `
--base $targetBranch `
--head $branch `
- --label infra
+ --label release
}
Export-ModuleMember -Function CreatePullRequestToUpdateChangelogsAndPublicApis
function LockPullRequestAndPostNoticeToCreateReleaseTag {
param(
+ [Parameter(Mandatory=$true)][string]$gitRepository,
[Parameter(Mandatory=$true)][string]$pullRequestNumber,
- [Parameter()][string]$gitUserName=$gitHubBotUserName,
- [Parameter()][string]$gitUserEmail=$gitHubBotEmail
+ [Parameter(Mandatory=$true)][string]$botUserName
)
- git config user.name $gitUserName
- git config user.email $gitUserEmail
-
$prViewResponse = gh pr view $pullRequestNumber --json mergeCommit,author,title | ConvertFrom-Json
- if ($prViewResponse.author.is_bot -eq $false -or $prViewResponse.author.login -ne 'app/github-actions')
+ if ($prViewResponse.author.login -ne $botUserName)
{
throw 'PR author was unexpected'
}
- $match = [regex]::Match($prViewResponse.title, '^\[repo\] Prepare release (.*)$')
+ $match = [regex]::Match($prViewResponse.title, '^\[release\] Prepare release (.*)$')
if ($match.Success -eq $false)
{
throw 'Could not parse tag from PR title'
@@ -103,7 +119,7 @@ function LockPullRequestAndPostNoticeToCreateReleaseTag {
@"
I noticed this PR was merged.
-Post a comment with "/CreateReleaseTag" in the body if you would like me to create the release tag ``$tag`` for [the merge commit](https://github.com/$gitRepository/commit/$commit) and then trigger the package workflow.
+Post a comment with "/CreateReleaseTag" in the body if you would like me to create the release tag ``$tag`` for [the merge commit](https://github.com/$gitRepository/commit/$commit) which will trigger the package workflow.
"@
gh pr comment $pullRequestNumber --body $body
@@ -113,32 +129,29 @@ Post a comment with "/CreateReleaseTag" in the body if you would like me to crea
Export-ModuleMember -Function LockPullRequestAndPostNoticeToCreateReleaseTag
-function CreateReleaseTag {
+function CreateReleaseTagAndPostNoticeOnPullRequest {
param(
+ [Parameter(Mandatory=$true)][string]$gitRepository,
[Parameter(Mandatory=$true)][string]$pullRequestNumber,
- [Parameter(Mandatory=$true)][string]$actionRunId,
- [Parameter()][string]$gitUserName=$gitHubBotUserName,
- [Parameter()][string]$gitUserEmail=$gitHubBotEmail,
- [Parameter()][ref]$tag
+ [Parameter(Mandatory=$true)][string]$botUserName,
+ [Parameter()][string]$gitUserName,
+ [Parameter()][string]$gitUserEmail
)
- git config user.name $gitUserName
- git config user.email $gitUserEmail
-
$prViewResponse = gh pr view $pullRequestNumber --json mergeCommit,author,title | ConvertFrom-Json
- if ($prViewResponse.author.is_bot -eq $false -or $prViewResponse.author.login -ne 'app/github-actions')
+ if ($prViewResponse.author.login -ne $botUserName)
{
throw 'PR author was unexpected'
}
- $match = [regex]::Match($prViewResponse.title, '^\[repo\] Prepare release (.*)$')
+ $match = [regex]::Match($prViewResponse.title, '^\[release\] Prepare release (.*)$')
if ($match.Success -eq $false)
{
throw 'Could not parse tag from PR title'
}
- $tagValue = $match.Groups[1].Value
+ $tag = $match.Groups[1].Value
$commit = $prViewResponse.mergeCommit.oid
if ([string]::IsNullOrEmpty($commit) -eq $true)
@@ -146,49 +159,138 @@ function CreateReleaseTag {
throw 'Could not find merge commit'
}
- git tag -a $tagValue -m "$tagValue" $commit 2>&1 | % ToString
+ if ([string]::IsNullOrEmpty($gitUserName) -eq $false)
+ {
+ git config user.name $gitUserName
+ }
+ if ([string]::IsNullOrEmpty($gitUserEmail) -eq $false)
+ {
+ git config user.email $gitUserEmail
+ }
+
+ git tag -a $tag -m "$tag" $commit 2>&1 | % ToString
if ($LASTEXITCODE -gt 0)
{
throw 'git tag failure'
}
- git push origin $tagValue 2>&1 | % ToString
+ git push origin $tag 2>&1 | % ToString
if ($LASTEXITCODE -gt 0)
{
throw 'git push failure'
}
- gh pr unlock $pullRequestNumber
-
$body =
@"
-I just pushed the [$tagValue](https://github.com/$gitRepository/releases/tag/$tagValue) tag.
+I just pushed the [$tag](https://github.com/$gitRepository/releases/tag/$tag) tag.
-The [package workflow](https://github.com/$gitRepository/actions/runs/$actionRunId) should begin momentarily.
+The [package workflow](https://github.com/$gitRepository/actions/workflows/publish-packages-1.0.yml) should begin momentarily.
"@
gh pr comment $pullRequestNumber --body $body
-
- $tag.value = $tagValue
}
-Export-ModuleMember -Function CreateReleaseTag
+Export-ModuleMember -Function CreateReleaseTagAndPostNoticeOnPullRequest
-function PostPackagesReadyNotice {
+function UpdateChangelogReleaseDatesAndPostNoticeOnPullRequest {
param(
+ [Parameter(Mandatory=$true)][string]$gitRepository,
[Parameter(Mandatory=$true)][string]$pullRequestNumber,
- [Parameter(Mandatory=$true)][string]$tag,
- [Parameter(Mandatory=$true)][string]$packagesUrl
+ [Parameter(Mandatory=$true)][string]$botUserName,
+ [Parameter(Mandatory=$true)][string]$commentUserName,
+ [Parameter()][string]$gitUserName,
+ [Parameter()][string]$gitUserEmail
)
- $body =
+ $prViewResponse = gh pr view $pullRequestNumber --json headRefName,author,title | ConvertFrom-Json
+
+ if ($prViewResponse.author.login -ne $botUserName)
+ {
+ throw 'PR author was unexpected'
+ }
+
+ $match = [regex]::Match($prViewResponse.title, '^\[release\] Prepare release (.*)$')
+ if ($match.Success -eq $false)
+ {
+ throw 'Could not parse tag from PR title'
+ }
+
+ $tag = $match.Groups[1].Value
+
+ $match = [regex]::Match($tag, '^(.*?-)(.*)$')
+ if ($match.Success -eq $false)
+ {
+ throw 'Could not parse prefix or version from tag'
+ }
+
+ $tagPrefix = $match.Groups[1].Value
+ $version = $match.Groups[2].Value
+
+ $commentUserPermission = gh api "repos/$gitRepository/collaborators/$commentUserName/permission" | ConvertFrom-Json
+ if ($commentUserPermission.permission -ne 'admin' -and $commentUserPermission.permission -ne 'write')
+ {
+ gh pr comment $pullRequestNumber `
+ --body "I'm sorry @$commentUserName but you don't have permission to update this PR. Only maintainers and approvers can update this PR."
+ return
+ }
+
+ if ([string]::IsNullOrEmpty($gitUserName) -eq $false)
+ {
+ git config user.name $gitUserName
+ }
+ if ([string]::IsNullOrEmpty($gitUserEmail) -eq $false)
+ {
+ git config user.email $gitUserEmail
+ }
+
+ git switch $prViewResponse.headRefName 2>&1 | % ToString
+ if ($LASTEXITCODE -gt 0)
+ {
+ throw 'git switch failure'
+ }
+
+ $updatedFiles = 0
+ $newHeader =
@"
-The packages for [$tag](https://github.com/$gitRepository/releases/tag/$tag) are now available: $packagesUrl.
+## $version
-Have a nice day!
+Released $(Get-Date -UFormat '%Y-%b-%d')
"@
- gh pr comment $pullRequestNumber --body $body
+ $projectDirs = Get-ChildItem -Path src/**/*.csproj | Select-String "$tagPrefix" -List | Select Path | Split-Path -Parent
+
+ foreach ($projectDir in $projectDirs)
+ {
+ $content = (Get-Content "$projectDir/CHANGELOG.md" -Raw)
+
+ $newContent = $content -replace "## $version\s*Released .*", $newHeader
+
+ if ($content -ne $newContent)
+ {
+ $updatedFiles++
+ Set-Content -Path "$projectDir/CHANGELOG.md" $newContent.Trim()
+ }
+ }
+
+ if ($updatedFiles -eq 0)
+ {
+ gh pr comment $pullRequestNumber --body "All of the CHANGELOG files have valid release dates."
+ return
+ }
+
+ git commit -a -m "Update CHANGELOG release dates for $tag." 2>&1 | % ToString
+ if ($LASTEXITCODE -gt 0)
+ {
+ throw 'git commit failure'
+ }
+
+ git push -u origin $prViewResponse.headRefName 2>&1 | % ToString
+ if ($LASTEXITCODE -gt 0)
+ {
+ throw 'git push failure'
+ }
+
+ gh pr comment $pullRequestNumber --body "I updated the CHANGELOG release dates."
}
-Export-ModuleMember -Function PostPackagesReadyNotice
+Export-ModuleMember -Function UpdateChangelogReleaseDatesAndPostNoticeOnPullRequest
diff --git a/build/scripts/test-aot-compatibility.ps1 b/build/scripts/test-aot-compatibility.ps1
index c7fc3acf7d..895055a1b4 100644
--- a/build/scripts/test-aot-compatibility.ps1
+++ b/build/scripts/test-aot-compatibility.ps1
@@ -44,7 +44,7 @@ $testPassed = 0
if ($actualWarningCount -ne $expectedWarningCount)
{
$testPassed = 1
- Write-Host "Actual warning count:", actualWarningCount, "is not as expected. Expected warning count is:", $expectedWarningCount
+ Write-Host "Actual warning count:", $actualWarningCount, "is not as expected. Expected warning count is:", $expectedWarningCount
}
Exit $testPassed
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000000..23d80c8a57
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,134 @@
+# OpenTelemetry .NET SDK
+
+## Initialize the SDK
+
+There are two different common initialization styles supported by OpenTelemetry.
+
+### Initialize the SDK using a host
+
+Users building applications based on
+[Microsoft.Extensions.Hosting](https://www.nuget.org/packages/Microsoft.Extensions.Hosting)
+should utilize the
+[OpenTelemetry.Extensions.Hosting](../src/OpenTelemetry.Extensions.Hosting/README.md)
+package to initialize OpenTelemetry. This style provides a deep integration
+between the host infrastructure (`IServiceCollection`, `IServiceProvider`,
+`IConfiguration`, etc.) and OpenTelemetry.
+
+[AspNetCore](https://learn.microsoft.com/aspnet/core/fundamentals/host/web-host)
+applications are the most common to use the hosting model but there is also a
+[Generic Host](https://learn.microsoft.com/dotnet/core/extensions/generic-host)
+which may be used in console, service, and worker applications.
+
+> [!NOTE]
+> When using `OpenTelemetry.Extensions.Hosting` only a single pipeline will be
+> created for each configured signal (logging, metrics, and/or tracing). Users
+> who need more granular control can create additional pipelines using the
+> manual style below.
+
+First install the
+[OpenTelemetry.Extensions.Hosting](../src/OpenTelemetry.Extensions.Hosting/README.md)
+package.
+
+Second call the `AddOpenTelemetry` extension using the host
+`IServiceCollection`:
+
+```csharp
+var builder = WebApplication.CreateBuilder(args);
+
+// Clear the default logging providers added by the host
+builder.Logging.ClearProviders();
+
+// Initialize OpenTelemetry
+builder.Services.AddOpenTelemetry()
+ .ConfigureResource(resource => /* Resource configuration goes here */)
+ .WithLogging(logging => /* Logging configuration goes here */)
+ .WithMetrics(metrics => /* Metrics configuration goes here */)
+ .WithTracing(tracing => /* Tracing configuration goes here */));
+```
+
+> [!NOTE]
+> Calling `WithLogging` automatically registers the OpenTelemetry
+> `ILoggerProvider` and enables `ILogger` integration.
+
+### Initialize the SDK manually
+
+Users running on .NET Framework or running without a host may initialize
+OpenTelemetry manually.
+
+> [!IMPORTANT]
+> When initializing OpenTelemetry manually make sure to ALWAYS dispose the SDK
+> and/or providers when the application is shutting down. Disposing
+> OpenTelemetry gives the SDK a chance to flush any telemetry held in memory.
+> Skipping this step may result in data loss.
+
+First install the [OpenTelemetry SDK](../src/OpenTelemetry/README.md) package or
+an exporter package such as
+[OpenTelemetry.Exporter.OpenTelemetryProtocol](../src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md).
+Exporter packages typically reference the SDK and will make it available via
+transitive reference.
+
+Second use one of the following initialization APIs (depending on the SDK
+version being used):
+
+#### Using 1.10.0 or newer
+
+The `OpenTelemetrySdk.Create` API can be used to initialize all signals off a
+single root builder and supports cross-cutting extensions such as
+`ConfigureResource` which configures a `Resource` to be used by all enabled
+signals. An `OpenTelemetrySdk` instance is returned which may be used to access
+providers for each signal. Calling `Dispose` on the returned instance will
+gracefully shutdown the SDK and flush any telemetry held in memory.
+
+> [!NOTE]
+> When calling `OpenTelemetrySdk.Create` a dedicated `IServiceCollection` and
+> `IServiceProvider` will be created for the SDK and shared by all signals. An
+> `IConfiguration` is created automatically from environment variables.
+
+```csharp
+using OpenTelemetry;
+
+var sdk = OpenTelemetrySdk.Create(builder => builder
+ .ConfigureResource(resource => /* Resource configuration goes here */)
+ .WithLogging(logging => /* Logging configuration goes here */)
+ .WithMetrics(metrics => /* Metrics configuration goes here */)
+ .WithTracing(tracing => /* Tracing configuration goes here */));
+
+// During application shutdown
+sdk.Dispose();
+```
+
+To obtain an `ILogger` instance for emitting logs when using the
+`OpenTelemetrySdk.Create` API call the `GetLoggerFactory` extension method using
+the returned `OpenTelemetrySdk` instance:
+
+```csharp
+var logger = sdk.GetLoggerFactory().CreateLogger();
+logger.LogInformation("Application started");
+```
+
+#### Using 1.9.0 or older
+
+The following shows how to create providers for each individual signal. Each
+provider is independent and must be managed and disposed explicitly. There is no
+mechanism using this style to perform cross-cutting actions across signals.
+
+```csharp
+using Microsoft.Extensions.Logging;
+using OpenTelemetry;
+
+var tracerProvider = Sdk.CreateTracerProviderBuilder()
+ /* Tracing configuration goes here */
+ .Build();
+
+var meterProvider = Sdk.CreateMeterProviderBuilder()
+ /* Metrics configuration goes here */
+ .Build();
+
+var loggerFactory = LoggerFactory.Create(builder => builder
+ .AddOpenTelemetry(options => /* Logging configuration goes here */));
+
+// During application shutdown
+tracerProvider.Dispose();
+meterProvider.Dispose();
+loggerFactory.Dispose();
+```
diff --git a/docs/diagnostics/experimental-apis/OTEL1000.md b/docs/diagnostics/experimental-apis/OTEL1000.md
index 1ea4be023a..28b8147293 100644
--- a/docs/diagnostics/experimental-apis/OTEL1000.md
+++ b/docs/diagnostics/experimental-apis/OTEL1000.md
@@ -4,11 +4,17 @@
This is an Experimental API diagnostic covering the following APIs:
+* `ILoggingBuilder.UseOpenTelemetry`
+
+Experimental APIs may be changed or removed in the future.
+
+The following portions of `OTEL1000` were released stable in `1.9.0` and are no
+longer considered experimental:
+
* `LoggerProviderBuilder`
* `LoggerProvider`
* `IDeferredLoggerProviderBuilder`
-
-Experimental APIs may be changed or removed in the future.
+* `OpenTelemetryBuilder.WithLogging`
## Details
diff --git a/docs/diagnostics/experimental-apis/OTEL1001.md b/docs/diagnostics/experimental-apis/OTEL1001.md
index 5386726e64..aeb8952630 100644
--- a/docs/diagnostics/experimental-apis/OTEL1001.md
+++ b/docs/diagnostics/experimental-apis/OTEL1001.md
@@ -9,6 +9,7 @@ This is an Experimental API diagnostic covering the following APIs:
* `LogRecordAttributeList`
* `LogRecordData`
* `LogRecordSeverity`
+* `Sdk.CreateLoggerProviderBuilder`
Experimental APIs may be changed or removed in the future.
diff --git a/docs/diagnostics/experimental-apis/OTEL1003.md b/docs/diagnostics/experimental-apis/OTEL1003.md
deleted file mode 100644
index 5f62f03575..0000000000
--- a/docs/diagnostics/experimental-apis/OTEL1003.md
+++ /dev/null
@@ -1,47 +0,0 @@
-# OpenTelemetry .NET Diagnostic: OTEL1003
-
-## Overview
-
-This is an Experimental API diagnostic covering the following API:
-
-* `MetricStreamConfiguration.CardinalityLimit.get`
-* `MetricStreamConfiguration.CardinalityLimit.set`
-
-Experimental APIs may be changed or removed in the future.
-
-## Details
-
-From the specification:
-
-> The cardinality limit for an aggregation is defined in one of three ways:
->
-> 1. A view with criteria matching the instrument an aggregation is created for
-> has an `aggregation_cardinality_limit` value defined for the stream, that
-> value SHOULD be used.
-> 2. If there is no matching view, but the `MetricReader` defines a default
-> cardinality limit value based on the instrument an aggregation is created
-> for, that value SHOULD be used.
-> 3. If none of the previous values are defined, the default value of 2000
-> SHOULD be used.
-
-We are exposing these APIs experimentally until the specification declares them
-stable.
-
-### Setting cardinality limit for a specific Metric via the View API
-
-The OpenTelemetry Specification defines the [cardinality
-limit](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#cardinality-limits)
-of a metric can be set by the matching view.
-
-```csharp
-using var meterProvider = Sdk.CreateMeterProviderBuilder()
- .AddView(
- instrumentName: "MyFruitCounter",
- new MetricStreamConfiguration { CardinalityLimit = 10 })
- .Build();
-```
-
-### Setting cardinality limit for a specific MetricReader
-
-[This is not currently supported by OpenTelemetry
-.NET.](https://github.com/open-telemetry/opentelemetry-dotnet/issues/5331)
diff --git a/docs/diagnostics/experimental-apis/README.md b/docs/diagnostics/experimental-apis/README.md
index 6c581030b4..daa80d34b3 100644
--- a/docs/diagnostics/experimental-apis/README.md
+++ b/docs/diagnostics/experimental-apis/README.md
@@ -27,12 +27,6 @@ Description: Logs Bridge API
Details: [OTEL1001](./OTEL1001.md)
-### OTEL1003
-
-Description: MetricStreamConfiguration CardinalityLimit Support
-
-Details: [OTEL1003](./OTEL1003.md)
-
### OTEL1004
Description: ExemplarReservoir Support
@@ -58,3 +52,11 @@ Description: Metrics Exemplar Support
Details: [OTEL1002](https://github.com/open-telemetry/opentelemetry-dotnet/blob/b8ea807bae1a5d9b0f3d6d23b1e1e10f5e096a25/docs/diagnostics/experimental-apis/OTEL1002.md)
Released stable: `1.9.0`
+
+### OTEL1003
+
+Description: MetricStreamConfiguration CardinalityLimit Support
+
+Details: [OTEL1003](https://github.com/open-telemetry/opentelemetry-dotnet/blob/9f41eadf03f3dcc5e76c686b61fb39849f046312/docs/diagnostics/experimental-apis/OTEL1003.md)
+
+Released stable: `1.10.0`
diff --git a/docs/logs/dedicated-pipeline/DedicatedLogging/DedicatedLoggingServiceCollectionExtensions.cs b/docs/logs/dedicated-pipeline/DedicatedLogging/DedicatedLoggingServiceCollectionExtensions.cs
index 538f23b5cb..c9343185e2 100644
--- a/docs/logs/dedicated-pipeline/DedicatedLogging/DedicatedLoggingServiceCollectionExtensions.cs
+++ b/docs/logs/dedicated-pipeline/DedicatedLogging/DedicatedLoggingServiceCollectionExtensions.cs
@@ -11,20 +11,25 @@ public static class DedicatedLoggingServiceCollectionExtensions
public static IServiceCollection AddDedicatedLogging(
this IServiceCollection services,
IConfiguration configuration,
- Action configureOpenTelemetry)
+ Action configureOpenTelemetry)
{
ArgumentNullException.ThrowIfNull(configureOpenTelemetry);
- services.TryAddSingleton(sp =>
+ services.TryAddSingleton(_ =>
{
- var loggerFactory = LoggerFactory.Create(builder =>
+ var services = new ServiceCollection();
+ services.AddLogging(builder =>
{
builder.AddConfiguration(configuration);
- builder.AddOpenTelemetry(configureOpenTelemetry);
+ builder.AddOpenTelemetry();
});
- return new DedicatedLoggerFactory(loggerFactory);
+ services.ConfigureOpenTelemetryLoggerProvider(configureOpenTelemetry);
+
+ var sp = services.BuildServiceProvider();
+
+ return new DedicatedLoggerFactory(sp);
});
services.TryAdd(ServiceDescriptor.Singleton(typeof(IDedicatedLogger<>), typeof(DedicatedLogger<>)));
@@ -54,11 +59,13 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except
private sealed class DedicatedLoggerFactory : ILoggerFactory
{
+ private readonly ServiceProvider serviceProvider;
private readonly ILoggerFactory innerLoggerFactory;
- public DedicatedLoggerFactory(ILoggerFactory loggerFactory)
+ public DedicatedLoggerFactory(ServiceProvider serviceProvider)
{
- this.innerLoggerFactory = loggerFactory;
+ this.serviceProvider = serviceProvider;
+ this.innerLoggerFactory = serviceProvider.GetRequiredService();
}
public void AddProvider(ILoggerProvider provider)
@@ -68,6 +75,6 @@ public ILogger CreateLogger(string categoryName)
=> this.innerLoggerFactory.CreateLogger(categoryName);
public void Dispose()
- => this.innerLoggerFactory.Dispose();
+ => this.serviceProvider.Dispose();
}
}
diff --git a/docs/logs/dedicated-pipeline/Program.cs b/docs/logs/dedicated-pipeline/Program.cs
index ad671445cd..c465c77d0d 100644
--- a/docs/logs/dedicated-pipeline/Program.cs
+++ b/docs/logs/dedicated-pipeline/Program.cs
@@ -8,18 +8,19 @@
builder.Logging.ClearProviders();
-builder.Logging.AddOpenTelemetry(options =>
-{
- // Set up primary pipeline for common app logs
- options.AddConsoleExporter();
-});
+builder.Services.AddOpenTelemetry()
+ .WithLogging(logging =>
+ {
+ // Set up primary pipeline for common app logs
+ logging.AddConsoleExporter();
+ });
builder.Services.AddDedicatedLogging(
builder.Configuration.GetSection("DedicatedLogging"), // Bind configuration for dedicated logging pipeline
- options =>
+ logging =>
{
// Set up secondary pipeline for dedicated logs
- options.AddConsoleExporter();
+ logging.AddConsoleExporter();
});
var app = builder.Build();
diff --git a/docs/logs/getting-started-aspnetcore/Program.cs b/docs/logs/getting-started-aspnetcore/Program.cs
index 179d9d2237..123bf54a2c 100644
--- a/docs/logs/getting-started-aspnetcore/Program.cs
+++ b/docs/logs/getting-started-aspnetcore/Program.cs
@@ -6,25 +6,21 @@
var builder = WebApplication.CreateBuilder(args);
-// Remove default providers and add OpenTelemetry logging provider.
-// For instructional purposes only, disable the default .NET console logging provider to
-// use the verbose OpenTelemetry console exporter instead. For most development
-// and production scenarios the default console provider works well and there is no need to
+// For instructional purposes only, disable the default .NET logging providers.
+// We remove the console logging provider in this demo to use the verbose
+// OpenTelemetry console exporter instead. For most development and production
+// scenarios the default console provider works well and there is no need to
// clear these providers.
builder.Logging.ClearProviders();
-builder.Logging.AddOpenTelemetry(logging =>
-{
- var resourceBuilder = ResourceBuilder
- .CreateDefault()
- .AddService(builder.Environment.ApplicationName);
-
- logging.SetResourceBuilder(resourceBuilder)
-
- // ConsoleExporter is used for demo purpose only.
- // In production environment, ConsoleExporter should be replaced with other exporters (e.g. OTLP Exporter).
- .AddConsoleExporter();
-});
+// Add OpenTelemetry logging provider by calling the WithLogging extension.
+builder.Services.AddOpenTelemetry()
+ .ConfigureResource(r => r.AddService(builder.Environment.ApplicationName))
+ .WithLogging(logging => logging
+ /* Note: ConsoleExporter is used for demo purpose only. In production
+ environment, ConsoleExporter should be replaced with other exporters
+ (e.g. OTLP Exporter). */
+ .AddConsoleExporter());
var app = builder.Build();
diff --git a/docs/logs/redaction/MyRedactionProcessor.cs b/docs/logs/redaction/MyRedactionProcessor.cs
index 7959faf3d6..cec1edc450 100644
--- a/docs/logs/redaction/MyRedactionProcessor.cs
+++ b/docs/logs/redaction/MyRedactionProcessor.cs
@@ -15,18 +15,18 @@ public override void OnEnd(LogRecord logRecord)
}
}
- internal sealed class MyClassWithRedactionEnumerator : IReadOnlyList>
+ internal sealed class MyClassWithRedactionEnumerator : IReadOnlyList>
{
- private readonly IReadOnlyList> state;
+ private readonly IReadOnlyList> state;
- public MyClassWithRedactionEnumerator(IReadOnlyList> state)
+ public MyClassWithRedactionEnumerator(IReadOnlyList> state)
{
this.state = state;
}
public int Count => this.state.Count;
- public KeyValuePair this[int index]
+ public KeyValuePair this[int index]
{
get
{
@@ -34,14 +34,14 @@ public KeyValuePair this[int index]
var entryVal = item.Value?.ToString();
if (entryVal != null && entryVal.Contains(""))
{
- return new KeyValuePair(item.Key, "newRedactedValueHere");
+ return new KeyValuePair(item.Key, "newRedactedValueHere");
}
return item;
}
}
- public IEnumerator> GetEnumerator()
+ public IEnumerator> GetEnumerator()
{
for (var i = 0; i < this.Count; i++)
{
diff --git a/docs/logs/redaction/redaction.csproj b/docs/logs/redaction/redaction.csproj
index 2dc5d8deb6..19aa979143 100644
--- a/docs/logs/redaction/redaction.csproj
+++ b/docs/logs/redaction/redaction.csproj
@@ -1,8 +1,4 @@
-
-
- disable
-
diff --git a/docs/metrics/README.md b/docs/metrics/README.md
index a96ade061b..0394f63451 100644
--- a/docs/metrics/README.md
+++ b/docs/metrics/README.md
@@ -10,11 +10,13 @@
* [Instruments](#instruments)
* [MeterProvider Management](#meterprovider-management)
* [Memory Management](#memory-management)
+ * [Example](#example)
* [Pre-Aggregation](#pre-aggregation)
* [Cardinality Limits](#cardinality-limits)
* [Memory Preallocation](#memory-preallocation)
* [Metrics Correlation](#metrics-correlation)
* [Metrics Enrichment](#metrics-enrichment)
+* [Common issues that lead to missing metrics](#common-issues-that-lead-to-missing-metrics)
@@ -86,7 +88,7 @@ static readonly Meter MyMeter = new("MyCompany.MyProduct.MyLibrary", "1.0");
| [Asynchronous Gauge](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#asynchronous-gauge) | [`ObservableGauge`](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.observablegauge-1) |
| [Asynchronous UpDownCounter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#asynchronous-updowncounter) | [`ObservableUpDownCounter`](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.observableupdowncounter-1) |
| [Counter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#counter) | [`Counter`](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.counter-1) |
- | [Gauge](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#gauge) (experimental) | N/A |
+ | [Gauge](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#gauge) | [`Gauge`](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.gauge-1) |
| [Histogram](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#histogram) | [`Histogram`](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.histogram-1) |
| [UpDownCounter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#updowncounter) | [`UpDownCounter`](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.updowncounter-1) |
@@ -127,7 +129,7 @@ There are two different ways of passing tags to an instrument API:
* Pass the tags directly to the instrument API:
```csharp
- counter.Add(100, ("Key1", "Value1"), ("Key2", "Value2"));
+ counter.Add(100, new("Key1", "Value1"), new("Key2", "Value2"));
```
* Use
@@ -386,22 +388,13 @@ and the `MetricStreamConfiguration.CardinalityLimit` setting. Refer to this
[doc](../../docs/metrics/customizing-the-sdk/README.md#changing-the-cardinality-limit-for-a-metric)
for more information.
-Given a metric, once the cardinality limit is reached, any new measurement which
-cannot be independently aggregated because of the limit will be dropped or
-aggregated using the [overflow
-attribute](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#overflow-attribute)
-(if enabled). When NOT using the overflow attribute feature a warning is written
-to the [self-diagnostic log](../../src/OpenTelemetry/README.md#self-diagnostics)
-the first time an overflow is detected for a given metric.
-
-> [!NOTE]
-> Overflow attribute was introduced in OpenTelemetry .NET
- [1.6.0-rc.1](../../src/OpenTelemetry/CHANGELOG.md#160-rc1). It is currently an
- experimental feature which can be turned on by setting the environment
- variable `OTEL_DOTNET_EXPERIMENTAL_METRICS_EMIT_OVERFLOW_ATTRIBUTE=true`. Once
- the [OpenTelemetry
- Specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#overflow-attribute)
- become stable, this feature will be turned on by default.
+Given a metric, once the cardinality limit is reached, any new measurement
+that could not be independently aggregated will be aggregated using the
+[overflow attribute](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#overflow-attribute).
+In versions prior to 1.10.0, the default behavior when cardinality limit was
+reached was to drop the measurement. Users had the ability to opt-in to use
+overflow attribute instead, but this behavior is the default and the only
+allowed behavior starting with version 1.10.0.
When [Delta Aggregation
Temporality](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#temporality)
diff --git a/docs/metrics/customizing-the-sdk/Program.cs b/docs/metrics/customizing-the-sdk/Program.cs
index c88a295fdd..bbfd4bea98 100644
--- a/docs/metrics/customizing-the-sdk/Program.cs
+++ b/docs/metrics/customizing-the-sdk/Program.cs
@@ -40,6 +40,12 @@ public static void Main()
// Drop the instrument "MyCounterDrop".
.AddView(instrumentName: "MyCounterDrop", MetricStreamConfiguration.Drop)
+ // Configure the Explicit Bucket Histogram aggregation with custom boundaries and new name.
+ .AddView(instrumentName: "histogramWithMultipleAggregations", new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 }, Name = "MyHistogramWithExplicitHistogram" })
+
+ // Use Base2 Exponential Bucket Histogram aggregation and new name.
+ .AddView(instrumentName: "histogramWithMultipleAggregations", new Base2ExponentialBucketHistogramConfiguration() { Name = "MyHistogramWithBase2ExponentialBucketHistogram" })
+
// An instrument which does not match any views
// gets processed with default behavior. (SDK default)
// Uncommenting the following line will
@@ -70,6 +76,12 @@ public static void Main()
exponentialBucketHistogram.Record(random.Next(1, 1000), new("tag1", "value1"), new("tag2", "value2"));
}
+ var histogramWithMultipleAggregations = Meter1.CreateHistogram("histogramWithMultipleAggregations");
+ for (int i = 0; i < 20000; i++)
+ {
+ histogramWithMultipleAggregations.Record(random.Next(1, 1000), new("tag1", "value1"), new("tag2", "value2"));
+ }
+
var counterCustomTags = Meter1.CreateCounter("MyCounterCustomTags");
for (int i = 0; i < 20000; i++)
{
diff --git a/docs/metrics/customizing-the-sdk/README.md b/docs/metrics/customizing-the-sdk/README.md
index 830ad66957..560149e20e 100644
--- a/docs/metrics/customizing-the-sdk/README.md
+++ b/docs/metrics/customizing-the-sdk/README.md
@@ -203,7 +203,7 @@ used.
By default, the boundaries used for a Histogram are [`{ 0, 5, 10, 25, 50, 75,
100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000}`](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.14.0/specification/metrics/sdk.md#explicit-bucket-histogram-aggregation).
Views can be used to provide custom boundaries for a Histogram. The measurements
-are then aggregated using the custom boundaries provided instead of the the
+are then aggregated using the custom boundaries provided instead of the
default boundaries. This requires the use of
`ExplicitBucketHistogramConfiguration`.
@@ -245,6 +245,90 @@ within the maximum number of buckets defined by `MaxSize`. The default
new Base2ExponentialBucketHistogramConfiguration { MaxSize = 40 })
```
+#### Produce multiple metrics from single instrument
+
+When an instrument matches multiple views, it can generate multiple metrics. For
+instance, if an instrument is matched by two different view configurations, it
+will result in two separate metrics being produced from that single instrument.
+Below is an example demonstrating how to leverage this capability to create two
+independent metrics from a single instrument. In this example, a histogram
+instrument is used to report measurements, and views are configured to produce
+two metrics : one aggregated using `ExplicitBucketHistogramConfiguration` and the
+other using `Base2ExponentialBucketHistogramConfiguration`.
+
+```csharp
+ var histogramWithMultipleAggregations = meter.CreateHistogram("HistogramWithMultipleAggregations");
+
+ // Configure the Explicit Bucket Histogram aggregation with custom boundaries and new name.
+ .AddView(instrumentName: "HistogramWithMultipleAggregations", new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 }, Name = "MyHistogramWithExplicitHistogram" })
+
+ // Use Base2 Exponential Bucket Histogram aggregation and new name.
+ .AddView(instrumentName: "HistogramWithMultipleAggregations", new Base2ExponentialBucketHistogramConfiguration() { Name = "MyHistogramWithBase2ExponentialBucketHistogram" })
+
+ // Both views rename the metric to avoid name conflicts. However, in this case,
+ // renaming one would be sufficient.
+
+ // This measurement will be aggregated into two separate metrics.
+ histogramWithMultipleAggregations.Record(10, new("tag1", "value1"), new("tag2", "value2"));
+```
+
+When using views that produce multiple metrics from single instrument, it's
+crucial to rename the metric to prevent conflicts. In the event of conflict,
+OpenTelemetry will emit an internal warning but will still export both metrics.
+The impact of this behavior depends on the backend or receiver being used. You
+can refer to [OpenTelemetry's
+specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#opentelemetry-protocol-data-model-consumer-recommendations)
+for more details.
+
+Below example is showing the *BAD* practice. DO NOT FOLLOW it.
+
+```csharp
+ var histogram = meter.CreateHistogram("MyHistogram");
+
+ // Configure a view to aggregate based only on the "location" tag.
+ .AddView(instrumentName: "MyHistogram", metricStreamConfiguration: new MetricStreamConfiguration
+ {
+ TagKeys = new string[] { "location" },
+ })
+
+ // Configure another view to aggregate based only on the "status" tag.
+ .AddView(instrumentName: "MyHistogram", metricStreamConfiguration: new MetricStreamConfiguration
+ {
+ TagKeys = new string[] { "status" },
+ })
+
+ // The measurement below will be aggregated into two metric streams, but both will have the same name.
+ // OpenTelemetry will issue a warning about this conflict and pass both streams to the exporter.
+ // However, this may cause issues depending on the backend.
+ histogram.Record(10, new("location", "seattle"), new("status", "OK"));
+```
+
+The modified version, avoiding name conflict is shown below:
+
+```csharp
+ var histogram = meter.CreateHistogram("MyHistogram");
+
+ // Configure a view to aggregate based only on the "location" tag,
+ // and rename the metric.
+ .AddView(instrumentName: "MyHistogram", metricStreamConfiguration: new MetricStreamConfiguration
+ {
+ Name = "MyHistogramWithLocation",
+ TagKeys = new string[] { "location" },
+ })
+
+ // Configure a view to aggregate based only on the "status" tag,
+ // and rename the metric.
+ .AddView(instrumentName: "MyHistogram", metricStreamConfiguration: new MetricStreamConfiguration
+ {
+ Name = "MyHistogramWithStatus",
+ TagKeys = new string[] { "status" },
+ })
+
+ // The measurement below will be aggregated into two separate metrics, "MyHistogramWithLocation"
+ // and "MyHistogramWithStatus".
+ histogram.Record(10, new("location", "seattle"), new("status", "OK"));
+```
+
> [!NOTE]
> The SDK currently does not support any changes to `Aggregation` type
by using Views.
@@ -319,9 +403,8 @@ metrics managed by a given `MeterProvider`, use the
> [!CAUTION]
> `MeterProviderBuilder.SetMaxMetricPointsPerMetricStream` is marked `Obsolete`
- in pre-release builds and has been replaced by
- `MetricStreamConfiguration.CardinalityLimit`. For details see:
- [OTEL1003](../../diagnostics/experimental-apis/OTEL1003.md).
+ in stable builds since 1.10.0 and has been replaced by
+ `MetricStreamConfiguration.CardinalityLimit`.
```csharp
using var meterProvider = Sdk.CreateMeterProviderBuilder()
@@ -337,11 +420,6 @@ To set the [cardinality limit](../README.md#cardinality-limits) for an
individual metric, use the `MetricStreamConfiguration.CardinalityLimit` property
on the View API:
-> [!NOTE]
-> `MetricStreamConfiguration.CardinalityLimit` is an experimental API only
- available in pre-release builds. For details see:
- [OTEL1003](../../diagnostics/experimental-apis/OTEL1003.md).
-
```csharp
var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter("MyCompany.MyProduct.MyLibrary")
diff --git a/docs/metrics/getting-started-prometheus-grafana/README.md b/docs/metrics/getting-started-prometheus-grafana/README.md
index 7f39b121a7..dfc3e09c1a 100644
--- a/docs/metrics/getting-started-prometheus-grafana/README.md
+++ b/docs/metrics/getting-started-prometheus-grafana/README.md
@@ -1,11 +1,16 @@
# Getting Started with Prometheus and Grafana
-- [Export metrics from the application](#export-metrics-from-the-application)
-- [Collect metrics using Prometheus](#collect-metrics-using-prometheus)
- - [Install and run Prometheus](#install-and-run-prometheus)
- - [View results in Prometheus](#view-results-in-prometheus)
-- [Explore metrics using Grafana](#explore-metrics-using-grafana)
-- [Learn more](#learn-more)
+
+Table of Contents
+
+* [Export metrics from the application](#export-metrics-from-the-application)
+* [Collect metrics using Prometheus](#collect-metrics-using-prometheus)
+ * [Install and run Prometheus](#install-and-run-prometheus)
+ * [View results in Prometheus](#view-results-in-prometheus)
+* [Explore metrics using Grafana](#explore-metrics-using-grafana)
+* [Learn more](#learn-more)
+
+
## Export metrics from the application
@@ -140,8 +145,8 @@ UI](https://user-images.githubusercontent.com/17327289/151636769-138ecb4f-b44f-4
## Learn more
-- [What is Prometheus?](https://prometheus.io/docs/introduction/overview/)
-- [Prometheus now supports OpenTelemetry
+* [What is Prometheus?](https://prometheus.io/docs/introduction/overview/)
+* [Prometheus now supports OpenTelemetry
Metrics](https://horovits.medium.com/prometheus-now-supports-opentelemetry-metrics-83f85878e46a)
-- [Grafana support for
+* [Grafana support for
Prometheus](https://prometheus.io/docs/visualization/grafana/#creating-a-prometheus-graph)
diff --git a/docs/trace/customizing-the-sdk/customizing-the-sdk.csproj b/docs/trace/customizing-the-sdk/customizing-the-sdk.csproj
index 2dc5d8deb6..19aa979143 100644
--- a/docs/trace/customizing-the-sdk/customizing-the-sdk.csproj
+++ b/docs/trace/customizing-the-sdk/customizing-the-sdk.csproj
@@ -1,8 +1,4 @@
-
-
- disable
-
diff --git a/docs/trace/extending-the-sdk/README.md b/docs/trace/extending-the-sdk/README.md
index 4f7380ee64..db75bad713 100644
--- a/docs/trace/extending-the-sdk/README.md
+++ b/docs/trace/extending-the-sdk/README.md
@@ -320,10 +320,10 @@ cases, it is recommended to use that option as it offers higher performance.
OpenTelemetry .NET SDK has provided the following built-in samplers:
-* [AlwaysOffSampler](../../../src/OpenTelemetry/Trace/AlwaysOffSampler.cs)
-* [AlwaysOnSampler](../../../src/OpenTelemetry/Trace/AlwaysOnSampler.cs)
-* [ParentBasedSampler](../../../src/OpenTelemetry/Trace/ParentBasedSampler.cs)
-* [TraceIdRatioBasedSampler](../../../src/OpenTelemetry/Trace/TraceIdRatioBasedSampler.cs)
+* [AlwaysOffSampler](../../../src/OpenTelemetry/Trace/Sampler/AlwaysOffSampler.cs)
+* [AlwaysOnSampler](../../../src/OpenTelemetry/Trace/Sampler/AlwaysOnSampler.cs)
+* [ParentBasedSampler](../../../src/OpenTelemetry/Trace/Sampler/ParentBasedSampler.cs)
+* [TraceIdRatioBasedSampler](../../../src/OpenTelemetry/Trace/Sampler/TraceIdRatioBasedSampler.cs)
Custom samplers can be implemented to cover more scenarios:
@@ -338,7 +338,7 @@ class MySampler : Sampler
{
public override SamplingResult ShouldSample(in SamplingParameters samplingParameters)
{
- return new SamplingResult(SamplingDecision.RecordAndSampled);
+ return new SamplingResult(SamplingDecision.RecordAndSample);
}
}
```
diff --git a/docs/trace/getting-started-aspnetcore/README.md b/docs/trace/getting-started-aspnetcore/README.md
index a9b7adf0b3..7febcf4d55 100644
--- a/docs/trace/getting-started-aspnetcore/README.md
+++ b/docs/trace/getting-started-aspnetcore/README.md
@@ -30,30 +30,30 @@ in the console for your application (ex `http://localhost:5154`). You should see
the trace output from the console.
```text
-Activity.TraceId: c1572aa14ee9c0ac037dbdc3e91e5dd7
-Activity.SpanId: 45406137f33cc279
+Activity.TraceId: c28f7b480d5c7dfc30cfbd80ad29028d
+Activity.SpanId: 27e478bbf9fdec10
Activity.TraceFlags: Recorded
-Activity.ActivitySourceName: OpenTelemetry.Instrumentation.AspNetCore
-Activity.DisplayName: /
+Activity.ActivitySourceName: Microsoft.AspNetCore
+Activity.DisplayName: GET /
Activity.Kind: Server
-Activity.StartTime: 2023-01-13T19:38:11.5417593Z
-Activity.Duration: 00:00:00.0167407
+Activity.StartTime: 2024-07-04T13:03:37.3318740Z
+Activity.Duration: 00:00:00.3693734
Activity.Tags:
- net.host.name: localhost
- net.host.port: 5154
- http.method: GET
- http.scheme: http
- http.target: /
- http.url: http://localhost:5154/
- http.flavor: 1.1
- http.user_agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.76
- http.status_code: 200
+ server.address: localhost
+ server.port: 5154
+ http.request.method: GET
+ url.scheme: https
+ url.path: /
+ network.protocol.version: 2
+ user_agent.original: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
+ http.route: /
+ http.response.status_code: 200
Resource associated with Activity:
service.name: getting-started-aspnetcore
- service.instance.id: 32c9371c-ed9d-474c-a698-b169e87a5577
+ service.instance.id: a388466b-4969-4bb0-ad96-8f39527fa66b
telemetry.sdk.name: opentelemetry
telemetry.sdk.language: dotnet
- telemetry.sdk.version: 1.5.1
+ telemetry.sdk.version: 1.9.0
```
Congratulations! You are now collecting traces using OpenTelemetry.
diff --git a/docs/trace/getting-started-jaeger/README.md b/docs/trace/getting-started-jaeger/README.md
index 4f8e36c387..92752ff66d 100644
--- a/docs/trace/getting-started-jaeger/README.md
+++ b/docs/trace/getting-started-jaeger/README.md
@@ -1,10 +1,15 @@
# Getting Started with Jaeger
-- [Export traces from the application](#export-traces-from-the-application)
- - [Check results in the console](#check-results-in-the-console)
-- [Collect and visualize traces using Jaeger](#collect-and-visualize-traces-using-jaeger)
-- [Final cleanup](#final-cleanup)
-- [Learn more](#learn-more)
+
+Table of Contents
+
+* [Export traces from the application](#export-traces-from-the-application)
+ * [Check results in the console](#check-results-in-the-console)
+* [Collect and visualize traces using Jaeger](#collect-and-visualize-traces-using-jaeger)
+* [Final cleanup](#final-cleanup)
+* [Learn more](#learn-more)
+
+
## Export traces from the application
@@ -42,25 +47,29 @@ Run the application again and we should see the trace output from the console:
```text
> dotnet run
-Activity.TraceId: a80c920e0aabb50b547e2bb7455cfd39
-Activity.SpanId: 4e45a1d51744f329
-Activity.TraceFlags: Recorded
-Activity.ParentSpanId: 4f7e9b78c55dcfad
-Activity.ActivitySourceName: OpenTelemetry.Instrumentation.Http
-Activity.DisplayName: HTTP GET
-Activity.Kind: Client
-Activity.StartTime: 2022-05-07T02:54:25.7840762Z
-Activity.Duration: 00:00:01.9615540
+Activity.TraceId: 693f1d15634bfe6ba3254d6f9d20df27
+Activity.SpanId: 429cc5a90a753fb3
+Activity.TraceFlags: Recorded
+Activity.ParentSpanId: 0d64498b736c9a11
+Activity.ActivitySourceName: System.Net.Http
+Activity.DisplayName: GET
+Activity.Kind: Client
+Activity.StartTime: 2024-07-04T13:18:12.2408786Z
+Activity.Duration: 00:00:02.1028562
Activity.Tags:
- http.method: GET
- http.host: httpstat.us
- http.url: https://httpstat.us/200?sleep=1000
- http.status_code: 200
+ http.request.method: GET
+ server.address: httpstat.us
+ server.port: 443
+ url.full: https://httpstat.us/200?sleep=Redacted
+ network.protocol.version: 1.1
+ http.response.status_code: 200
Resource associated with Activity:
service.name: DemoApp
service.version: 1.0.0
- service.instance.id: 1b3b3a6f-be43-46b0-819a-4db1200c633d
-
+ service.instance.id: 03ccafab-e9a7-440a-a9cd-9a0163e0d06c
+ telemetry.sdk.name: opentelemetry
+ telemetry.sdk.language: dotnet
+ telemetry.sdk.version: 1.9.0
...
```
@@ -178,6 +187,6 @@ BatchExportProcessor --> | Batch | OtlpExporter
## Learn more
-- [Jaeger Tracing](https://www.jaegertracing.io/)
-- [OTLP Exporter for OpenTelemetry
+* [Jaeger Tracing](https://www.jaegertracing.io/)
+* [OTLP Exporter for OpenTelemetry
.NET](../../../src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md)
diff --git a/examples/AspNetCore/Program.cs b/examples/AspNetCore/Program.cs
index 89ac46932d..809534f5c7 100644
--- a/examples/AspNetCore/Program.cs
+++ b/examples/AspNetCore/Program.cs
@@ -24,20 +24,21 @@
// Note: Switch between Explicit/Exponential by setting HistogramAggregation in appsettings.json
var histogramAggregation = appBuilder.Configuration.GetValue("HistogramAggregation", defaultValue: "explicit")!.ToLowerInvariant();
-// Build a resource configuration action to set service information.
-Action configureResource = r => r.AddService(
- serviceName: appBuilder.Configuration.GetValue("ServiceName", defaultValue: "otel-test")!,
- serviceVersion: typeof(Program).Assembly.GetName().Version?.ToString() ?? "unknown",
- serviceInstanceId: Environment.MachineName);
-
// Create a service to expose ActivitySource, and Metric Instruments
// for manual instrumentation
appBuilder.Services.AddSingleton();
-// Configure OpenTelemetry tracing & metrics with auto-start using the
+// Clear default logging providers used by WebApplication host.
+appBuilder.Logging.ClearProviders();
+
+// Configure OpenTelemetry logging, metrics, & tracing with auto-start using the
// AddOpenTelemetry extension from OpenTelemetry.Extensions.Hosting.
appBuilder.Services.AddOpenTelemetry()
- .ConfigureResource(configureResource)
+ .ConfigureResource(r => r
+ .AddService(
+ serviceName: appBuilder.Configuration.GetValue("ServiceName", defaultValue: "otel-test")!,
+ serviceVersion: typeof(Program).Assembly.GetName().Version?.ToString() ?? "unknown",
+ serviceInstanceId: Environment.MachineName))
.WithTracing(builder =>
{
// Tracing
@@ -121,34 +122,25 @@
builder.AddConsoleExporter();
break;
}
- });
-
-// Clear default logging providers used by WebApplication host.
-appBuilder.Logging.ClearProviders();
-
-// Configure OpenTelemetry Logging.
-appBuilder.Logging.AddOpenTelemetry(options =>
-{
- // Note: See appsettings.json Logging:OpenTelemetry section for configuration.
-
- var resourceBuilder = ResourceBuilder.CreateDefault();
- configureResource(resourceBuilder);
- options.SetResourceBuilder(resourceBuilder);
-
- switch (logExporter)
+ })
+ .WithLogging(builder =>
{
- case "otlp":
- options.AddOtlpExporter(otlpOptions =>
- {
- // Use IConfiguration directly for Otlp exporter endpoint option.
- otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue("Otlp:Endpoint", defaultValue: "http://localhost:4317")!);
- });
- break;
- default:
- options.AddConsoleExporter();
- break;
- }
-});
+ // Note: See appsettings.json Logging:OpenTelemetry section for configuration.
+
+ switch (logExporter)
+ {
+ case "otlp":
+ builder.AddOtlpExporter(otlpOptions =>
+ {
+ // Use IConfiguration directly for Otlp exporter endpoint option.
+ otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue("Otlp:Endpoint", defaultValue: "http://localhost:4317")!);
+ });
+ break;
+ default:
+ builder.AddConsoleExporter();
+ break;
+ }
+ });
appBuilder.Services.AddControllers();
diff --git a/docs/metrics/exemplars/docker-compose.yaml b/examples/AspNetCore/docker-compose.yaml
similarity index 96%
rename from docs/metrics/exemplars/docker-compose.yaml
rename to examples/AspNetCore/docker-compose.yaml
index c8cc94fa4b..7cdb95106e 100644
--- a/docs/metrics/exemplars/docker-compose.yaml
+++ b/examples/AspNetCore/docker-compose.yaml
@@ -3,7 +3,7 @@ services:
# OTEL Collector to receive logs, metrics and traces from the application
otel-collector:
- image: otel/opentelemetry-collector:0.70.0
+ image: otel/opentelemetry-collector:0.111.0
command: [ "--config=/etc/otel-collector.yaml" ]
volumes:
- ./otel-collector.yaml:/etc/otel-collector.yaml
diff --git a/docs/metrics/exemplars/grafana-datasources.yaml b/examples/AspNetCore/grafana-datasources.yaml
similarity index 100%
rename from docs/metrics/exemplars/grafana-datasources.yaml
rename to examples/AspNetCore/grafana-datasources.yaml
diff --git a/docs/metrics/exemplars/otel-collector.yaml b/examples/AspNetCore/otel-collector.yaml
similarity index 67%
rename from docs/metrics/exemplars/otel-collector.yaml
rename to examples/AspNetCore/otel-collector.yaml
index bcf0cb5d6d..fa9999d66c 100644
--- a/docs/metrics/exemplars/otel-collector.yaml
+++ b/examples/AspNetCore/otel-collector.yaml
@@ -2,11 +2,13 @@ receivers:
otlp:
protocols:
grpc:
+ endpoint: 0.0.0.0:4317
http:
+ endpoint: 0.0.0.0:4318
exporters:
- logging:
- loglevel: debug
+ debug:
+ verbosity: detailed
prometheus:
endpoint: ":9201"
send_timestamps: true
@@ -21,10 +23,10 @@ service:
pipelines:
traces:
receivers: [otlp]
- exporters: [logging,otlp]
+ exporters: [debug, otlp]
metrics:
receivers: [otlp]
- exporters: [logging,prometheus]
+ exporters: [debug, prometheus]
logs:
receivers: [otlp]
- exporters: [logging]
+ exporters: [debug]
diff --git a/docs/metrics/exemplars/prometheus.yaml b/examples/AspNetCore/prometheus.yaml
similarity index 100%
rename from docs/metrics/exemplars/prometheus.yaml
rename to examples/AspNetCore/prometheus.yaml
diff --git a/docs/metrics/exemplars/tempo.yaml b/examples/AspNetCore/tempo.yaml
similarity index 100%
rename from docs/metrics/exemplars/tempo.yaml
rename to examples/AspNetCore/tempo.yaml
diff --git a/examples/Console/Examples.Console.csproj b/examples/Console/Examples.Console.csproj
index d2b74f2e64..86c6b1df03 100644
--- a/examples/Console/Examples.Console.csproj
+++ b/examples/Console/Examples.Console.csproj
@@ -4,9 +4,6 @@
Exe
$(DefaultTargetFrameworkForExampleApps)
$(NoWarn),CS0618
-
-
- disable
diff --git a/examples/Console/InstrumentationWithActivitySource.cs b/examples/Console/InstrumentationWithActivitySource.cs
index 240f58289d..706d68ad99 100644
--- a/examples/Console/InstrumentationWithActivitySource.cs
+++ b/examples/Console/InstrumentationWithActivitySource.cs
@@ -47,13 +47,13 @@ public void Start(string url)
var context = this.listener.GetContext();
using var activity = source.StartActivity(
- $"{context.Request.HttpMethod}:{context.Request.Url.AbsolutePath}",
+ $"{context.Request.HttpMethod}:{context.Request.Url!.AbsolutePath}",
ActivityKind.Server);
var headerKeys = context.Request.Headers.AllKeys;
foreach (var headerKey in headerKeys)
{
- string headerValue = context.Request.Headers[headerKey];
+ string? headerValue = context.Request.Headers[headerKey];
activity?.SetTag($"http.header.{headerKey}", headerValue);
}
@@ -62,7 +62,7 @@ public void Start(string url)
using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
{
requestContent = reader.ReadToEnd();
- childSpan.AddEvent(new ActivityEvent("StreamReader.ReadToEnd"));
+ childSpan?.AddEvent(new ActivityEvent("StreamReader.ReadToEnd"));
}
activity?.SetTag("request.content", requestContent);
@@ -90,8 +90,8 @@ public void Dispose()
private class SampleClient : IDisposable
{
- private CancellationTokenSource cts;
- private Task requestTask;
+ private CancellationTokenSource? cts;
+ private Task? requestTask;
public void Start(string url)
{
@@ -154,7 +154,7 @@ public void Dispose()
if (this.cts != null)
{
this.cts.Cancel();
- this.requestTask.Wait();
+ this.requestTask!.Wait();
this.requestTask.Dispose();
this.cts.Dispose();
}
diff --git a/examples/Console/Program.cs b/examples/Console/Program.cs
index 2b93979e07..bca2e4339c 100644
--- a/examples/Console/Program.cs
+++ b/examples/Console/Program.cs
@@ -33,16 +33,16 @@ public static void Main(string[] args)
{
Parser.Default.ParseArguments(args)
.MapResult(
- (ZipkinOptions options) => TestZipkinExporter.Run(options.Uri),
- (PrometheusOptions options) => TestPrometheusExporter.Run(options.Port),
+ (ZipkinOptions options) => TestZipkinExporter.Run(options),
+ (PrometheusOptions options) => TestPrometheusExporter.Run(options),
(MetricsOptions options) => TestMetrics.Run(options),
(LogsOptions options) => TestLogs.Run(options),
- (GrpcNetClientOptions options) => TestGrpcNetClient.Run(),
- (HttpClientOptions options) => TestHttpClient.Run(),
+ (GrpcNetClientOptions options) => TestGrpcNetClient.Run(options),
+ (HttpClientOptions options) => TestHttpClient.Run(options),
(ConsoleOptions options) => TestConsoleExporter.Run(options),
(OpenTelemetryShimOptions options) => TestOTelShimWithConsoleExporter.Run(options),
(OpenTracingShimOptions options) => TestOpenTracingShim.Run(options),
- (OtlpOptions options) => TestOtlpExporter.Run(options.Endpoint, options.Protocol),
+ (OtlpOptions options) => TestOtlpExporter.Run(options),
(InMemoryOptions options) => TestInMemoryExporter.Run(options),
errs => 1);
}
@@ -54,7 +54,7 @@ public static void Main(string[] args)
internal class ZipkinOptions
{
[Option('u', "uri", HelpText = "Please specify the uri of Zipkin backend", Required = true)]
- public string Uri { get; set; }
+ public required string Uri { get; set; }
}
[Verb("prometheus", HelpText = "Specify the options required to test Prometheus")]
@@ -83,10 +83,10 @@ internal class MetricsOptions
public int DefaultCollectionPeriodMilliseconds { get; set; }
[Option("useExporter", Default = "console", HelpText = "Options include otlp or console.", Required = false)]
- public string UseExporter { get; set; }
+ public string? UseExporter { get; set; }
[Option('e', "endpoint", HelpText = "Target to which the exporter is going to send metrics (default value depends on protocol).", Default = null)]
- public string Endpoint { get; set; }
+ public string? Endpoint { get; set; }
[Option('p', "useGrpc", HelpText = "Use gRPC or HTTP when using the OTLP exporter", Required = false, Default = true)]
public bool UseGrpc { get; set; }
@@ -121,26 +121,26 @@ internal class OpenTracingShimOptions
internal class OtlpOptions
{
[Option('e', "endpoint", HelpText = "Target to which the exporter is going to send traces (default value depends on protocol).", Default = null)]
- public string Endpoint { get; set; }
+ public string? Endpoint { get; set; }
[Option('p', "protocol", HelpText = "Transport protocol used by exporter. Supported values: grpc and http/protobuf.", Default = "grpc")]
- public string Protocol { get; set; }
+ public string? Protocol { get; set; }
}
[Verb("logs", HelpText = "Specify the options required to test Logs")]
internal class LogsOptions
{
[Option("useExporter", Default = "otlp", HelpText = "Options include otlp or console.", Required = false)]
- public string UseExporter { get; set; }
+ public string? UseExporter { get; set; }
[Option('e', "endpoint", HelpText = "Target to which the OTLP exporter is going to send logs (default value depends on protocol).", Default = null)]
- public string Endpoint { get; set; }
+ public string? Endpoint { get; set; }
[Option('p', "protocol", HelpText = "Transport protocol used by OTLP exporter. Supported values: grpc and http/protobuf. Only applicable if Exporter is OTLP", Default = "grpc")]
- public string Protocol { get; set; }
+ public string? Protocol { get; set; }
[Option("processorType", Default = "batch", HelpText = "export processor type. Supported values: simple and batch", Required = false)]
- public string ProcessorType { get; set; }
+ public string? ProcessorType { get; set; }
[Option("scheduledDelay", Default = 5000, HelpText = "The delay interval in milliseconds between two consecutive exports.", Required = false)]
public int ScheduledDelayInMilliseconds { get; set; }
diff --git a/examples/Console/TestConsoleExporter.cs b/examples/Console/TestConsoleExporter.cs
index cf3f803c4f..7a70c0ef1e 100644
--- a/examples/Console/TestConsoleExporter.cs
+++ b/examples/Console/TestConsoleExporter.cs
@@ -15,21 +15,21 @@ internal class TestConsoleExporter
// (eg: C:\repos\opentelemetry-dotnet\examples\Console\)
//
// dotnet run console
- internal static object Run(ConsoleOptions options)
+ internal static int Run(ConsoleOptions options)
{
return RunWithActivitySource();
}
- private static object RunWithActivitySource()
+ private static int RunWithActivitySource()
{
// Enable OpenTelemetry for the sources "Samples.SampleServer" and "Samples.SampleClient"
// and use Console exporter.
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
- .AddSource("Samples.SampleClient", "Samples.SampleServer")
- .ConfigureResource(res => res.AddService("console-test"))
- .AddProcessor(new MyProcessor()) // This must be added before ConsoleExporter
- .AddConsoleExporter()
- .Build();
+ .AddSource("Samples.SampleClient", "Samples.SampleServer")
+ .ConfigureResource(res => res.AddService("console-test"))
+ .AddProcessor(new MyProcessor()) // This must be added before ConsoleExporter
+ .AddConsoleExporter()
+ .Build();
// The above line is required only in applications
// which decide to use OpenTelemetry.
@@ -43,7 +43,7 @@ private static object RunWithActivitySource()
System.Console.ReadLine();
}
- return null;
+ return 0;
}
///
diff --git a/examples/Console/TestGrpcNetClient.cs b/examples/Console/TestGrpcNetClient.cs
index d179d93913..31dce4a167 100644
--- a/examples/Console/TestGrpcNetClient.cs
+++ b/examples/Console/TestGrpcNetClient.cs
@@ -12,8 +12,10 @@ namespace Examples.Console;
internal class TestGrpcNetClient
{
- internal static object Run()
+ internal static int Run(GrpcNetClientOptions options)
{
+ Debug.Assert(options != null, "options was null");
+
// Prerequisite for running this example.
// In a separate console window, start the example
// ASP.NET Core gRPC service by running the following command
@@ -55,6 +57,6 @@ internal static object Run()
System.Console.WriteLine("Press Enter key to exit.");
System.Console.ReadLine();
- return null;
+ return 0;
}
}
diff --git a/examples/Console/TestHttpClient.cs b/examples/Console/TestHttpClient.cs
index 27305a5052..7629a622af 100644
--- a/examples/Console/TestHttpClient.cs
+++ b/examples/Console/TestHttpClient.cs
@@ -15,8 +15,10 @@ internal class TestHttpClient
// (eg: C:\repos\opentelemetry-dotnet\examples\Console\)
//
// dotnet run httpclient
- internal static object Run()
+ internal static int Run(HttpClientOptions options)
{
+ Debug.Assert(options != null, "options was null");
+
System.Console.WriteLine("Hello World!");
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
@@ -36,6 +38,6 @@ internal static object Run()
System.Console.WriteLine("Press Enter key to exit.");
System.Console.ReadLine();
- return null;
+ return 0;
}
}
diff --git a/examples/Console/TestInMemoryExporter.cs b/examples/Console/TestInMemoryExporter.cs
index 53d3dd7f49..057bc19cde 100644
--- a/examples/Console/TestInMemoryExporter.cs
+++ b/examples/Console/TestInMemoryExporter.cs
@@ -15,7 +15,7 @@ internal class TestInMemoryExporter
// (eg: C:\repos\opentelemetry-dotnet\examples\Console\)
//
// dotnet run inmemory
- internal static object Run(InMemoryOptions options)
+ internal static int Run(InMemoryOptions options)
{
// List that will be populated with the traces by InMemoryExporter
var exportedItems = new List();
@@ -28,7 +28,7 @@ internal static object Run(InMemoryOptions options)
System.Console.WriteLine($"ActivitySource: {activity.Source.Name} logged the activity {activity.DisplayName}");
}
- return null;
+ return 0;
}
private static void RunWithActivitySource(ICollection exportedItems)
@@ -36,10 +36,10 @@ private static void RunWithActivitySource(ICollection exportedItems)
// Enable OpenTelemetry for the sources "Samples.SampleServer" and "Samples.SampleClient"
// and use InMemory exporter.
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
- .AddSource("Samples.SampleClient", "Samples.SampleServer")
- .ConfigureResource(r => r.AddService("inmemory-test"))
- .AddInMemoryExporter(exportedItems)
- .Build();
+ .AddSource("Samples.SampleClient", "Samples.SampleServer")
+ .ConfigureResource(r => r.AddService("inmemory-test"))
+ .AddInMemoryExporter(exportedItems)
+ .Build();
// The above line is required only in applications
// which decide to use OpenTelemetry.
diff --git a/examples/Console/TestLogs.cs b/examples/Console/TestLogs.cs
index 4c88753ffd..427193799a 100644
--- a/examples/Console/TestLogs.cs
+++ b/examples/Console/TestLogs.cs
@@ -9,7 +9,7 @@ namespace Examples.Console;
internal class TestLogs
{
- internal static object Run(LogsOptions options)
+ internal static int Run(LogsOptions options)
{
using var loggerFactory = LoggerFactory.Create(builder =>
{
@@ -17,7 +17,8 @@ internal static object Run(LogsOptions options)
{
opt.IncludeFormattedMessage = true;
opt.IncludeScopes = true;
- if (options.UseExporter.Equals("otlp", StringComparison.OrdinalIgnoreCase))
+
+ if ("otlp".Equals(options.UseExporter, StringComparison.OrdinalIgnoreCase))
{
/*
* Prerequisite to run this example:
@@ -43,31 +44,46 @@ internal static object Run(LogsOptions options)
var protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
- if (options.Protocol.Trim().ToLower().Equals("grpc"))
- {
- protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
- }
- else if (options.Protocol.Trim().ToLower().Equals("http/protobuf"))
+ if (!string.IsNullOrEmpty(options.Protocol))
{
- protocol = OpenTelemetry.Exporter.OtlpExportProtocol.HttpProtobuf;
+ switch (options.Protocol.Trim())
+ {
+ case "grpc":
+ protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
+ break;
+ case "http/protobuf":
+ protocol = OpenTelemetry.Exporter.OtlpExportProtocol.HttpProtobuf;
+ break;
+ default:
+ System.Console.WriteLine($"Export protocol {options.Protocol} is not supported. Default protocol 'grpc' will be used.");
+ break;
+ }
}
else
{
- System.Console.WriteLine($"Export protocol {options.Protocol} is not supported. Default protocol 'grpc' will be used.");
+ System.Console.WriteLine("Protocol is null or empty. Default protocol 'grpc' will be used.");
}
var processorType = ExportProcessorType.Batch;
- if (options.ProcessorType.Trim().ToLower().Equals("batch"))
- {
- processorType = ExportProcessorType.Batch;
- }
- else if (options.ProcessorType.Trim().ToLower().Equals("simple"))
+
+ if (!string.IsNullOrEmpty(options.ProcessorType))
{
- processorType = ExportProcessorType.Simple;
+ switch (options.ProcessorType.Trim())
+ {
+ case "batch":
+ processorType = ExportProcessorType.Batch;
+ break;
+ case "simple":
+ processorType = ExportProcessorType.Simple;
+ break;
+ default:
+ System.Console.WriteLine($"Export processor type {options.ProcessorType} is not supported. Default processor type 'batch' will be used.");
+ break;
+ }
}
else
{
- System.Console.WriteLine($"Export processor type {options.ProcessorType} is not supported. Default processor type 'batch' will be used.");
+ System.Console.WriteLine("Processor type is null or empty. Default processor type 'batch' will be used.");
}
opt.AddOtlpExporter((exporterOptions, processorOptions) =>
@@ -103,6 +119,6 @@ internal static object Run(LogsOptions options)
logger.LogInformation("Hello from {name} {price}.", "tomato", 2.99);
}
- return null;
+ return 0;
}
}
diff --git a/examples/Console/TestMetrics.cs b/examples/Console/TestMetrics.cs
index ba943e9177..9582a0f561 100644
--- a/examples/Console/TestMetrics.cs
+++ b/examples/Console/TestMetrics.cs
@@ -12,10 +12,10 @@ namespace Examples.Console;
internal class TestMetrics
{
- internal static object Run(MetricsOptions options)
+ internal static int Run(MetricsOptions options)
{
var meterVersion = "1.0";
- var meterTags = new List>
+ var meterTags = new List>
{
new(
"MeterTagKey",
@@ -27,7 +27,7 @@ internal static object Run(MetricsOptions options)
.ConfigureResource(r => r.AddService("myservice"))
.AddMeter(meter.Name); // All instruments from this meter are enabled.
- if (options.UseExporter.Equals("otlp", StringComparison.OrdinalIgnoreCase))
+ if ("otlp".Equals(options.UseExporter, StringComparison.OrdinalIgnoreCase))
{
/*
* Prerequisite to run this example:
@@ -79,13 +79,13 @@ internal static object Run(MetricsOptions options)
using var provider = providerBuilder.Build();
- Counter counter = null;
+ Counter? counter = null;
if (options.FlagCounter ?? true)
{
counter = meter.CreateCounter("counter", "things", "A count of things");
}
- Histogram histogram = null;
+ Histogram? histogram = null;
if (options.FlagHistogram ?? false)
{
histogram = meter.CreateHistogram("histogram");
@@ -99,7 +99,7 @@ internal static object Run(MetricsOptions options)
{
new Measurement(
(int)Process.GetCurrentProcess().PrivateMemorySize64,
- new KeyValuePair("tag1", "value1")),
+ new KeyValuePair("tag1", "value1")),
};
});
}
@@ -111,45 +111,45 @@ internal static object Run(MetricsOptions options)
histogram?.Record(
100,
- new KeyValuePair("tag1", "value1"));
+ new KeyValuePair("tag1", "value1"));
histogram?.Record(
200,
- new KeyValuePair("tag1", "value2"),
- new KeyValuePair("tag2", "value2"));
+ new KeyValuePair("tag1", "value2"),
+ new KeyValuePair("tag2", "value2"));
histogram?.Record(
100,
- new KeyValuePair("tag1", "value1"));
+ new KeyValuePair("tag1", "value1"));
histogram?.Record(
200,
- new KeyValuePair("tag2", "value2"),
- new KeyValuePair("tag1", "value2"));
+ new KeyValuePair("tag2", "value2"),
+ new KeyValuePair("tag1", "value2"));
counter?.Add(10);
counter?.Add(
100,
- new KeyValuePair("tag1", "value1"));
+ new KeyValuePair("tag1", "value1"));
counter?.Add(
200,
- new KeyValuePair("tag1", "value2"),
- new KeyValuePair("tag2", "value2"));
+ new KeyValuePair("tag1", "value2"),
+ new KeyValuePair("tag2", "value2"));
counter?.Add(
100,
- new KeyValuePair("tag1", "value1"));
+ new KeyValuePair("tag1", "value1"));
counter?.Add(
200,
- new KeyValuePair("tag2", "value2"),
- new KeyValuePair("tag1", "value2"));
+ new KeyValuePair("tag2", "value2"),
+ new KeyValuePair("tag1", "value2"));
Task.Delay(500).Wait();
}
- return null;
+ return 0;
}
}
diff --git a/examples/Console/TestOTelShimWithConsoleExporter.cs b/examples/Console/TestOTelShimWithConsoleExporter.cs
index 6557357a96..42e6f368f5 100644
--- a/examples/Console/TestOTelShimWithConsoleExporter.cs
+++ b/examples/Console/TestOTelShimWithConsoleExporter.cs
@@ -9,15 +9,15 @@ namespace Examples.Console;
internal class TestOTelShimWithConsoleExporter
{
- internal static object Run(OpenTelemetryShimOptions options)
+ internal static int Run(OpenTelemetryShimOptions options)
{
// Enable OpenTelemetry for the source "MyCompany.MyProduct.MyWebServer"
// and use a single pipeline with a custom MyProcessor, and Console exporter.
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
- .AddSource("MyCompany.MyProduct.MyWebServer")
- .ConfigureResource(r => r.AddService("MyServiceName"))
- .AddConsoleExporter()
- .Build();
+ .AddSource("MyCompany.MyProduct.MyWebServer")
+ .ConfigureResource(r => r.AddService("MyServiceName"))
+ .AddConsoleExporter()
+ .Build();
// The above line is required only in applications
// which decide to use OpenTelemetry.
@@ -40,6 +40,6 @@ internal static object Run(OpenTelemetryShimOptions options)
System.Console.WriteLine("Press Enter key to exit.");
System.Console.ReadLine();
- return null;
+ return 0;
}
}
diff --git a/examples/Console/TestOpenTracingShim.cs b/examples/Console/TestOpenTracingShim.cs
index 0de2419b6e..386cfe48ab 100644
--- a/examples/Console/TestOpenTracingShim.cs
+++ b/examples/Console/TestOpenTracingShim.cs
@@ -12,15 +12,15 @@ namespace Examples.Console;
internal class TestOpenTracingShim
{
- internal static object Run(OpenTracingShimOptions options)
+ internal static int Run(OpenTracingShimOptions options)
{
// Enable OpenTelemetry for the source "opentracing-shim"
// and use Console exporter.
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
- .AddSource("opentracing-shim")
- .ConfigureResource(r => r.AddService("MyServiceName"))
- .AddConsoleExporter()
- .Build();
+ .AddSource("opentracing-shim")
+ .ConfigureResource(r => r.AddService("MyServiceName"))
+ .AddConsoleExporter()
+ .Build();
// Instantiate the OpenTracing shim. The underlying OpenTelemetry tracer will create
// spans using the "opentracing-shim" source.
@@ -53,6 +53,6 @@ internal static object Run(OpenTracingShimOptions options)
System.Console.WriteLine("Press Enter key to exit.");
System.Console.ReadLine();
- return null;
+ return 0;
}
}
diff --git a/examples/Console/TestOtlpExporter.cs b/examples/Console/TestOtlpExporter.cs
index 94d749eafe..3af0ceea14 100644
--- a/examples/Console/TestOtlpExporter.cs
+++ b/examples/Console/TestOtlpExporter.cs
@@ -10,7 +10,7 @@ namespace Examples.Console;
internal static class TestOtlpExporter
{
- internal static object Run(string endpoint, string protocol)
+ internal static int Run(OtlpOptions options)
{
/*
* Prerequisite to run this example:
@@ -36,36 +36,36 @@ internal static object Run(string endpoint, string protocol)
* For more information about the OpenTelemetry Collector go to https://github.com/open-telemetry/opentelemetry-collector
*
*/
- return RunWithActivitySource(endpoint, protocol);
+ return RunWithActivitySource(options);
}
- private static object RunWithActivitySource(string endpoint, string protocol)
+ private static int RunWithActivitySource(OtlpOptions options)
{
- var otlpExportProtocol = ToOtlpExportProtocol(protocol);
+ var otlpExportProtocol = ToOtlpExportProtocol(options.Protocol);
if (!otlpExportProtocol.HasValue)
{
- System.Console.WriteLine($"Export protocol {protocol} is not supported. Default protocol 'grpc' will be used.");
+ System.Console.WriteLine($"Export protocol {options.Protocol} is not supported. Default protocol 'grpc' will be used.");
otlpExportProtocol = OtlpExportProtocol.Grpc;
}
// Enable OpenTelemetry for the sources "Samples.SampleServer" and "Samples.SampleClient"
// and use OTLP exporter.
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
- .AddSource("Samples.SampleClient", "Samples.SampleServer")
- .ConfigureResource(r => r.AddService("otlp-test"))
- .AddOtlpExporter(opt =>
+ .AddSource("Samples.SampleClient", "Samples.SampleServer")
+ .ConfigureResource(r => r.AddService("otlp-test"))
+ .AddOtlpExporter(opt =>
+ {
+ // If endpoint was not specified, the proper one will be selected according to the protocol.
+ if (!string.IsNullOrEmpty(options.Endpoint))
{
- // If endpoint was not specified, the proper one will be selected according to the protocol.
- if (!string.IsNullOrEmpty(endpoint))
- {
- opt.Endpoint = new Uri(endpoint);
- }
+ opt.Endpoint = new Uri(options.Endpoint);
+ }
- opt.Protocol = otlpExportProtocol.Value;
+ opt.Protocol = otlpExportProtocol.Value;
- System.Console.WriteLine($"OTLP Exporter is using {opt.Protocol} protocol and endpoint {opt.Endpoint}");
- })
- .Build();
+ System.Console.WriteLine($"OTLP Exporter is using {opt.Protocol} protocol and endpoint {opt.Endpoint}");
+ })
+ .Build();
// The above line is required only in Applications
// which decide to use OpenTelemetry.
@@ -79,11 +79,11 @@ private static object RunWithActivitySource(string endpoint, string protocol)
System.Console.ReadLine();
}
- return null;
+ return 0;
}
- private static OtlpExportProtocol? ToOtlpExportProtocol(string protocol) =>
- protocol.Trim().ToLower() switch
+ private static OtlpExportProtocol? ToOtlpExportProtocol(string? protocol) =>
+ protocol?.Trim().ToLower() switch
{
"grpc" => OtlpExportProtocol.Grpc,
"http/protobuf" => OtlpExportProtocol.HttpProtobuf,
diff --git a/examples/Console/TestPrometheusExporter.cs b/examples/Console/TestPrometheusExporter.cs
index 57f38c466d..a6bc1888f2 100644
--- a/examples/Console/TestPrometheusExporter.cs
+++ b/examples/Console/TestPrometheusExporter.cs
@@ -17,7 +17,7 @@ internal class TestPrometheusExporter
private static readonly Histogram MyHistogram = MyMeter.CreateHistogram("myHistogram");
private static readonly ThreadLocal ThreadLocalRandom = new(() => new Random());
- internal static object Run(int port)
+ internal static int Run(PrometheusOptions options)
{
/* prometheus.yml example. Adjust port as per actual.
@@ -35,7 +35,7 @@ internal static object Run(int port)
.AddMeter(MyMeter.Name)
.AddMeter(MyMeter2.Name)
.AddPrometheusHttpListener(
- options => options.UriPrefixes = new string[] { $"http://localhost:{port}/" })
+ o => o.UriPrefixes = new string[] { $"http://localhost:{options.Port}/" })
.Build();
var process = Process.GetCurrentProcess();
@@ -57,12 +57,12 @@ internal static object Run(int port)
{
Counter.Add(9.9, new("name", "apple"), new("color", "red"));
Counter.Add(99.9, new("name", "lemon"), new("color", "yellow"));
- MyHistogram.Record(ThreadLocalRandom.Value.Next(1, 1500), new("tag1", "value1"), new("tag2", "value2"));
+ MyHistogram.Record(ThreadLocalRandom.Value!.Next(1, 1500), new("tag1", "value1"), new("tag2", "value2"));
Task.Delay(10).Wait();
}
});
- System.Console.WriteLine($"PrometheusExporter exposes metrics via http://localhost:{port}/metrics/");
+ System.Console.WriteLine($"PrometheusExporter exposes metrics via http://localhost:{options.Port}/metrics/");
System.Console.WriteLine($"Press Esc key to exit...");
while (true)
{
@@ -80,7 +80,7 @@ internal static object Run(int port)
Task.Delay(200).Wait();
}
- return null;
+ return 0;
}
private static IEnumerable> GetThreadCpuTime(Process process)
diff --git a/examples/Console/TestZipkinExporter.cs b/examples/Console/TestZipkinExporter.cs
index 271826a7c2..0bb6432344 100644
--- a/examples/Console/TestZipkinExporter.cs
+++ b/examples/Console/TestZipkinExporter.cs
@@ -9,7 +9,7 @@ namespace Examples.Console;
internal class TestZipkinExporter
{
- internal static object Run(string zipkinUri)
+ internal static int Run(ZipkinOptions options)
{
// Prerequisite for running this example.
// Setup zipkin inside local docker using following command:
@@ -23,14 +23,15 @@ internal static object Run(string zipkinUri)
// Enable OpenTelemetry for the sources "Samples.SampleServer" and "Samples.SampleClient"
// and use the Zipkin exporter.
+
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
- .AddSource("Samples.SampleClient", "Samples.SampleServer")
- .ConfigureResource(r => r.AddService("zipkin-test"))
- .AddZipkinExporter(o =>
- {
- o.Endpoint = new Uri(zipkinUri);
- })
- .Build();
+ .AddSource("Samples.SampleClient", "Samples.SampleServer")
+ .ConfigureResource(r => r.AddService("zipkin-test"))
+ .AddZipkinExporter(o =>
+ {
+ o.Endpoint = new Uri(options.Uri);
+ })
+ .Build();
using (var sample = new InstrumentationWithActivitySource())
{
@@ -42,6 +43,6 @@ internal static object Run(string zipkinUri)
System.Console.ReadLine();
}
- return null;
+ return 0;
}
}
diff --git a/examples/Console/otlp-collector-example/config.yaml b/examples/Console/otlp-collector-example/config.yaml
index 932f24a193..57e59398b7 100644
--- a/examples/Console/otlp-collector-example/config.yaml
+++ b/examples/Console/otlp-collector-example/config.yaml
@@ -8,20 +8,22 @@ receivers:
otlp:
protocols:
grpc:
+ endpoint: 0.0.0.0:4317
http:
+ endpoint: 0.0.0.0:4318
exporters:
- logging:
+ debug:
verbosity: detailed
service:
pipelines:
traces:
receivers: [otlp]
- exporters: [logging]
+ exporters: [debug]
metrics:
receivers: [otlp]
- exporters: [logging]
+ exporters: [debug]
logs:
receivers: [otlp]
- exporters: [logging]
+ exporters: [debug]
diff --git a/examples/Directory.Build.targets b/examples/Directory.Build.targets
new file mode 100644
index 0000000000..a0db146202
--- /dev/null
+++ b/examples/Directory.Build.targets
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/examples/Directory.Packages.props b/examples/Directory.Packages.props
deleted file mode 100644
index 902efc8cc0..0000000000
--- a/examples/Directory.Packages.props
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/examples/MicroserviceExample/Utils/Messaging/RabbitMqHelper.cs b/examples/MicroserviceExample/Utils/Messaging/RabbitMqHelper.cs
index 476bc26a85..cbc8f0d834 100644
--- a/examples/MicroserviceExample/Utils/Messaging/RabbitMqHelper.cs
+++ b/examples/MicroserviceExample/Utils/Messaging/RabbitMqHelper.cs
@@ -54,7 +54,7 @@ public static void StartConsumer(IModel channel, Action p
channel.BasicConsume(queue: TestQueueName, autoAck: true, consumer: consumer);
}
- public static void AddMessagingTags(Activity activity)
+ public static void AddMessagingTags(Activity? activity)
{
// These tags are added demonstrating the semantic conventions of the OpenTelemetry messaging specification
// See:
diff --git a/examples/MicroserviceExample/Utils/Utils.csproj b/examples/MicroserviceExample/Utils/Utils.csproj
index cc7382d499..54d0724347 100644
--- a/examples/MicroserviceExample/Utils/Utils.csproj
+++ b/examples/MicroserviceExample/Utils/Utils.csproj
@@ -1,9 +1,6 @@
netstandard2.0
-
-
- disable
diff --git a/global.json b/global.json
index 0aca8b1293..f459bbb82e 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
"rollForward": "latestFeature",
- "version": "8.0.100"
+ "version": "9.0.100-rc.1.24452.12"
}
}
diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets
index ef4301eb07..6cef70da6c 100644
--- a/src/Directory.Build.targets
+++ b/src/Directory.Build.targets
@@ -1,5 +1,7 @@
+
+
-
-
-
(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder) -> OpenTelemetry.Logs.LoggerProviderBuilder!
-static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Logs.LoggerProviderBuilder!
-static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Logs.LoggerProviderBuilder!
-static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, T! instrumentation) -> OpenTelemetry.Logs.LoggerProviderBuilder!
-static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, System.Action! configure) -> OpenTelemetry.Logs.LoggerProviderBuilder!
-static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions.ConfigureOpenTelemetryLoggerProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
-static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions.ConfigureOpenTelemetryLoggerProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
diff --git a/src/OpenTelemetry.Api.ProviderBuilderExtensions/.publicApi/Stable/PublicAPI.Shipped.txt b/src/OpenTelemetry.Api.ProviderBuilderExtensions/.publicApi/Stable/PublicAPI.Shipped.txt
index ca48e185f6..8c11dafee8 100644
--- a/src/OpenTelemetry.Api.ProviderBuilderExtensions/.publicApi/Stable/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Api.ProviderBuilderExtensions/.publicApi/Stable/PublicAPI.Shipped.txt
@@ -1,21 +1,30 @@
#nullable enable
OpenTelemetry.IOpenTelemetryBuilder
OpenTelemetry.IOpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
+OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions
+OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions
OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions
OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions
OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions
OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions
-static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, T! instrumentation) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, System.Action! configure) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions.ConfigureOpenTelemetryLoggerProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
+static OpenTelemetry.Logs.OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions.ConfigureOpenTelemetryLoggerProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, T! instrumentation) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions.ConfigureOpenTelemetryMeterProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions.ConfigureOpenTelemetryMeterProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
-static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, T! instrumentation) -> OpenTelemetry.Trace.TracerProviderBuilder!
+static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.ConfigureOpenTelemetryTracerProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.ConfigureOpenTelemetryTracerProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
diff --git a/src/OpenTelemetry.Api.ProviderBuilderExtensions/CHANGELOG.md b/src/OpenTelemetry.Api.ProviderBuilderExtensions/CHANGELOG.md
index 1f2a27b7f3..1b39470bda 100644
--- a/src/OpenTelemetry.Api.ProviderBuilderExtensions/CHANGELOG.md
+++ b/src/OpenTelemetry.Api.ProviderBuilderExtensions/CHANGELOG.md
@@ -1,7 +1,34 @@
# Changelog
+This file contains individual changes for the
+OpenTelemetry.Api.ProviderBuilderExtensions package. For highlights and
+announcements covering all components see: [Release
+Notes](../../RELEASENOTES.md).
+
## Unreleased
+## 1.10.0-beta.1
+
+Released 2024-Sep-30
+
+* Updated `Microsoft.Extensions.DependencyInjection.Abstractions` package
+ version to `9.0.0-rc.1.24431.7`.
+ ([#5853](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5853))
+
+## 1.9.0
+
+Released 2024-Jun-14
+
+## 1.9.0-rc.1
+
+Released 2024-Jun-07
+
+* The experimental APIs previously covered by `OTEL1000`
+ (`LoggerProviderBuilder` `AddInstrumentation` & `ConfigureServices` extensions
+ and `IServiceCollection.ConfigureOpenTelemetryLoggerProvider` extension) are
+ now part of the public API and supported in stable builds.
+ ([#5648](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5648))
+
## 1.9.0-alpha.1
Released 2024-May-20
diff --git a/src/OpenTelemetry.Api.ProviderBuilderExtensions/Logs/OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.cs b/src/OpenTelemetry.Api.ProviderBuilderExtensions/Logs/OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.cs
index 257b7332be..4a96f1b081 100644
--- a/src/OpenTelemetry.Api.ProviderBuilderExtensions/Logs/OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.cs
+++ b/src/OpenTelemetry.Api.ProviderBuilderExtensions/Logs/OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions.cs
@@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#if NET6_0_OR_GREATER
+#if NET
using System.Diagnostics.CodeAnalysis;
#endif
using Microsoft.Extensions.DependencyInjection;
@@ -13,42 +13,20 @@ namespace OpenTelemetry.Logs;
///
/// Contains extension methods for the class.
///
-#if EXPOSE_EXPERIMENTAL_FEATURES
-#if NET8_0_OR_GREATER
-[Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
-public
-#else
-internal
-#endif
-static class OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions
+public static class OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions
{
-#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Adds instrumentation to the provider.
///
///
- ///
/// Note: The type specified by will be
/// registered as a singleton service into application services.
///
/// Instrumentation type.
/// .
/// The supplied for chaining.
-#else
- ///
- /// Adds instrumentation to the provider.
- ///
- ///
- /// Note: The type specified by will be
- /// registered as a singleton service into application services.
- ///
- /// Instrumentation type.
- /// .
- /// The supplied for chaining.
-#endif
public static LoggerProviderBuilder AddInstrumentation<
-#if NET6_0_OR_GREATER
+#if NET
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(this LoggerProviderBuilder loggerProviderBuilder)
@@ -64,24 +42,13 @@ public static LoggerProviderBuilder AddInstrumentation<
return loggerProviderBuilder;
}
-#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Adds instrumentation to the provider.
///
/// Instrumentation type.
- /// WARNING: This is an experimental API which might change or be removed in the future. Use at your own risk.
/// .
/// Instrumentation instance.
/// The supplied for chaining.
-#else
- ///
- /// Adds instrumentation to the provider.
- ///
- /// Instrumentation type.
- /// .
- /// Instrumentation instance.
- /// The supplied for chaining.
-#endif
public static LoggerProviderBuilder AddInstrumentation(this LoggerProviderBuilder loggerProviderBuilder, T instrumentation)
where T : class
{
@@ -95,24 +62,13 @@ public static LoggerProviderBuilder AddInstrumentation(this LoggerProviderBui
return loggerProviderBuilder;
}
-#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Adds instrumentation to the provider.
///
/// Instrumentation type.
- ///
/// .
/// Instrumentation factory.
/// The supplied for chaining.
-#else
- ///
- /// Adds instrumentation to the provider.
- ///
- /// Instrumentation type.
- /// .
- /// Instrumentation factory.
- /// The supplied for chaining.
-#endif
public static LoggerProviderBuilder AddInstrumentation(
this LoggerProviderBuilder loggerProviderBuilder,
Func instrumentationFactory)
@@ -128,16 +84,6 @@ public static LoggerProviderBuilder AddInstrumentation(
return loggerProviderBuilder;
}
-#if EXPOSE_EXPERIMENTAL_FEATURES
- ///
- /// Adds instrumentation to the provider.
- ///
- /// Instrumentation type.
- ///
- /// .
- /// Instrumentation factory.
- /// The supplied for chaining.
-#else
///
/// Adds instrumentation to the provider.
///
@@ -145,7 +91,6 @@ public static LoggerProviderBuilder AddInstrumentation(
/// .
/// Instrumentation factory.
/// The supplied for chaining.
-#endif
public static LoggerProviderBuilder AddInstrumentation(
this LoggerProviderBuilder loggerProviderBuilder,
Func instrumentationFactory)
@@ -165,32 +110,17 @@ public static LoggerProviderBuilder AddInstrumentation(
return loggerProviderBuilder;
}
-#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Register a callback action to configure the where logging services are configured.
///
///
- ///
/// Note: Logging services are only available during the application
/// configuration phase.
///
/// .
/// Configuration callback.
/// The supplied for chaining.
-#else
- ///
- /// Register a callback action to configure the where logging services are configured.
- ///
- ///
- /// Note: Logging services are only available during the application
- /// configuration phase.
- ///
- /// .
- /// Configuration callback.
- /// The supplied for chaining.
-#endif
public static LoggerProviderBuilder ConfigureServices(
this LoggerProviderBuilder loggerProviderBuilder,
Action configure)
diff --git a/src/OpenTelemetry.Api.ProviderBuilderExtensions/Logs/OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions.cs b/src/OpenTelemetry.Api.ProviderBuilderExtensions/Logs/OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions.cs
index 8e6f899b24..8d33a420a6 100644
--- a/src/OpenTelemetry.Api.ProviderBuilderExtensions/Logs/OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions.cs
+++ b/src/OpenTelemetry.Api.ProviderBuilderExtensions/Logs/OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions.cs
@@ -1,9 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#if EXPOSE_EXPERIMENTAL_FEATURES && NET8_0_OR_GREATER
-using System.Diagnostics.CodeAnalysis;
-#endif
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Internal;
@@ -12,23 +9,13 @@ namespace OpenTelemetry.Logs;
///
/// Extension methods for setting up OpenTelemetry logging services in an .
///
-#if EXPOSE_EXPERIMENTAL_FEATURES
-#if NET8_0_OR_GREATER
-[Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
-public
-#else
-internal
-#endif
-static class OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions
+public static class OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions
{
-#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Registers an action used to configure the OpenTelemetry .
///
///
- ///
/// Notes:
///
/// - This is safe to be called multiple times and by library authors.
@@ -45,29 +32,6 @@ static class OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions
/// cref="LoggerProviderBuilder"/>.
/// The so that additional calls
/// can be chained.
-#else
- ///
- /// Registers an action used to configure the OpenTelemetry .
- ///
- ///
- /// Notes:
- ///
- /// - This is safe to be called multiple times and by library authors.
- /// Each registered configuration action will be applied
- /// sequentially.
- /// - A will NOT be created automatically
- /// using this method. To begin collecting logs use the
- /// IServiceCollection.AddOpenTelemetry extension in the
- /// OpenTelemetry.Extensions.Hosting package.
- ///
- ///
- /// .
- /// Callback action to configure the .
- /// The so that additional calls
- /// can be chained.
-#endif
public static IServiceCollection ConfigureOpenTelemetryLoggerProvider(
this IServiceCollection services,
Action configure)
@@ -80,40 +44,6 @@ public static IServiceCollection ConfigureOpenTelemetryLoggerProvider(
return services;
}
-#if EXPOSE_EXPERIMENTAL_FEATURES
- ///
- /// Registers an action used to configure the OpenTelemetry once the
- /// is available.
- ///
- ///
- ///
- /// Notes:
- ///
- /// - This is safe to be called multiple times and by library authors.
- /// Each registered configuration action will be applied
- /// sequentially.
- /// - A will NOT be created automatically
- /// using this method. To begin collecting logs use the
- /// IServiceCollection.AddOpenTelemetry extension in the
- /// OpenTelemetry.Extensions.Hosting package.
- /// - The supplied configuration delegate is called once the is available. Services may NOT be added to a
- /// once the has been created. Many helper extensions
- /// register services and may throw if invoked inside the configuration
- /// delegate. If you don't need access to the
- /// call instead which is safe to be used with
- /// helper extensions.
- ///
- ///
- /// .
- /// Callback action to configure the .
- /// The so that additional calls
- /// can be chained.
-#else
///
/// Registers an action used to configure the OpenTelemetry once the
@@ -145,7 +75,6 @@ public static IServiceCollection ConfigureOpenTelemetryLoggerProvider(
/// cref="LoggerProviderBuilder"/>.
/// The so that additional calls
/// can be chained.
-#endif
public static IServiceCollection ConfigureOpenTelemetryLoggerProvider(
this IServiceCollection services,
Action configure)
diff --git a/src/OpenTelemetry.Api.ProviderBuilderExtensions/Metrics/OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Api.ProviderBuilderExtensions/Metrics/OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.cs
index 457ddc8766..fea2275e9a 100644
--- a/src/OpenTelemetry.Api.ProviderBuilderExtensions/Metrics/OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.cs
+++ b/src/OpenTelemetry.Api.ProviderBuilderExtensions/Metrics/OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.cs
@@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#if NET6_0_OR_GREATER
+#if NET
using System.Diagnostics.CodeAnalysis;
#endif
using Microsoft.Extensions.DependencyInjection;
@@ -26,7 +26,7 @@ public static class OpenTelemetryDependencyInjectionMeterProviderBuilderExtensio
/// .
/// The supplied for chaining.
public static MeterProviderBuilder AddInstrumentation<
-#if NET6_0_OR_GREATER
+#if NET
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(this MeterProviderBuilder meterProviderBuilder)
diff --git a/src/OpenTelemetry.Api.ProviderBuilderExtensions/Trace/OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Api.ProviderBuilderExtensions/Trace/OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.cs
index 35088b2a5e..2e6ab37628 100644
--- a/src/OpenTelemetry.Api.ProviderBuilderExtensions/Trace/OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.cs
+++ b/src/OpenTelemetry.Api.ProviderBuilderExtensions/Trace/OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.cs
@@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#if NET6_0_OR_GREATER
+#if NET
using System.Diagnostics.CodeAnalysis;
#endif
using Microsoft.Extensions.DependencyInjection;
@@ -26,7 +26,7 @@ public static class OpenTelemetryDependencyInjectionTracerProviderBuilderExtensi
/// .
/// The supplied for chaining.
public static TracerProviderBuilder AddInstrumentation<
-#if NET6_0_OR_GREATER
+#if NET
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(this TracerProviderBuilder tracerProviderBuilder)
diff --git a/src/OpenTelemetry.Api/.publicApi/Experimental/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Api/.publicApi/Experimental/PublicAPI.Unshipped.txt
index 2c2dcbb59e..4cb12fd296 100644
--- a/src/OpenTelemetry.Api/.publicApi/Experimental/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry.Api/.publicApi/Experimental/PublicAPI.Unshipped.txt
@@ -1,19 +1,12 @@
abstract OpenTelemetry.Logs.Logger.EmitLog(in OpenTelemetry.Logs.LogRecordData data, in OpenTelemetry.Logs.LogRecordAttributeList attributes) -> void
-abstract OpenTelemetry.Logs.LoggerProviderBuilder.AddInstrumentation(System.Func! instrumentationFactory) -> OpenTelemetry.Logs.LoggerProviderBuilder!
-OpenTelemetry.Logs.IDeferredLoggerProviderBuilder
-OpenTelemetry.Logs.IDeferredLoggerProviderBuilder.Configure(System.Action! configure) -> OpenTelemetry.Logs.LoggerProviderBuilder!
OpenTelemetry.Logs.Logger
OpenTelemetry.Logs.Logger.EmitLog(in OpenTelemetry.Logs.LogRecordData data) -> void
OpenTelemetry.Logs.Logger.Logger(string? name) -> void
OpenTelemetry.Logs.Logger.Name.get -> string!
OpenTelemetry.Logs.Logger.Version.get -> string?
-OpenTelemetry.Logs.LoggerProvider
OpenTelemetry.Logs.LoggerProvider.GetLogger() -> OpenTelemetry.Logs.Logger!
OpenTelemetry.Logs.LoggerProvider.GetLogger(string? name) -> OpenTelemetry.Logs.Logger!
OpenTelemetry.Logs.LoggerProvider.GetLogger(string? name, string? version) -> OpenTelemetry.Logs.Logger!
-OpenTelemetry.Logs.LoggerProvider.LoggerProvider() -> void
-OpenTelemetry.Logs.LoggerProviderBuilder
-OpenTelemetry.Logs.LoggerProviderBuilder.LoggerProviderBuilder() -> void
OpenTelemetry.Logs.LogRecordAttributeList
OpenTelemetry.Logs.LogRecordAttributeList.Add(string! key, object? value) -> void
OpenTelemetry.Logs.LogRecordAttributeList.Add(System.Collections.Generic.KeyValuePair attribute) -> void
diff --git a/src/OpenTelemetry.Api/.publicApi/Stable/PublicAPI.Shipped.txt b/src/OpenTelemetry.Api/.publicApi/Stable/PublicAPI.Shipped.txt
index a87bb70121..821cf08067 100644
--- a/src/OpenTelemetry.Api/.publicApi/Stable/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Api/.publicApi/Stable/PublicAPI.Shipped.txt
@@ -1,57 +1,18 @@
#nullable enable
-~abstract OpenTelemetry.Context.Propagation.TextMapPropagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func> getter) -> OpenTelemetry.Context.Propagation.PropagationContext
-~abstract OpenTelemetry.Context.Propagation.TextMapPropagator.Fields.get -> System.Collections.Generic.ISet
-~abstract OpenTelemetry.Context.Propagation.TextMapPropagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action setter) -> void
-~OpenTelemetry.Baggage.GetBaggage() -> System.Collections.Generic.IReadOnlyDictionary
-~OpenTelemetry.Baggage.GetBaggage(string name) -> string
-~OpenTelemetry.Baggage.GetEnumerator() -> System.Collections.Generic.Dictionary.Enumerator
-~OpenTelemetry.Baggage.RemoveBaggage(string name) -> OpenTelemetry.Baggage
-~OpenTelemetry.Baggage.SetBaggage(params System.Collections.Generic.KeyValuePair[] baggageItems) -> OpenTelemetry.Baggage
-~OpenTelemetry.Baggage.SetBaggage(string name, string value) -> OpenTelemetry.Baggage
-~OpenTelemetry.Baggage.SetBaggage(System.Collections.Generic.IEnumerable> baggageItems) -> OpenTelemetry.Baggage
-~OpenTelemetry.Context.AsyncLocalRuntimeContextSlot.AsyncLocalRuntimeContextSlot(string name) -> void
-~OpenTelemetry.Context.AsyncLocalRuntimeContextSlot.Value.get -> object
-~OpenTelemetry.Context.AsyncLocalRuntimeContextSlot.Value.set -> void
-~OpenTelemetry.Context.IRuntimeContextSlotValueAccessor.Value.get -> object
-~OpenTelemetry.Context.IRuntimeContextSlotValueAccessor.Value.set -> void
-~OpenTelemetry.Context.Propagation.CompositeTextMapPropagator.CompositeTextMapPropagator(System.Collections.Generic.IEnumerable propagators) -> void
-~OpenTelemetry.Context.RuntimeContextSlot.Name.get -> string
-~OpenTelemetry.Context.RuntimeContextSlot.RuntimeContextSlot(string name) -> void
-~OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.ThreadLocalRuntimeContextSlot(string name) -> void
-~OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.Value.get -> object
-~OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.Value.set -> void
-~override OpenTelemetry.Baggage.Equals(object obj) -> bool
-~override OpenTelemetry.Context.Propagation.B3Propagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func> getter) -> OpenTelemetry.Context.Propagation.PropagationContext
-~override OpenTelemetry.Context.Propagation.B3Propagator.Fields.get -> System.Collections.Generic.ISet
-~override OpenTelemetry.Context.Propagation.B3Propagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action setter) -> void
-~override OpenTelemetry.Context.Propagation.BaggagePropagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func> getter) -> OpenTelemetry.Context.Propagation.PropagationContext
-~override OpenTelemetry.Context.Propagation.BaggagePropagator.Fields.get -> System.Collections.Generic.ISet
-~override OpenTelemetry.Context.Propagation.BaggagePropagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action setter) -> void
-~override OpenTelemetry.Context.Propagation.CompositeTextMapPropagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func> getter) -> OpenTelemetry.Context.Propagation.PropagationContext
-~override OpenTelemetry.Context.Propagation.CompositeTextMapPropagator.Fields.get -> System.Collections.Generic.ISet
-~override OpenTelemetry.Context.Propagation.CompositeTextMapPropagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action setter) -> void
-~override OpenTelemetry.Context.Propagation.PropagationContext.Equals(object obj) -> bool
-~override OpenTelemetry.Context.Propagation.TraceContextPropagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func> getter) -> OpenTelemetry.Context.Propagation.PropagationContext
-~override OpenTelemetry.Context.Propagation.TraceContextPropagator.Fields.get -> System.Collections.Generic.ISet
-~override OpenTelemetry.Context.Propagation.TraceContextPropagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action setter) -> void
-~static OpenTelemetry.Baggage.Create(System.Collections.Generic.Dictionary baggageItems = null) -> OpenTelemetry.Baggage
-~static OpenTelemetry.Baggage.GetBaggage(OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> System.Collections.Generic.IReadOnlyDictionary
-~static OpenTelemetry.Baggage.GetBaggage(string name, OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> string
-~static OpenTelemetry.Baggage.GetEnumerator(OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> System.Collections.Generic.Dictionary.Enumerator
-~static OpenTelemetry.Baggage.RemoveBaggage(string name, OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> OpenTelemetry.Baggage
-~static OpenTelemetry.Baggage.SetBaggage(string name, string value, OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> OpenTelemetry.Baggage
-~static OpenTelemetry.Baggage.SetBaggage(System.Collections.Generic.IEnumerable> baggageItems, OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> OpenTelemetry.Baggage
-~static OpenTelemetry.Context.Propagation.Propagators.DefaultTextMapPropagator.get -> OpenTelemetry.Context.Propagation.TextMapPropagator
-~static OpenTelemetry.Context.RuntimeContext.ContextSlotType.get -> System.Type
-~static OpenTelemetry.Context.RuntimeContext.ContextSlotType.set -> void
-~static OpenTelemetry.Context.RuntimeContext.GetSlot(string slotName) -> OpenTelemetry.Context.RuntimeContextSlot
-~static OpenTelemetry.Context.RuntimeContext.GetValue(string slotName) -> object
-~static OpenTelemetry.Context.RuntimeContext.GetValue(string slotName) -> T
-~static OpenTelemetry.Context.RuntimeContext.RegisterSlot(string slotName) -> OpenTelemetry.Context.RuntimeContextSlot
-~static OpenTelemetry.Context.RuntimeContext.SetValue(string slotName, object value) -> void
-~static OpenTelemetry.Context.RuntimeContext.SetValue(string slotName, T value) -> void
-abstract OpenTelemetry.Context.RuntimeContextSlot.Get() -> T
+static OpenTelemetry.Context.RuntimeContext.ContextSlotType.get -> System.Type!
+static OpenTelemetry.Context.RuntimeContext.ContextSlotType.set -> void
+static OpenTelemetry.Context.RuntimeContext.GetSlot(string! slotName) -> OpenTelemetry.Context.RuntimeContextSlot!
+static OpenTelemetry.Context.RuntimeContext.GetValue(string! slotName) -> object?
+static OpenTelemetry.Context.RuntimeContext.GetValue(string! slotName) -> T?
+static OpenTelemetry.Context.RuntimeContext.RegisterSlot(string! slotName) -> OpenTelemetry.Context.RuntimeContextSlot!
+static OpenTelemetry.Context.RuntimeContext.SetValue(string! slotName, object? value) -> void
+static OpenTelemetry.Context.RuntimeContext.SetValue(string! slotName, T value) -> void
+abstract OpenTelemetry.Context.Propagation.TextMapPropagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func?>! getter) -> OpenTelemetry.Context.Propagation.PropagationContext
+abstract OpenTelemetry.Context.Propagation.TextMapPropagator.Fields.get -> System.Collections.Generic.ISet?
+abstract OpenTelemetry.Context.Propagation.TextMapPropagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action! setter) -> void
+abstract OpenTelemetry.Context.RuntimeContextSlot.Get() -> T?
abstract OpenTelemetry.Context.RuntimeContextSlot.Set(T value) -> void
+abstract OpenTelemetry.Logs.LoggerProviderBuilder.AddInstrumentation(System.Func! instrumentationFactory) -> OpenTelemetry.Logs.LoggerProviderBuilder!
abstract OpenTelemetry.Metrics.MeterProviderBuilder.AddInstrumentation(System.Func! instrumentationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder!
abstract OpenTelemetry.Metrics.MeterProviderBuilder.AddMeter(params string![]! names) -> OpenTelemetry.Metrics.MeterProviderBuilder!
abstract OpenTelemetry.Trace.TracerProviderBuilder.AddInstrumentation(System.Func! instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder!
@@ -63,15 +24,28 @@ OpenTelemetry.Baggage.Baggage() -> void
OpenTelemetry.Baggage.ClearBaggage() -> OpenTelemetry.Baggage
OpenTelemetry.Baggage.Count.get -> int
OpenTelemetry.Baggage.Equals(OpenTelemetry.Baggage other) -> bool
+OpenTelemetry.Baggage.GetBaggage() -> System.Collections.Generic.IReadOnlyDictionary!
+OpenTelemetry.Baggage.GetBaggage(string! name) -> string?
+OpenTelemetry.Baggage.GetEnumerator() -> System.Collections.Generic.Dictionary.Enumerator
+OpenTelemetry.Baggage.RemoveBaggage(string! name) -> OpenTelemetry.Baggage
+OpenTelemetry.Baggage.SetBaggage(params System.Collections.Generic.KeyValuePair[]! baggageItems) -> OpenTelemetry.Baggage
+OpenTelemetry.Baggage.SetBaggage(string! name, string? value) -> OpenTelemetry.Baggage
+OpenTelemetry.Baggage.SetBaggage(System.Collections.Generic.IEnumerable>! baggageItems) -> OpenTelemetry.Baggage
OpenTelemetry.BaseProvider
OpenTelemetry.BaseProvider.~BaseProvider() -> void
OpenTelemetry.BaseProvider.BaseProvider() -> void
OpenTelemetry.BaseProvider.Dispose() -> void
OpenTelemetry.Context.AsyncLocalRuntimeContextSlot
+OpenTelemetry.Context.AsyncLocalRuntimeContextSlot.AsyncLocalRuntimeContextSlot(string! name) -> void
+OpenTelemetry.Context.AsyncLocalRuntimeContextSlot.Value.get -> object?
+OpenTelemetry.Context.AsyncLocalRuntimeContextSlot.Value.set -> void
OpenTelemetry.Context.IRuntimeContextSlotValueAccessor
+OpenTelemetry.Context.IRuntimeContextSlotValueAccessor.Value.get -> object?
+OpenTelemetry.Context.IRuntimeContextSlotValueAccessor.Value.set -> void
OpenTelemetry.Context.Propagation.B3Propagator
OpenTelemetry.Context.Propagation.B3Propagator.B3Propagator() -> void
OpenTelemetry.Context.Propagation.B3Propagator.B3Propagator(bool singleHeader) -> void
+OpenTelemetry.Context.Propagation.CompositeTextMapPropagator.CompositeTextMapPropagator(System.Collections.Generic.IEnumerable! propagators) -> void
OpenTelemetry.Context.Propagation.BaggagePropagator
OpenTelemetry.Context.Propagation.BaggagePropagator.BaggagePropagator() -> void
OpenTelemetry.Context.Propagation.CompositeTextMapPropagator
@@ -89,7 +63,18 @@ OpenTelemetry.Context.Propagation.TraceContextPropagator.TraceContextPropagator(
OpenTelemetry.Context.RuntimeContext
OpenTelemetry.Context.RuntimeContextSlot
OpenTelemetry.Context.RuntimeContextSlot.Dispose() -> void
+OpenTelemetry.Context.RuntimeContextSlot.Name.get -> string!
+OpenTelemetry.Context.RuntimeContextSlot.RuntimeContextSlot(string! name) -> void
OpenTelemetry.Context.ThreadLocalRuntimeContextSlot
+OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.ThreadLocalRuntimeContextSlot(string! name) -> void
+OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.Value.get -> object?
+OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.Value.set -> void
+OpenTelemetry.Logs.IDeferredLoggerProviderBuilder
+OpenTelemetry.Logs.IDeferredLoggerProviderBuilder.Configure(System.Action! configure) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+OpenTelemetry.Logs.LoggerProvider
+OpenTelemetry.Logs.LoggerProvider.LoggerProvider() -> void
+OpenTelemetry.Logs.LoggerProviderBuilder
+OpenTelemetry.Logs.LoggerProviderBuilder.LoggerProviderBuilder() -> void
OpenTelemetry.Metrics.IDeferredMeterProviderBuilder
OpenTelemetry.Metrics.IDeferredMeterProviderBuilder.Configure(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Metrics.MeterProvider
@@ -104,8 +89,8 @@ OpenTelemetry.Trace.Link.Attributes.get -> System.Collections.Generic.IEnumerabl
OpenTelemetry.Trace.Link.Context.get -> OpenTelemetry.Trace.SpanContext
OpenTelemetry.Trace.Link.Equals(OpenTelemetry.Trace.Link other) -> bool
OpenTelemetry.Trace.Link.Link() -> void
-OpenTelemetry.Trace.Link.Link(in OpenTelemetry.Trace.SpanContext spanContext) -> void
OpenTelemetry.Trace.Link.Link(in OpenTelemetry.Trace.SpanContext spanContext, OpenTelemetry.Trace.SpanAttributes? attributes) -> void
+OpenTelemetry.Trace.Link.Link(in OpenTelemetry.Trace.SpanContext spanContext) -> void
OpenTelemetry.Trace.SpanAttributes
OpenTelemetry.Trace.SpanAttributes.Add(string! key, bool value) -> void
OpenTelemetry.Trace.SpanAttributes.Add(string! key, bool[]? values) -> void
@@ -145,10 +130,10 @@ OpenTelemetry.Trace.StatusCode.Error = 2 -> OpenTelemetry.Trace.StatusCode
OpenTelemetry.Trace.StatusCode.Ok = 1 -> OpenTelemetry.Trace.StatusCode
OpenTelemetry.Trace.StatusCode.Unset = 0 -> OpenTelemetry.Trace.StatusCode
OpenTelemetry.Trace.TelemetrySpan
-OpenTelemetry.Trace.TelemetrySpan.AddEvent(string! name) -> OpenTelemetry.Trace.TelemetrySpan!
OpenTelemetry.Trace.TelemetrySpan.AddEvent(string! name, OpenTelemetry.Trace.SpanAttributes? attributes) -> OpenTelemetry.Trace.TelemetrySpan!
-OpenTelemetry.Trace.TelemetrySpan.AddEvent(string! name, System.DateTimeOffset timestamp) -> OpenTelemetry.Trace.TelemetrySpan!
OpenTelemetry.Trace.TelemetrySpan.AddEvent(string! name, System.DateTimeOffset timestamp, OpenTelemetry.Trace.SpanAttributes? attributes) -> OpenTelemetry.Trace.TelemetrySpan!
+OpenTelemetry.Trace.TelemetrySpan.AddEvent(string! name, System.DateTimeOffset timestamp) -> OpenTelemetry.Trace.TelemetrySpan!
+OpenTelemetry.Trace.TelemetrySpan.AddEvent(string! name) -> OpenTelemetry.Trace.TelemetrySpan!
OpenTelemetry.Trace.TelemetrySpan.Context.get -> OpenTelemetry.Trace.SpanContext
OpenTelemetry.Trace.TelemetrySpan.Dispose() -> void
OpenTelemetry.Trace.TelemetrySpan.End() -> void
@@ -178,12 +163,26 @@ OpenTelemetry.Trace.TracerProvider.GetTracer(string! name, string? version = nul
OpenTelemetry.Trace.TracerProvider.TracerProvider() -> void
OpenTelemetry.Trace.TracerProviderBuilder
OpenTelemetry.Trace.TracerProviderBuilder.TracerProviderBuilder() -> void
+override OpenTelemetry.Baggage.Equals(object? obj) -> bool
override OpenTelemetry.Baggage.GetHashCode() -> int
-override OpenTelemetry.Context.AsyncLocalRuntimeContextSlot.Get() -> T
+override OpenTelemetry.Context.AsyncLocalRuntimeContextSlot.Get() -> T?
override OpenTelemetry.Context.AsyncLocalRuntimeContextSlot.Set(T value) -> void
+override OpenTelemetry.Context.Propagation.B3Propagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func?>! getter) -> OpenTelemetry.Context.Propagation.PropagationContext
+override OpenTelemetry.Context.Propagation.B3Propagator.Fields.get -> System.Collections.Generic.ISet!
+override OpenTelemetry.Context.Propagation.B3Propagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action! setter) -> void
+override OpenTelemetry.Context.Propagation.BaggagePropagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func?>! getter) -> OpenTelemetry.Context.Propagation.PropagationContext
+override OpenTelemetry.Context.Propagation.BaggagePropagator.Fields.get -> System.Collections.Generic.ISet!
+override OpenTelemetry.Context.Propagation.BaggagePropagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action! setter) -> void
+override OpenTelemetry.Context.Propagation.CompositeTextMapPropagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func?>! getter) -> OpenTelemetry.Context.Propagation.PropagationContext
+override OpenTelemetry.Context.Propagation.CompositeTextMapPropagator.Fields.get -> System.Collections.Generic.ISet!
+override OpenTelemetry.Context.Propagation.CompositeTextMapPropagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action! setter) -> void
override OpenTelemetry.Context.Propagation.PropagationContext.GetHashCode() -> int
+override OpenTelemetry.Context.Propagation.PropagationContext.Equals(object? obj) -> bool
+override OpenTelemetry.Context.Propagation.TraceContextPropagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func?>! getter) -> OpenTelemetry.Context.Propagation.PropagationContext
+override OpenTelemetry.Context.Propagation.TraceContextPropagator.Fields.get -> System.Collections.Generic.ISet!
+override OpenTelemetry.Context.Propagation.TraceContextPropagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action! setter) -> void
override OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.Dispose(bool disposing) -> void
-override OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.Get() -> T
+override OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.Get() -> T?
override OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.Set(T value) -> void
override OpenTelemetry.Trace.Link.Equals(object? obj) -> bool
override OpenTelemetry.Trace.Link.GetHashCode() -> int
@@ -195,16 +194,24 @@ override OpenTelemetry.Trace.Status.ToString() -> string!
override OpenTelemetry.Trace.TracerProvider.Dispose(bool disposing) -> void
static OpenTelemetry.ActivityContextExtensions.IsValid(this System.Diagnostics.ActivityContext ctx) -> bool
static OpenTelemetry.Baggage.ClearBaggage(OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> OpenTelemetry.Baggage
+static OpenTelemetry.Baggage.Create(System.Collections.Generic.Dictionary? baggageItems = null) -> OpenTelemetry.Baggage
static OpenTelemetry.Baggage.Current.get -> OpenTelemetry.Baggage
static OpenTelemetry.Baggage.Current.set -> void
+static OpenTelemetry.Baggage.GetBaggage(OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> System.Collections.Generic.IReadOnlyDictionary!
+static OpenTelemetry.Baggage.GetBaggage(string! name, OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> string?
+static OpenTelemetry.Baggage.GetEnumerator(OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> System.Collections.Generic.Dictionary.Enumerator
static OpenTelemetry.Baggage.operator !=(OpenTelemetry.Baggage left, OpenTelemetry.Baggage right) -> bool
static OpenTelemetry.Baggage.operator ==(OpenTelemetry.Baggage left, OpenTelemetry.Baggage right) -> bool
+static OpenTelemetry.Baggage.RemoveBaggage(string! name, OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> OpenTelemetry.Baggage
+static OpenTelemetry.Baggage.SetBaggage(string! name, string? value, OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> OpenTelemetry.Baggage
+static OpenTelemetry.Baggage.SetBaggage(System.Collections.Generic.IEnumerable>! baggageItems, OpenTelemetry.Baggage baggage = default(OpenTelemetry.Baggage)) -> OpenTelemetry.Baggage
static OpenTelemetry.Context.Propagation.PropagationContext.operator !=(OpenTelemetry.Context.Propagation.PropagationContext left, OpenTelemetry.Context.Propagation.PropagationContext right) -> bool
static OpenTelemetry.Context.Propagation.PropagationContext.operator ==(OpenTelemetry.Context.Propagation.PropagationContext left, OpenTelemetry.Context.Propagation.PropagationContext right) -> bool
-static OpenTelemetry.Trace.ActivityExtensions.GetStatus(this System.Diagnostics.Activity! activity) -> OpenTelemetry.Trace.Status
-static OpenTelemetry.Trace.ActivityExtensions.RecordException(this System.Diagnostics.Activity! activity, System.Exception? ex) -> void
-static OpenTelemetry.Trace.ActivityExtensions.RecordException(this System.Diagnostics.Activity! activity, System.Exception? ex, in System.Diagnostics.TagList tags) -> void
-static OpenTelemetry.Trace.ActivityExtensions.SetStatus(this System.Diagnostics.Activity! activity, OpenTelemetry.Trace.Status status) -> void
+static OpenTelemetry.Context.Propagation.Propagators.DefaultTextMapPropagator.get -> OpenTelemetry.Context.Propagation.TextMapPropagator!
+static OpenTelemetry.Trace.ActivityExtensions.GetStatus(this System.Diagnostics.Activity? activity) -> OpenTelemetry.Trace.Status
+static OpenTelemetry.Trace.ActivityExtensions.RecordException(this System.Diagnostics.Activity? activity, System.Exception? ex, in System.Diagnostics.TagList tags) -> void
+static OpenTelemetry.Trace.ActivityExtensions.RecordException(this System.Diagnostics.Activity? activity, System.Exception? ex) -> void
+static OpenTelemetry.Trace.ActivityExtensions.SetStatus(this System.Diagnostics.Activity? activity, OpenTelemetry.Trace.Status status) -> void
static OpenTelemetry.Trace.Link.operator !=(OpenTelemetry.Trace.Link link1, OpenTelemetry.Trace.Link link2) -> bool
static OpenTelemetry.Trace.Link.operator ==(OpenTelemetry.Trace.Link link1, OpenTelemetry.Trace.Link link2) -> bool
static OpenTelemetry.Trace.SpanContext.implicit operator System.Diagnostics.ActivityContext(OpenTelemetry.Trace.SpanContext spanContext) -> System.Diagnostics.ActivityContext
diff --git a/src/OpenTelemetry.Api/.publicApi/Stable/net462/PublicAPI.Shipped.txt b/src/OpenTelemetry.Api/.publicApi/Stable/net462/PublicAPI.Shipped.txt
index 58383768cd..378097ec65 100644
--- a/src/OpenTelemetry.Api/.publicApi/Stable/net462/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Api/.publicApi/Stable/net462/PublicAPI.Shipped.txt
@@ -1,6 +1,6 @@
-~OpenTelemetry.Context.RemotingRuntimeContextSlot.RemotingRuntimeContextSlot(string name) -> void
-~OpenTelemetry.Context.RemotingRuntimeContextSlot.Value.get -> object
-~OpenTelemetry.Context.RemotingRuntimeContextSlot.Value.set -> void
OpenTelemetry.Context.RemotingRuntimeContextSlot
-override OpenTelemetry.Context.RemotingRuntimeContextSlot.Get() -> T
+OpenTelemetry.Context.RemotingRuntimeContextSlot.RemotingRuntimeContextSlot(string! name) -> void
+OpenTelemetry.Context.RemotingRuntimeContextSlot.Value.get -> object?
+OpenTelemetry.Context.RemotingRuntimeContextSlot.Value.set -> void
+override OpenTelemetry.Context.RemotingRuntimeContextSlot.Get() -> T?
override OpenTelemetry.Context.RemotingRuntimeContextSlot.Set(T value) -> void
diff --git a/src/OpenTelemetry.Api/ActivityContextExtensions.cs b/src/OpenTelemetry.Api/ActivityContextExtensions.cs
index f50a9af8fe..fb630ae661 100644
--- a/src/OpenTelemetry.Api/ActivityContextExtensions.cs
+++ b/src/OpenTelemetry.Api/ActivityContextExtensions.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
// The ActivityContext class is in the System.Diagnostics namespace.
diff --git a/src/OpenTelemetry.Api/Baggage.cs b/src/OpenTelemetry.Api/Baggage.cs
index 46cdedbd7d..93b972f4f1 100644
--- a/src/OpenTelemetry.Api/Baggage.cs
+++ b/src/OpenTelemetry.Api/Baggage.cs
@@ -87,7 +87,7 @@ public static Baggage Current
///
/// Baggage key/value pairs.
/// .
- public static Baggage Create(Dictionary baggageItems = null)
+ public static Baggage Create(Dictionary? baggageItems = null)
{
if (baggageItems == null)
{
@@ -133,7 +133,7 @@ public static Dictionary.Enumerator GetEnumerator(Baggage baggag
/// Optional . is used if not specified.
/// Baggage item or if nothing was found.
[SuppressMessage("roslyn", "RS0026", Justification = "TODO: fix APIs that violate the backcompt requirement - multiple overloads with optional parameters: https://github.com/dotnet/roslyn/blob/main/docs/Adding%20Optional%20Parameters%20in%20Public%20API.md.")]
- public static string GetBaggage(string name, Baggage baggage = default)
+ public static string? GetBaggage(string name, Baggage baggage = default)
=> baggage == default ? Current.GetBaggage(name) : baggage.GetBaggage(name);
///
@@ -145,7 +145,7 @@ public static string GetBaggage(string name, Baggage baggage = default)
/// New containing the key/value pair.
/// Note: The returned will be set as the new instance.
[SuppressMessage("roslyn", "RS0026", Justification = "TODO: fix APIs that violate the backcompt requirement - multiple overloads with optional parameters: https://github.com/dotnet/roslyn/blob/main/docs/Adding%20Optional%20Parameters%20in%20Public%20API.md.")]
- public static Baggage SetBaggage(string name, string value, Baggage baggage = default)
+ public static Baggage SetBaggage(string name, string? value, Baggage baggage = default)
{
var baggageHolder = EnsureBaggageHolder();
lock (baggageHolder)
@@ -164,7 +164,7 @@ public static Baggage SetBaggage(string name, string value, Baggage baggage = de
/// New containing the new key/value pairs.
/// Note: The returned will be set as the new instance.
[SuppressMessage("roslyn", "RS0026", Justification = "TODO: fix APIs that violate the backcompt requirement - multiple overloads with optional parameters: https://github.com/dotnet/roslyn/blob/main/docs/Adding%20Optional%20Parameters%20in%20Public%20API.md.")]
- public static Baggage SetBaggage(IEnumerable> baggageItems, Baggage baggage = default)
+ public static Baggage SetBaggage(IEnumerable> baggageItems, Baggage baggage = default)
{
var baggageHolder = EnsureBaggageHolder();
lock (baggageHolder)
@@ -222,11 +222,11 @@ public IReadOnlyDictionary GetBaggage()
///
/// Baggage item name.
/// Baggage item or if nothing was found.
- public string GetBaggage(string name)
+ public string? GetBaggage(string name)
{
Guard.ThrowIfNullOrEmpty(name);
- return this.baggage != null && this.baggage.TryGetValue(name, out string value)
+ return this.baggage != null && this.baggage.TryGetValue(name, out string? value)
? value
: null;
}
@@ -237,7 +237,7 @@ public string GetBaggage(string name)
/// Baggage item name.
/// Baggage item value.
/// New containing the key/value pair.
- public Baggage SetBaggage(string name, string value)
+ public Baggage SetBaggage(string name, string? value)
{
if (string.IsNullOrEmpty(value))
{
@@ -247,7 +247,7 @@ public Baggage SetBaggage(string name, string value)
return new Baggage(
new Dictionary(this.baggage ?? EmptyBaggage, StringComparer.OrdinalIgnoreCase)
{
- [name] = value,
+ [name] = value!,
});
}
@@ -256,15 +256,15 @@ public Baggage SetBaggage(string name, string value)
///
/// Baggage key/value pairs.
/// New containing the key/value pairs.
- public Baggage SetBaggage(params KeyValuePair[] baggageItems)
- => this.SetBaggage((IEnumerable>)baggageItems);
+ public Baggage SetBaggage(params KeyValuePair[] baggageItems)
+ => this.SetBaggage((IEnumerable>)baggageItems);
///
/// Returns a new which contains the new key/value pairs.
///
/// Baggage key/value pairs.
/// New containing the key/value pairs.
- public Baggage SetBaggage(IEnumerable> baggageItems)
+ public Baggage SetBaggage(IEnumerable> baggageItems)
{
if (baggageItems?.Any() != true)
{
@@ -281,7 +281,7 @@ public Baggage SetBaggage(IEnumerable> baggageItems
}
else
{
- newBaggage[item.Key] = item.Value;
+ newBaggage[item.Key] = item.Value!;
}
}
@@ -325,11 +325,11 @@ public bool Equals(Baggage other)
return false;
}
- return baggageIsNullOrEmpty || this.baggage.SequenceEqual(other.baggage);
+ return baggageIsNullOrEmpty || this.baggage!.SequenceEqual(other.baggage!);
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
=> (obj is Baggage baggage) && this.Equals(baggage);
///
diff --git a/src/OpenTelemetry.Api/BaseProvider.cs b/src/OpenTelemetry.Api/BaseProvider.cs
index ce8e30a46b..117f18c3c6 100644
--- a/src/OpenTelemetry.Api/BaseProvider.cs
+++ b/src/OpenTelemetry.Api/BaseProvider.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry;
///
diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md
index 9bdc9bf5d1..a1a16a7f8c 100644
--- a/src/OpenTelemetry.Api/CHANGELOG.md
+++ b/src/OpenTelemetry.Api/CHANGELOG.md
@@ -1,7 +1,61 @@
# Changelog
+This file contains individual changes for the OpenTelemetry.Api package. For
+highlights and announcements covering all components see: [Release
+Notes](../../RELEASENOTES.md).
+
## Unreleased
+## 1.10.0-beta.1
+
+Released 2024-Sep-30
+
+* **Breaking change:** CompositeTextMapPropagator.Fields now returns a
+ unioned set of fields from all combined propagators. Previously this always
+ returned an empty set.
+ ([#5745](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5745))
+
+* Optimize performance of `TraceContextPropagator.Extract`.
+ ([#5749](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5749))
+
+* Obsoleted the `ActivityExtensions.GetStatus` and
+ `ActivityExtensions.SetStatus` extension methods. Users should migrate to the
+ `System.Diagnostics.DiagnosticSource`
+ [Activity.SetStatus](https://learn.microsoft.com/dotnet/api/system.diagnostics.activity.setstatus)
+ API for setting the status and
+ [Activity.Status](https://learn.microsoft.com/dotnet/api/system.diagnostics.activity.status)
+ &
+ [Activity.StatusDescription](https://learn.microsoft.com/dotnet/api/system.diagnostics.activity.statusdescription)
+ APIs for reading the status of an `Activity` instance.
+ ([#5781](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5781))
+
+* Updated `System.Diagnostics.DiagnosticSource` package version to
+ `9.0.0-rc.1.24431.7`.
+ ([#5853](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5853))
+
+* Obsoleted the `ActivityExtensions.RecordException` extension method. Users
+ should migrate to the `System.Diagnostics.DiagnosticSource`
+ [Activity.AddException](https://learn.microsoft.com/dotnet/api/system.diagnostics.activity.addexception)
+ API for adding exceptions on an `Activity` instance.
+ ([#5841](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5841))
+
+## 1.9.0
+
+Released 2024-Jun-14
+
+* **Breaking change:** Revert space character encoding change from `+` to `%20`
+ for baggage item values from [#5303](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5303)
+ ([#5687](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5687))
+
+## 1.9.0-rc.1
+
+Released 2024-Jun-07
+
+* The experimental APIs previously covered by `OTEL1000` (`LoggerProvider`,
+ `LoggerProviderBuilder`, & `IDeferredLoggerProviderBuilder`) are now part of
+ the public API and supported in stable builds.
+ ([#5648](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5648))
+
## 1.9.0-alpha.1
Released 2024-May-20
diff --git a/src/OpenTelemetry.Api/Context/AsyncLocalRuntimeContextSlot.cs b/src/OpenTelemetry.Api/Context/AsyncLocalRuntimeContextSlot.cs
index 15eb31d08c..7bafc0e951 100644
--- a/src/OpenTelemetry.Api/Context/AsyncLocalRuntimeContextSlot.cs
+++ b/src/OpenTelemetry.Api/Context/AsyncLocalRuntimeContextSlot.cs
@@ -24,15 +24,25 @@ public AsyncLocalRuntimeContextSlot(string name)
}
///
- public object Value
+ public object? Value
{
get => this.slot.Value;
- set => this.slot.Value = (T)value;
+ set
+ {
+ if (typeof(T).IsValueType && value is null)
+ {
+ this.slot.Value = default!;
+ }
+ else
+ {
+ this.slot.Value = (T)value!;
+ }
+ }
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public override T Get()
+ public override T? Get()
{
return this.slot.Value;
}
diff --git a/src/OpenTelemetry.Api/Context/IRuntimeContextSlotValueAccessor.cs b/src/OpenTelemetry.Api/Context/IRuntimeContextSlotValueAccessor.cs
index 1e16ea4260..19c02050cd 100644
--- a/src/OpenTelemetry.Api/Context/IRuntimeContextSlotValueAccessor.cs
+++ b/src/OpenTelemetry.Api/Context/IRuntimeContextSlotValueAccessor.cs
@@ -11,5 +11,5 @@ public interface IRuntimeContextSlotValueAccessor
///
/// Gets or sets the value of the slot as an .
///
- object Value { get; set; }
+ object? Value { get; set; }
}
diff --git a/src/OpenTelemetry.Api/Context/Propagation/B3Propagator.cs b/src/OpenTelemetry.Api/Context/Propagation/B3Propagator.cs
index 10b4aee1d8..1827617210 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/B3Propagator.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/B3Propagator.cs
@@ -66,7 +66,7 @@ public B3Propagator(bool singleHeader)
///
[Obsolete("Use B3Propagator class from OpenTelemetry.Extensions.Propagators namespace, shipped as part of OpenTelemetry.Extensions.Propagators package.")]
#pragma warning disable CS0809 // Obsolete member overrides non-obsolete member
- public override PropagationContext Extract(PropagationContext context, T carrier, Func> getter)
+ public override PropagationContext Extract(PropagationContext context, T carrier, Func?> getter)
#pragma warning restore CS0809 // Obsolete member overrides non-obsolete member
{
if (context.ActivityContext.IsValid())
@@ -146,7 +146,7 @@ public override void Inject(PropagationContext context, T carrier, Action(PropagationContext context, T carrier, Func> getter)
+ private static PropagationContext ExtractFromMultipleHeaders(PropagationContext context, T carrier, Func?> getter)
{
try
{
@@ -179,7 +179,8 @@ private static PropagationContext ExtractFromMultipleHeaders(PropagationConte
}
var traceOptions = ActivityTraceFlags.None;
- if (SampledValues.Contains(getter(carrier, XB3Sampled)?.FirstOrDefault())
+ var xb3Sampled = getter(carrier, XB3Sampled)?.FirstOrDefault();
+ if ((xb3Sampled != null && SampledValues.Contains(xb3Sampled))
|| FlagsValue.Equals(getter(carrier, XB3Flags)?.FirstOrDefault(), StringComparison.Ordinal))
{
traceOptions |= ActivityTraceFlags.Recorded;
@@ -196,7 +197,7 @@ private static PropagationContext ExtractFromMultipleHeaders(PropagationConte
}
}
- private static PropagationContext ExtractFromSingleHeader(PropagationContext context, T carrier, Func> getter)
+ private static PropagationContext ExtractFromSingleHeader(PropagationContext context, T carrier, Func?> getter)
{
try
{
@@ -206,7 +207,7 @@ private static PropagationContext ExtractFromSingleHeader(PropagationContext
return context;
}
- var parts = header.Split(XB3CombinedDelimiter);
+ var parts = header!.Split(XB3CombinedDelimiter);
if (parts.Length < 2 || parts.Length > 4)
{
return context;
diff --git a/src/OpenTelemetry.Api/Context/Propagation/BaggagePropagator.cs b/src/OpenTelemetry.Api/Context/Propagation/BaggagePropagator.cs
index e9dc29d950..938980931e 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/BaggagePropagator.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/BaggagePropagator.cs
@@ -1,6 +1,10 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
+#if NET
+using System.Diagnostics.CodeAnalysis;
+#endif
+using System.Net;
using System.Text;
using OpenTelemetry.Internal;
@@ -23,7 +27,7 @@ public class BaggagePropagator : TextMapPropagator
public override ISet Fields => new HashSet { BaggageHeaderName };
///
- public override PropagationContext Extract(PropagationContext context, T carrier, Func> getter)
+ public override PropagationContext Extract(PropagationContext context, T carrier, Func?> getter)
{
if (context.Baggage != default)
{
@@ -45,16 +49,16 @@ public override PropagationContext Extract(PropagationContext context, T carr
try
{
- Dictionary baggage = null;
var baggageCollection = getter(carrier, BaggageHeaderName);
if (baggageCollection?.Any() ?? false)
{
- TryExtractBaggage(baggageCollection.ToArray(), out baggage);
+ if (TryExtractBaggage(baggageCollection.ToArray(), out var baggage))
+ {
+ return new PropagationContext(context.ActivityContext, new Baggage(baggage!));
+ }
}
- return new PropagationContext(
- context.ActivityContext,
- baggage == null ? context.Baggage : new Baggage(baggage));
+ return new PropagationContext(context.ActivityContext, context.Baggage);
}
catch (Exception ex)
{
@@ -93,7 +97,7 @@ public override void Inject(PropagationContext context, T carrier, Action(PropagationContext context, T carrier, Action baggage)
+ internal static bool TryExtractBaggage(
+ string[] baggageCollection,
+#if NET
+ [NotNullWhen(true)]
+#endif
+ out Dictionary? baggage)
{
int baggageLength = -1;
bool done = false;
- Dictionary baggageDictionary = null;
+ Dictionary? baggageDictionary = null;
foreach (var item in baggageCollection)
{
@@ -140,8 +149,8 @@ internal static bool TryExtractBaggage(string[] baggageCollection, out Dictionar
continue;
}
- var key = Uri.UnescapeDataString(parts[0]);
- var value = Uri.UnescapeDataString(parts[1]);
+ var key = WebUtility.UrlDecode(parts[0]);
+ var value = WebUtility.UrlDecode(parts[1]);
if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value))
{
diff --git a/src/OpenTelemetry.Api/Context/Propagation/CompositeTextMapPropagator.cs b/src/OpenTelemetry.Api/Context/Propagation/CompositeTextMapPropagator.cs
index a6b12c3cd1..e160bc8ac7 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/CompositeTextMapPropagator.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/CompositeTextMapPropagator.cs
@@ -11,8 +11,8 @@ namespace OpenTelemetry.Context.Propagation;
///
public class CompositeTextMapPropagator : TextMapPropagator
{
- private static readonly ISet EmptyFields = new HashSet();
- private readonly List propagators;
+ private readonly IReadOnlyList propagators;
+ private readonly ISet allFields;
///
/// Initializes a new instance of the class.
@@ -22,18 +22,55 @@ public CompositeTextMapPropagator(IEnumerable propagators)
{
Guard.ThrowIfNull(propagators);
- this.propagators = new List(propagators);
+ var propagatorsList = new List();
+
+ foreach (var propagator in propagators)
+ {
+ if (propagator is not null)
+ {
+ propagatorsList.Add(propagator);
+ }
+ }
+
+ this.propagators = propagatorsList;
+
+ // For efficiency, we resolve the fields from all propagators only once, as they are
+ // not expected to change (although the implementation doesn't strictly prevent that).
+ if (this.propagators.Count == 0)
+ {
+ // Use a new empty HashSet for each instance to avoid any potential mutation issues.
+ this.allFields = new HashSet();
+ }
+ else
+ {
+ ISet? fields = this.propagators[0].Fields;
+
+ var output = fields is not null
+ ? new HashSet(fields)
+ : [];
+
+ for (int i = 1; i < this.propagators.Count; i++)
+ {
+ fields = this.propagators[i].Fields;
+ if (fields is not null)
+ {
+ output.UnionWith(fields);
+ }
+ }
+
+ this.allFields = output;
+ }
}
///
- public override ISet Fields => EmptyFields;
+ public override ISet Fields => this.allFields;
///
- public override PropagationContext Extract(PropagationContext context, T carrier, Func> getter)
+ public override PropagationContext Extract(PropagationContext context, T carrier, Func?> getter)
{
- foreach (var propagator in this.propagators)
+ for (int i = 0; i < this.propagators.Count; i++)
{
- context = propagator.Extract(context, carrier, getter);
+ context = this.propagators[i].Extract(context, carrier, getter);
}
return context;
@@ -42,9 +79,9 @@ public override PropagationContext Extract(PropagationContext context, T carr
///
public override void Inject(PropagationContext context, T carrier, Action setter)
{
- foreach (var propagator in this.propagators)
+ for (int i = 0; i < this.propagators.Count; i++)
{
- propagator.Inject(context, carrier, setter);
+ this.propagators[i].Inject(context, carrier, setter);
}
}
}
diff --git a/src/OpenTelemetry.Api/Context/Propagation/NoopTextMapPropagator.cs b/src/OpenTelemetry.Api/Context/Propagation/NoopTextMapPropagator.cs
index 03dd45785d..a722a4f087 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/NoopTextMapPropagator.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/NoopTextMapPropagator.cs
@@ -7,9 +7,9 @@ internal sealed class NoopTextMapPropagator : TextMapPropagator
{
private static readonly PropagationContext DefaultPropagationContext = default;
- public override ISet Fields => null;
+ public override ISet? Fields => null;
- public override PropagationContext Extract(PropagationContext context, T carrier, Func> getter)
+ public override PropagationContext Extract(PropagationContext context, T carrier, Func?> getter)
{
return DefaultPropagationContext;
}
diff --git a/src/OpenTelemetry.Api/Context/Propagation/PropagationContext.cs b/src/OpenTelemetry.Api/Context/Propagation/PropagationContext.cs
index 77b6c71e77..0923ed45d6 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/PropagationContext.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/PropagationContext.cs
@@ -53,7 +53,7 @@ public bool Equals(PropagationContext value)
}
///
- public override bool Equals(object obj) => (obj is PropagationContext context) && this.Equals(context);
+ public override bool Equals(object? obj) => (obj is PropagationContext context) && this.Equals(context);
///
public override int GetHashCode()
diff --git a/src/OpenTelemetry.Api/Context/Propagation/TextMapPropagator.cs b/src/OpenTelemetry.Api/Context/Propagation/TextMapPropagator.cs
index 1000b317bf..bb0432378b 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/TextMapPropagator.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/TextMapPropagator.cs
@@ -15,12 +15,12 @@ public abstract class TextMapPropagator
/// * allow pre-allocation of fields, especially in systems like gRPC Metadata
/// * allow a single-pass over an iterator (ex OpenTracing has no getter in TextMap).
///
- public abstract ISet Fields { get; }
+ public abstract ISet? Fields { get; }
///
/// Injects the context into a carrier.
///
- /// Type of an object to set context on. Typically HttpRequest or similar.
+ /// Type of object to set context on. Typically,HttpRequest or similar.
/// The default context to transmit over the wire.
/// Object to set context on. Instance of this object will be passed to setter.
/// Action that will set name and value pair on the object.
@@ -29,10 +29,10 @@ public abstract class TextMapPropagator
///
/// Extracts the context from a carrier.
///
- /// Type of object to extract context from. Typically HttpRequest or similar.
+ /// Type of object to extract context from. Typically, HttpRequest or similar.
/// The default context to be used if Extract fails.
/// Object to extract context from. Instance of this object will be passed to the getter.
/// Function that will return string value of a key with the specified name.
- /// Context from it's text representation.
- public abstract PropagationContext Extract(PropagationContext context, T carrier, Func> getter);
+ /// Context from its text representation.
+ public abstract PropagationContext Extract(PropagationContext context, T carrier, Func?> getter);
}
diff --git a/src/OpenTelemetry.Api/Context/Propagation/TraceContextPropagator.cs b/src/OpenTelemetry.Api/Context/Propagation/TraceContextPropagator.cs
index de71129542..ee67aaaaaf 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/TraceContextPropagator.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/TraceContextPropagator.cs
@@ -1,9 +1,9 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
+using System.Buffers;
using System.Diagnostics;
using System.Runtime.CompilerServices;
-using System.Text;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Context.Propagation;
@@ -34,7 +34,7 @@ public class TraceContextPropagator : TextMapPropagator
public override ISet Fields => new HashSet { TraceState, TraceParent };
///
- public override PropagationContext Extract(PropagationContext context, T carrier, Func> getter)
+ public override PropagationContext Extract(PropagationContext context, T carrier, Func?> getter)
{
if (context.ActivityContext.IsValid())
{
@@ -72,11 +72,11 @@ public override PropagationContext Extract(PropagationContext context, T carr
return context;
}
- string tracestate = null;
+ string? tracestate = null;
var tracestateCollection = getter(carrier, TraceState);
if (tracestateCollection?.Any() ?? false)
{
- TryExtractTracestate(tracestateCollection.ToArray(), out tracestate);
+ TryExtractTracestate(tracestateCollection, out tracestate);
}
return new PropagationContext(
@@ -113,7 +113,7 @@ public override void Inject(PropagationContext context, T carrier, Action(PropagationContext context, T carrier, Action 0)
{
setter(carrier, TraceState, tracestateStr);
@@ -220,31 +220,37 @@ internal static bool TryExtractTraceparent(string traceparent, out ActivityTrace
return true;
}
- internal static bool TryExtractTracestate(string[] tracestateCollection, out string tracestateResult)
+ internal static bool TryExtractTracestate(IEnumerable tracestateCollection, out string tracestateResult)
{
tracestateResult = string.Empty;
- if (tracestateCollection != null)
+ char[]? rentedArray = null;
+ Span traceStateBuffer = stackalloc char[128]; // 256B
+ Span keyLookupBuffer = stackalloc char[96]; // 192B (3x32 keys)
+ int keys = 0;
+ int charsWritten = 0;
+
+ try
{
- var keySet = new HashSet();
- var result = new StringBuilder();
- for (int i = 0; i < tracestateCollection.Length; ++i)
+ foreach (var tracestateItem in tracestateCollection)
{
- var tracestate = tracestateCollection[i].AsSpan();
- int begin = 0;
- while (begin < tracestate.Length)
+ var tracestate = tracestateItem.AsSpan();
+ int position = 0;
+
+ while (position < tracestate.Length)
{
- int length = tracestate.Slice(begin).IndexOf(',');
+ int length = tracestate.Slice(position).IndexOf(',');
ReadOnlySpan listMember;
+
if (length != -1)
{
- listMember = tracestate.Slice(begin, length).Trim();
- begin += length + 1;
+ listMember = tracestate.Slice(position, length).Trim();
+ position += length + 1;
}
else
{
- listMember = tracestate.Slice(begin).Trim();
- begin = tracestate.Length;
+ listMember = tracestate.Slice(position).Trim();
+ position = tracestate.Length;
}
// https://github.com/w3c/trace-context/blob/master/spec/20-http_request_header_format.md#tracestate-header-field-values
@@ -255,7 +261,7 @@ internal static bool TryExtractTracestate(string[] tracestateCollection, out str
continue;
}
- if (keySet.Count >= 32)
+ if (keys >= 32)
{
// https://github.com/w3c/trace-context/blob/master/spec/20-http_request_header_format.md#list
// test_tracestate_member_count_limit
@@ -286,25 +292,107 @@ internal static bool TryExtractTracestate(string[] tracestateCollection, out str
}
// ValidateKey() call above has ensured the key does not contain upper case letters.
- if (!keySet.Add(key.ToString()))
+
+ var duplicationCheckLength = Math.Min(key.Length, 3);
+
+ if (keys > 0)
{
- // test_tracestate_duplicated_keys
- return false;
+ // Fast path check of first three chars for potential duplicated keys
+ var potentialMatchingKeyPosition = 1;
+ var found = false;
+ for (int i = 0; i < keys * 3; i += 3)
+ {
+ if (keyLookupBuffer.Slice(i, duplicationCheckLength).SequenceEqual(key.Slice(0, duplicationCheckLength)))
+ {
+ found = true;
+ break;
+ }
+
+ potentialMatchingKeyPosition++;
+ }
+
+ // If the fast check has found a possible duplicate, we need to do a full check
+ if (found)
+ {
+ var bufferToCompare = traceStateBuffer.Slice(0, charsWritten);
+
+ // We know which key is the first possible duplicate, so skip to that key
+ // by slicing to the position after the appropriate comma.
+ for (int i = 1; i < potentialMatchingKeyPosition; i++)
+ {
+ var commaIndex = bufferToCompare.IndexOf(',');
+
+ if (commaIndex > -1)
+ {
+ bufferToCompare.Slice(commaIndex);
+ }
+ }
+
+ int existingIndex = -1;
+ while ((existingIndex = bufferToCompare.IndexOf(key)) > -1)
+ {
+ if ((existingIndex > 0 && bufferToCompare[existingIndex - 1] != ',') || bufferToCompare[existingIndex + key.Length] != '=')
+ {
+ continue; // this is not a key
+ }
+
+ return false; // test_tracestate_duplicated_keys
+ }
+ }
}
- if (result.Length > 0)
+ // Store up to the first three characters of the key for use in the duplicate lookup fast path
+ var startKeyLookupIndex = keys > 0 ? keys * 3 : 0;
+ key.Slice(0, duplicationCheckLength).CopyTo(keyLookupBuffer.Slice(startKeyLookupIndex));
+
+ // Check we have capacity to write the key and value
+ var requiredCapacity = charsWritten > 0 ? listMember.Length + 1 : listMember.Length;
+
+ while (charsWritten + requiredCapacity > traceStateBuffer.Length)
{
- result.Append(',');
+ GrowBuffer(ref rentedArray, ref traceStateBuffer);
}
- result.Append(listMember.ToString());
+ if (charsWritten > 0)
+ {
+ traceStateBuffer[charsWritten++] = ',';
+ }
+
+ listMember.CopyTo(traceStateBuffer.Slice(charsWritten));
+ charsWritten += listMember.Length;
+
+ keys++;
}
}
- tracestateResult = result.ToString();
+ tracestateResult = traceStateBuffer.Slice(0, charsWritten).ToString();
+
+ return true;
+ }
+ finally
+ {
+ if (rentedArray is not null)
+ {
+ ArrayPool.Shared.Return(rentedArray);
+ rentedArray = null;
+ }
}
- return true;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static void GrowBuffer(ref char[]? array, ref Span buffer)
+ {
+ var newBuffer = ArrayPool.Shared.Rent(buffer.Length * 2);
+
+ buffer.CopyTo(newBuffer.AsSpan());
+
+ if (array is not null)
+ {
+ ArrayPool.Shared.Return(array);
+ }
+
+ array = newBuffer;
+ buffer = array.AsSpan();
+ }
}
private static byte HexCharToByte(char c)
@@ -430,7 +518,7 @@ private static bool IsLowerAlphaDigit(char c)
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z');
}
-#if NET6_0_OR_GREATER
+#if NET
private static void WriteTraceParentIntoSpan(Span destination, ActivityContext context)
{
"00-".CopyTo(destination);
diff --git a/src/OpenTelemetry.Api/Context/Propagation/TraceStateUtilsNew.cs b/src/OpenTelemetry.Api/Context/Propagation/TraceStateUtilsNew.cs
index 717e1a9458..eef28f8ad9 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/TraceStateUtilsNew.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/TraceStateUtilsNew.cs
@@ -56,7 +56,7 @@ internal static bool AppendTraceState(string traceStateString, List(keyStr, value.ToString()));
+ tracestate!.Add(new KeyValuePair(keyStr, value.ToString()));
}
else
{
@@ -82,7 +82,7 @@ internal static bool AppendTraceState(string traceStateString, List> traceState)
+ internal static string GetString(IEnumerable>? traceState)
{
if (traceState == null || !traceState.Any())
{
diff --git a/src/OpenTelemetry.Api/Context/RemotingRuntimeContextSlot.cs b/src/OpenTelemetry.Api/Context/RemotingRuntimeContextSlot.cs
index 61d2722653..93f7bd4754 100644
--- a/src/OpenTelemetry.Api/Context/RemotingRuntimeContextSlot.cs
+++ b/src/OpenTelemetry.Api/Context/RemotingRuntimeContextSlot.cs
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
#if NETFRAMEWORK
+
using System.Collections;
using System.Reflection;
using System.Runtime.CompilerServices;
@@ -38,25 +39,39 @@ public RemotingRuntimeContextSlot(string name)
}
///
- public object Value
+ public object? Value
{
get => this.Get();
- set => this.Set((T)value);
+ set
+ {
+ if (typeof(T).IsValueType && value is null)
+ {
+ this.Set(default!);
+ }
+ else
+ {
+ this.Set((T)value!);
+ }
+ }
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public override T Get()
+ public override T? Get()
{
- if (!(CallContext.LogicalGetData(this.Name) is BitArray wrapper))
+ if (CallContext.LogicalGetData(this.Name) is not BitArray wrapper)
{
return default;
}
var value = WrapperField.GetValue(wrapper);
- return value is T t
- ? t
- : default;
+
+ if (typeof(T).IsValueType && value is null)
+ {
+ return default;
+ }
+
+ return (T)value;
}
///
diff --git a/src/OpenTelemetry.Api/Context/RuntimeContext.cs b/src/OpenTelemetry.Api/Context/RuntimeContext.cs
index 93c96299d2..c984147bf4 100644
--- a/src/OpenTelemetry.Api/Context/RuntimeContext.cs
+++ b/src/OpenTelemetry.Api/Context/RuntimeContext.cs
@@ -56,7 +56,8 @@ public static Type ContextSlotType
public static RuntimeContextSlot RegisterSlot(string slotName)
{
Guard.ThrowIfNullOrEmpty(slotName);
- RuntimeContextSlot slot = null;
+
+ RuntimeContextSlot? slot = null;
lock (Slots)
{
@@ -80,6 +81,10 @@ public static RuntimeContextSlot RegisterSlot(string slotName)
slot = new RemotingRuntimeContextSlot(slotName);
}
#endif
+ else
+ {
+ throw new NotSupportedException($"ContextSlotType '{ContextSlotType}' is not supported");
+ }
Slots[slotName] = slot;
return slot;
@@ -95,9 +100,10 @@ public static RuntimeContextSlot RegisterSlot(string slotName)
public static RuntimeContextSlot GetSlot(string slotName)
{
Guard.ThrowIfNullOrEmpty(slotName);
+
var slot = GuardNotFound(slotName);
- var contextSlot = Guard.ThrowIfNotOfType>(slot);
- return contextSlot;
+
+ return Guard.ThrowIfNotOfType>(slot);
}
/*
@@ -143,7 +149,7 @@ public static void SetValue(string slotName, T value)
/// The type of the value.
/// The value retrieved from the context slot.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static T GetValue(string slotName)
+ public static T? GetValue(string slotName)
{
return GetSlot(slotName).Get();
}
@@ -153,12 +159,13 @@ public static T GetValue(string slotName)
///
/// The name of the context slot.
/// The value to be set.
- public static void SetValue(string slotName, object value)
+ public static void SetValue(string slotName, object? value)
{
Guard.ThrowIfNullOrEmpty(slotName);
+
var slot = GuardNotFound(slotName);
- var runtimeContextSlotValueAccessor = Guard.ThrowIfNotOfType(slot);
- runtimeContextSlotValueAccessor.Value = value;
+
+ Guard.ThrowIfNotOfType(slot).Value = value;
}
///
@@ -166,12 +173,13 @@ public static void SetValue(string slotName, object value)
///
/// The name of the context slot.
/// The value retrieved from the context slot.
- public static object GetValue(string slotName)
+ public static object? GetValue(string slotName)
{
Guard.ThrowIfNullOrEmpty(slotName);
+
var slot = GuardNotFound(slotName);
- var runtimeContextSlotValueAccessor = Guard.ThrowIfNotOfType(slot);
- return runtimeContextSlotValueAccessor.Value;
+
+ return Guard.ThrowIfNotOfType(slot).Value;
}
// For testing purpose
diff --git a/src/OpenTelemetry.Api/Context/RuntimeContextSlot.cs b/src/OpenTelemetry.Api/Context/RuntimeContextSlot.cs
index 918e4b7942..a89afd394a 100644
--- a/src/OpenTelemetry.Api/Context/RuntimeContextSlot.cs
+++ b/src/OpenTelemetry.Api/Context/RuntimeContextSlot.cs
@@ -1,6 +1,8 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
+using OpenTelemetry.Internal;
+
namespace OpenTelemetry.Context;
///
@@ -15,6 +17,8 @@ public abstract class RuntimeContextSlot : IDisposable
/// The name of the context slot.
protected RuntimeContextSlot(string name)
{
+ Guard.ThrowIfNullOrEmpty(name);
+
this.Name = name;
}
@@ -27,7 +31,7 @@ protected RuntimeContextSlot(string name)
/// Get the value from the context slot.
///
/// The value retrieved from the context slot.
- public abstract T Get();
+ public abstract T? Get();
///
/// Set the value to the context slot.
diff --git a/src/OpenTelemetry.Api/Context/ThreadLocalRuntimeContextSlot.cs b/src/OpenTelemetry.Api/Context/ThreadLocalRuntimeContextSlot.cs
index c7724a842b..360f9df564 100644
--- a/src/OpenTelemetry.Api/Context/ThreadLocalRuntimeContextSlot.cs
+++ b/src/OpenTelemetry.Api/Context/ThreadLocalRuntimeContextSlot.cs
@@ -25,15 +25,25 @@ public ThreadLocalRuntimeContextSlot(string name)
}
///
- public object Value
+ public object? Value
{
get => this.slot.Value;
- set => this.slot.Value = (T)value;
+ set
+ {
+ if (typeof(T).IsValueType && value is null)
+ {
+ this.slot.Value = default!;
+ }
+ else
+ {
+ this.slot.Value = (T)value!;
+ }
+ }
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public override T Get()
+ public override T? Get()
{
return this.slot.Value;
}
diff --git a/src/OpenTelemetry.Api/Internal/OpenTelemetryApiEventSource.cs b/src/OpenTelemetry.Api/Internal/OpenTelemetryApiEventSource.cs
index ea802a6ed1..5ac56d362f 100644
--- a/src/OpenTelemetry.Api/Internal/OpenTelemetryApiEventSource.cs
+++ b/src/OpenTelemetry.Api/Internal/OpenTelemetryApiEventSource.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics.Tracing;
namespace OpenTelemetry.Internal;
diff --git a/src/OpenTelemetry.Api/Logs/IDeferredLoggerProviderBuilder.cs b/src/OpenTelemetry.Api/Logs/IDeferredLoggerProviderBuilder.cs
index 70528fe6cb..11397157ce 100644
--- a/src/OpenTelemetry.Api/Logs/IDeferredLoggerProviderBuilder.cs
+++ b/src/OpenTelemetry.Api/Logs/IDeferredLoggerProviderBuilder.cs
@@ -1,35 +1,14 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
-#if NET8_0_OR_GREATER && EXPOSE_EXPERIMENTAL_FEATURES
-using System.Diagnostics.CodeAnalysis;
-using OpenTelemetry.Internal;
-#endif
-
namespace OpenTelemetry.Logs;
-#if EXPOSE_EXPERIMENTAL_FEATURES
-///
-/// Describes a logger provider builder that supports deferred
-/// initialization using an to perform
-/// dependency injection.
-///
-///
-#if NET8_0_OR_GREATER
-[Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
-public
-#else
///
/// Describes a logger provider builder that supports deferred
/// initialization using an to perform
/// dependency injection.
///
-internal
-#endif
-interface IDeferredLoggerProviderBuilder
+public interface IDeferredLoggerProviderBuilder
{
///
/// Register a callback action to configure the
///
-#if NET8_0_OR_GREATER
+#if NET
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
public
diff --git a/src/OpenTelemetry.Api/Logs/LogRecordData.cs b/src/OpenTelemetry.Api/Logs/LogRecordData.cs
index cb3c49292a..20d8d5f264 100644
--- a/src/OpenTelemetry.Api/Logs/LogRecordData.cs
+++ b/src/OpenTelemetry.Api/Logs/LogRecordData.cs
@@ -1,10 +1,8 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
-#if NET8_0_OR_GREATER && EXPOSE_EXPERIMENTAL_FEATURES
+#if NET && EXPOSE_EXPERIMENTAL_FEATURES
using System.Diagnostics.CodeAnalysis;
using OpenTelemetry.Internal;
#endif
@@ -16,7 +14,7 @@ namespace OpenTelemetry.Logs;
/// Stores details about a log message.
///
///
-#if NET8_0_OR_GREATER
+#if NET
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
public
diff --git a/src/OpenTelemetry.Api/Logs/LogRecordSeverity.cs b/src/OpenTelemetry.Api/Logs/LogRecordSeverity.cs
index 9f48e71e85..b6a5b3e000 100644
--- a/src/OpenTelemetry.Api/Logs/LogRecordSeverity.cs
+++ b/src/OpenTelemetry.Api/Logs/LogRecordSeverity.cs
@@ -1,9 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
-#if NET8_0_OR_GREATER && EXPOSE_EXPERIMENTAL_FEATURES
+#if NET && EXPOSE_EXPERIMENTAL_FEATURES
using System.Diagnostics.CodeAnalysis;
using OpenTelemetry.Internal;
#endif
@@ -15,7 +13,7 @@ namespace OpenTelemetry.Logs;
/// Describes the severity level of a log record.
///
///
-#if NET8_0_OR_GREATER
+#if NET
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
public
diff --git a/src/OpenTelemetry.Api/Logs/LogRecordSeverityExtensions.cs b/src/OpenTelemetry.Api/Logs/LogRecordSeverityExtensions.cs
index f171edbc9c..81453d0302 100644
--- a/src/OpenTelemetry.Api/Logs/LogRecordSeverityExtensions.cs
+++ b/src/OpenTelemetry.Api/Logs/LogRecordSeverityExtensions.cs
@@ -1,9 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
-#if NET8_0_OR_GREATER && EXPOSE_EXPERIMENTAL_FEATURES
+#if NET && EXPOSE_EXPERIMENTAL_FEATURES
using System.Diagnostics.CodeAnalysis;
using OpenTelemetry.Internal;
#endif
@@ -15,7 +13,7 @@ namespace OpenTelemetry.Logs;
/// Contains extension methods for the enum.
///
///
-#if NET8_0_OR_GREATER
+#if NET
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
public
diff --git a/src/OpenTelemetry.Api/Logs/Logger.cs b/src/OpenTelemetry.Api/Logs/Logger.cs
index 71baf7d611..f8a50f2a6d 100644
--- a/src/OpenTelemetry.Api/Logs/Logger.cs
+++ b/src/OpenTelemetry.Api/Logs/Logger.cs
@@ -1,9 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
-#if NET8_0_OR_GREATER && EXPOSE_EXPERIMENTAL_FEATURES
+#if NET && EXPOSE_EXPERIMENTAL_FEATURES
using System.Diagnostics.CodeAnalysis;
using OpenTelemetry.Internal;
#endif
@@ -15,7 +13,7 @@ namespace OpenTelemetry.Logs;
/// Logger is the class responsible for creating log records.
///
/// WARNING: This is an experimental API which might change or be removed in the future. Use at your own risk.
-#if NET8_0_OR_GREATER
+#if NET
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
public
diff --git a/src/OpenTelemetry.Api/Logs/LoggerProvider.cs b/src/OpenTelemetry.Api/Logs/LoggerProvider.cs
index c7993dc664..71cc40e232 100644
--- a/src/OpenTelemetry.Api/Logs/LoggerProvider.cs
+++ b/src/OpenTelemetry.Api/Logs/LoggerProvider.cs
@@ -1,33 +1,19 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
+#if NETSTANDARD2_1_OR_GREATER || NET
using System.Diagnostics.CodeAnalysis;
#endif
-#if NET8_0_OR_GREATER
+#if EXPOSE_EXPERIMENTAL_FEATURES && NET
using OpenTelemetry.Internal;
#endif
namespace OpenTelemetry.Logs;
-#if EXPOSE_EXPERIMENTAL_FEATURES
-///
-/// LoggerProvider is the entry point of the OpenTelemetry API. It provides access to .
-///
-///
-#if NET8_0_OR_GREATER
-[Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
-public
-#else
///
/// LoggerProvider is the entry point of the OpenTelemetry API. It provides access to .
///
-internal
-#endif
- class LoggerProvider : BaseProvider
+public class LoggerProvider : BaseProvider
{
private static readonly NoopLogger NoopLogger = new();
@@ -38,37 +24,55 @@ protected LoggerProvider()
{
}
+#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Gets a logger.
///
+ ///
/// instance.
-#if NET8_0_OR_GREATER
+#if NET
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
- public Logger GetLogger()
+ public
+#else
+ internal
+#endif
+ Logger GetLogger()
=> this.GetLogger(name: null, version: null);
+#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Gets a logger with the given name.
///
+ ///
/// Optional name identifying the instrumentation library.
/// instance.
-#if NET8_0_OR_GREATER
+#if NET
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
- public Logger GetLogger(string? name)
+ public
+#else
+ internal
+#endif
+ Logger GetLogger(string? name)
=> this.GetLogger(name, version: null);
+#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Gets a logger with the given name and version.
///
+ ///
/// Optional name identifying the instrumentation library.
/// Optional version of the instrumentation library.
/// instance.
-#if NET8_0_OR_GREATER
+#if NET
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
- public Logger GetLogger(string? name, string? version)
+ public
+#else
+ internal
+#endif
+ Logger GetLogger(string? name, string? version)
{
if (!this.TryCreateLogger(name, out var logger))
{
@@ -80,18 +84,24 @@ public Logger GetLogger(string? name, string? version)
return logger;
}
+#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Try to create a logger with the given name.
///
+ ///
/// Optional name identifying the instrumentation library.
/// .
/// if the logger was created.
-#if NET8_0_OR_GREATER
+#if NET
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
- protected virtual bool TryCreateLogger(
+ protected
+#else
+ internal
+#endif
+ virtual bool TryCreateLogger(
string? name,
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
+#if NETSTANDARD2_1_OR_GREATER || NET
[NotNullWhen(true)]
#endif
out Logger? logger)
diff --git a/src/OpenTelemetry.Api/Logs/LoggerProviderBuilder.cs b/src/OpenTelemetry.Api/Logs/LoggerProviderBuilder.cs
index 3fa9c6fc74..2bc69d1d0c 100644
--- a/src/OpenTelemetry.Api/Logs/LoggerProviderBuilder.cs
+++ b/src/OpenTelemetry.Api/Logs/LoggerProviderBuilder.cs
@@ -1,31 +1,12 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
-#if NET8_0_OR_GREATER && EXPOSE_EXPERIMENTAL_FEATURES
-using System.Diagnostics.CodeAnalysis;
-using OpenTelemetry.Internal;
-#endif
-
namespace OpenTelemetry.Logs;
-#if EXPOSE_EXPERIMENTAL_FEATURES
-///
-/// LoggerProviderBuilder base class.
-///
-///
-#if NET8_0_OR_GREATER
-[Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
-public
-#else
///
/// LoggerProviderBuilder base class.
///
-internal
-#endif
- abstract class LoggerProviderBuilder
+public abstract class LoggerProviderBuilder
{
///
/// Initializes a new instance of the class.
diff --git a/src/OpenTelemetry.Api/Logs/NoopLogger.cs b/src/OpenTelemetry.Api/Logs/NoopLogger.cs
index f33ec668ac..2c2b61c418 100644
--- a/src/OpenTelemetry.Api/Logs/NoopLogger.cs
+++ b/src/OpenTelemetry.Api/Logs/NoopLogger.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Logs;
internal sealed class NoopLogger : Logger
diff --git a/src/OpenTelemetry.Api/Metrics/IDeferredMeterProviderBuilder.cs b/src/OpenTelemetry.Api/Metrics/IDeferredMeterProviderBuilder.cs
index c283219c43..5f0dc38d34 100644
--- a/src/OpenTelemetry.Api/Metrics/IDeferredMeterProviderBuilder.cs
+++ b/src/OpenTelemetry.Api/Metrics/IDeferredMeterProviderBuilder.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Metrics;
///
diff --git a/src/OpenTelemetry.Api/Metrics/MeterProvider.cs b/src/OpenTelemetry.Api/Metrics/MeterProvider.cs
index a16fd88df9..64fcb5e8e5 100644
--- a/src/OpenTelemetry.Api/Metrics/MeterProvider.cs
+++ b/src/OpenTelemetry.Api/Metrics/MeterProvider.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Metrics;
///
diff --git a/src/OpenTelemetry.Api/Metrics/MeterProviderBuilder.cs b/src/OpenTelemetry.Api/Metrics/MeterProviderBuilder.cs
index 95075dbe70..4fb6bb007d 100644
--- a/src/OpenTelemetry.Api/Metrics/MeterProviderBuilder.cs
+++ b/src/OpenTelemetry.Api/Metrics/MeterProviderBuilder.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Metrics;
///
diff --git a/src/OpenTelemetry.Api/OpenTelemetry.Api.csproj b/src/OpenTelemetry.Api/OpenTelemetry.Api.csproj
index 0a781a9417..0e6d270b40 100644
--- a/src/OpenTelemetry.Api/OpenTelemetry.Api.csproj
+++ b/src/OpenTelemetry.Api/OpenTelemetry.Api.csproj
@@ -4,9 +4,6 @@
OpenTelemetry .NET API
OpenTelemetry
core-
-
-
- disable
@@ -19,6 +16,7 @@
+
diff --git a/src/OpenTelemetry.Api/README.md b/src/OpenTelemetry.Api/README.md
index 5fd769f446..db0471e177 100644
--- a/src/OpenTelemetry.Api/README.md
+++ b/src/OpenTelemetry.Api/README.md
@@ -539,4 +539,8 @@ seeing these internal logs.
## References
-* [OpenTelemetry Project](https://opentelemetry.io/)
+* [OpenTelemetry Baggage API specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/baggage/api.md)
+* [OpenTelemetry Logs Bridge API specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/bridge-api.md)
+* [OpenTelemetry Metrics API specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md)
+* [OpenTelemetry Propagators API specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/api-propagators.md)
+* [OpenTelemetry Tracing API specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md)
diff --git a/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs b/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs
index d8ac769b9c..b22339267b 100644
--- a/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs
+++ b/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using System.Runtime.CompilerServices;
using OpenTelemetry.Internal;
@@ -21,17 +19,34 @@ public static class ActivityExtensions
{
///
/// Sets the status of activity execution.
- /// Activity class in .NET does not support 'Status'.
- /// This extension provides a workaround to store Status as special tags with key name of otel.status_code and otel.status_description.
- /// Read more about SetStatus here https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status.
///
+ ///
+ /// Note: This method is obsolete. Call the
+ /// method instead. For more details see: .
+ ///
/// Activity instance.
/// Activity execution status.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void SetStatus(this Activity activity, Status status)
+ [Obsolete("Call Activity.SetStatus instead this method will be removed in a future version.")]
+ public static void SetStatus(this Activity? activity, Status status)
{
if (activity != null)
{
+ switch (status.StatusCode)
+ {
+ case StatusCode.Ok:
+ activity.SetStatus(ActivityStatusCode.Ok);
+ break;
+ case StatusCode.Unset:
+ activity.SetStatus(ActivityStatusCode.Unset);
+ break;
+ case StatusCode.Error:
+ activity.SetStatus(ActivityStatusCode.Error, status.Description);
+ break;
+ }
+
activity.SetTag(SpanAttributeConstants.StatusCodeKey, StatusHelper.GetTagValueForStatusCode(status.StatusCode));
activity.SetTag(SpanAttributeConstants.StatusDescriptionKey, status.Description);
}
@@ -39,21 +54,37 @@ public static void SetStatus(this Activity activity, Status status)
///
/// Gets the status of activity execution.
- /// Activity class in .NET does not support 'Status'.
- /// This extension provides a workaround to retrieve Status from special tags with key name otel.status_code and otel.status_description.
///
+ ///
+ /// Note: This method is obsolete. Use the and
+ /// properties instead. For more
+ /// details see: .
+ ///
/// Activity instance.
/// Activity execution status.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Status GetStatus(this Activity activity)
+ [Obsolete("Use Activity.Status and Activity.StatusDescription instead this method will be removed in a future version.")]
+ public static Status GetStatus(this Activity? activity)
{
- if (activity == null
- || !activity.TryGetStatus(out var statusCode, out var statusDescription))
+ if (activity != null)
{
- return Status.Unset;
+ switch (activity.Status)
+ {
+ case ActivityStatusCode.Ok:
+ return Status.Ok;
+ case ActivityStatusCode.Error:
+ return new Status(StatusCode.Error, activity.StatusDescription);
+ }
+
+ if (activity.TryGetStatus(out var statusCode, out var statusDescription))
+ {
+ return new Status(statusCode, statusDescription);
+ }
}
- return new Status(statusCode, statusDescription);
+ return Status.Unset;
}
///
@@ -61,11 +92,14 @@ public static Status GetStatus(this Activity activity)
///
/// Activity instance.
/// Exception to be recorded.
- /// The exception is recorded as per specification.
+ ///
+ /// Note: This method is obsolete. Please use instead.
+ /// The exception is recorded as per specification.
/// "exception.stacktrace" is represented using the value of Exception.ToString.
///
+ [Obsolete("Call Activity.AddException instead this method will be removed in a future version.")]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void RecordException(this Activity activity, Exception? ex)
+ public static void RecordException(this Activity? activity, Exception? ex)
=> RecordException(activity, ex, default);
///
@@ -74,33 +108,20 @@ public static void RecordException(this Activity activity, Exception? ex)
/// Activity instance.
/// Exception to be recorded.
/// Additional tags to record on the event.
- /// The exception is recorded as per specification.
+ ///
+ /// Note: This method is obsolete. Please use instead.
+ /// The exception is recorded as per specification.
/// "exception.stacktrace" is represented using the value of Exception.ToString.
///
+ [Obsolete("Call Activity.AddException instead this method will be removed in a future version.")]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void RecordException(this Activity activity, Exception? ex, in TagList tags)
+ public static void RecordException(this Activity? activity, Exception? ex, in TagList tags)
{
if (ex == null || activity == null)
{
return;
}
- var tagsCollection = new ActivityTagsCollection
- {
- { SemanticConventions.AttributeExceptionType, ex.GetType().FullName },
- { SemanticConventions.AttributeExceptionStacktrace, ex.ToInvariantString() },
- };
-
- if (!string.IsNullOrWhiteSpace(ex.Message))
- {
- tagsCollection.Add(SemanticConventions.AttributeExceptionMessage, ex.Message);
- }
-
- foreach (var tag in tags)
- {
- tagsCollection[tag.Key] = tag.Value;
- }
-
- activity.AddEvent(new ActivityEvent(SemanticConventions.AttributeExceptionEventName, default, tagsCollection));
+ activity.AddException(ex, in tags);
}
}
diff --git a/src/OpenTelemetry.Api/Trace/IDeferredTracerProviderBuilder.cs b/src/OpenTelemetry.Api/Trace/IDeferredTracerProviderBuilder.cs
index 8be46ae443..7b0d3f7123 100644
--- a/src/OpenTelemetry.Api/Trace/IDeferredTracerProviderBuilder.cs
+++ b/src/OpenTelemetry.Api/Trace/IDeferredTracerProviderBuilder.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Trace;
///
diff --git a/src/OpenTelemetry.Api/Trace/Link.cs b/src/OpenTelemetry.Api/Trace/Link.cs
index 45af879162..1972a624c2 100644
--- a/src/OpenTelemetry.Api/Trace/Link.cs
+++ b/src/OpenTelemetry.Api/Trace/Link.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
namespace OpenTelemetry.Trace;
diff --git a/src/OpenTelemetry.Api/Trace/SpanAttributes.cs b/src/OpenTelemetry.Api/Trace/SpanAttributes.cs
index 84850ae048..5975830c98 100644
--- a/src/OpenTelemetry.Api/Trace/SpanAttributes.cs
+++ b/src/OpenTelemetry.Api/Trace/SpanAttributes.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using OpenTelemetry.Internal;
diff --git a/src/OpenTelemetry.Api/Trace/SpanContext.cs b/src/OpenTelemetry.Api/Trace/SpanContext.cs
index b94f50cc5f..825ad62bb4 100644
--- a/src/OpenTelemetry.Api/Trace/SpanContext.cs
+++ b/src/OpenTelemetry.Api/Trace/SpanContext.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using OpenTelemetry.Context.Propagation;
@@ -85,13 +83,14 @@ public IEnumerable> TraceState
{
get
{
- if (string.IsNullOrEmpty(this.ActivityContext.TraceState))
+ var traceState = this.ActivityContext.TraceState;
+ if (string.IsNullOrEmpty(traceState))
{
return Enumerable.Empty>();
}
var traceStateResult = new List>();
- TraceStateUtilsNew.AppendTraceState(this.ActivityContext.TraceState, traceStateResult);
+ TraceStateUtilsNew.AppendTraceState(traceState!, traceStateResult);
return traceStateResult;
}
}
diff --git a/src/OpenTelemetry.Api/Trace/SpanKind.cs b/src/OpenTelemetry.Api/Trace/SpanKind.cs
index f3237a6bd4..07358f7b0e 100644
--- a/src/OpenTelemetry.Api/Trace/SpanKind.cs
+++ b/src/OpenTelemetry.Api/Trace/SpanKind.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Trace;
///
diff --git a/src/OpenTelemetry.Api/Trace/Status.cs b/src/OpenTelemetry.Api/Trace/Status.cs
index b7d0eb35c3..a39ee8dd75 100644
--- a/src/OpenTelemetry.Api/Trace/Status.cs
+++ b/src/OpenTelemetry.Api/Trace/Status.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Trace;
///
diff --git a/src/OpenTelemetry.Api/Trace/StatusCode.cs b/src/OpenTelemetry.Api/Trace/StatusCode.cs
index 9332d708d0..28d691c10e 100644
--- a/src/OpenTelemetry.Api/Trace/StatusCode.cs
+++ b/src/OpenTelemetry.Api/Trace/StatusCode.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Trace;
///
diff --git a/src/OpenTelemetry.Api/Trace/TelemetrySpan.cs b/src/OpenTelemetry.Api/Trace/TelemetrySpan.cs
index f70598d078..47e67c6095 100644
--- a/src/OpenTelemetry.Api/Trace/TelemetrySpan.cs
+++ b/src/OpenTelemetry.Api/Trace/TelemetrySpan.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using System.Runtime.CompilerServices;
using OpenTelemetry.Internal;
@@ -47,7 +45,9 @@ public ActivitySpanId ParentSpanId
/// Status to be set.
public void SetStatus(Status value)
{
- this.Activity?.SetStatus(value);
+#pragma warning disable
+ this.Activity.SetStatus(value);
+#pragma warning restore
}
///
diff --git a/src/OpenTelemetry.Api/Trace/Tracer.cs b/src/OpenTelemetry.Api/Trace/Tracer.cs
index 44bf17e1f5..d0fb906ec1 100644
--- a/src/OpenTelemetry.Api/Trace/Tracer.cs
+++ b/src/OpenTelemetry.Api/Trace/Tracer.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
@@ -54,7 +52,7 @@ public static TelemetrySpan CurrentSpan
///
/// The span to be made current.
/// The supplied span for call chaining.
-#if NET6_0_OR_GREATER
+#if NET
[return: NotNullIfNotNull(nameof(span))]
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/src/OpenTelemetry.Api/Trace/TracerProvider.cs b/src/OpenTelemetry.Api/Trace/TracerProvider.cs
index 1dc0a5f293..21197d0abd 100644
--- a/src/OpenTelemetry.Api/Trace/TracerProvider.cs
+++ b/src/OpenTelemetry.Api/Trace/TracerProvider.cs
@@ -1,10 +1,8 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Collections.Concurrent;
-#if NET6_0_OR_GREATER
+#if NET
using System.Diagnostics.CodeAnalysis;
#endif
@@ -36,7 +34,7 @@ protected TracerProvider()
/// Version of the instrumentation library.
/// Tracer instance.
public Tracer GetTracer(
-#if NET6_0_OR_GREATER
+#if NET
[AllowNull]
#endif
string name,
diff --git a/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs b/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs
index 0a8c3dae3d..ac9b7a2dbe 100644
--- a/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs
+++ b/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
namespace OpenTelemetry.Trace;
diff --git a/src/OpenTelemetry.Exporter.Console/.publicApi/Experimental/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Console/.publicApi/Experimental/PublicAPI.Unshipped.txt
index be114835cc..e69de29bb2 100644
--- a/src/OpenTelemetry.Exporter.Console/.publicApi/Experimental/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry.Exporter.Console/.publicApi/Experimental/PublicAPI.Unshipped.txt
@@ -1,3 +0,0 @@
-static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.LoggerProviderBuilder loggerProviderBuilder) -> OpenTelemetry.Logs.LoggerProviderBuilder
-static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.LoggerProviderBuilder loggerProviderBuilder, string name, System.Action configure) -> OpenTelemetry.Logs.LoggerProviderBuilder
-static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.LoggerProviderBuilder loggerProviderBuilder, System.Action configure) -> OpenTelemetry.Logs.LoggerProviderBuilder
diff --git a/src/OpenTelemetry.Exporter.Console/.publicApi/Stable/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Console/.publicApi/Stable/PublicAPI.Shipped.txt
index 6f900a1f6f..9927c4d147 100644
--- a/src/OpenTelemetry.Exporter.Console/.publicApi/Stable/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Exporter.Console/.publicApi/Stable/PublicAPI.Shipped.txt
@@ -1,8 +1,9 @@
+#nullable enable
OpenTelemetry.Exporter.ConsoleActivityExporter
-OpenTelemetry.Exporter.ConsoleActivityExporter.ConsoleActivityExporter(OpenTelemetry.Exporter.ConsoleExporterOptions options) -> void
+OpenTelemetry.Exporter.ConsoleActivityExporter.ConsoleActivityExporter(OpenTelemetry.Exporter.ConsoleExporterOptions! options) -> void
OpenTelemetry.Exporter.ConsoleExporter
-OpenTelemetry.Exporter.ConsoleExporter.ConsoleExporter(OpenTelemetry.Exporter.ConsoleExporterOptions options) -> void
-OpenTelemetry.Exporter.ConsoleExporter.WriteLine(string message) -> void
+OpenTelemetry.Exporter.ConsoleExporter.ConsoleExporter(OpenTelemetry.Exporter.ConsoleExporterOptions! options) -> void
+OpenTelemetry.Exporter.ConsoleExporter.WriteLine(string! message) -> void
OpenTelemetry.Exporter.ConsoleExporterOptions
OpenTelemetry.Exporter.ConsoleExporterOptions.ConsoleExporterOptions() -> void
OpenTelemetry.Exporter.ConsoleExporterOptions.Targets.get -> OpenTelemetry.Exporter.ConsoleExporterOutputTargets
@@ -11,23 +12,26 @@ OpenTelemetry.Exporter.ConsoleExporterOutputTargets
OpenTelemetry.Exporter.ConsoleExporterOutputTargets.Console = 1 -> OpenTelemetry.Exporter.ConsoleExporterOutputTargets
OpenTelemetry.Exporter.ConsoleExporterOutputTargets.Debug = 2 -> OpenTelemetry.Exporter.ConsoleExporterOutputTargets
OpenTelemetry.Exporter.ConsoleLogRecordExporter
-OpenTelemetry.Exporter.ConsoleLogRecordExporter.ConsoleLogRecordExporter(OpenTelemetry.Exporter.ConsoleExporterOptions options) -> void
+OpenTelemetry.Exporter.ConsoleLogRecordExporter.ConsoleLogRecordExporter(OpenTelemetry.Exporter.ConsoleExporterOptions! options) -> void
OpenTelemetry.Exporter.ConsoleMetricExporter
-OpenTelemetry.Exporter.ConsoleMetricExporter.ConsoleMetricExporter(OpenTelemetry.Exporter.ConsoleExporterOptions options) -> void
+OpenTelemetry.Exporter.ConsoleMetricExporter.ConsoleMetricExporter(OpenTelemetry.Exporter.ConsoleExporterOptions! options) -> void
OpenTelemetry.Logs.ConsoleExporterLoggingExtensions
OpenTelemetry.Metrics.ConsoleExporterMetricsExtensions
OpenTelemetry.Trace.ConsoleExporterHelperExtensions
-override OpenTelemetry.Exporter.ConsoleActivityExporter.Export(in OpenTelemetry.Batch batch) -> OpenTelemetry.ExportResult
+override OpenTelemetry.Exporter.ConsoleActivityExporter.Export(in OpenTelemetry.Batch batch) -> OpenTelemetry.ExportResult
override OpenTelemetry.Exporter.ConsoleLogRecordExporter.Dispose(bool disposing) -> void
-override OpenTelemetry.Exporter.ConsoleLogRecordExporter.Export(in OpenTelemetry.Batch batch) -> OpenTelemetry.ExportResult
-override OpenTelemetry.Exporter.ConsoleMetricExporter.Export(in OpenTelemetry.Batch batch) -> OpenTelemetry.ExportResult
-static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions loggerOptions) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions
-static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions loggerOptions, System.Action configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions
-static OpenTelemetry.Metrics.ConsoleExporterMetricsExtensions.AddConsoleExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.ConsoleExporterMetricsExtensions.AddConsoleExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, string name, System.Action configureExporterAndMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.ConsoleExporterMetricsExtensions.AddConsoleExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, string name, System.Action configureExporter) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.ConsoleExporterMetricsExtensions.AddConsoleExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configureExporterAndMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.ConsoleExporterMetricsExtensions.AddConsoleExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configureExporter) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Trace.ConsoleExporterHelperExtensions.AddConsoleExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder) -> OpenTelemetry.Trace.TracerProviderBuilder
-static OpenTelemetry.Trace.ConsoleExporterHelperExtensions.AddConsoleExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, string name, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder
-static OpenTelemetry.Trace.ConsoleExporterHelperExtensions.AddConsoleExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder
+override OpenTelemetry.Exporter.ConsoleLogRecordExporter.Export(in OpenTelemetry.Batch batch) -> OpenTelemetry.ExportResult
+override OpenTelemetry.Exporter.ConsoleMetricExporter.Export(in OpenTelemetry.Batch batch) -> OpenTelemetry.ExportResult
+static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, string? name, System.Action? configure) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, System.Action! configure) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions! loggerOptions) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions!
+static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions! loggerOptions, System.Action? configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions!
+static OpenTelemetry.Metrics.ConsoleExporterMetricsExtensions.AddConsoleExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.ConsoleExporterMetricsExtensions.AddConsoleExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, string? name, System.Action? configureExporterAndMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.ConsoleExporterMetricsExtensions.AddConsoleExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, string? name, System.Action? configureExporter) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.ConsoleExporterMetricsExtensions.AddConsoleExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, System.Action? configureExporterAndMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.ConsoleExporterMetricsExtensions.AddConsoleExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, System.Action! configureExporter) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Trace.ConsoleExporterHelperExtensions.AddConsoleExporter(this OpenTelemetry.Trace.TracerProviderBuilder! builder) -> OpenTelemetry.Trace.TracerProviderBuilder!
+static OpenTelemetry.Trace.ConsoleExporterHelperExtensions.AddConsoleExporter(this OpenTelemetry.Trace.TracerProviderBuilder! builder, string? name, System.Action? configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
+static OpenTelemetry.Trace.ConsoleExporterHelperExtensions.AddConsoleExporter(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
diff --git a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md
index 6605e9d684..2702c92541 100644
--- a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md
+++ b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md
@@ -1,7 +1,40 @@
# Changelog
+This file contains individual changes for the OpenTelemetry.Exporter.Console
+package. For highlights and announcements covering all components see: [Release
+Notes](../../RELEASENOTES.md).
+
## Unreleased
+* Added direct reference to `System.Text.Json` for the `net8.0` target with
+ minimum version of `8.0.5` in response to
+ [CVE-2024-30105](https://github.com/advisories/GHSA-hh2w-p6rv-4g7w) &
+ [CVE-2024-43485](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-43485).
+ ([#5874](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5874),
+ [#5891](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5891))
+
+* Added support for Instrumentation Scope Attributes (i.e
+ [ActivitySource.Tags](https://learn.microsoft.com/dotnet/api/system.diagnostics.activitysource.tags))
+ when writing traces to the console.
+ ([#5935](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5935))
+
+## 1.10.0-beta.1
+
+Released 2024-Sep-30
+
+## 1.9.0
+
+Released 2024-Jun-14
+
+## 1.9.0-rc.1
+
+Released 2024-Jun-07
+
+* The experimental APIs previously covered by `OTEL1000`
+ (`LoggerProviderBuilder.AddConsoleExporter` extension) are now part of the
+ public API and supported in stable builds.
+ ([#5648](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5648))
+
## 1.9.0-alpha.1
Released 2024-May-20
@@ -33,9 +66,9 @@ Released 2023-Dec-08
Released 2023-Nov-29
-* Add support for Instrumentation Scope Attributes (i.e [Meter
- Tags](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.meter.tags)),
- fixing issue
+* Added support for Instrumentation Scope Attributes (i.e
+ [Meter.Tags](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.meter.tags)),
+ when writing metrics to the console, fixing issue
[#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563).
([#5089](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5089))
@@ -93,7 +126,8 @@ Released 2023-May-25
([#4507](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4507))
* Added direct reference to `System.Text.Encodings.Web` with minimum version of
-`4.7.2` in response to [CVE-2021-26701](https://github.com/dotnet/runtime/issues/49377).
+ `4.7.2` in response to
+ [CVE-2021-26701](https://github.com/dotnet/runtime/issues/49377).
([#4390](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4390))
* Updated `LogRecord` console output: `Body` is now shown (if set),
diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleActivityExporter.cs b/src/OpenTelemetry.Exporter.Console/ConsoleActivityExporter.cs
index 9197cd1287..c1b707b3e4 100644
--- a/src/OpenTelemetry.Exporter.Console/ConsoleActivityExporter.cs
+++ b/src/OpenTelemetry.Exporter.Console/ConsoleActivityExporter.cs
@@ -31,12 +31,6 @@ public override ExportResult Export(in Batch batch)
this.WriteLine($"Activity.ParentSpanId: {activity.ParentSpanId}");
}
- this.WriteLine($"Activity.ActivitySourceName: {activity.Source.Name}");
- if (!string.IsNullOrEmpty(activity.Source.Version))
- {
- this.WriteLine($"Activity.ActivitySourceVersion: {activity.Source.Version}");
- }
-
this.WriteLine($"Activity.DisplayName: {activity.DisplayName}");
this.WriteLine($"Activity.Kind: {activity.Kind}");
this.WriteLine($"Activity.StartTime: {activity.StartTimeUtc:yyyy-MM-ddTHH:mm:ss.fffffffZ}");
@@ -117,13 +111,32 @@ public override ExportResult Export(in Batch batch)
}
}
+ this.WriteLine("Instrumentation scope (ActivitySource):");
+ this.WriteLine($" Name: {activity.Source.Name}");
+ if (!string.IsNullOrEmpty(activity.Source.Version))
+ {
+ this.WriteLine($" Version: {activity.Source.Version}");
+ }
+
+ if (activity.Source.Tags?.Any() == true)
+ {
+ this.WriteLine(" Tags:");
+ foreach (var activitySourceTag in activity.Source.Tags)
+ {
+ if (this.TagWriter.TryTransformTag(activitySourceTag, out var result))
+ {
+ this.WriteLine($" {result.Key}: {result.Value}");
+ }
+ }
+ }
+
var resource = this.ParentProvider.GetResource();
if (resource != Resource.Empty)
{
this.WriteLine("Resource associated with Activity:");
foreach (var resourceAttribute in resource.Attributes)
{
- if (this.TagWriter.TryTransformTag(resourceAttribute, out var result))
+ if (this.TagWriter.TryTransformTag(resourceAttribute.Key, resourceAttribute.Value, out var result))
{
this.WriteLine($" {result.Key}: {result.Value}");
}
diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.Console/ConsoleExporterHelperExtensions.cs
index b79aa0d9ed..68a811669e 100644
--- a/src/OpenTelemetry.Exporter.Console/ConsoleExporterHelperExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Console/ConsoleExporterHelperExtensions.cs
@@ -31,13 +31,13 @@ public static TracerProviderBuilder AddConsoleExporter(this TracerProviderBuilde
/// Adds Console exporter to the TracerProvider.
///
/// builder to use.
- /// Name which is used when retrieving options.
- /// Callback action for configuring .
+ /// Optional name which is used when retrieving options.
+ /// Optional callback action for configuring .
/// The instance of to chain the calls.
public static TracerProviderBuilder AddConsoleExporter(
this TracerProviderBuilder builder,
- string name,
- Action configure)
+ string? name,
+ Action? configure)
{
Guard.ThrowIfNull(builder);
diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleExporterLoggingExtensions.cs b/src/OpenTelemetry.Exporter.Console/ConsoleExporterLoggingExtensions.cs
index 6b024498cb..498aa3a926 100644
--- a/src/OpenTelemetry.Exporter.Console/ConsoleExporterLoggingExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Console/ConsoleExporterLoggingExtensions.cs
@@ -1,9 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#if EXPOSE_EXPERIMENTAL_FEATURES && NET8_0_OR_GREATER
-using System.Diagnostics.CodeAnalysis;
-#endif
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenTelemetry.Exporter;
@@ -18,7 +15,7 @@ public static class ConsoleExporterLoggingExtensions
///
/// options to use.
/// The instance of to chain the calls.
- /// todo: [Obsolete("Call LoggerProviderBuilder.AddConsoleExporter instead this method will be removed in a future version.")]
+ // TODO: [Obsolete("Call LoggerProviderBuilder.AddConsoleExporter instead this method will be removed in a future version.")]
public static OpenTelemetryLoggerOptions AddConsoleExporter(this OpenTelemetryLoggerOptions loggerOptions)
=> AddConsoleExporter(loggerOptions, configure: null);
@@ -26,10 +23,10 @@ public static OpenTelemetryLoggerOptions AddConsoleExporter(this OpenTelemetryLo
/// Adds Console exporter with OpenTelemetryLoggerOptions.
///
/// options to use.
- /// Callback action for configuring .
+ /// Optional callback action for configuring .
/// The instance of to chain the calls.
- /// todo: [Obsolete("Call LoggerProviderBuilder.AddConsoleExporter instead this method will be removed in a future version.")]
- public static OpenTelemetryLoggerOptions AddConsoleExporter(this OpenTelemetryLoggerOptions loggerOptions, Action configure)
+ // TODO: [Obsolete("Call LoggerProviderBuilder.AddConsoleExporter instead this method will be removed in a future version.")]
+ public static OpenTelemetryLoggerOptions AddConsoleExporter(this OpenTelemetryLoggerOptions loggerOptions, Action? configure)
{
Guard.ThrowIfNull(loggerOptions);
@@ -38,82 +35,37 @@ public static OpenTelemetryLoggerOptions AddConsoleExporter(this OpenTelemetryLo
return loggerOptions.AddProcessor(new SimpleLogRecordExportProcessor(new ConsoleLogRecordExporter(options)));
}
-#if EXPOSE_EXPERIMENTAL_FEATURES
- ///
- /// Adds Console exporter with LoggerProviderBuilder.
- ///
- /// WARNING: This is an experimental API which might change or be removed in the future. Use at your own risk.
- /// .
- /// The supplied instance of to chain the calls.
-#if NET8_0_OR_GREATER
- [Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
- public
-#else
///
/// Adds Console exporter with LoggerProviderBuilder.
///
/// .
/// The supplied instance of to chain the calls.
- internal
-#endif
- static LoggerProviderBuilder AddConsoleExporter(
+ public static LoggerProviderBuilder AddConsoleExporter(
this LoggerProviderBuilder loggerProviderBuilder)
=> AddConsoleExporter(loggerProviderBuilder, name: null, configure: null);
-#if EXPOSE_EXPERIMENTAL_FEATURES
- ///
- /// Adds Console exporter with LoggerProviderBuilder.
- ///
- ///
- /// .
- /// Callback action for configuring .
- /// The supplied instance of to chain the calls.
-#if NET8_0_OR_GREATER
- [Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
- public
-#else
///
/// Adds Console exporter with LoggerProviderBuilder.
///
/// .
/// Callback action for configuring .
/// The supplied instance of to chain the calls.
- internal
-#endif
- static LoggerProviderBuilder AddConsoleExporter(
+ public static LoggerProviderBuilder AddConsoleExporter(
this LoggerProviderBuilder loggerProviderBuilder,
Action configure)
=> AddConsoleExporter(loggerProviderBuilder, name: null, configure);
-#if EXPOSE_EXPERIMENTAL_FEATURES
- ///
- /// Adds Console exporter with LoggerProviderBuilder.
- ///
- ///
- /// .
- /// Name which is used when retrieving options.
- /// Callback action for configuring .
- /// The supplied instance of to chain the calls.
-#if NET8_0_OR_GREATER
- [Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
- public
-#else
///
/// Adds Console exporter with LoggerProviderBuilder.
///
/// .
- /// Name which is used when retrieving options.
- /// Callback action for configuring .
+ /// Optional name which is used when retrieving options.
+ /// Optional callback action for configuring .
/// The supplied instance of to chain the calls.
- internal
-#endif
- static LoggerProviderBuilder AddConsoleExporter(
+ public static LoggerProviderBuilder AddConsoleExporter(
this LoggerProviderBuilder loggerProviderBuilder,
- string name,
- Action configure)
+ string? name,
+ Action? configure)
{
Guard.ThrowIfNull(loggerProviderBuilder);
diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleExporterMetricsExtensions.cs b/src/OpenTelemetry.Exporter.Console/ConsoleExporterMetricsExtensions.cs
index 103593efdd..78ee90829d 100644
--- a/src/OpenTelemetry.Exporter.Console/ConsoleExporterMetricsExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Console/ConsoleExporterMetricsExtensions.cs
@@ -37,13 +37,13 @@ public static MeterProviderBuilder AddConsoleExporter(this MeterProviderBuilder
/// Adds to the .
///
/// builder to use.
- /// Name which is used when retrieving options.
- /// Callback action for configuring .
+ /// Optional name which is used when retrieving options.
+ /// Optional callback action for configuring .
/// The instance of to chain the calls.
public static MeterProviderBuilder AddConsoleExporter(
this MeterProviderBuilder builder,
- string name,
- Action configureExporter)
+ string? name,
+ Action? configureExporter)
{
Guard.ThrowIfNull(builder);
@@ -72,7 +72,7 @@ public static MeterProviderBuilder AddConsoleExporter(
/// The instance of to chain the calls.
public static MeterProviderBuilder AddConsoleExporter(
this MeterProviderBuilder builder,
- Action configureExporterAndMetricReader)
+ Action? configureExporterAndMetricReader)
=> AddConsoleExporter(builder, name: null, configureExporterAndMetricReader);
///
@@ -86,8 +86,8 @@ public static MeterProviderBuilder AddConsoleExporter(
/// The instance of to chain the calls.
public static MeterProviderBuilder AddConsoleExporter(
this MeterProviderBuilder builder,
- string name,
- Action configureExporterAndMetricReader)
+ string? name,
+ Action? configureExporterAndMetricReader)
{
Guard.ThrowIfNull(builder);
diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs b/src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs
index 3ad9091095..0dfe396b30 100644
--- a/src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs
+++ b/src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs
@@ -10,9 +10,9 @@ namespace OpenTelemetry.Exporter;
public class ConsoleLogRecordExporter : ConsoleExporter
{
private const int RightPaddingLength = 35;
- private readonly object syncObject = new();
+ private readonly Lock syncObject = new();
private bool disposed;
- private string disposedStackTrace;
+ private string? disposedStackTrace;
private bool isDisposeMessageSent;
public ConsoleLogRecordExporter(ConsoleExporterOptions options)
@@ -39,7 +39,7 @@ public override ExportResult Export(in Batch batch)
this.WriteLine("The console exporter is still being invoked after it has been disposed. This could be due to the application's incorrect lifecycle management of the LoggerFactory/OpenTelemetry .NET SDK.");
this.WriteLine(Environment.StackTrace);
this.WriteLine(Environment.NewLine + "Dispose was called on the following stack trace:");
- this.WriteLine(this.disposedStackTrace);
+ this.WriteLine(this.disposedStackTrace!);
}
return ExportResult.Failure;
@@ -90,7 +90,7 @@ public override ExportResult Export(in Batch batch)
// See https://github.com/open-telemetry/opentelemetry-dotnet/pull/3182
// for explanation.
var valueToTransform = logRecord.Attributes[i].Key.Equals("{OriginalFormat}")
- ? new KeyValuePair("OriginalFormat (a.k.a Body)", logRecord.Attributes[i].Value)
+ ? new KeyValuePair("OriginalFormat (a.k.a Body)", logRecord.Attributes[i].Value)
: logRecord.Attributes[i];
if (this.TagWriter.TryTransformTag(valueToTransform, out var result))
@@ -125,7 +125,7 @@ void ProcessScope(LogRecordScope scope, ConsoleLogRecordExporter exporter)
exporter.WriteLine("LogRecord.ScopeValues (Key:Value):");
}
- foreach (KeyValuePair scopeItem in scope)
+ foreach (KeyValuePair scopeItem in scope)
{
if (this.TagWriter.TryTransformTag(scopeItem, out var result))
{
@@ -140,7 +140,7 @@ void ProcessScope(LogRecordScope scope, ConsoleLogRecordExporter exporter)
this.WriteLine("\nResource associated with LogRecord:");
foreach (var resourceAttribute in resource.Attributes)
{
- if (this.TagWriter.TryTransformTag(resourceAttribute, out var result))
+ if (this.TagWriter.TryTransformTag(resourceAttribute.Key, resourceAttribute.Value, out var result))
{
this.WriteLine($"{result.Key}: {result.Value}");
}
diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs b/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs
index 4bd9772b21..97ba3bbe25 100644
--- a/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs
+++ b/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs
@@ -10,8 +10,6 @@ namespace OpenTelemetry.Exporter;
public class ConsoleMetricExporter : ConsoleExporter
{
- private Resource resource;
-
public ConsoleMetricExporter(ConsoleExporterOptions options)
: base(options)
{
@@ -19,30 +17,13 @@ public ConsoleMetricExporter(ConsoleExporterOptions options)
public override ExportResult Export(in Batch batch)
{
- if (this.resource == null)
- {
- this.resource = this.ParentProvider.GetResource();
- if (this.resource != Resource.Empty)
- {
- this.WriteLine("Resource associated with Metric:");
- foreach (var resourceAttribute in this.resource.Attributes)
- {
- if (this.TagWriter.TryTransformTag(resourceAttribute, out var result))
- {
- this.WriteLine($" {result.Key}: {result.Value}");
- }
- }
- }
- }
-
foreach (var metric in batch)
{
var msg = new StringBuilder($"\n");
msg.Append($"Metric Name: {metric.Name}");
if (metric.Description != string.Empty)
{
- msg.Append(", ");
- msg.Append(metric.Description);
+ msg.Append($", Description: {metric.Description}");
}
if (metric.Unit != string.Empty)
@@ -50,30 +31,8 @@ public override ExportResult Export(in Batch batch)
msg.Append($", Unit: {metric.Unit}");
}
- if (!string.IsNullOrEmpty(metric.MeterName))
- {
- msg.Append($", Meter: {metric.MeterName}");
-
- if (!string.IsNullOrEmpty(metric.MeterVersion))
- {
- msg.Append($"/{metric.MeterVersion}");
- }
- }
-
this.WriteLine(msg.ToString());
- if (metric.MeterTags != null)
- {
- foreach (var meterTag in metric.MeterTags)
- {
- this.WriteLine("\tMeter Tags:");
- if (this.TagWriter.TryTransformTag(meterTag, out var result))
- {
- this.WriteLine($"\t\t{result.Key}: {result.Value}");
- }
- }
- }
-
foreach (ref readonly var metricPoint in metric.GetMetricPoints())
{
string valueDisplay = string.Empty;
@@ -220,7 +179,7 @@ public override ExportResult Export(in Batch batch)
{
if (!appendedTagString)
{
- exemplarString.Append(" Filtered Tags : ");
+ exemplarString.Append(" Filtered Tags: ");
appendedTagString = true;
}
@@ -257,6 +216,38 @@ public override ExportResult Export(in Batch batch)
}
this.WriteLine(msg.ToString());
+
+ this.WriteLine("Instrumentation scope (Meter):");
+ this.WriteLine($"\tName: {metric.MeterName}");
+ if (!string.IsNullOrEmpty(metric.MeterVersion))
+ {
+ this.WriteLine($"\tVersion: {metric.MeterVersion}");
+ }
+
+ if (metric.MeterTags?.Any() == true)
+ {
+ this.WriteLine("\tTags:");
+ foreach (var meterTag in metric.MeterTags)
+ {
+ if (this.TagWriter.TryTransformTag(meterTag, out var result))
+ {
+ this.WriteLine($"\t\t{result.Key}: {result.Value}");
+ }
+ }
+ }
+
+ var resource = this.ParentProvider.GetResource();
+ if (resource != Resource.Empty)
+ {
+ this.WriteLine("Resource associated with Metric:");
+ foreach (var resourceAttribute in resource.Attributes)
+ {
+ if (this.TagWriter.TryTransformTag(resourceAttribute.Key, resourceAttribute.Value, out var result))
+ {
+ this.WriteLine($"\t{result.Key}: {result.Value}");
+ }
+ }
+ }
}
}
diff --git a/src/OpenTelemetry.Exporter.Console/Implementation/ConsoleTagWriter.cs b/src/OpenTelemetry.Exporter.Console/Implementation/ConsoleTagWriter.cs
index 2f36df0091..fcaf9cdb43 100644
--- a/src/OpenTelemetry.Exporter.Console/Implementation/ConsoleTagWriter.cs
+++ b/src/OpenTelemetry.Exporter.Console/Implementation/ConsoleTagWriter.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using System.Text;
using OpenTelemetry.Internal;
@@ -21,9 +19,14 @@ public ConsoleTagWriter(Action onUnsupportedTagDropped)
}
public bool TryTransformTag(KeyValuePair tag, out KeyValuePair result)
+ {
+ return this.TryTransformTag(tag.Key, tag.Value, out result);
+ }
+
+ public bool TryTransformTag(string key, object? value, out KeyValuePair result)
{
ConsoleTag consoleTag = default;
- if (this.TryWriteTag(ref consoleTag, tag))
+ if (this.TryWriteTag(ref consoleTag, key, value))
{
result = new KeyValuePair(consoleTag.Key!, consoleTag.Value!);
return true;
diff --git a/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj b/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj
index 1f1aa356b5..75bcbe0c3c 100644
--- a/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj
+++ b/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj
@@ -5,20 +5,13 @@
Console exporter for OpenTelemetry .NET
$(PackageTags);Console;distributed-tracing
core-
-
-
- disable
+ true
$(NoWarn),1591
-
-
-
-
-
diff --git a/src/OpenTelemetry.Exporter.InMemory/.publicApi/Experimental/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.InMemory/.publicApi/Experimental/PublicAPI.Unshipped.txt
index f7378ee36c..e69de29bb2 100644
--- a/src/OpenTelemetry.Exporter.InMemory/.publicApi/Experimental/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry.Exporter.InMemory/.publicApi/Experimental/PublicAPI.Unshipped.txt
@@ -1 +0,0 @@
-static OpenTelemetry.Logs.InMemoryExporterLoggingExtensions.AddInMemoryExporter(this OpenTelemetry.Logs.LoggerProviderBuilder loggerProviderBuilder, System.Collections.Generic.ICollection exportedItems) -> OpenTelemetry.Logs.LoggerProviderBuilder
diff --git a/src/OpenTelemetry.Exporter.InMemory/.publicApi/Stable/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.InMemory/.publicApi/Stable/PublicAPI.Shipped.txt
index 499065e2d0..3a85e139a8 100644
--- a/src/OpenTelemetry.Exporter.InMemory/.publicApi/Stable/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Exporter.InMemory/.publicApi/Stable/PublicAPI.Shipped.txt
@@ -1,24 +1,26 @@
+#nullable enable
OpenTelemetry.Exporter.InMemoryExporter
-OpenTelemetry.Exporter.InMemoryExporter.InMemoryExporter(System.Collections.Generic.ICollection exportedItems) -> void
+OpenTelemetry.Exporter.InMemoryExporter.InMemoryExporter(System.Collections.Generic.ICollection! exportedItems) -> void
OpenTelemetry.Logs.InMemoryExporterLoggingExtensions
OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions
OpenTelemetry.Metrics.MetricSnapshot
-OpenTelemetry.Metrics.MetricSnapshot.Description.get -> string
-OpenTelemetry.Metrics.MetricSnapshot.MeterName.get -> string
-OpenTelemetry.Metrics.MetricSnapshot.MeterVersion.get -> string
-OpenTelemetry.Metrics.MetricSnapshot.MetricPoints.get -> System.Collections.Generic.IReadOnlyList
-OpenTelemetry.Metrics.MetricSnapshot.MetricSnapshot(OpenTelemetry.Metrics.Metric metric) -> void
+OpenTelemetry.Metrics.MetricSnapshot.Description.get -> string!
+OpenTelemetry.Metrics.MetricSnapshot.MeterName.get -> string!
+OpenTelemetry.Metrics.MetricSnapshot.MeterVersion.get -> string!
+OpenTelemetry.Metrics.MetricSnapshot.MetricPoints.get -> System.Collections.Generic.IReadOnlyList!
+OpenTelemetry.Metrics.MetricSnapshot.MetricSnapshot(OpenTelemetry.Metrics.Metric! metric) -> void
OpenTelemetry.Metrics.MetricSnapshot.MetricType.get -> OpenTelemetry.Metrics.MetricType
-OpenTelemetry.Metrics.MetricSnapshot.Name.get -> string
-OpenTelemetry.Metrics.MetricSnapshot.Unit.get -> string
+OpenTelemetry.Metrics.MetricSnapshot.Name.get -> string!
+OpenTelemetry.Metrics.MetricSnapshot.Unit.get -> string!
OpenTelemetry.Trace.InMemoryExporterHelperExtensions
override OpenTelemetry.Exporter.InMemoryExporter.Dispose(bool disposing) -> void
-override OpenTelemetry.Exporter.InMemoryExporter.Export(in OpenTelemetry.Batch batch) -> OpenTelemetry.ExportResult
-static OpenTelemetry.Logs.InMemoryExporterLoggingExtensions.AddInMemoryExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions loggerOptions, System.Collections.Generic.ICollection exportedItems) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions
-static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, string name, System.Collections.Generic.ICollection exportedItems, System.Action configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, string name, System.Collections.Generic.ICollection exportedItems, System.Action configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Collections.Generic.ICollection exportedItems) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Collections.Generic.ICollection exportedItems, System.Action configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Collections.Generic.ICollection exportedItems) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Collections.Generic.ICollection exportedItems, System.Action configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Trace.InMemoryExporterHelperExtensions.AddInMemoryExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Collections.Generic.ICollection exportedItems) -> OpenTelemetry.Trace.TracerProviderBuilder
+override OpenTelemetry.Exporter.InMemoryExporter.Export(in OpenTelemetry.Batch batch) -> OpenTelemetry.ExportResult
+static OpenTelemetry.Logs.InMemoryExporterLoggingExtensions.AddInMemoryExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, System.Collections.Generic.ICollection! exportedItems) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.InMemoryExporterLoggingExtensions.AddInMemoryExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions! loggerOptions, System.Collections.Generic.ICollection! exportedItems) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions!
+static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, string? name, System.Collections.Generic.ICollection! exportedItems, System.Action? configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, string? name, System.Collections.Generic.ICollection! exportedItems, System.Action? configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, System.Collections.Generic.ICollection! exportedItems) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, System.Collections.Generic.ICollection! exportedItems, System.Action! configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, System.Collections.Generic.ICollection! exportedItems) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, System.Collections.Generic.ICollection! exportedItems, System.Action! configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Trace.InMemoryExporterHelperExtensions.AddInMemoryExporter(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Collections.Generic.ICollection! exportedItems) -> OpenTelemetry.Trace.TracerProviderBuilder!
diff --git a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md
index d4aa853c67..37dcd673c8 100644
--- a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md
+++ b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md
@@ -1,7 +1,28 @@
# Changelog
+This file contains individual changes for the OpenTelemetry.Exporter.InMemory
+package. For highlights and announcements covering all components see: [Release
+Notes](../../RELEASENOTES.md).
+
## Unreleased
+## 1.10.0-beta.1
+
+Released 2024-Sep-30
+
+## 1.9.0
+
+Released 2024-Jun-14
+
+## 1.9.0-rc.1
+
+Released 2024-Jun-07
+
+* The experimental APIs previously covered by `OTEL1000`
+ (`LoggerProviderBuilder.AddInMemoryExporter` extension) are now part of the
+ public API and supported in stable builds.
+ ([#5648](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5648))
+
## 1.9.0-alpha.1
Released 2024-May-20
diff --git a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporter.cs b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporter.cs
index dedcf65b37..8533108ce8 100644
--- a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporter.cs
+++ b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporter.cs
@@ -6,10 +6,10 @@ namespace OpenTelemetry.Exporter;
public class InMemoryExporter : BaseExporter
where T : class
{
- private readonly ICollection exportedItems;
+ private readonly ICollection? exportedItems;
private readonly ExportFunc onExport;
private bool disposed;
- private string disposedStackTrace;
+ private string? disposedStackTrace;
public InMemoryExporter(ICollection exportedItems)
{
diff --git a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterLoggingExtensions.cs b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterLoggingExtensions.cs
index 982595f882..19b2079921 100644
--- a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterLoggingExtensions.cs
+++ b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterLoggingExtensions.cs
@@ -1,9 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#if EXPOSE_EXPERIMENTAL_FEATURES && NET8_0_OR_GREATER
-using System.Diagnostics.CodeAnalysis;
-#endif
using OpenTelemetry.Exporter;
using OpenTelemetry.Internal;
@@ -17,7 +14,7 @@ public static class InMemoryExporterLoggingExtensions
/// options to use.
/// Collection which will be populated with the exported .
/// The supplied instance of to chain the calls.
- /// todo: [Obsolete("Call LoggerProviderBuilder.AddInMemoryExporter instead this method will be removed in a future version.")]
+ // TODO: [Obsolete("Call LoggerProviderBuilder.AddInMemoryExporter instead this method will be removed in a future version.")]
public static OpenTelemetryLoggerOptions AddInMemoryExporter(
this OpenTelemetryLoggerOptions loggerOptions,
ICollection exportedItems)
@@ -31,28 +28,13 @@ public static OpenTelemetryLoggerOptions AddInMemoryExporter(
new SimpleLogRecordExportProcessor(logExporter));
}
-#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Adds InMemory exporter to the LoggerProviderBuilder.
///
- /// WARNING: This is an experimental API which might change or be removed in the future. Use at your own risk.
/// .
/// Collection which will be populated with the exported .
/// The supplied instance of to chain the calls.
-#if NET8_0_OR_GREATER
- [Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
- public
-#else
- ///
- /// Adds InMemory exporter to the LoggerProviderBuilder.
- ///
- /// .
- /// Collection which will be populated with the exported .
- /// The supplied instance of to chain the calls.
- internal
-#endif
- static LoggerProviderBuilder AddInMemoryExporter(
+ public static LoggerProviderBuilder AddInMemoryExporter(
this LoggerProviderBuilder loggerProviderBuilder,
ICollection exportedItems)
{
diff --git a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterMetricsExtensions.cs b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterMetricsExtensions.cs
index e645b67b45..da5ecda24d 100644
--- a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterMetricsExtensions.cs
+++ b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterMetricsExtensions.cs
@@ -51,15 +51,15 @@ public static MeterProviderBuilder AddInMemoryExporter(
/// Be aware that may continue to be updated after export.
///
/// builder to use.
- /// Name which is used when retrieving options.
+ /// Optional name which is used when retrieving options.
/// Collection which will be populated with the exported .
- /// Callback action for configuring .
+ /// Optional callback action for configuring .
/// The instance of to chain the calls.
public static MeterProviderBuilder AddInMemoryExporter(
this MeterProviderBuilder builder,
- string name,
+ string? name,
ICollection exportedItems,
- Action configureMetricReader)
+ Action? configureMetricReader)
{
Guard.ThrowIfNull(builder);
Guard.ThrowIfNull(exportedItems);
@@ -119,15 +119,15 @@ public static MeterProviderBuilder AddInMemoryExporter(
/// Use this if you need a copy of that will not be updated after export.
///
/// builder to use.
- /// Name which is used when retrieving options.
+ /// Optional name which is used when retrieving options.
/// Collection which will be populated with the exported represented as .
- /// Callback action for configuring .
+ /// Optional callback action for configuring .
/// The instance of to chain the calls.
public static MeterProviderBuilder AddInMemoryExporter(
this MeterProviderBuilder builder,
- string name,
+ string? name,
ICollection exportedItems,
- Action configureMetricReader)
+ Action? configureMetricReader)
{
Guard.ThrowIfNull(builder);
Guard.ThrowIfNull(exportedItems);
diff --git a/src/OpenTelemetry.Exporter.InMemory/OpenTelemetry.Exporter.InMemory.csproj b/src/OpenTelemetry.Exporter.InMemory/OpenTelemetry.Exporter.InMemory.csproj
index f27ac13801..8ca97988f6 100644
--- a/src/OpenTelemetry.Exporter.InMemory/OpenTelemetry.Exporter.InMemory.csproj
+++ b/src/OpenTelemetry.Exporter.InMemory/OpenTelemetry.Exporter.InMemory.csproj
@@ -5,9 +5,6 @@
In-memory exporter for OpenTelemetry .NET
$(PackageTags)
core-
-
-
- disable
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/.publicApi/Experimental/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/.publicApi/Experimental/PublicAPI.Unshipped.txt
index e6bd747c9d..e69de29bb2 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/.publicApi/Experimental/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/.publicApi/Experimental/PublicAPI.Unshipped.txt
@@ -1,5 +0,0 @@
-static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder) -> OpenTelemetry.Logs.LoggerProviderBuilder!
-static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder, string? name, System.Action? configureExporterAndProcessor) -> OpenTelemetry.Logs.LoggerProviderBuilder!
-static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder, string? name, System.Action? configureExporter) -> OpenTelemetry.Logs.LoggerProviderBuilder!
-static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder, System.Action! configureExporterAndProcessor) -> OpenTelemetry.Logs.LoggerProviderBuilder!
-static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder, System.Action! configureExporter) -> OpenTelemetry.Logs.LoggerProviderBuilder!
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/.publicApi/Stable/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/.publicApi/Stable/PublicAPI.Shipped.txt
index 2fd5a42942..f46941162a 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/.publicApi/Stable/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/.publicApi/Stable/PublicAPI.Shipped.txt
@@ -1,8 +1,4 @@
#nullable enable
-~OpenTelemetry.Exporter.OtlpMetricExporter.OtlpMetricExporter(OpenTelemetry.Exporter.OtlpExporterOptions options) -> void
-~OpenTelemetry.Exporter.OtlpTraceExporter.OtlpTraceExporter(OpenTelemetry.Exporter.OtlpExporterOptions options) -> void
-~override OpenTelemetry.Exporter.OtlpMetricExporter.Export(in OpenTelemetry.Batch metrics) -> OpenTelemetry.ExportResult
-~override OpenTelemetry.Exporter.OtlpTraceExporter.Export(in OpenTelemetry.Batch activityBatch) -> OpenTelemetry.ExportResult
OpenTelemetry.Exporter.OtlpExporterOptions
OpenTelemetry.Exporter.OtlpExporterOptions.BatchExportProcessorOptions.get -> OpenTelemetry.BatchExportProcessorOptions!
OpenTelemetry.Exporter.OtlpExporterOptions.BatchExportProcessorOptions.set -> void
@@ -25,14 +21,23 @@ OpenTelemetry.Exporter.OtlpExportProtocol.HttpProtobuf = 1 -> OpenTelemetry.Expo
OpenTelemetry.Exporter.OtlpLogExporter
OpenTelemetry.Exporter.OtlpLogExporter.OtlpLogExporter(OpenTelemetry.Exporter.OtlpExporterOptions! options) -> void
OpenTelemetry.Exporter.OtlpMetricExporter
+OpenTelemetry.Exporter.OtlpMetricExporter.OtlpMetricExporter(OpenTelemetry.Exporter.OtlpExporterOptions! options) -> void
OpenTelemetry.Exporter.OtlpTraceExporter
+OpenTelemetry.Exporter.OtlpTraceExporter.OtlpTraceExporter(OpenTelemetry.Exporter.OtlpExporterOptions! options) -> void
OpenTelemetry.Logs.OtlpLogExporterHelperExtensions
OpenTelemetry.Metrics.OtlpMetricExporterExtensions
OpenTelemetry.OpenTelemetryBuilderOtlpExporterExtensions
OpenTelemetry.Trace.OtlpTraceExporterHelperExtensions
override OpenTelemetry.Exporter.OtlpLogExporter.Export(in OpenTelemetry.Batch logRecordBatch) -> OpenTelemetry.ExportResult
+override OpenTelemetry.Exporter.OtlpMetricExporter.Export(in OpenTelemetry.Batch metrics) -> OpenTelemetry.ExportResult
override OpenTelemetry.Exporter.OtlpMetricExporter.OnShutdown(int timeoutMilliseconds) -> bool
+override OpenTelemetry.Exporter.OtlpTraceExporter.Export(in OpenTelemetry.Batch activityBatch) -> OpenTelemetry.ExportResult
override OpenTelemetry.Exporter.OtlpTraceExporter.OnShutdown(int timeoutMilliseconds) -> bool
+static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder, string? name, System.Action? configureExporterAndProcessor) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder, string? name, System.Action? configureExporter) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder, System.Action! configureExporterAndProcessor) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder, System.Action! configureExporter) -> OpenTelemetry.Logs.LoggerProviderBuilder!
static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions! loggerOptions) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions!
static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions! loggerOptions, string? name, System.Action? configureExporterAndProcessor) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions!
static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions! loggerOptions, string? name, System.Action? configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions!
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OpenTelemetryBuilderOtlpExporterExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OpenTelemetryBuilderOtlpExporterExtensions.cs
index 80164f0fa5..6b1d2afeba 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OpenTelemetryBuilderOtlpExporterExtensions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OpenTelemetryBuilderOtlpExporterExtensions.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using Microsoft.Extensions.Configuration;
using OpenTelemetry.Exporter;
using OpenTelemetry.Internal;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilder.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilder.cs
index 4c3d37cf28..d5a04aa60f 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilder.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilder.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -40,7 +38,7 @@ internal OtlpExporterBuilder(
name ??= Options.DefaultName;
- RegisterOtlpExporterServices(services!, name!);
+ RegisterOtlpExporterServices(services!, name);
this.name = name;
this.Services = services!;
@@ -176,9 +174,9 @@ private static void RegisterOtlpExporterServices(IServiceCollection services, st
services!.AddOtlpExporterTracingServices();
// Note: UseOtlpExporterRegistration is added to the service collection
- // to detect repeated calls to "UseOtlpExporter" and to throw if
- // "AddOtlpExporter" extensions are called
- services!.AddSingleton();
+ // for each invocation to detect repeated calls to "UseOtlpExporter" and
+ // to throw if "AddOtlpExporter" extensions are called
+ services!.AddSingleton(UseOtlpExporterRegistration.Instance);
services!.RegisterOptionsFactory((sp, configuration, name) => new OtlpExporterBuilderOptions(
configuration,
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilderOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilderOptions.cs
index e3ba3541ff..7d9786bb04 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilderOptions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilderOptions.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using Microsoft.Extensions.Configuration;
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/UseOtlpExporterRegistration.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/UseOtlpExporterRegistration.cs
index ad0ad9fbc9..e2de10663f 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/UseOtlpExporterRegistration.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/UseOtlpExporterRegistration.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Exporter;
// Note: This class is added to the IServiceCollection when UseOtlpExporter is
@@ -10,4 +8,15 @@ namespace OpenTelemetry.Exporter;
// calls to signal-specific AddOtlpExporter can throw.
internal sealed class UseOtlpExporterRegistration
{
+ public static readonly UseOtlpExporterRegistration Instance = new();
+
+ private UseOtlpExporterRegistration()
+ {
+ // Note: Some dependency injection containers (ex: Unity, Grace) will
+ // automatically create services if they have a public constructor even
+ // if the service was never registered into the IServiceCollection. The
+ // behavior of UseOtlpExporterRegistration requires that it should only
+ // exist if registered. This private constructor is intended to prevent
+ // automatic instantiation.
+ }
}
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md
index 0831012508..93577e9df6 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md
@@ -1,7 +1,52 @@
# Changelog
+This file contains individual changes for the
+OpenTelemetry.Exporter.OpenTelemetryProtocol package. For highlights and
+announcements covering all components see: [Release
+Notes](../../RELEASENOTES.md).
+
## Unreleased
+* Added support for exporting instrumentation scope attributes from
+ `ActivitySource.Tags`.
+ ([#5897](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5897))
+
+## 1.10.0-beta.1
+
+Released 2024-Sep-30
+
+* **Breaking change**: Non-primitive attribute (logs) and tag (traces) values
+ converted using `Convert.ToString` will now format using
+ `CultureInfo.InvariantCulture`.
+ ([#5700](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5700))
+
+* Fixed an issue causing `NotSupportedException`s to be thrown on startup when
+ `AddOtlpExporter` registration extensions are called while using custom
+ dependency injection containers which automatically create services (Unity,
+ Grace, etc.).
+ ([#5808](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5808))
+
+ * Fixed `PlatformNotSupportedException`s being thrown during export when running
+ on mobile platforms which caused telemetry to be dropped silently.
+ ([#5821](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/5821))
+
+* Updated `Microsoft.Extensions.Hosting.Abstractions` package
+ version to `9.0.0-rc.1.24431.7`.
+ ([#5853](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5853))
+
+## 1.9.0
+
+Released 2024-Jun-14
+
+## 1.9.0-rc.1
+
+Released 2024-Jun-07
+
+* The experimental APIs previously covered by `OTEL1000`
+ (`LoggerProviderBuilder.AddOtlpExporter` extension) are now part of the public
+ API and supported in stable builds.
+ ([#5648](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5648))
+
## 1.9.0-alpha.1
Released 2024-May-20
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/IOtlpExporterOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/IOtlpExporterOptions.cs
index 4c394759a1..d6402bc85a 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/IOtlpExporterOptions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/IOtlpExporterOptions.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
#if NETFRAMEWORK
using System.Net.Http;
#endif
@@ -16,7 +14,7 @@ namespace OpenTelemetry.Exporter;
internal interface IOtlpExporterOptions
{
///
- /// Gets or sets the the OTLP transport protocol.
+ /// Gets or sets the OTLP transport protocol.
///
OtlpExportProtocol Protocol { get; set; }
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs
index d3dacb3a1f..313a8e9f59 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs
@@ -32,9 +32,11 @@ internal static void AddBatch(
};
request.ResourceSpans.Add(resourceSpans);
+ var maxTags = sdkLimitOptions.AttributeCountLimit ?? int.MaxValue;
+
foreach (var activity in activityBatch)
{
- Span span = activity.ToOtlpSpan(sdkLimitOptions);
+ Span? span = activity.ToOtlpSpan(sdkLimitOptions);
if (span == null)
{
OpenTelemetryProtocolExporterEventSource.Log.CouldNotTranslateActivity(
@@ -44,15 +46,15 @@ internal static void AddBatch(
}
var activitySourceName = activity.Source.Name;
- if (!spansByLibrary.TryGetValue(activitySourceName, out var spans))
+ if (!spansByLibrary.TryGetValue(activitySourceName, out var scopeSpans))
{
- spans = GetSpanListFromPool(activitySourceName, activity.Source.Version);
+ scopeSpans = GetSpanListFromPool(activity.Source, maxTags, sdkLimitOptions.AttributeValueLengthLimit);
- spansByLibrary.Add(activitySourceName, spans);
- resourceSpans.ScopeSpans.Add(spans);
+ spansByLibrary.Add(activitySourceName, scopeSpans);
+ resourceSpans.ScopeSpans.Add(scopeSpans);
}
- spans.Spans.Add(span);
+ scopeSpans.Spans.Add(span);
}
}
@@ -65,38 +67,73 @@ internal static void Return(this ExportTraceServiceRequest request)
return;
}
- foreach (var scope in resourceSpans.ScopeSpans)
+ foreach (var scopeSpan in resourceSpans.ScopeSpans)
{
- scope.Spans.Clear();
- SpanListPool.Add(scope);
+ scopeSpan.Spans.Clear();
+ scopeSpan.Scope.Attributes.Clear();
+ SpanListPool.Add(scopeSpan);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static ScopeSpans GetSpanListFromPool(string name, string version)
+ internal static ScopeSpans GetSpanListFromPool(ActivitySource activitySource, int maxTags, int? attributeValueLengthLimit)
{
- if (!SpanListPool.TryTake(out var spans))
+ if (!SpanListPool.TryTake(out var scopeSpans))
{
- spans = new ScopeSpans
+ scopeSpans = new ScopeSpans
{
Scope = new InstrumentationScope
{
- Name = name, // Name is enforced to not be null, but it can be empty.
- Version = version ?? string.Empty, // NRE throw by proto
+ Name = activitySource.Name, // Name is enforced to not be null, but it can be empty.
+ Version = activitySource.Version ?? string.Empty, // NRE throw by proto
},
};
}
else
{
- spans.Scope.Name = name;
- spans.Scope.Version = version ?? string.Empty;
+ scopeSpans.Scope.Name = activitySource.Name; // Name is enforced to not be null, but it can be empty.
+ scopeSpans.Scope.Version = activitySource.Version ?? string.Empty; // NRE throw by proto
+ }
+
+ if (activitySource.Tags != null)
+ {
+ var scopeAttributes = scopeSpans.Scope.Attributes;
+
+ if (activitySource.Tags is IReadOnlyList> activitySourceTagsList)
+ {
+ for (int i = 0; i < activitySourceTagsList.Count; i++)
+ {
+ if (scopeAttributes.Count < maxTags)
+ {
+ OtlpTagWriter.Instance.TryWriteTag(ref scopeAttributes, activitySourceTagsList[i], attributeValueLengthLimit);
+ }
+ else
+ {
+ scopeSpans.Scope.DroppedAttributesCount++;
+ }
+ }
+ }
+ else
+ {
+ foreach (var tag in activitySource.Tags)
+ {
+ if (scopeAttributes.Count < maxTags)
+ {
+ OtlpTagWriter.Instance.TryWriteTag(ref scopeAttributes, tag, attributeValueLengthLimit);
+ }
+ else
+ {
+ scopeSpans.Scope.DroppedAttributesCount++;
+ }
+ }
+ }
}
- return spans;
+ return scopeSpans;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static Span ToOtlpSpan(this Activity activity, SdkLimitOptions sdkLimitOptions)
+ internal static Span? ToOtlpSpan(this Activity activity, SdkLimitOptions sdkLimitOptions)
{
if (activity.IdFormat != ActivityIdFormat.W3C)
{
@@ -145,7 +182,7 @@ internal static Span ToOtlpSpan(this Activity activity, SdkLimitOptions sdkLimit
if (activity.Kind == ActivityKind.Client || activity.Kind == ActivityKind.Producer)
{
- PeerServiceResolver.Resolve(ref otlpTags, out string peerServiceName, out bool addAsTag);
+ PeerServiceResolver.Resolve(ref otlpTags, out string? peerServiceName, out bool addAsTag);
if (peerServiceName != null && addAsTag)
{
@@ -180,7 +217,7 @@ internal static Span ToOtlpSpan(this Activity activity, SdkLimitOptions sdkLimit
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static OtlpTrace.Status ToOtlpStatus(this Activity activity, ref TagEnumerationState otlpTags)
+ private static OtlpTrace.Status? ToOtlpStatus(this Activity activity, ref TagEnumerationState otlpTags)
{
var statusCodeForTagValue = StatusHelper.GetStatusCodeForTagValue(otlpTags.StatusCode);
if (activity.Status == ActivityStatusCode.Unset && statusCodeForTagValue == null)
@@ -189,7 +226,7 @@ private static OtlpTrace.Status ToOtlpStatus(this Activity activity, ref TagEnum
}
OtlpTrace.Status.Types.StatusCode otlpActivityStatusCode = OtlpTrace.Status.Types.StatusCode.Unset;
- string otlpStatusDescription = null;
+ string? otlpStatusDescription = null;
if (activity.Status != ActivityStatusCode.Unset)
{
// The numerical values of the two enumerations match, a simple cast is enough.
@@ -204,7 +241,7 @@ private static OtlpTrace.Status ToOtlpStatus(this Activity activity, ref TagEnum
if (statusCodeForTagValue != StatusCode.Unset)
{
// The numerical values of the two enumerations match, a simple cast is enough.
- otlpActivityStatusCode = (OtlpTrace.Status.Types.StatusCode)(int)statusCodeForTagValue;
+ otlpActivityStatusCode = (OtlpTrace.Status.Types.StatusCode)(int)statusCodeForTagValue!;
if (statusCodeForTagValue == StatusCode.Error && !string.IsNullOrEmpty(otlpTags.StatusDescription))
{
otlpStatusDescription = otlpTags.StatusDescription;
@@ -304,17 +341,17 @@ private struct TagEnumerationState : PeerServiceResolver.IPeerServiceState
public Span Span;
- public string StatusCode;
+ public string? StatusCode;
- public string StatusDescription;
+ public string? StatusDescription;
- public string PeerService { get; set; }
+ public string? PeerService { get; set; }
public int? PeerServicePriority { get; set; }
- public string HostName { get; set; }
+ public string? HostName { get; set; }
- public string IpAddress { get; set; }
+ public string? IpAddress { get; set; }
public long Port { get; set; }
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExperimentalOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExperimentalOptions.cs
index 65d0bf57ee..25b345ac96 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExperimentalOptions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExperimentalOptions.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using Microsoft.Extensions.Configuration;
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/BaseOtlpGrpcExportClient.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/BaseOtlpGrpcExportClient.cs
index 493d267bc7..b585f2fc08 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/BaseOtlpGrpcExportClient.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/BaseOtlpGrpcExportClient.cs
@@ -3,7 +3,7 @@
using Grpc.Core;
using OpenTelemetry.Internal;
-#if NETSTANDARD2_1 || NET6_0_OR_GREATER
+#if NETSTANDARD2_1 || NET
using Grpc.Net.Client;
#endif
@@ -25,10 +25,10 @@ protected BaseOtlpGrpcExportClient(OtlpExporterOptions options)
this.TimeoutMilliseconds = options.TimeoutMilliseconds;
}
-#if NETSTANDARD2_1 || NET6_0_OR_GREATER
- internal GrpcChannel Channel { get; set; }
+#if NETSTANDARD2_1 || NET
+ internal GrpcChannel? Channel { get; set; }
#else
- internal Channel Channel { get; set; }
+ internal Channel? Channel { get; set; }
#endif
internal Uri Endpoint { get; }
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/BaseOtlpHttpExportClient.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/BaseOtlpHttpExportClient.cs
index 4fedc6b617..7e975fa133 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/BaseOtlpHttpExportClient.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/BaseOtlpHttpExportClient.cs
@@ -13,6 +13,9 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClie
internal abstract class BaseOtlpHttpExportClient : IExportClient
{
private static readonly ExportClientHttpResponse SuccessExportResponse = new ExportClientHttpResponse(success: true, deadlineUtc: default, response: null, exception: null);
+#if NET
+ private readonly bool synchronousSendSupportedByCurrentPlatform;
+#endif
protected BaseOtlpHttpExportClient(OtlpExporterOptions options, HttpClient httpClient, string signalPath)
{
@@ -27,6 +30,14 @@ protected BaseOtlpHttpExportClient(OtlpExporterOptions options, HttpClient httpC
this.Endpoint = new UriBuilder(exporterEndpoint).Uri;
this.Headers = options.GetHeaders>((d, k, v) => d.Add(k, v));
this.HttpClient = httpClient;
+
+#if NET
+ // See: https://github.com/dotnet/runtime/blob/280f2a0c60ce0378b8db49adc0eecc463d00fe5d/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs#L767
+ this.synchronousSendSupportedByCurrentPlatform = !OperatingSystem.IsAndroid()
+ && !OperatingSystem.IsIOS()
+ && !OperatingSystem.IsTvOS()
+ && !OperatingSystem.IsBrowser();
+#endif
}
internal HttpClient HttpClient { get; }
@@ -88,8 +99,10 @@ protected HttpRequestMessage CreateHttpRequest(TRequest exportRequest)
protected HttpResponseMessage SendHttpRequest(HttpRequestMessage request, CancellationToken cancellationToken)
{
-#if NET6_0_OR_GREATER
- return this.HttpClient.Send(request, cancellationToken);
+#if NET
+ return this.synchronousSendSupportedByCurrentPlatform
+ ? this.HttpClient.Send(request, cancellationToken)
+ : this.HttpClient.SendAsync(request, cancellationToken).GetAwaiter().GetResult();
#else
return this.HttpClient.SendAsync(request, cancellationToken).GetAwaiter().GetResult();
#endif
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/ExportClientGrpcResponse.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/ExportClientGrpcResponse.cs
index f7c95107a7..4a96a7ad7c 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/ExportClientGrpcResponse.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/ExportClientGrpcResponse.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient;
internal sealed class ExportClientGrpcResponse : ExportClientResponse
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/ExportClientHttpResponse.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/ExportClientHttpResponse.cs
index 9d274b0ffe..7e94996e7b 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/ExportClientHttpResponse.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/ExportClientHttpResponse.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Net;
#if NETFRAMEWORK
using System.Net.Http;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/ExportClientResponse.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/ExportClientResponse.cs
index 49f8c0eb20..3a14b53725 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/ExportClientResponse.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/ExportClientResponse.cs
@@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
+using System.Diagnostics.CodeAnalysis;
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient;
@@ -14,6 +14,7 @@ protected ExportClientResponse(bool success, DateTime deadlineUtc, Exception? ex
this.DeadlineUtc = deadlineUtc;
}
+ [MemberNotNullWhen(false, nameof(Exception))]
public bool Success { get; }
public Exception? Exception { get; }
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/IExportClient.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/IExportClient.cs
index 0c44da6ef3..26c7c5e33c 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/IExportClient.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/IExportClient.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient;
/// Export client interface.
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpGrpcLogExportClient.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpGrpcLogExportClient.cs
index b45837cd82..e90f05ff5d 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpGrpcLogExportClient.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpGrpcLogExportClient.cs
@@ -11,7 +11,7 @@ internal sealed class OtlpGrpcLogExportClient : BaseOtlpGrpcExportClient> meterTags)
+ internal static ScopeMetrics GetMetricListFromPool(string name, string version, IEnumerable>? meterTags)
{
if (!MetricListPool.TryTake(out var scopeMetrics))
{
@@ -432,7 +432,7 @@ private static void AddAttributes(ReadOnlyTagCollection tags, RepeatedField> meterTags, RepeatedField attributes)
+ private static void AddScopeAttributes(IEnumerable> meterTags, RepeatedField attributes)
{
foreach (var tag in meterTags)
{
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpExporterOptionsConfigurationType.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpExporterOptionsConfigurationType.cs
index d3cedd6915..0fb01edc25 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpExporterOptionsConfigurationType.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpExporterOptionsConfigurationType.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Exporter;
[Flags]
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpLogRecordTransformer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpLogRecordTransformer.cs
index e3d70c4018..e6942286e2 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpLogRecordTransformer.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpLogRecordTransformer.cs
@@ -102,9 +102,9 @@ internal OtlpLogs.ScopeLogs GetLogListFromPool(string name)
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal OtlpLogs.LogRecord ToOtlpLog(LogRecord logRecord)
+ internal OtlpLogs.LogRecord? ToOtlpLog(LogRecord logRecord)
{
- OtlpLogs.LogRecord otlpLogRecord = null;
+ OtlpLogs.LogRecord? otlpLogRecord = null;
try
{
@@ -238,7 +238,7 @@ void ProcessScope(LogRecordScope scope, OtlpLogs.LogRecord otlpLog)
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void AddAttribute(OtlpLogs.LogRecord logRecord, KeyValuePair attribute, int maxAttributeCount, int? maxValueLength)
+ private static void AddAttribute(OtlpLogs.LogRecord logRecord, KeyValuePair attribute, int maxAttributeCount, int? maxValueLength)
{
var logRecordAttributes = logRecord.Attributes;
@@ -253,9 +253,9 @@ private static void AddAttribute(OtlpLogs.LogRecord logRecord, KeyValuePair(key, value);
+ var attributeItem = new KeyValuePair(key, value);
AddAttribute(logRecord, attributeItem, maxAttributeCount, maxValueLength);
}
@@ -263,7 +263,7 @@ private static void AddStringAttribute(OtlpLogs.LogRecord logRecord, string key,
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void AddIntAttribute(OtlpLogs.LogRecord logRecord, string key, int value, int maxAttributeCount)
{
- var attributeItem = new KeyValuePair(key, value);
+ var attributeItem = new KeyValuePair(key, value);
AddAttribute(logRecord, attributeItem, maxAttributeCount, maxValueLength: null);
}
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpServiceCollectionExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpServiceCollectionExtensions.cs
index 282c84ed27..79c7ddb476 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpServiceCollectionExtensions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpServiceCollectionExtensions.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpTagWriter.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpTagWriter.cs
index 64315fd8e0..c713d4b646 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpTagWriter.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpTagWriter.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using Google.Protobuf.Collections;
using OpenTelemetry.Internal;
using OtlpCommon = OpenTelemetry.Proto.Common.V1;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ResourceExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ResourceExtensions.cs
index 656fa4eea6..f114f07297 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ResourceExtensions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ResourceExtensions.cs
@@ -17,7 +17,7 @@ public static OtlpResource.Resource ToOtlpResource(this Resource resource)
foreach (KeyValuePair attribute in resource.Attributes)
{
- OtlpTagWriter.Instance.TryWriteTag(ref processResourceAttributes, attribute);
+ OtlpTagWriter.Instance.TryWriteTag(ref processResourceAttributes, attribute.Key, attribute.Value);
}
if (!processResource.Attributes.Any(kvp => kvp.Key == ResourceSemanticConventions.AttributeServiceName))
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpLogFieldNumberConstants.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpLogFieldNumberConstants.cs
new file mode 100644
index 0000000000..3361a8551c
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpLogFieldNumberConstants.cs
@@ -0,0 +1,88 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Serializer;
+
+internal static class ProtobufOtlpLogFieldNumberConstants
+{
+ // Resource Logs
+#pragma warning disable SA1310 // Field names should not contain underscore
+ internal const int ResourceLogs_Resource = 1;
+ internal const int ResourceLogs_Scope_Logs = 2;
+ internal const int ResourceLogs_Schema_Url = 3;
+
+ // Resource
+ internal const int Resource_Attributes = 1;
+
+ // ScopeLogs
+ internal const int ScopeLogs_Scope = 1;
+ internal const int ScopeLogs_Log_Records = 2;
+ internal const int ScopeLogs_Schema_Url = 3;
+
+ // LogRecord
+ internal const int LogRecord_Time_Unix_Nano = 1;
+ internal const int LogRecord_Observed_Time_Unix_Nano = 11;
+ internal const int LogRecord_Severity_Number = 2;
+ internal const int LogRecord_Severity_Text = 3;
+ internal const int LogRecord_Body = 5;
+ internal const int LogRecord_Attributes = 6;
+ internal const int LogRecord_Dropped_Attributes_Count = 7;
+ internal const int LogRecord_Flags = 8;
+ internal const int LogRecord_Trace_Id = 9;
+ internal const int LogRecord_Span_Id = 10;
+
+ // SeverityNumber
+ internal const int Severity_Number_Unspecified = 0;
+ internal const int Severity_Number_Trace = 1;
+ internal const int Severity_Number_Trace2 = 2;
+ internal const int Severity_Number_Trace3 = 3;
+ internal const int Severity_Number_Trace4 = 4;
+ internal const int Severity_Number_Debug = 5;
+ internal const int Severity_Number_Debug2 = 6;
+ internal const int Severity_Number_Debug3 = 7;
+ internal const int Severity_Number_Debug4 = 8;
+ internal const int Severity_Number_Info = 9;
+ internal const int Severity_Number_Info2 = 10;
+ internal const int Severity_Number_Info3 = 11;
+ internal const int Severity_Number_Info4 = 12;
+ internal const int Severity_Number_Warn = 13;
+ internal const int Severity_Number_Warn2 = 14;
+ internal const int Severity_Number_Warn3 = 15;
+ internal const int Severity_Number_Warn4 = 16;
+ internal const int Severity_Number_Error = 17;
+ internal const int Severity_Number_Error2 = 18;
+ internal const int Severity_Number_Error3 = 19;
+ internal const int Severity_Number_Error4 = 20;
+ internal const int Severity_Number_Fatal = 21;
+ internal const int Severity_Number_Fatal2 = 22;
+ internal const int Severity_Number_Fatal3 = 23;
+ internal const int Severity_Number_Fatal4 = 24;
+
+ // LogRecordFlags
+
+ internal const int LogRecord_Flags_Do_Not_Use = 0;
+ internal const int LogRecord_Flags_Trace_Flags_Mask = 0x000000FF;
+
+ // InstrumentationScope
+ internal const int InstrumentationScope_Name = 1;
+ internal const int InstrumentationScope_Version = 2;
+ internal const int InstrumentationScope_Attributes = 3;
+ internal const int InstrumentationScope_Dropped_Attributes_Count = 4;
+
+ // KeyValue
+ internal const int KeyValue_Key = 1;
+ internal const int KeyValue_Value = 2;
+
+ // AnyValue
+ internal const int AnyValue_String_Value = 1;
+ internal const int AnyValue_Bool_Value = 2;
+ internal const int AnyValue_Int_Value = 3;
+ internal const int AnyValue_Double_Value = 4;
+ internal const int AnyValue_Array_Value = 5;
+ internal const int AnyValue_Kvlist_Value = 6;
+ internal const int AnyValue_Bytes_Value = 7;
+
+ internal const int ArrayValue_Value = 1;
+#pragma warning restore SA1310 // Field names should not contain underscore
+}
+
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpLogSerializer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpLogSerializer.cs
new file mode 100644
index 0000000000..4c2f9c95ac
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpLogSerializer.cs
@@ -0,0 +1,290 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using OpenTelemetry.Internal;
+using OpenTelemetry.Logs;
+using OpenTelemetry.Trace;
+
+namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Serializer;
+
+internal static class ProtobufOtlpLogSerializer
+{
+ private const int ReserveSizeForLength = 4;
+ private const int TraceIdSize = 16;
+ private const int SpanIdSize = 8;
+
+ private static readonly Stack> LogsListPool = [];
+ private static readonly Dictionary> ScopeLogsList = [];
+
+ [ThreadStatic]
+ private static SerializationState? threadSerializationState;
+
+ internal static int WriteLogsData(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, ExperimentalOptions experimentalOptions, Resources.Resource? resource, in Batch logRecordBatch)
+ {
+ foreach (var logRecord in logRecordBatch)
+ {
+ var scopeName = logRecord.Logger.Name;
+ if (!ScopeLogsList.TryGetValue(scopeName, out var logRecords))
+ {
+ logRecords = LogsListPool.Count > 0 ? LogsListPool.Pop() : [];
+ ScopeLogsList[scopeName] = logRecords;
+ }
+
+ logRecords.Add(logRecord);
+ }
+
+ writePosition = WriteResourceLogs(buffer, writePosition, sdkLimitOptions, experimentalOptions, resource, ScopeLogsList);
+ ReturnLogRecordListToPool();
+
+ return writePosition;
+ }
+
+ internal static void ReturnLogRecordListToPool()
+ {
+ if (ScopeLogsList.Count != 0)
+ {
+ foreach (var entry in ScopeLogsList)
+ {
+ entry.Value.Clear();
+ LogsListPool.Push(entry.Value);
+ }
+
+ ScopeLogsList.Clear();
+ }
+ }
+
+ internal static int WriteResourceLogs(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, ExperimentalOptions experimentalOptions, Resources.Resource? resource, Dictionary> scopeLogs)
+ {
+ writePosition = ProtobufOtlpResourceSerializer.WriteResource(buffer, writePosition, resource);
+ writePosition = WriteScopeLogs(buffer, writePosition, sdkLimitOptions, experimentalOptions, scopeLogs);
+ return writePosition;
+ }
+
+ internal static int WriteScopeLogs(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, ExperimentalOptions experimentalOptions, Dictionary> scopeLogs)
+ {
+ if (scopeLogs != null)
+ {
+ foreach (KeyValuePair> entry in scopeLogs)
+ {
+ writePosition = ProtobufSerializer.WriteTag(buffer, writePosition, ProtobufOtlpLogFieldNumberConstants.ResourceLogs_Scope_Logs, ProtobufWireType.LEN);
+ int resourceLogsScopeLogsLengthPosition = writePosition;
+ writePosition += ReserveSizeForLength;
+
+ writePosition = WriteScopeLog(buffer, writePosition, sdkLimitOptions, experimentalOptions, entry.Value[0].Logger.Name, entry.Value);
+ ProtobufSerializer.WriteReservedLength(buffer, resourceLogsScopeLogsLengthPosition, writePosition - (resourceLogsScopeLogsLengthPosition + ReserveSizeForLength));
+ }
+ }
+
+ return writePosition;
+ }
+
+ internal static int WriteScopeLog(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, ExperimentalOptions experimentalOptions, string loggerName, List logRecords)
+ {
+ var value = loggerName.AsSpan();
+ var numberOfUtf8CharsInString = ProtobufSerializer.GetNumberOfUtf8CharsInString(value);
+ var serializedLengthSize = ProtobufSerializer.ComputeVarInt64Size((ulong)numberOfUtf8CharsInString);
+
+ // numberOfUtf8CharsInString + tagSize + length field size.
+ writePosition = ProtobufSerializer.WriteTagAndLength(buffer, writePosition, numberOfUtf8CharsInString + 1 + serializedLengthSize, ProtobufOtlpLogFieldNumberConstants.ScopeLogs_Scope, ProtobufWireType.LEN);
+ writePosition = ProtobufSerializer.WriteStringWithTag(buffer, writePosition, ProtobufOtlpLogFieldNumberConstants.InstrumentationScope_Name, numberOfUtf8CharsInString, value);
+
+ for (int i = 0; i < logRecords.Count; i++)
+ {
+ writePosition = WriteLogRecord(buffer, writePosition, sdkLimitOptions, experimentalOptions, logRecords[i]);
+ }
+
+ return writePosition;
+ }
+
+ internal static int WriteLogRecord(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, ExperimentalOptions experimentalOptions, LogRecord logRecord)
+ {
+ var state = threadSerializationState ??= new();
+
+ state.AttributeValueLengthLimit = sdkLimitOptions.LogRecordAttributeValueLengthLimit;
+ state.AttributeCountLimit = sdkLimitOptions.LogRecordAttributeCountLimit ?? int.MaxValue;
+ state.TagWriterState = new ProtobufOtlpTagWriter.OtlpTagWriterState
+ {
+ Buffer = buffer,
+ WritePosition = writePosition,
+ TagCount = 0,
+ DroppedTagCount = 0,
+ };
+
+ ref var otlpTagWriterState = ref state.TagWriterState;
+
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.ScopeLogs_Log_Records, ProtobufWireType.LEN);
+ int logRecordLengthPosition = otlpTagWriterState.WritePosition;
+ otlpTagWriterState.WritePosition += ReserveSizeForLength;
+
+ var timestamp = (ulong)logRecord.Timestamp.ToUnixTimeNanoseconds();
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteFixed64WithTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.LogRecord_Time_Unix_Nano, timestamp);
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteFixed64WithTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.LogRecord_Observed_Time_Unix_Nano, timestamp);
+
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteEnumWithTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.LogRecord_Severity_Number, logRecord.Severity.HasValue ? (int)logRecord.Severity : 0);
+
+ if (!string.IsNullOrWhiteSpace(logRecord.SeverityText))
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteStringWithTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.LogRecord_Severity_Text, logRecord.SeverityText!);
+ }
+ else if (logRecord.Severity.HasValue)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteStringWithTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.LogRecord_Severity_Text, logRecord.Severity.Value.ToShortName());
+ }
+
+ if (experimentalOptions.EmitLogEventAttributes)
+ {
+ if (logRecord.EventId.Id != default)
+ {
+ AddLogAttribute(state, ExperimentalOptions.LogRecordEventIdAttribute, logRecord.EventId.Id);
+ }
+
+ if (!string.IsNullOrEmpty(logRecord.EventId.Name))
+ {
+ AddLogAttribute(state, ExperimentalOptions.LogRecordEventNameAttribute, logRecord.EventId.Name!);
+ }
+ }
+
+ if (logRecord.Exception != null)
+ {
+ AddLogAttribute(state, SemanticConventions.AttributeExceptionType, logRecord.Exception.GetType().Name);
+ AddLogAttribute(state, SemanticConventions.AttributeExceptionMessage, logRecord.Exception.Message);
+ AddLogAttribute(state, SemanticConventions.AttributeExceptionStacktrace, logRecord.Exception.ToInvariantString());
+ }
+
+ bool bodyPopulatedFromFormattedMessage = false;
+ bool isLogRecordBodySet = false;
+
+ if (logRecord.FormattedMessage != null)
+ {
+ otlpTagWriterState.WritePosition = WriteLogRecordBody(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, logRecord.FormattedMessage.AsSpan());
+ bodyPopulatedFromFormattedMessage = true;
+ isLogRecordBodySet = true;
+ }
+
+ if (logRecord.Attributes != null)
+ {
+ foreach (var attribute in logRecord.Attributes)
+ {
+ // Special casing {OriginalFormat}
+ // See https://github.com/open-telemetry/opentelemetry-dotnet/pull/3182
+ // for explanation.
+ if (attribute.Key.Equals("{OriginalFormat}") && !bodyPopulatedFromFormattedMessage)
+ {
+ otlpTagWriterState.WritePosition = WriteLogRecordBody(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, (attribute.Value as string).AsSpan());
+ isLogRecordBodySet = true;
+ }
+ else
+ {
+ AddLogAttribute(state, attribute);
+ }
+ }
+
+ // Supports setting Body directly on LogRecord for the Logs Bridge API.
+ if (!isLogRecordBodySet && logRecord.Body != null)
+ {
+ // If {OriginalFormat} is not present in the attributes,
+ // use logRecord.Body if it is set.
+ otlpTagWriterState.WritePosition = WriteLogRecordBody(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, logRecord.Body.AsSpan());
+ }
+ }
+
+ if (logRecord.TraceId != default && logRecord.SpanId != default)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTagAndLength(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, TraceIdSize, ProtobufOtlpLogFieldNumberConstants.LogRecord_Trace_Id, ProtobufWireType.LEN);
+ otlpTagWriterState.WritePosition = ProtobufOtlpTraceSerializer.WriteTraceId(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, logRecord.TraceId);
+
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTagAndLength(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, SpanIdSize, ProtobufOtlpLogFieldNumberConstants.LogRecord_Span_Id, ProtobufWireType.LEN);
+ otlpTagWriterState.WritePosition = ProtobufOtlpTraceSerializer.WriteSpanId(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, logRecord.SpanId);
+
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteFixed32WithTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.LogRecord_Flags, (uint)logRecord.TraceFlags);
+ }
+
+ logRecord.ForEachScope(ProcessScope, state);
+
+ if (otlpTagWriterState.DroppedTagCount > 0)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(buffer, otlpTagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.LogRecord_Dropped_Attributes_Count, ProtobufWireType.VARINT);
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteVarInt32(buffer, otlpTagWriterState.WritePosition, (uint)otlpTagWriterState.DroppedTagCount);
+ }
+
+ ProtobufSerializer.WriteReservedLength(otlpTagWriterState.Buffer, logRecordLengthPosition, otlpTagWriterState.WritePosition - (logRecordLengthPosition + ReserveSizeForLength));
+
+ return otlpTagWriterState.WritePosition;
+
+ static void ProcessScope(LogRecordScope scope, SerializationState state)
+ {
+ foreach (var scopeItem in scope)
+ {
+ if (scopeItem.Key.Equals("{OriginalFormat}") || string.IsNullOrEmpty(scopeItem.Key))
+ {
+ // Ignore if the scope key is empty.
+ // Ignore if the scope key is {OriginalFormat}
+ // Attributes should not contain duplicates,
+ // and it is expensive to de-dup, so this
+ // exporter is going to pass the scope items as is.
+ // {OriginalFormat} is going to be the key
+ // if one uses formatted string for scopes
+ // and if there are nested scopes, this is
+ // guaranteed to create duplicate keys.
+ // Similar for empty keys, which is what the
+ // key is going to be if user simply
+ // passes a string as scope.
+ // To summarize this exporter only allows
+ // IReadOnlyList>
+ // or IEnumerable>.
+ // and expect users to provide unique keys.
+ // Note: It is possible that we allow users
+ // to override this exporter feature. So not blocking
+ // empty/{OriginalFormat} in the SDK itself.
+ }
+ else
+ {
+ AddLogAttribute(state, scopeItem);
+ }
+ }
+ }
+ }
+
+ private static int WriteLogRecordBody(byte[] buffer, int writePosition, ReadOnlySpan value)
+ {
+ var numberOfUtf8CharsInString = ProtobufSerializer.GetNumberOfUtf8CharsInString(value);
+ var serializedLengthSize = ProtobufSerializer.ComputeVarInt64Size((ulong)numberOfUtf8CharsInString);
+
+ // length = numberOfUtf8CharsInString + tagSize + length field size.
+ writePosition = ProtobufSerializer.WriteTagAndLength(buffer, writePosition, numberOfUtf8CharsInString + 1 + serializedLengthSize, ProtobufOtlpLogFieldNumberConstants.LogRecord_Body, ProtobufWireType.LEN);
+ writePosition = ProtobufSerializer.WriteStringWithTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.AnyValue_String_Value, numberOfUtf8CharsInString, value);
+ return writePosition;
+ }
+
+ private static void AddLogAttribute(SerializationState state, KeyValuePair attribute)
+ {
+ AddLogAttribute(state, attribute.Key, attribute.Value);
+ }
+
+ private static void AddLogAttribute(SerializationState state, string key, object? value)
+ {
+ if (state.TagWriterState.TagCount == state.AttributeCountLimit)
+ {
+ state.TagWriterState.DroppedTagCount++;
+ }
+ else
+ {
+ state.TagWriterState.WritePosition = ProtobufSerializer.WriteTag(state.TagWriterState.Buffer, state.TagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.LogRecord_Attributes, ProtobufWireType.LEN);
+ int logAttributesLengthPosition = state.TagWriterState.WritePosition;
+ state.TagWriterState.WritePosition += ReserveSizeForLength;
+
+ ProtobufOtlpTagWriter.Instance.TryWriteTag(ref state.TagWriterState, key, value, state.AttributeValueLengthLimit);
+
+ var logAttributesLength = state.TagWriterState.WritePosition - (logAttributesLengthPosition + ReserveSizeForLength);
+ ProtobufSerializer.WriteReservedLength(state.TagWriterState.Buffer, logAttributesLengthPosition, logAttributesLength);
+ state.TagWriterState.TagCount++;
+ }
+ }
+
+ private sealed class SerializationState
+ {
+ public int? AttributeValueLengthLimit;
+ public int AttributeCountLimit;
+ public ProtobufOtlpTagWriter.OtlpTagWriterState TagWriterState;
+ }
+}
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpResourceSerializer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpResourceSerializer.cs
new file mode 100644
index 0000000000..0d315778c9
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpResourceSerializer.cs
@@ -0,0 +1,80 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using OpenTelemetry.Resources;
+
+namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Serializer;
+
+internal static class ProtobufOtlpResourceSerializer
+{
+ private const int ReserveSizeForLength = 4;
+
+ private static readonly string DefaultServiceName = ResourceBuilder.CreateDefault().Build().Attributes.FirstOrDefault(
+ kvp => kvp.Key == ResourceSemanticConventions.AttributeServiceName).Value as string ?? "unknown_service";
+
+ internal static int WriteResource(byte[] buffer, int writePosition, Resource? resource)
+ {
+ ProtobufOtlpTagWriter.OtlpTagWriterState otlpTagWriterState = new ProtobufOtlpTagWriter.OtlpTagWriterState
+ {
+ Buffer = buffer,
+ WritePosition = writePosition,
+ };
+
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpTraceFieldNumberConstants.ResourceSpans_Resource, ProtobufWireType.LEN);
+ int resourceLengthPosition = otlpTagWriterState.WritePosition;
+ otlpTagWriterState.WritePosition += ReserveSizeForLength;
+
+ bool isServiceNamePresent = false;
+ if (resource != null && resource != Resource.Empty)
+ {
+ if (resource.Attributes is IReadOnlyList> resourceAttributesList)
+ {
+ for (int i = 0; i < resourceAttributesList.Count; i++)
+ {
+ var attribute = resourceAttributesList[i];
+ if (attribute.Key == ResourceSemanticConventions.AttributeServiceName)
+ {
+ isServiceNamePresent = true;
+ }
+
+ otlpTagWriterState = ProcessResourceAttribute(ref otlpTagWriterState, attribute);
+ }
+ }
+ else
+ {
+ foreach (var attribute in resource.Attributes)
+ {
+ if (attribute.Key == ResourceSemanticConventions.AttributeServiceName)
+ {
+ isServiceNamePresent = true;
+ }
+
+ otlpTagWriterState = ProcessResourceAttribute(ref otlpTagWriterState, attribute);
+ }
+ }
+ }
+
+ if (!isServiceNamePresent)
+ {
+ otlpTagWriterState = ProcessResourceAttribute(ref otlpTagWriterState, new KeyValuePair(ResourceSemanticConventions.AttributeServiceName, DefaultServiceName));
+ }
+
+ var resourceLength = otlpTagWriterState.WritePosition - (resourceLengthPosition + ReserveSizeForLength);
+ ProtobufSerializer.WriteReservedLength(otlpTagWriterState.Buffer, resourceLengthPosition, resourceLength);
+
+ return otlpTagWriterState.WritePosition;
+ }
+
+ private static ProtobufOtlpTagWriter.OtlpTagWriterState ProcessResourceAttribute(ref ProtobufOtlpTagWriter.OtlpTagWriterState otlpTagWriterState, KeyValuePair attribute)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpTraceFieldNumberConstants.Resource_Attributes, ProtobufWireType.LEN);
+ int resourceAttributesLengthPosition = otlpTagWriterState.WritePosition;
+ otlpTagWriterState.WritePosition += ReserveSizeForLength;
+
+ ProtobufOtlpTagWriter.Instance.TryWriteTag(ref otlpTagWriterState, attribute.Key, attribute.Value);
+
+ var resourceAttributesLength = otlpTagWriterState.WritePosition - (resourceAttributesLengthPosition + ReserveSizeForLength);
+ ProtobufSerializer.WriteReservedLength(otlpTagWriterState.Buffer, resourceAttributesLengthPosition, resourceAttributesLength);
+ return otlpTagWriterState;
+ }
+}
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpTagWriter.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpTagWriter.cs
new file mode 100644
index 0000000000..79b3213a1c
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpTagWriter.cs
@@ -0,0 +1,153 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using OpenTelemetry.Internal;
+
+namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Serializer;
+
+internal sealed class ProtobufOtlpTagWriter : TagWriter
+{
+ private ProtobufOtlpTagWriter()
+ : base(new OtlpArrayTagWriter())
+ {
+ }
+
+ public static ProtobufOtlpTagWriter Instance { get; } = new();
+
+ protected override void WriteIntegralTag(ref OtlpTagWriterState state, string key, long value)
+ {
+ // Write KeyValue tag
+ state.WritePosition = ProtobufSerializer.WriteStringWithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.KeyValue_Key, key);
+
+ // Write KeyValue.Value tag, length and value.
+ var size = ProtobufSerializer.ComputeVarInt64Size((ulong)value) + 1; // ComputeVarint64Size(ulong) + TagSize
+ state.WritePosition = ProtobufSerializer.WriteTagAndLength(state.Buffer, state.WritePosition, size, ProtobufOtlpTraceFieldNumberConstants.KeyValue_Value, ProtobufWireType.LEN);
+ state.WritePosition = ProtobufSerializer.WriteInt64WithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.AnyValue_Int_Value, (ulong)value);
+ }
+
+ protected override void WriteFloatingPointTag(ref OtlpTagWriterState state, string key, double value)
+ {
+ // Write KeyValue tag
+ state.WritePosition = ProtobufSerializer.WriteStringWithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.KeyValue_Key, key);
+
+ // Write KeyValue.Value tag, length and value.
+ state.WritePosition = ProtobufSerializer.WriteTagAndLength(state.Buffer, state.WritePosition, 9, ProtobufOtlpTraceFieldNumberConstants.KeyValue_Value, ProtobufWireType.LEN); // 8 + TagSize
+ state.WritePosition = ProtobufSerializer.WriteDoubleWithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.AnyValue_Double_Value, value);
+ }
+
+ protected override void WriteBooleanTag(ref OtlpTagWriterState state, string key, bool value)
+ {
+ // Write KeyValue tag
+ state.WritePosition = ProtobufSerializer.WriteStringWithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.KeyValue_Key, key);
+
+ // Write KeyValue.Value tag, length and value.
+ state.WritePosition = ProtobufSerializer.WriteTagAndLength(state.Buffer, state.WritePosition, 2, ProtobufOtlpTraceFieldNumberConstants.KeyValue_Value, ProtobufWireType.LEN); // 1 + TagSize
+ state.WritePosition = ProtobufSerializer.WriteBoolWithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.AnyValue_Bool_Value, value);
+ }
+
+ protected override void WriteStringTag(ref OtlpTagWriterState state, string key, ReadOnlySpan value)
+ {
+ // Write KeyValue tag
+ state.WritePosition = ProtobufSerializer.WriteStringWithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.KeyValue_Key, key);
+
+ // Write KeyValue.Value tag, length and value.
+ var numberOfUtf8CharsInString = ProtobufSerializer.GetNumberOfUtf8CharsInString(value);
+ var serializedLengthSize = ProtobufSerializer.ComputeVarInt64Size((ulong)numberOfUtf8CharsInString);
+
+ // length = numberOfUtf8CharsInString + tagSize + length field size.
+ state.WritePosition = ProtobufSerializer.WriteTagAndLength(state.Buffer, state.WritePosition, numberOfUtf8CharsInString + 1 + serializedLengthSize, ProtobufOtlpTraceFieldNumberConstants.KeyValue_Value, ProtobufWireType.LEN);
+ state.WritePosition = ProtobufSerializer.WriteStringWithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.AnyValue_String_Value, numberOfUtf8CharsInString, value);
+ }
+
+ protected override void WriteArrayTag(ref OtlpTagWriterState state, string key, ref OtlpTagWriterArrayState value)
+ {
+ // TODO: Expand OtlpTagWriterArrayState.Buffer on IndexOutOfRangeException.
+ // Write KeyValue tag
+ state.WritePosition = ProtobufSerializer.WriteStringWithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.KeyValue_Key, key);
+
+ // Write KeyValue.Value tag and length
+ var serializedLengthSize = ProtobufSerializer.ComputeVarInt64Size((ulong)value.WritePosition);
+ state.WritePosition = ProtobufSerializer.WriteTagAndLength(state.Buffer, state.WritePosition, value.WritePosition + 1 + serializedLengthSize, ProtobufOtlpTraceFieldNumberConstants.KeyValue_Value, ProtobufWireType.LEN); // Array content length + Array tag size + length field size
+
+ // Write Array tag and length
+ state.WritePosition = ProtobufSerializer.WriteTagAndLength(state.Buffer, state.WritePosition, value.WritePosition, ProtobufOtlpTraceFieldNumberConstants.AnyValue_Array_Value, ProtobufWireType.LEN);
+ Buffer.BlockCopy(value.Buffer, 0, state.Buffer, state.WritePosition, value.WritePosition);
+ state.WritePosition += value.WritePosition;
+ }
+
+ protected override void OnUnsupportedTagDropped(
+ string tagKey,
+ string tagValueTypeFullName) => OpenTelemetryProtocolExporterEventSource.Log.UnsupportedAttributeType(
+ tagValueTypeFullName,
+ tagKey);
+
+ internal struct OtlpTagWriterState
+ {
+ public byte[] Buffer;
+ public int DroppedTagCount;
+ public int TagCount;
+ public int WritePosition;
+ }
+
+ internal struct OtlpTagWriterArrayState
+ {
+ public byte[] Buffer;
+ public int WritePosition;
+ }
+
+ private sealed class OtlpArrayTagWriter : ArrayTagWriter
+ {
+ [ThreadStatic]
+ private static byte[]? threadBuffer;
+
+ public override OtlpTagWriterArrayState BeginWriteArray()
+ {
+ threadBuffer ??= new byte[2048];
+
+ return new OtlpTagWriterArrayState
+ {
+ Buffer = threadBuffer,
+ WritePosition = 0,
+ };
+ }
+
+ public override void WriteNullValue(ref OtlpTagWriterArrayState state)
+ {
+ state.WritePosition = ProtobufSerializer.WriteTagAndLength(state.Buffer, state.WritePosition, 0, ProtobufOtlpTraceFieldNumberConstants.ArrayValue_Value, ProtobufWireType.LEN);
+ }
+
+ public override void WriteIntegralValue(ref OtlpTagWriterArrayState state, long value)
+ {
+ var size = ProtobufSerializer.ComputeVarInt64Size((ulong)value) + 1;
+ state.WritePosition = ProtobufSerializer.WriteTagAndLength(state.Buffer, state.WritePosition, size, ProtobufOtlpTraceFieldNumberConstants.ArrayValue_Value, ProtobufWireType.LEN);
+ state.WritePosition = ProtobufSerializer.WriteInt64WithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.AnyValue_Int_Value, (ulong)value);
+ }
+
+ public override void WriteFloatingPointValue(ref OtlpTagWriterArrayState state, double value)
+ {
+ state.WritePosition = ProtobufSerializer.WriteTagAndLength(state.Buffer, state.WritePosition, 9, ProtobufOtlpTraceFieldNumberConstants.ArrayValue_Value, ProtobufWireType.LEN);
+ state.WritePosition = ProtobufSerializer.WriteDoubleWithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.AnyValue_Double_Value, value);
+ }
+
+ public override void WriteBooleanValue(ref OtlpTagWriterArrayState state, bool value)
+ {
+ state.WritePosition = ProtobufSerializer.WriteTagAndLength(state.Buffer, state.WritePosition, 2, ProtobufOtlpTraceFieldNumberConstants.ArrayValue_Value, ProtobufWireType.LEN);
+ state.WritePosition = ProtobufSerializer.WriteBoolWithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.AnyValue_Bool_Value, value);
+ }
+
+ public override void WriteStringValue(ref OtlpTagWriterArrayState state, ReadOnlySpan value)
+ {
+ // Write KeyValue.Value tag, length and value.
+ var numberOfUtf8CharsInString = ProtobufSerializer.GetNumberOfUtf8CharsInString(value);
+ var serializedLengthSize = ProtobufSerializer.ComputeVarInt64Size((ulong)numberOfUtf8CharsInString);
+
+ // length = numberOfUtf8CharsInString + tagSize + length field size.
+ state.WritePosition = ProtobufSerializer.WriteTagAndLength(state.Buffer, state.WritePosition, numberOfUtf8CharsInString + 1 + serializedLengthSize, ProtobufOtlpTraceFieldNumberConstants.ArrayValue_Value, ProtobufWireType.LEN);
+ state.WritePosition = ProtobufSerializer.WriteStringWithTag(state.Buffer, state.WritePosition, ProtobufOtlpTraceFieldNumberConstants.AnyValue_String_Value, numberOfUtf8CharsInString, value);
+ }
+
+ public override void EndWriteArray(ref OtlpTagWriterArrayState state)
+ {
+ }
+ }
+}
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpTraceFieldNumberConstants.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpTraceFieldNumberConstants.cs
new file mode 100644
index 0000000000..c7d0198a99
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpTraceFieldNumberConstants.cs
@@ -0,0 +1,92 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Serializer;
+
+internal static class ProtobufOtlpTraceFieldNumberConstants
+{
+ // Resource spans
+#pragma warning disable SA1310 // Field names should not contain underscore
+ internal const int ResourceSpans_Resource = 1;
+ internal const int ResourceSpans_Scope_Spans = 2;
+ internal const int ResourceSpans_Schema_Url = 3;
+
+ // Resource
+ internal const int Resource_Attributes = 1;
+
+ // ScopeSpans
+ internal const int ScopeSpans_Scope = 1;
+ internal const int ScopeSpans_Span = 2;
+ internal const int ScopeSpans_Schema_Url = 3;
+
+ // Span
+ internal const int Span_Trace_Id = 1;
+ internal const int Span_Span_Id = 2;
+ internal const int Span_Trace_State = 3;
+ internal const int Span_Parent_Span_Id = 4;
+ internal const int Span_Name = 5;
+ internal const int Span_Kind = 6;
+ internal const int Span_Start_Time_Unix_Nano = 7;
+ internal const int Span_End_Time_Unix_Nano = 8;
+ internal const int Span_Attributes = 9;
+ internal const int Span_Dropped_Attributes_Count = 10;
+ internal const int Span_Events = 11;
+ internal const int Span_Dropped_Events_Count = 12;
+ internal const int Span_Links = 13;
+ internal const int Span_Dropped_Links_Count = 14;
+ internal const int Span_Status = 15;
+ internal const int Span_Flags = 16;
+
+ // SpanKind
+ internal const int SpanKind_Internal = 2;
+ internal const int SpanKind_Server = 3;
+ internal const int SpanKind_Client = 4;
+ internal const int SpanKind_Producer = 5;
+ internal const int SpanKind_Consumer = 6;
+
+ // Events
+ internal const int Event_Time_Unix_Nano = 1;
+ internal const int Event_Name = 2;
+ internal const int Event_Attributes = 3;
+ internal const int Event_Dropped_Attributes_Count = 4;
+
+ // Links
+ internal const int Link_Trace_Id = 1;
+ internal const int Link_Span_Id = 2;
+ internal const int Link_Trace_State = 3;
+ internal const int Link_Attributes = 4;
+ internal const int Link_Dropped_Attributes_Count = 5;
+ internal const int Link_Flags = 6;
+
+ // Status
+ internal const int Status_Message = 2;
+ internal const int Status_Code = 3;
+
+ // StatusCode
+ internal const int StatusCode_Unset = 0;
+ internal const int StatusCode_Ok = 1;
+ internal const int StatusCode_Error = 2;
+
+ // InstrumentationScope
+ internal const int InstrumentationScope_Name = 1;
+ internal const int InstrumentationScope_Version = 2;
+ internal const int InstrumentationScope_Attributes = 3;
+ internal const int InstrumentationScope_Dropped_Attributes_Count = 4;
+
+ // KeyValue
+ internal const int KeyValue_Key = 1;
+ internal const int KeyValue_Value = 2;
+
+ // AnyValue
+ internal const int AnyValue_String_Value = 1;
+ internal const int AnyValue_Bool_Value = 2;
+ internal const int AnyValue_Int_Value = 3;
+ internal const int AnyValue_Double_Value = 4;
+ internal const int AnyValue_Array_Value = 5;
+ internal const int AnyValue_Kvlist_Value = 6;
+ internal const int AnyValue_Bytes_Value = 7;
+
+ internal const int ArrayValue_Value = 1;
+#pragma warning restore SA1310 // Field names should not contain underscore
+}
+
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpTraceSerializer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpTraceSerializer.cs
new file mode 100644
index 0000000000..1301ba22a1
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpTraceSerializer.cs
@@ -0,0 +1,484 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using System.Diagnostics;
+using OpenTelemetry.Trace;
+
+namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Serializer;
+
+internal static class ProtobufOtlpTraceSerializer
+{
+ private const int ReserveSizeForLength = 4;
+ private const string UnsetStatusCodeTagValue = "UNSET";
+ private const string OkStatusCodeTagValue = "OK";
+ private const string ErrorStatusCodeTagValue = "ERROR";
+ private const int TraceIdSize = 16;
+ private const int SpanIdSize = 8;
+
+ private static readonly Stack> ActivityListPool = [];
+ private static readonly Dictionary> ScopeTracesList = [];
+
+ internal static int WriteTraceData(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, Resources.Resource? resource, in Batch batch)
+ {
+ foreach (var activity in batch)
+ {
+ var sourceName = activity.Source.Name;
+ if (!ScopeTracesList.TryGetValue(sourceName, out var activities))
+ {
+ activities = ActivityListPool.Count > 0 ? ActivityListPool.Pop() : new List();
+ ScopeTracesList[sourceName] = activities;
+ }
+
+ activities.Add(activity);
+ }
+
+ writePosition = WriteResourceSpans(buffer, writePosition, sdkLimitOptions, resource, ScopeTracesList);
+ ReturnActivityListToPool();
+
+ return writePosition;
+ }
+
+ internal static void ReturnActivityListToPool()
+ {
+ if (ScopeTracesList.Count != 0)
+ {
+ foreach (var entry in ScopeTracesList)
+ {
+ entry.Value.Clear();
+ ActivityListPool.Push(entry.Value);
+ }
+
+ ScopeTracesList.Clear();
+ }
+ }
+
+ internal static int WriteResourceSpans(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, Resources.Resource? resource, Dictionary> scopeTraces)
+ {
+ writePosition = ProtobufOtlpResourceSerializer.WriteResource(buffer, writePosition, resource);
+ writePosition = WriteScopeSpans(buffer, writePosition, sdkLimitOptions, scopeTraces);
+
+ return writePosition;
+ }
+
+ internal static int WriteScopeSpans(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, Dictionary> scopeTraces)
+ {
+ if (scopeTraces != null)
+ {
+ foreach (KeyValuePair> entry in scopeTraces)
+ {
+ writePosition = ProtobufSerializer.WriteTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.ResourceSpans_Scope_Spans, ProtobufWireType.LEN);
+ int resourceSpansScopeSpansLengthPosition = writePosition;
+ writePosition += ReserveSizeForLength;
+
+ writePosition = WriteScopeSpan(buffer, writePosition, sdkLimitOptions, entry.Value[0].Source, entry.Value);
+ ProtobufSerializer.WriteReservedLength(buffer, resourceSpansScopeSpansLengthPosition, writePosition - (resourceSpansScopeSpansLengthPosition + ReserveSizeForLength));
+ }
+ }
+
+ return writePosition;
+ }
+
+ internal static int WriteScopeSpan(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, ActivitySource activitySource, List activities)
+ {
+ writePosition = ProtobufSerializer.WriteTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.ScopeSpans_Scope, ProtobufWireType.LEN);
+ int instrumentationScopeLengthPosition = writePosition;
+ writePosition += ReserveSizeForLength;
+
+ writePosition = ProtobufSerializer.WriteStringWithTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.InstrumentationScope_Name, activitySource.Name);
+ if (activitySource.Version != null)
+ {
+ writePosition = ProtobufSerializer.WriteStringWithTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.InstrumentationScope_Version, activitySource.Version);
+ }
+
+ if (activitySource.Tags != null)
+ {
+ var maxAttributeCount = sdkLimitOptions.SpanAttributeCountLimit ?? int.MaxValue;
+ var maxAttributeValueLength = sdkLimitOptions.AttributeValueLengthLimit ?? int.MaxValue;
+ ProtobufOtlpTagWriter.OtlpTagWriterState otlpTagWriterState = new ProtobufOtlpTagWriter.OtlpTagWriterState
+ {
+ Buffer = buffer,
+ WritePosition = writePosition,
+ TagCount = 0,
+ DroppedTagCount = 0,
+ };
+
+ if (activitySource.Tags is IReadOnlyList> activitySourceTagsList)
+ {
+ for (int i = 0; i < activitySourceTagsList.Count; i++)
+ {
+ if (otlpTagWriterState.TagCount < maxAttributeCount)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpTraceFieldNumberConstants.InstrumentationScope_Attributes, ProtobufWireType.LEN);
+ int instrumentationScopeAttributesLengthPosition = otlpTagWriterState.WritePosition;
+ otlpTagWriterState.WritePosition += ReserveSizeForLength;
+
+ ProtobufOtlpTagWriter.Instance.TryWriteTag(ref otlpTagWriterState, activitySourceTagsList[i].Key, activitySourceTagsList[i].Value, maxAttributeValueLength);
+
+ var instrumentationScopeAttributesLength = otlpTagWriterState.WritePosition - (instrumentationScopeAttributesLengthPosition + ReserveSizeForLength);
+ ProtobufSerializer.WriteReservedLength(otlpTagWriterState.Buffer, instrumentationScopeAttributesLengthPosition, instrumentationScopeAttributesLength);
+ otlpTagWriterState.TagCount++;
+ }
+ else
+ {
+ otlpTagWriterState.DroppedTagCount++;
+ }
+ }
+ }
+ else
+ {
+ foreach (var tag in activitySource.Tags)
+ {
+ if (otlpTagWriterState.TagCount < maxAttributeCount)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpTraceFieldNumberConstants.InstrumentationScope_Attributes, ProtobufWireType.LEN);
+ int instrumentationScopeAttributesLengthPosition = otlpTagWriterState.WritePosition;
+ otlpTagWriterState.WritePosition += ReserveSizeForLength;
+
+ ProtobufOtlpTagWriter.Instance.TryWriteTag(ref otlpTagWriterState, tag.Key, tag.Value, maxAttributeValueLength);
+
+ var instrumentationScopeAttributesLength = otlpTagWriterState.WritePosition - (instrumentationScopeAttributesLengthPosition + ReserveSizeForLength);
+ ProtobufSerializer.WriteReservedLength(otlpTagWriterState.Buffer, instrumentationScopeAttributesLengthPosition, instrumentationScopeAttributesLength);
+ otlpTagWriterState.TagCount++;
+ }
+ else
+ {
+ otlpTagWriterState.DroppedTagCount++;
+ }
+ }
+ }
+
+ if (otlpTagWriterState.DroppedTagCount > 0)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(buffer, otlpTagWriterState.WritePosition, ProtobufOtlpTraceFieldNumberConstants.InstrumentationScope_Dropped_Attributes_Count, ProtobufWireType.VARINT);
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteVarInt32(buffer, otlpTagWriterState.WritePosition, (uint)otlpTagWriterState.DroppedTagCount);
+ }
+
+ writePosition = otlpTagWriterState.WritePosition;
+ }
+
+ ProtobufSerializer.WriteReservedLength(buffer, instrumentationScopeLengthPosition, writePosition - (instrumentationScopeLengthPosition + ReserveSizeForLength));
+
+ for (int i = 0; i < activities.Count; i++)
+ {
+ writePosition = WriteSpan(buffer, writePosition, sdkLimitOptions, activities[i]);
+ }
+
+ return writePosition;
+ }
+
+ internal static int WriteSpan(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, Activity activity)
+ {
+ writePosition = ProtobufSerializer.WriteTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.ScopeSpans_Span, ProtobufWireType.LEN);
+ int spanLengthPosition = writePosition;
+ writePosition += ReserveSizeForLength;
+
+ writePosition = ProtobufSerializer.WriteTagAndLength(buffer, writePosition, TraceIdSize, ProtobufOtlpTraceFieldNumberConstants.Span_Trace_Id, ProtobufWireType.LEN);
+ writePosition = WriteTraceId(buffer, writePosition, activity.TraceId);
+
+ writePosition = ProtobufSerializer.WriteTagAndLength(buffer, writePosition, SpanIdSize, ProtobufOtlpTraceFieldNumberConstants.Span_Span_Id, ProtobufWireType.LEN);
+ writePosition = WriteSpanId(buffer, writePosition, activity.SpanId);
+
+ if (activity.TraceStateString != null)
+ {
+ writePosition = ProtobufSerializer.WriteStringWithTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.Span_Trace_State, activity.TraceStateString);
+ }
+
+ if (activity.ParentSpanId != default)
+ {
+ writePosition = ProtobufSerializer.WriteTagAndLength(buffer, writePosition, SpanIdSize, ProtobufOtlpTraceFieldNumberConstants.Span_Parent_Span_Id, ProtobufWireType.LEN);
+ writePosition = WriteSpanId(buffer, writePosition, activity.ParentSpanId);
+ }
+
+ writePosition = WriteTraceFlags(buffer, writePosition, activity.ActivityTraceFlags, activity.HasRemoteParent, ProtobufOtlpTraceFieldNumberConstants.Span_Flags);
+ writePosition = ProtobufSerializer.WriteStringWithTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.Span_Name, activity.DisplayName);
+ writePosition = ProtobufSerializer.WriteEnumWithTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.Span_Kind, (int)activity.Kind + 1);
+ writePosition = ProtobufSerializer.WriteFixed64WithTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.Span_Start_Time_Unix_Nano, (ulong)activity.StartTimeUtc.ToUnixTimeNanoseconds());
+ writePosition = ProtobufSerializer.WriteFixed64WithTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.Span_End_Time_Unix_Nano, (ulong)(activity.StartTimeUtc.ToUnixTimeNanoseconds() + activity.Duration.ToNanoseconds()));
+
+ (writePosition, StatusCode? statusCode, string? statusMessage) = WriteActivityTags(buffer, writePosition, sdkLimitOptions, activity);
+ writePosition = WriteSpanEvents(buffer, writePosition, sdkLimitOptions, activity);
+ writePosition = WriteSpanLinks(buffer, writePosition, sdkLimitOptions, activity);
+ writePosition = WriteSpanStatus(buffer, writePosition, activity, statusCode, statusMessage);
+ ProtobufSerializer.WriteReservedLength(buffer, spanLengthPosition, writePosition - (spanLengthPosition + ReserveSizeForLength));
+
+ return writePosition;
+ }
+
+ internal static int WriteTraceId(byte[] buffer, int position, ActivityTraceId activityTraceId)
+ {
+ var traceBytes = new Span(buffer, position, TraceIdSize);
+ activityTraceId.CopyTo(traceBytes);
+ return position + TraceIdSize;
+ }
+
+ internal static int WriteSpanId(byte[] buffer, int position, ActivitySpanId activitySpanId)
+ {
+ var spanIdBytes = new Span(buffer, position, SpanIdSize);
+ activitySpanId.CopyTo(spanIdBytes);
+ return position + SpanIdSize;
+ }
+
+ internal static int WriteTraceFlags(byte[] buffer, int position, ActivityTraceFlags activityTraceFlags, bool hasRemoteParent, int fieldNumber)
+ {
+ uint spanFlags = (uint)activityTraceFlags & (byte)0x000000FF;
+
+ spanFlags |= 0x00000100;
+ if (hasRemoteParent)
+ {
+ spanFlags |= 0x00000200;
+ }
+
+ position = ProtobufSerializer.WriteFixed32WithTag(buffer, position, fieldNumber, spanFlags);
+
+ return position;
+ }
+
+ internal static (int Position, StatusCode? StatusCode, string? StatusMessage) WriteActivityTags(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, Activity activity)
+ {
+ StatusCode? statusCode = null;
+ string? statusMessage = null;
+ int maxAttributeCount = sdkLimitOptions.SpanAttributeCountLimit ?? int.MaxValue;
+ int maxAttributeValueLength = sdkLimitOptions.AttributeValueLengthLimit ?? int.MaxValue;
+ ProtobufOtlpTagWriter.OtlpTagWriterState otlpTagWriterState = new ProtobufOtlpTagWriter.OtlpTagWriterState
+ {
+ Buffer = buffer,
+ WritePosition = writePosition,
+ TagCount = 0,
+ DroppedTagCount = 0,
+ };
+
+ foreach (ref readonly var tag in activity.EnumerateTagObjects())
+ {
+ switch (tag.Key)
+ {
+ case "otel.status_code":
+
+ statusCode = tag.Value switch
+ {
+ /*
+ * Note: Order here does matter for perf. Unset is
+ * first because assumption is most spans will be
+ * Unset, then Error. Ok is not set by the SDK.
+ */
+ not null when UnsetStatusCodeTagValue.Equals(tag.Value as string, StringComparison.OrdinalIgnoreCase) => StatusCode.Unset,
+ not null when ErrorStatusCodeTagValue.Equals(tag.Value as string, StringComparison.OrdinalIgnoreCase) => StatusCode.Error,
+ not null when OkStatusCodeTagValue.Equals(tag.Value as string, StringComparison.OrdinalIgnoreCase) => StatusCode.Ok,
+ _ => null,
+ };
+ continue;
+ case "otel.status_description":
+ statusMessage = tag.Value as string;
+ continue;
+ }
+
+ if (otlpTagWriterState.TagCount < maxAttributeCount)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpTraceFieldNumberConstants.Span_Attributes, ProtobufWireType.LEN);
+ int spanAttributesLengthPosition = otlpTagWriterState.WritePosition;
+ otlpTagWriterState.WritePosition += ReserveSizeForLength;
+
+ ProtobufOtlpTagWriter.Instance.TryWriteTag(ref otlpTagWriterState, tag.Key, tag.Value, maxAttributeValueLength);
+
+ ProtobufSerializer.WriteReservedLength(buffer, spanAttributesLengthPosition, otlpTagWriterState.WritePosition - (spanAttributesLengthPosition + 4));
+ otlpTagWriterState.TagCount++;
+ }
+ else
+ {
+ otlpTagWriterState.DroppedTagCount++;
+ }
+ }
+
+ if (otlpTagWriterState.DroppedTagCount > 0)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(buffer, otlpTagWriterState.WritePosition, ProtobufOtlpTraceFieldNumberConstants.Span_Dropped_Attributes_Count, ProtobufWireType.VARINT);
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteVarInt32(buffer, otlpTagWriterState.WritePosition, (uint)otlpTagWriterState.DroppedTagCount);
+ }
+
+ return (otlpTagWriterState.WritePosition, statusCode, statusMessage);
+ }
+
+ internal static int WriteSpanEvents(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, Activity activity)
+ {
+ int maxEventCountLimit = sdkLimitOptions.SpanEventCountLimit ?? int.MaxValue;
+ int eventCount = 0;
+ int droppedEventCount = 0;
+ foreach (ref readonly var evnt in activity.EnumerateEvents())
+ {
+ if (eventCount < maxEventCountLimit)
+ {
+ writePosition = ProtobufSerializer.WriteTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.Span_Events, ProtobufWireType.LEN);
+ int spanEventsLengthPosition = writePosition;
+ writePosition += ReserveSizeForLength; // Reserve 4 bytes for length
+
+ writePosition = ProtobufSerializer.WriteStringWithTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.Event_Name, evnt.Name);
+ writePosition = ProtobufSerializer.WriteFixed64WithTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.Event_Time_Unix_Nano, (ulong)evnt.Timestamp.ToUnixTimeNanoseconds());
+ writePosition = WriteEventAttributes(ref buffer, writePosition, sdkLimitOptions, evnt);
+
+ ProtobufSerializer.WriteReservedLength(buffer, spanEventsLengthPosition, writePosition - (spanEventsLengthPosition + ReserveSizeForLength));
+ eventCount++;
+ }
+ else
+ {
+ droppedEventCount++;
+ }
+ }
+
+ if (droppedEventCount > 0)
+ {
+ writePosition = ProtobufSerializer.WriteTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.Span_Dropped_Events_Count, ProtobufWireType.VARINT);
+ writePosition = ProtobufSerializer.WriteVarInt32(buffer, writePosition, (uint)droppedEventCount);
+ }
+
+ return writePosition;
+ }
+
+ internal static int WriteEventAttributes(ref byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, ActivityEvent evnt)
+ {
+ int maxAttributeCount = sdkLimitOptions.SpanEventAttributeCountLimit ?? int.MaxValue;
+ int maxAttributeValueLength = sdkLimitOptions.AttributeValueLengthLimit ?? int.MaxValue;
+
+ ProtobufOtlpTagWriter.OtlpTagWriterState otlpTagWriterState = new ProtobufOtlpTagWriter.OtlpTagWriterState
+ {
+ Buffer = buffer,
+ WritePosition = writePosition,
+ TagCount = 0,
+ DroppedTagCount = 0,
+ };
+
+ foreach (ref readonly var tag in evnt.EnumerateTagObjects())
+ {
+ if (otlpTagWriterState.TagCount < maxAttributeCount)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpTraceFieldNumberConstants.Event_Attributes, ProtobufWireType.LEN);
+ int eventAttributesLengthPosition = otlpTagWriterState.WritePosition;
+ otlpTagWriterState.WritePosition += ReserveSizeForLength;
+ ProtobufOtlpTagWriter.Instance.TryWriteTag(ref otlpTagWriterState, tag.Key, tag.Value, maxAttributeValueLength);
+ ProtobufSerializer.WriteReservedLength(buffer, eventAttributesLengthPosition, otlpTagWriterState.WritePosition - (eventAttributesLengthPosition + ReserveSizeForLength));
+ otlpTagWriterState.TagCount++;
+ }
+ else
+ {
+ otlpTagWriterState.DroppedTagCount++;
+ }
+ }
+
+ if (otlpTagWriterState.DroppedTagCount > 0)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(buffer, otlpTagWriterState.WritePosition, ProtobufOtlpTraceFieldNumberConstants.Event_Dropped_Attributes_Count, ProtobufWireType.VARINT);
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteVarInt32(buffer, otlpTagWriterState.WritePosition, (uint)otlpTagWriterState.DroppedTagCount);
+ }
+
+ return otlpTagWriterState.WritePosition;
+ }
+
+ internal static int WriteSpanLinks(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, Activity activity)
+ {
+ int maxLinksCount = sdkLimitOptions.SpanLinkCountLimit ?? int.MaxValue;
+ int linkCount = 0;
+ int droppedLinkCount = 0;
+
+ foreach (ref readonly var link in activity.EnumerateLinks())
+ {
+ if (linkCount < maxLinksCount)
+ {
+ writePosition = ProtobufSerializer.WriteTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.Span_Links, ProtobufWireType.LEN);
+ int spanLinksLengthPosition = writePosition;
+ writePosition += ReserveSizeForLength; // Reserve 4 bytes for length
+
+ writePosition = ProtobufSerializer.WriteTagAndLength(buffer, writePosition, TraceIdSize, ProtobufOtlpTraceFieldNumberConstants.Link_Trace_Id, ProtobufWireType.LEN);
+ writePosition = WriteTraceId(buffer, writePosition, link.Context.TraceId);
+ writePosition = ProtobufSerializer.WriteTagAndLength(buffer, writePosition, SpanIdSize, ProtobufOtlpTraceFieldNumberConstants.Link_Span_Id, ProtobufWireType.LEN);
+ writePosition = WriteSpanId(buffer, writePosition, link.Context.SpanId);
+ if (link.Context.TraceState != null)
+ {
+ writePosition = ProtobufSerializer.WriteStringWithTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.Span_Trace_State, link.Context.TraceState);
+ }
+
+ writePosition = WriteLinkAttributes(buffer, writePosition, sdkLimitOptions, link);
+ writePosition = WriteTraceFlags(buffer, writePosition, link.Context.TraceFlags, link.Context.IsRemote, ProtobufOtlpTraceFieldNumberConstants.Link_Flags);
+
+ ProtobufSerializer.WriteReservedLength(buffer, spanLinksLengthPosition, writePosition - (spanLinksLengthPosition + ReserveSizeForLength));
+ linkCount++;
+ }
+ else
+ {
+ droppedLinkCount++;
+ }
+ }
+
+ if (droppedLinkCount > 0)
+ {
+ writePosition = ProtobufSerializer.WriteTag(buffer, writePosition, ProtobufOtlpTraceFieldNumberConstants.Span_Dropped_Links_Count, ProtobufWireType.VARINT);
+ writePosition = ProtobufSerializer.WriteVarInt32(buffer, writePosition, (uint)droppedLinkCount);
+ }
+
+ return writePosition;
+ }
+
+ internal static int WriteLinkAttributes(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, ActivityLink link)
+ {
+ int maxAttributeCount = sdkLimitOptions.SpanLinkAttributeCountLimit ?? int.MaxValue;
+ int maxAttributeValueLength = sdkLimitOptions.AttributeValueLengthLimit ?? int.MaxValue;
+ ProtobufOtlpTagWriter.OtlpTagWriterState otlpTagWriterState = new ProtobufOtlpTagWriter.OtlpTagWriterState
+ {
+ Buffer = buffer,
+ WritePosition = writePosition,
+ TagCount = 0,
+ DroppedTagCount = 0,
+ };
+
+ foreach (ref readonly var tag in link.EnumerateTagObjects())
+ {
+ if (otlpTagWriterState.TagCount < maxAttributeCount)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpTraceFieldNumberConstants.Link_Attributes, ProtobufWireType.LEN);
+ int linkAttributesLengthPosition = otlpTagWriterState.WritePosition;
+ otlpTagWriterState.WritePosition += ReserveSizeForLength;
+ ProtobufOtlpTagWriter.Instance.TryWriteTag(ref otlpTagWriterState, tag.Key, tag.Value, maxAttributeValueLength);
+ ProtobufSerializer.WriteReservedLength(buffer, linkAttributesLengthPosition, otlpTagWriterState.WritePosition - (linkAttributesLengthPosition + ReserveSizeForLength));
+ otlpTagWriterState.TagCount++;
+ }
+ else
+ {
+ otlpTagWriterState.DroppedTagCount++;
+ }
+ }
+
+ if (otlpTagWriterState.DroppedTagCount > 0)
+ {
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteTag(buffer, otlpTagWriterState.WritePosition, ProtobufOtlpTraceFieldNumberConstants.Link_Dropped_Attributes_Count, ProtobufWireType.VARINT);
+ otlpTagWriterState.WritePosition = ProtobufSerializer.WriteVarInt32(buffer, otlpTagWriterState.WritePosition, (uint)otlpTagWriterState.DroppedTagCount);
+ }
+
+ return otlpTagWriterState.WritePosition;
+ }
+
+ internal static int WriteSpanStatus(byte[] buffer, int position, Activity activity, StatusCode? statusCode, string? statusMessage)
+ {
+ if (activity.Status == ActivityStatusCode.Unset && statusCode == null)
+ {
+ return position;
+ }
+
+ var useActivity = activity.Status != ActivityStatusCode.Unset;
+ var isError = useActivity ? activity.Status == ActivityStatusCode.Error : statusCode == StatusCode.Error;
+ var description = useActivity ? activity.StatusDescription : statusMessage;
+
+ if (isError && description != null)
+ {
+ var descriptionSpan = description.AsSpan();
+ var numberOfUtf8CharsInString = ProtobufSerializer.GetNumberOfUtf8CharsInString(descriptionSpan);
+ position = ProtobufSerializer.WriteTagAndLength(buffer, position, numberOfUtf8CharsInString + 4, ProtobufOtlpTraceFieldNumberConstants.Span_Status, ProtobufWireType.LEN);
+ position = ProtobufSerializer.WriteStringWithTag(buffer, position, ProtobufOtlpTraceFieldNumberConstants.Status_Message, numberOfUtf8CharsInString, descriptionSpan);
+ }
+ else
+ {
+ position = ProtobufSerializer.WriteTagAndLength(buffer, position, 2, ProtobufOtlpTraceFieldNumberConstants.Span_Status, ProtobufWireType.LEN);
+ }
+
+ var finalStatusCode = useActivity ? (int)activity.Status : (statusCode != null && statusCode != StatusCode.Unset) ? (int)statusCode! : (int)StatusCode.Unset;
+ position = ProtobufSerializer.WriteEnumWithTag(buffer, position, ProtobufOtlpTraceFieldNumberConstants.Status_Code, finalStatusCode);
+
+ return position;
+ }
+}
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufSerializer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufSerializer.cs
new file mode 100644
index 0000000000..763a56db97
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufSerializer.cs
@@ -0,0 +1,337 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using System.Buffers.Binary;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+#if NETFRAMEWORK || NETSTANDARD2_0
+using System.Runtime.InteropServices;
+#endif
+using System.Text;
+
+namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Serializer;
+
+internal static class ProtobufSerializer
+{
+ private const uint UInt128 = 0x80;
+ private const ulong ULong128 = 0x80;
+ private const int Fixed32Size = 4;
+ private const int Fixed64Size = 8;
+
+ private static readonly Encoding Utf8Encoding = Encoding.UTF8;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static uint GetTagValue(int fieldNumber, ProtobufWireType wireType) => ((uint)(fieldNumber << 3)) | (uint)wireType;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteTag(byte[] buffer, int writePosition, int fieldNumber, ProtobufWireType type) => WriteVarInt32(buffer, writePosition, GetTagValue(fieldNumber, type));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteLength(byte[] buffer, int writePosition, int length) => WriteVarInt32(buffer, writePosition, (uint)length);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteTagAndLength(byte[] buffer, int writePosition, int contentLength, int fieldNumber, ProtobufWireType type)
+ {
+ writePosition = WriteTag(buffer, writePosition, fieldNumber, type);
+ writePosition = WriteLength(buffer, writePosition, contentLength);
+
+ return writePosition;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void WriteReservedLength(byte[] buffer, int writePosition, int length)
+ {
+ int byteLength = 0;
+ int? firstByte = null;
+ int? secondByte = null;
+ int? thirdByte = null;
+ int? fourthByte = null;
+
+ do
+ {
+ switch (byteLength)
+ {
+ case 0:
+ firstByte = length & 0x7F;
+ break;
+ case 1:
+ secondByte = length & 0x7F;
+ break;
+ case 2:
+ thirdByte = length & 0x7F;
+ break;
+ case 3:
+ fourthByte = length & 0x7F;
+ break;
+ }
+
+ length >>= 7;
+ byteLength++;
+ }
+ while (length > 0);
+
+ if (fourthByte.HasValue)
+ {
+ buffer[writePosition++] = (byte)(firstByte!.Value | 0x80);
+ buffer[writePosition++] = (byte)(secondByte!.Value | 0x80);
+ buffer[writePosition++] = (byte)(thirdByte!.Value | 0x80);
+ buffer[writePosition++] = (byte)fourthByte!.Value;
+ }
+ else if (thirdByte.HasValue)
+ {
+ buffer[writePosition++] = (byte)(firstByte!.Value | 0x80);
+ buffer[writePosition++] = (byte)(secondByte!.Value | 0x80);
+ buffer[writePosition++] = (byte)(thirdByte!.Value | 0x80);
+ buffer[writePosition++] = 0;
+ }
+ else if (secondByte.HasValue)
+ {
+ buffer[writePosition++] = (byte)(firstByte!.Value | 0x80);
+ buffer[writePosition++] = (byte)(secondByte!.Value | 0x80);
+ buffer[writePosition++] = 0x80;
+ buffer[writePosition++] = 0;
+ }
+ else
+ {
+ buffer[writePosition++] = (byte)(firstByte!.Value | 0x80);
+ buffer[writePosition++] = 0x80;
+ buffer[writePosition++] = 0x80;
+ buffer[writePosition++] = 0;
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteBoolWithTag(byte[] buffer, int writePosition, int fieldNumber, bool value)
+ {
+ writePosition = WriteTag(buffer, writePosition, fieldNumber, ProtobufWireType.VARINT);
+ buffer[writePosition++] = value ? (byte)1 : (byte)0;
+ return writePosition;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteEnumWithTag(byte[] buffer, int writePosition, int fieldNumber, int value)
+ {
+ writePosition = WriteTag(buffer, writePosition, fieldNumber, ProtobufWireType.VARINT);
+ buffer[writePosition++] = (byte)value;
+ return writePosition;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteFixed32LittleEndianFormat(byte[] buffer, int writePosition, uint value)
+ {
+ Span span = new(buffer, writePosition, Fixed32Size);
+ BinaryPrimitives.WriteUInt32LittleEndian(span, value);
+ writePosition += Fixed32Size;
+
+ return writePosition;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteFixed64LittleEndianFormat(byte[] buffer, int writePosition, ulong value)
+ {
+ Span span = new(buffer, writePosition, Fixed64Size);
+ BinaryPrimitives.WriteUInt64LittleEndian(span, value);
+ writePosition += Fixed64Size;
+
+ return writePosition;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteFixed32WithTag(byte[] buffer, int writePosition, int fieldNumber, uint value)
+ {
+ writePosition = WriteTag(buffer, writePosition, fieldNumber, ProtobufWireType.I32);
+ writePosition = WriteFixed32LittleEndianFormat(buffer, writePosition, value);
+
+ return writePosition;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteFixed64WithTag(byte[] buffer, int writePosition, int fieldNumber, ulong value)
+ {
+ writePosition = WriteTag(buffer, writePosition, fieldNumber, ProtobufWireType.I64);
+ writePosition = WriteFixed64LittleEndianFormat(buffer, writePosition, value);
+
+ return writePosition;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteVarInt32(byte[] buffer, int writePosition, uint value)
+ {
+ while (value >= UInt128)
+ {
+ buffer[writePosition++] = (byte)(0x80 | (value & 0x7F));
+ value >>= 7;
+ }
+
+ buffer[writePosition++] = (byte)value;
+ return writePosition;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteVarInt64(byte[] buffer, int writePosition, ulong value)
+ {
+ while (value >= ULong128)
+ {
+ buffer[writePosition++] = (byte)(0x80 | (value & 0x7F));
+ value >>= 7;
+ }
+
+ buffer[writePosition++] = (byte)value;
+ return writePosition;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteInt64WithTag(byte[] buffer, int writePosition, int fieldNumber, ulong value)
+ {
+ writePosition = WriteTag(buffer, writePosition, fieldNumber, ProtobufWireType.VARINT);
+ writePosition = WriteVarInt64(buffer, writePosition, value);
+
+ return writePosition;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteDoubleWithTag(byte[] buffer, int writePosition, int fieldNumber, double value)
+ {
+ writePosition = WriteTag(buffer, writePosition, fieldNumber, ProtobufWireType.I64);
+ writePosition = WriteFixed64LittleEndianFormat(buffer, writePosition, (ulong)BitConverter.DoubleToInt64Bits(value));
+
+ return writePosition;
+ }
+
+ ///
+ /// Computes the number of bytes required to encode a 64-bit unsigned integer in Protocol Buffers' varint format.
+ ///
+ ///
+ /// Protocol Buffers uses variable-length encoding (varint) to serialize integers efficiently:
+ /// - Each byte uses 7 bits to encode the number and 1 bit (MSB) to indicate if more bytes follow
+ /// - The algorithm checks how many significant bits the number contains by shifting and masking
+ /// - Numbers are encoded in groups of 7 bits, from least to most significant
+ /// - Each group requires one byte, so the method returns the number of 7-bit groups needed
+ ///
+ /// Examples:
+ /// - Values 0-127 (7 bits) require 1 byte
+ /// - Values 128-16383 (14 bits) require 2 bytes
+ /// - Values 16384-2097151 (21 bits) require 3 bytes
+ /// And so on...
+ ///
+ /// For more details, see:
+ /// - Protocol Buffers encoding reference: https://developers.google.com/protocol-buffers/docs/encoding#varints.
+ ///
+ /// The unsigned 64-bit integer to be encoded.
+ /// Number of bytes needed to encode the value.
+ internal static int ComputeVarInt64Size(ulong value)
+ {
+ if ((value & (0xffffffffffffffffL << 7)) == 0)
+ {
+ return 1;
+ }
+
+ if ((value & (0xffffffffffffffffL << 14)) == 0)
+ {
+ return 2;
+ }
+
+ if ((value & (0xffffffffffffffffL << 21)) == 0)
+ {
+ return 3;
+ }
+
+ if ((value & (0xffffffffffffffffL << 28)) == 0)
+ {
+ return 4;
+ }
+
+ if ((value & (0xffffffffffffffffL << 35)) == 0)
+ {
+ return 5;
+ }
+
+ if ((value & (0xffffffffffffffffL << 42)) == 0)
+ {
+ return 6;
+ }
+
+ if ((value & (0xffffffffffffffffL << 49)) == 0)
+ {
+ return 7;
+ }
+
+ if ((value & (0xffffffffffffffffL << 56)) == 0)
+ {
+ return 8;
+ }
+
+ if ((value & (0xffffffffffffffffL << 63)) == 0)
+ {
+ return 9;
+ }
+
+ return 10;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteStringWithTag(byte[] buffer, int writePosition, int fieldNumber, string value)
+ {
+ Debug.Assert(value != null, "value was null");
+
+ return WriteStringWithTag(buffer, writePosition, fieldNumber, value.AsSpan());
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int GetNumberOfUtf8CharsInString(ReadOnlySpan value)
+ {
+#if NETFRAMEWORK || NETSTANDARD2_0
+ int numberOfUtf8CharsInString;
+ unsafe
+ {
+ fixed (char* strPtr = &GetNonNullPinnableReference(value))
+ {
+ numberOfUtf8CharsInString = Utf8Encoding.GetByteCount(strPtr, value.Length);
+ }
+ }
+#else
+ int numberOfUtf8CharsInString = Utf8Encoding.GetByteCount(value);
+#endif
+ return numberOfUtf8CharsInString;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteStringWithTag(byte[] buffer, int writePosition, int fieldNumber, ReadOnlySpan value)
+ {
+ var numberOfUtf8CharsInString = GetNumberOfUtf8CharsInString(value);
+ return WriteStringWithTag(buffer, writePosition, fieldNumber, numberOfUtf8CharsInString, value);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int WriteStringWithTag(byte[] buffer, int writePosition, int fieldNumber, int numberOfUtf8CharsInString, ReadOnlySpan value)
+ {
+ writePosition = WriteTag(buffer, writePosition, fieldNumber, ProtobufWireType.LEN);
+ writePosition = WriteLength(buffer, writePosition, numberOfUtf8CharsInString);
+
+#if NETFRAMEWORK || NETSTANDARD2_0
+ unsafe
+ {
+ fixed (char* strPtr = &GetNonNullPinnableReference(value))
+ {
+ fixed (byte* bufferPtr = buffer)
+ {
+ var bytesWritten = Utf8Encoding.GetBytes(strPtr, value.Length, bufferPtr + writePosition, numberOfUtf8CharsInString);
+ Debug.Assert(bytesWritten == numberOfUtf8CharsInString, "bytesWritten did not match numberOfUtf8CharsInString");
+ }
+ }
+ }
+#else
+ var bytesWritten = Utf8Encoding.GetBytes(value, buffer.AsSpan().Slice(writePosition));
+ Debug.Assert(bytesWritten == numberOfUtf8CharsInString, "bytesWritten did not match numberOfUtf8CharsInString");
+#endif
+
+ writePosition += numberOfUtf8CharsInString;
+ return writePosition;
+ }
+
+#if NETFRAMEWORK || NETSTANDARD2_0
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe ref T GetNonNullPinnableReference(ReadOnlySpan span)
+ => ref (span.Length != 0) ? ref Unsafe.AsRef(in MemoryMarshal.GetReference(span)) : ref Unsafe.AsRef((void*)1);
+#endif
+}
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufWireType.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufWireType.cs
new file mode 100644
index 0000000000..b3b5fe4031
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufWireType.cs
@@ -0,0 +1,47 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Serializer;
+
+///
+/// Wire types within protobuf encoding.
+/// https://protobuf.dev/programming-guides/encoding/#structure.
+///
+internal enum ProtobufWireType : uint
+{
+ ///
+ /// Variable-length integer.
+ /// Used for int32, int64, uint32, uint64, sint32, sint64, bool, enum.
+ ///
+ VARINT = 0,
+
+ ///
+ /// A fixed-length 64-bit value.
+ /// Used for fixed64, sfixed64, double.
+ ///
+ I64 = 1,
+
+ ///
+ /// A length-delimited value.
+ /// Used for string, bytes, embedded messages, packed repeated fields.
+ ///
+ LEN = 2,
+
+ ///
+ /// Group Start value.
+ /// (Deprecated).
+ ///
+ SGROUP = 3,
+
+ ///
+ /// Group End value.
+ /// (Deprecated).
+ ///
+ EGROUP = 4,
+
+ ///
+ /// A fixed-length 32-bit value.
+ /// Used for fixed32, sfixed32, float.
+ ///
+ I32 = 5,
+}
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/OtlpExporterPersistentStorageTransmissionHandler.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/OtlpExporterPersistentStorageTransmissionHandler.cs
index e8ed3da211..9d4d86c71d 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/OtlpExporterPersistentStorageTransmissionHandler.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/OtlpExporterPersistentStorageTransmissionHandler.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using Google.Protobuf;
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/OtlpExporterRetryTransmissionHandler.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/OtlpExporterRetryTransmissionHandler.cs
index d4be5c9d64..6904dc8dc4 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/OtlpExporterRetryTransmissionHandler.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/OtlpExporterRetryTransmissionHandler.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient;
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Transmission;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/OtlpExporterTransmissionHandler.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/OtlpExporterTransmissionHandler.cs
index 2b56e16dd7..12b76bdf83 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/OtlpExporterTransmissionHandler.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/OtlpExporterTransmissionHandler.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient;
using OpenTelemetry.Internal;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/RetryHelper.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/RetryHelper.cs
index cf663a5f79..f68d1255e4 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/RetryHelper.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Transmission/RetryHelper.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient;
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Transmission;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/opentelemetry/proto/collector/profiles/v1experimental/profiles_service_http.yaml b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/opentelemetry/proto/collector/profiles/v1experimental/profiles_service_http.yaml
index 6bb7cf740b..ea501afbbb 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/opentelemetry/proto/collector/profiles/v1experimental/profiles_service_http.yaml
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/opentelemetry/proto/collector/profiles/v1experimental/profiles_service_http.yaml
@@ -4,6 +4,6 @@ type: google.api.Service
config_version: 3
http:
rules:
- - selector: opentelemetry.proto.collector.profiles.v1.ProfilesService.Export
+ - selector: opentelemetry.proto.collector.profiles.v1experimental.ProfilesService.Export
post: /v1experimental/profiles
body: "*"
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/opentelemetry/proto/profiles/v1experimental/pprofextended.proto b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/opentelemetry/proto/profiles/v1experimental/pprofextended.proto
index bd30083554..b5b5b88fce 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/opentelemetry/proto/profiles/v1experimental/pprofextended.proto
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/opentelemetry/proto/profiles/v1experimental/pprofextended.proto
@@ -59,6 +59,8 @@ package opentelemetry.proto.profiles.v1experimental;
import "opentelemetry/proto/common/v1/common.proto";
option csharp_namespace = "OpenTelemetry.Proto.Profiles.V1Experimental";
+option java_multiple_files = true;
+option java_package = "io.opentelemetry.proto.profiles.v1experimental";
option go_package = "go.opentelemetry.io/proto/otlp/profiles/v1experimental";
// Represents a complete profile, including sample types, samples,
@@ -203,7 +205,7 @@ enum AggregationTemporality {
11. A request is received, the system measures 1 request.
12. The 1 second collection cycle ends. A metric is exported for the
number of requests received over the interval of time t_1 to
- t_0+1 with a value of 1.
+ t_1+1 with a value of 1.
Note: Even though, when reporting changes since last report time, using
CUMULATIVE is valid, it is not recommended. */
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/opentelemetry/proto/profiles/v1experimental/profiles.proto b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/opentelemetry/proto/profiles/v1experimental/profiles.proto
index bbc2b2931d..84b0108f86 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/opentelemetry/proto/profiles/v1experimental/profiles.proto
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/opentelemetry/proto/profiles/v1experimental/profiles.proto
@@ -55,7 +55,7 @@ option go_package = "go.opentelemetry.io/proto/otlp/profiles/v1experimental";
// ┌──────────────────┐
// │ Profile │
// └──────────────────┘
-// │ 1-n
+// │ n-1
// │ 1-n ┌───────────────────────────────────────┐
// ▼ │ ▽
// ┌──────────────────┐ 1-n ┌──────────────┐ ┌──────────┐
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj
index f5922910ec..cfeae2fa85 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj
@@ -5,8 +5,6 @@
$(PackageTags);OTLP
core-
-
- disable
BUILDING_INTERNAL_PERSISTENT_STORAGE;$(DefineConstants)
true
@@ -18,6 +16,7 @@
https://github.com/open-telemetry/opentelemetry-dotnet/pull/5520#discussion_r1556221048
and https://github.com/dotnet/runtime/issues/92509 -->
$(NoWarn);SYSLIB1100;SYSLIB1101
+ true
@@ -25,7 +24,7 @@
-
+
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs
index 7c14310d17..355ab37674 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
#if NETFRAMEWORK
using System.Net.Http;
@@ -32,7 +30,7 @@ public class OtlpExporterOptions : IOtlpExporterOptions
internal static readonly KeyValuePair[] StandardHeaders = new KeyValuePair[]
{
- new KeyValuePair("User-Agent", GetUserAgentString()),
+ new("User-Agent", GetUserAgentString()),
};
internal readonly Func DefaultHttpClientFactory;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs
index ba68de1326..b755e15880 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs
@@ -8,7 +8,7 @@
using Grpc.Core;
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation;
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient;
-#if NETSTANDARD2_1 || NET6_0_OR_GREATER
+#if NETSTANDARD2_1 || NET
using Grpc.Net.Client;
#endif
using System.Diagnostics;
@@ -22,7 +22,7 @@ namespace OpenTelemetry.Exporter;
internal static class OtlpExporterOptionsExtensions
{
-#if NETSTANDARD2_1 || NET6_0_OR_GREATER
+#if NETSTANDARD2_1 || NET
public static GrpcChannel CreateChannel(this OtlpExporterOptions options)
#else
public static Channel CreateChannel(this OtlpExporterOptions options)
@@ -33,7 +33,7 @@ public static Channel CreateChannel(this OtlpExporterOptions options)
throw new NotSupportedException($"Endpoint URI scheme ({options.Endpoint.Scheme}) is not supported. Currently only \"http\" and \"https\" are supported.");
}
-#if NETSTANDARD2_1 || NET6_0_OR_GREATER
+#if NETSTANDARD2_1 || NET
return GrpcChannel.ForAddress(options.Endpoint);
#else
ChannelCredentials channelCredentials;
@@ -233,13 +233,13 @@ public static void TryEnableIHttpClientFactoryIntegration(this OtlpExporterOptio
{
options.HttpClientFactory = () =>
{
- Type httpClientFactoryType = Type.GetType("System.Net.Http.IHttpClientFactory, Microsoft.Extensions.Http", throwOnError: false);
+ Type? httpClientFactoryType = Type.GetType("System.Net.Http.IHttpClientFactory, Microsoft.Extensions.Http", throwOnError: false);
if (httpClientFactoryType != null)
{
- object httpClientFactory = serviceProvider.GetService(httpClientFactoryType);
+ object? httpClientFactory = serviceProvider.GetService(httpClientFactoryType);
if (httpClientFactory != null)
{
- MethodInfo createClientMethod = httpClientFactoryType.GetMethod(
+ MethodInfo? createClientMethod = httpClientFactoryType.GetMethod(
"CreateClient",
BindingFlags.Public | BindingFlags.Instance,
binder: null,
@@ -247,11 +247,14 @@ public static void TryEnableIHttpClientFactoryIntegration(this OtlpExporterOptio
modifiers: null);
if (createClientMethod != null)
{
- HttpClient client = (HttpClient)createClientMethod.Invoke(httpClientFactory, new object[] { httpClientName });
+ HttpClient? client = (HttpClient?)createClientMethod.Invoke(httpClientFactory, new object[] { httpClientName });
- client.Timeout = TimeSpan.FromMilliseconds(options.TimeoutMilliseconds);
+ if (client != null)
+ {
+ client.Timeout = TimeSpan.FromMilliseconds(options.TimeoutMilliseconds);
- return client;
+ return client;
+ }
}
}
}
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs
index b3781c4c34..dec5e8cc3e 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation;
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Transmission;
@@ -49,7 +47,7 @@ internal OtlpLogExporter(
Debug.Assert(sdkLimitOptions != null, "sdkLimitOptions was null");
Debug.Assert(experimentalOptions != null, "experimentalOptions was null");
- this.transmissionHandler = transmissionHandler ?? exporterOptions.GetLogsExportTransmissionHandler(experimentalOptions!);
+ this.transmissionHandler = transmissionHandler ?? exporterOptions!.GetLogsExportTransmissionHandler(experimentalOptions!);
this.otlpLogRecordTransformer = new OtlpLogRecordTransformer(sdkLimitOptions!, experimentalOptions!);
}
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporterHelperExtensions.cs
index ca5a759caf..42faf42535 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporterHelperExtensions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporterHelperExtensions.cs
@@ -1,12 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
-#if EXPOSE_EXPERIMENTAL_FEATURES && NET8_0_OR_GREATER
-using System.Diagnostics.CodeAnalysis;
-#endif
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -28,6 +23,7 @@ public static class OtlpLogExporterHelperExtensions
///
/// options to use.
/// The instance of to chain the calls.
+ // TODO: [Obsolete("Call LoggerProviderBuilder.AddOtlpExporter instead this method will be removed in a future version.")]
public static OpenTelemetryLoggerOptions AddOtlpExporter(this OpenTelemetryLoggerOptions loggerOptions)
=> AddOtlpExporter(loggerOptions, name: null, configure: null);
@@ -37,6 +33,7 @@ public static OpenTelemetryLoggerOptions AddOtlpExporter(this OpenTelemetryLogge
/// options to use.
/// Callback action for configuring .
/// The instance of to chain the calls.
+ // TODO: [Obsolete("Call LoggerProviderBuilder.AddOtlpExporter instead this method will be removed in a future version.")]
public static OpenTelemetryLoggerOptions AddOtlpExporter(
this OpenTelemetryLoggerOptions loggerOptions,
Action configure)
@@ -49,6 +46,7 @@ public static OpenTelemetryLoggerOptions AddOtlpExporter(
/// Optional name which is used when retrieving options.
/// Optional callback action for configuring .
/// The instance of to chain the calls.
+ // TODO: [Obsolete("Call LoggerProviderBuilder.AddOtlpExporter instead this method will be removed in a future version.")]
public static OpenTelemetryLoggerOptions AddOtlpExporter(
this OpenTelemetryLoggerOptions loggerOptions,
string? name,
@@ -81,6 +79,7 @@ public static OpenTelemetryLoggerOptions AddOtlpExporter(
/// options to use.
/// Callback action for configuring and .
/// The instance of to chain the calls.
+ // TODO: [Obsolete("Call LoggerProviderBuilder.AddOtlpExporter instead this method will be removed in a future version.")]
public static OpenTelemetryLoggerOptions AddOtlpExporter(
this OpenTelemetryLoggerOptions loggerOptions,
Action configureExporterAndProcessor)
@@ -93,6 +92,7 @@ public static OpenTelemetryLoggerOptions AddOtlpExporter(
/// Optional name which is used when retrieving options.
/// Optional callback action for configuring and .
/// The instance of to chain the calls.
+ // TODO: [Obsolete("Call LoggerProviderBuilder.AddOtlpExporter instead this method will be removed in a future version.")]
public static OpenTelemetryLoggerOptions AddOtlpExporter(
this OpenTelemetryLoggerOptions loggerOptions,
string? name,
@@ -119,86 +119,34 @@ public static OpenTelemetryLoggerOptions AddOtlpExporter(
});
}
-#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Adds an OTLP exporter to the LoggerProvider.
///
- /// WARNING: This is an experimental API which might change or be removed in the future. Use at your own risk.
/// builder to use.
/// The instance of to chain the calls.
-#if NET8_0_OR_GREATER
- [Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
- public
-#else
- ///
- /// Adds an OTLP exporter to the LoggerProvider.
- ///
- /// builder to use.
- /// The instance of to chain the calls.
- internal
-#endif
- static LoggerProviderBuilder AddOtlpExporter(this LoggerProviderBuilder builder)
+ public static LoggerProviderBuilder AddOtlpExporter(this LoggerProviderBuilder builder)
=> AddOtlpExporter(builder, name: null, configureExporter: null);
-#if EXPOSE_EXPERIMENTAL_FEATURES
- ///
- /// Adds an OTLP exporter to the LoggerProvider.
- ///
- /// WARNING: This is an experimental API which might change or be removed in the future. Use at your own risk.
- /// builder to use.
- /// Callback action for configuring .
- /// The instance of to chain the calls.
-#if NET8_0_OR_GREATER
- [Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
- public
-#else
///
/// Adds an OTLP exporter to the LoggerProvider.
///
/// builder to use.
/// Callback action for configuring .
/// The instance of to chain the calls.
- internal
-#endif
- static LoggerProviderBuilder AddOtlpExporter(this LoggerProviderBuilder builder, Action configureExporter)
+ public static LoggerProviderBuilder AddOtlpExporter(this LoggerProviderBuilder builder, Action configureExporter)
=> AddOtlpExporter(builder, name: null, configureExporter);
-#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Adds an OTLP exporter to the LoggerProvider.
///
- /// WARNING: This is an experimental API which might change or be removed in the future. Use at your own risk.
/// builder to use.
/// Callback action for
/// configuring and .
/// The instance of to chain the calls.
-#if NET8_0_OR_GREATER
- [Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
- public
-#else
- internal
-#endif
- static LoggerProviderBuilder AddOtlpExporter(this LoggerProviderBuilder builder, Action configureExporterAndProcessor)
+ public static LoggerProviderBuilder AddOtlpExporter(this LoggerProviderBuilder builder, Action configureExporterAndProcessor)
=> AddOtlpExporter(builder, name: null, configureExporterAndProcessor);
-#if EXPOSE_EXPERIMENTAL_FEATURES
- ///
- /// Adds OpenTelemetry Protocol (OTLP) exporter to the LoggerProvider.
- ///
- /// WARNING: This is an experimental API which might change or be removed in the future. Use at your own risk.
- /// builder to use.
- /// Optional name which is used when retrieving options.
- /// Optional callback action for configuring .
- /// The instance of to chain the calls.
-#if NET8_0_OR_GREATER
- [Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
- public
-#else
///
/// Adds OpenTelemetry Protocol (OTLP) exporter to the LoggerProvider.
///
@@ -206,9 +154,7 @@ static LoggerProviderBuilder AddOtlpExporter(this LoggerProviderBuilder builder,
/// Optional name which is used when retrieving options.
/// Optional callback action for configuring .
/// The instance of to chain the calls.
- internal
-#endif
- static LoggerProviderBuilder AddOtlpExporter(
+ public static LoggerProviderBuilder AddOtlpExporter(
this LoggerProviderBuilder builder,
string? name,
Action? configureExporter)
@@ -265,22 +211,6 @@ static LoggerProviderBuilder AddOtlpExporter(
});
}
-#if EXPOSE_EXPERIMENTAL_FEATURES
- ///
- /// Adds an OTLP exporter to the LoggerProvider.
- ///
- /// WARNING: This is an experimental API which might change or be removed in the future. Use at your own risk.
- /// builder to use.
- /// Optional name which is used when retrieving options.
- /// Optional callback action for
- /// configuring and .
- /// The instance of to chain the calls.
-#if NET8_0_OR_GREATER
- [Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
- public
-#else
///
/// Adds an OTLP exporter to the LoggerProvider.
///
@@ -290,9 +220,7 @@ static LoggerProviderBuilder AddOtlpExporter(
/// configuring and .
/// The instance of to chain the calls.
- internal
-#endif
- static LoggerProviderBuilder AddOtlpExporter(
+ public static LoggerProviderBuilder AddOtlpExporter(
this LoggerProviderBuilder builder,
string? name,
Action? configureExporterAndProcessor)
@@ -358,7 +286,7 @@ internal static BaseProcessor BuildOtlpLogExporter(
if (!skipUseOtlpExporterRegistrationCheck)
{
- serviceProvider.EnsureNoUseOtlpExporterRegistrations();
+ serviceProvider!.EnsureNoUseOtlpExporterRegistrations();
}
/*
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporter.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporter.cs
index b2b0c3e576..aef2bdc4fe 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporter.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporter.cs
@@ -18,7 +18,7 @@ public class OtlpMetricExporter : BaseExporter
{
private readonly OtlpExporterTransmissionHandler transmissionHandler;
- private OtlpResource.Resource processResource;
+ private OtlpResource.Resource? processResource;
///
/// Initializes a new instance of the class.
@@ -38,12 +38,12 @@ public OtlpMetricExporter(OtlpExporterOptions options)
internal OtlpMetricExporter(
OtlpExporterOptions exporterOptions,
ExperimentalOptions experimentalOptions,
- OtlpExporterTransmissionHandler transmissionHandler = null)
+ OtlpExporterTransmissionHandler? transmissionHandler = null)
{
Debug.Assert(exporterOptions != null, "exporterOptions was null");
Debug.Assert(experimentalOptions != null, "experimentalOptions was null");
- this.transmissionHandler = transmissionHandler ?? exporterOptions.GetMetricsExportTransmissionHandler(experimentalOptions);
+ this.transmissionHandler = transmissionHandler ?? exporterOptions!.GetMetricsExportTransmissionHandler(experimentalOptions!);
}
internal OtlpResource.Resource ProcessResource => this.processResource ??= this.ParentProvider.GetResource().ToOtlpResource();
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs
index 57ad3dd47e..1a8ef2f1b4 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
@@ -172,12 +170,12 @@ internal static MetricReader BuildOtlpExporterMetricReader(
if (!skipUseOtlpExporterRegistrationCheck)
{
- serviceProvider.EnsureNoUseOtlpExporterRegistrations();
+ serviceProvider!.EnsureNoUseOtlpExporterRegistrations();
}
- exporterOptions.TryEnableIHttpClientFactoryIntegration(serviceProvider, "OtlpMetricExporter");
+ exporterOptions!.TryEnableIHttpClientFactoryIntegration(serviceProvider!, "OtlpMetricExporter");
- BaseExporter metricExporter = new OtlpMetricExporter(exporterOptions, experimentalOptions);
+ BaseExporter metricExporter = new OtlpMetricExporter(exporterOptions!, experimentalOptions!);
if (configureExporterInstance != null)
{
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporter.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporter.cs
index b02d348bd8..da92667e03 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporter.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporter.cs
@@ -18,7 +18,7 @@ public class OtlpTraceExporter : BaseExporter
private readonly SdkLimitOptions sdkLimitOptions;
private readonly OtlpExporterTransmissionHandler transmissionHandler;
- private OtlpResource.Resource processResource;
+ private OtlpResource.Resource? processResource;
///
/// Initializes a new instance of the class.
@@ -40,14 +40,14 @@ internal OtlpTraceExporter(
OtlpExporterOptions exporterOptions,
SdkLimitOptions sdkLimitOptions,
ExperimentalOptions experimentalOptions,
- OtlpExporterTransmissionHandler transmissionHandler = null)
+ OtlpExporterTransmissionHandler? transmissionHandler = null)
{
Debug.Assert(exporterOptions != null, "exporterOptions was null");
Debug.Assert(sdkLimitOptions != null, "sdkLimitOptions was null");
- this.sdkLimitOptions = sdkLimitOptions;
+ this.sdkLimitOptions = sdkLimitOptions!;
- this.transmissionHandler = transmissionHandler ?? exporterOptions.GetTraceExportTransmissionHandler(experimentalOptions);
+ this.transmissionHandler = transmissionHandler ?? exporterOptions!.GetTraceExportTransmissionHandler(experimentalOptions);
}
internal OtlpResource.Resource ProcessResource => this.processResource ??= this.ParentProvider.GetResource().ToOtlpResource();
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs
index 036e9a90dd..3a18b3da42 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
@@ -133,12 +131,12 @@ internal static BaseProcessor BuildOtlpExporterProcessor(
if (!skipUseOtlpExporterRegistrationCheck)
{
- serviceProvider.EnsureNoUseOtlpExporterRegistrations();
+ serviceProvider!.EnsureNoUseOtlpExporterRegistrations();
}
- exporterOptions.TryEnableIHttpClientFactoryIntegration(serviceProvider, "OtlpTraceExporter");
+ exporterOptions!.TryEnableIHttpClientFactoryIntegration(serviceProvider!, "OtlpTraceExporter");
- BaseExporter otlpExporter = new OtlpTraceExporter(exporterOptions, sdkLimitOptions, experimentalOptions);
+ BaseExporter otlpExporter = new OtlpTraceExporter(exporterOptions!, sdkLimitOptions!, experimentalOptions!);
if (configureExporterInstance != null)
{
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/DirectorySizeTracker.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/DirectorySizeTracker.cs
index a60715d185..2bbc352817 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/DirectorySizeTracker.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/DirectorySizeTracker.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.PersistentStorage.FileSystem;
///
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/FileBlob.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/FileBlob.cs
index 337c322624..cfb1c395d0 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/FileBlob.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/FileBlob.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics.CodeAnalysis;
using OpenTelemetry.Internal;
using OpenTelemetry.PersistentStorage.Abstractions;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/FileBlobProvider.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/FileBlobProvider.cs
index c9afdf34ce..4d79046995 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/FileBlobProvider.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/FileBlobProvider.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics.CodeAnalysis;
using System.Timers;
using OpenTelemetry.Internal;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/PersistentBlob.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/PersistentBlob.cs
index 2f0912feb7..aca1491ba2 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/PersistentBlob.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/PersistentBlob.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics.CodeAnalysis;
namespace OpenTelemetry.PersistentStorage.Abstractions;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/PersistentBlobProvider.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/PersistentBlobProvider.cs
index 5d4895f8d4..29d3dee8a0 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/PersistentBlobProvider.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/PersistentBlobProvider.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics.CodeAnalysis;
namespace OpenTelemetry.PersistentStorage.Abstractions;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/PersistentStorageHelper.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/PersistentStorageHelper.cs
index 538597dc18..63005646fc 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/PersistentStorageHelper.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/PersistentStorage/PersistentStorageHelper.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Globalization;
using System.Runtime.CompilerServices;
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/PublicAPI.Shipped.txt
index e69de29bb2..7dc5c58110 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/PublicAPI.Shipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/PublicAPI.Unshipped.txt
index 99d1e9e493..92eaa1e411 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/PublicAPI.Unshipped.txt
@@ -4,18 +4,18 @@ OpenTelemetry.Exporter.PrometheusAspNetCoreOptions
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.DisableTotalNameSuffixForCounters.get -> bool
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.DisableTotalNameSuffixForCounters.set -> void
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.PrometheusAspNetCoreOptions() -> void
-OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScrapeEndpointPath.get -> string
+OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScrapeEndpointPath.get -> string?
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScrapeEndpointPath.set -> void
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScrapeResponseCacheDurationMilliseconds.get -> int
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScrapeResponseCacheDurationMilliseconds.set -> void
OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions
-static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder app) -> Microsoft.AspNetCore.Builder.IApplicationBuilder
-static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder app, OpenTelemetry.Metrics.MeterProvider meterProvider, System.Func predicate, string path, System.Action configureBranchedPipeline, string optionsName) -> Microsoft.AspNetCore.Builder.IApplicationBuilder
-static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder app, string path) -> Microsoft.AspNetCore.Builder.IApplicationBuilder
-static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder app, System.Func predicate) -> Microsoft.AspNetCore.Builder.IApplicationBuilder
-static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder
-static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string path) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder
-static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string path, OpenTelemetry.Metrics.MeterProvider meterProvider, System.Action configureBranchedPipeline, string optionsName) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder
-static OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions.AddPrometheusExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions.AddPrometheusExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, string name, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions.AddPrometheusExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder
+static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app) -> Microsoft.AspNetCore.Builder.IApplicationBuilder!
+static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, OpenTelemetry.Metrics.MeterProvider? meterProvider, System.Func? predicate, string? path, System.Action? configureBranchedPipeline, string? optionsName) -> Microsoft.AspNetCore.Builder.IApplicationBuilder!
+static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, string! path) -> Microsoft.AspNetCore.Builder.IApplicationBuilder!
+static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, System.Func! predicate) -> Microsoft.AspNetCore.Builder.IApplicationBuilder!
+static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder! endpoints) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder!
+static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder! endpoints, string! path) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder!
+static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder! endpoints, string? path, OpenTelemetry.Metrics.MeterProvider? meterProvider, System.Action? configureBranchedPipeline, string? optionsName) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder!
+static OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions.AddPrometheusExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions.AddPrometheusExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, string? name, System.Action? configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions.AddPrometheusExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md
index 703074b0be..33cf84f17d 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md
@@ -1,7 +1,34 @@
# Changelog
+This file contains individual changes for the
+OpenTelemetry.Exporter.Prometheus.AspNetCore package. For highlights and
+announcements covering all components see: [Release
+Notes](../../RELEASENOTES.md).
+
## Unreleased
+* Added meter-level tags to Prometheus exporter
+ ([#5837](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5837))
+
+## 1.9.0-beta.2
+
+Released 2024-Jun-24
+
+* Fixed a bug which lead to empty responses when the internal buffer is resized
+ processing a collection request
+ ([#5676](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5676))
+
+## 1.9.0-beta.1
+
+Released 2024-Jun-14
+
+## 1.9.0-alpha.2
+
+Released 2024-May-29
+
+* Fixed issue with OpenMetrics suffixes for Prometheus
+ ([#5646](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5646))
+
## 1.9.0-alpha.1
Released 2024-May-20
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj
index a143d39ac1..f6a49fe6a6 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj
@@ -7,9 +7,6 @@
$(PackageTags);prometheus;metrics
coreunstable-
$(DefineConstants);PROMETHEUS_ASPNETCORE
-
-
- disable
@@ -25,7 +22,6 @@
-
@@ -36,6 +32,8 @@
+
+
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusAspNetCoreOptions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusAspNetCoreOptions.cs
index 75acb56517..ed8186ec88 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusAspNetCoreOptions.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusAspNetCoreOptions.cs
@@ -15,7 +15,7 @@ public class PrometheusAspNetCoreOptions
///
/// Gets or sets the path to use for the scraping endpoint. Default value: "/metrics".
///
- public string ScrapeEndpointPath { get; set; } = DefaultScrapeEndpointPath;
+ public string? ScrapeEndpointPath { get; set; } = DefaultScrapeEndpointPath;
///
/// Gets or sets a value indicating whether addition of _total suffix for counter metric names is disabled. Default value: .
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs
index 946f07d05a..38559e6b20 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs
@@ -93,11 +93,11 @@ public static IApplicationBuilder UseOpenTelemetryPrometheusScrapingEndpoint(thi
/// cref="IApplicationBuilder"/> for chaining calls.
public static IApplicationBuilder UseOpenTelemetryPrometheusScrapingEndpoint(
this IApplicationBuilder app,
- MeterProvider meterProvider,
- Func predicate,
- string path,
- Action configureBranchedPipeline,
- string optionsName)
+ MeterProvider? meterProvider,
+ Func? predicate,
+ string? path,
+ Action? configureBranchedPipeline,
+ string? optionsName)
{
// Note: Order is important here. MeterProvider is accessed before
// GetOptions so that any changes made to
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs
index 4e70f2f76c..45639b378f 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs
@@ -64,10 +64,10 @@ public static IEndpointConventionBuilder MapPrometheusScrapingEndpoint(this IEnd
/// A convention routes for the Prometheus scraping endpoint.
public static IEndpointConventionBuilder MapPrometheusScrapingEndpoint(
this IEndpointRouteBuilder endpoints,
- string path,
- MeterProvider meterProvider,
- Action configureBranchedPipeline,
- string optionsName)
+ string? path,
+ MeterProvider? meterProvider,
+ Action? configureBranchedPipeline,
+ string? optionsName)
{
var builder = endpoints.CreateApplicationBuilder();
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs
index 6a075fc1b9..f73455d3b0 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs
@@ -37,13 +37,13 @@ public static MeterProviderBuilder AddPrometheusExporter(
/// Adds to the .
///
/// builder to use.
- /// Name which is used when retrieving options.
- /// Callback action for configuring .
+ /// Optional name which is used when retrieving options.
+ /// Optional callback action for configuring .
/// The instance of to chain the calls.
public static MeterProviderBuilder AddPrometheusExporter(
this MeterProviderBuilder builder,
- string name,
- Action configure)
+ string? name,
+ Action? configure)
{
Guard.ThrowIfNull(builder);
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs
index fdfcd2b711..f91a93f66b 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs
@@ -25,8 +25,9 @@ internal sealed class PrometheusExporterMiddleware
public PrometheusExporterMiddleware(MeterProvider meterProvider, RequestDelegate next)
{
Guard.ThrowIfNull(meterProvider);
+ Guard.ThrowIfNull(next);
- if (!meterProvider.TryFindExporter(out PrometheusExporter exporter))
+ if (!meterProvider.TryFindExporter(out PrometheusExporter? exporter))
{
throw new ArgumentException("A PrometheusExporter could not be found configured on the provided MeterProvider.");
}
@@ -36,6 +37,8 @@ public PrometheusExporterMiddleware(MeterProvider meterProvider, RequestDelegate
internal PrometheusExporterMiddleware(PrometheusExporter exporter)
{
+ Debug.Assert(exporter != null, "exporter was null");
+
this.exporter = exporter;
}
@@ -62,7 +65,7 @@ public async Task InvokeAsync(HttpContext httpContext)
if (dataView.Count > 0)
{
response.StatusCode = 200;
-#if NET8_0_OR_GREATER
+#if NET
response.Headers.Append("Last-Modified", collectionResponse.GeneratedAtUtc.ToString("R"));
#else
response.Headers.Add("Last-Modified", collectionResponse.GeneratedAtUtc.ToString("R"));
@@ -71,7 +74,7 @@ public async Task InvokeAsync(HttpContext httpContext)
? "application/openmetrics-text; version=1.0.0; charset=utf-8"
: "text/plain; charset=utf-8; version=0.0.4";
- await response.Body.WriteAsync(dataView.Array, 0, dataView.Count).ConfigureAwait(false);
+ await response.Body.WriteAsync(dataView.Array!, 0, dataView.Count).ConfigureAwait(false);
}
else
{
@@ -93,8 +96,6 @@ public async Task InvokeAsync(HttpContext httpContext)
response.StatusCode = 500;
}
}
-
- this.exporter.OnExport = null;
}
private static bool AcceptsOpenMetrics(HttpRequest request)
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/PublicAPI.Shipped.txt
index e69de29bb2..7dc5c58110 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/PublicAPI.Shipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/PublicAPI.Unshipped.txt
index d05f12424e..6caa1a77cb 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/PublicAPI.Unshipped.txt
@@ -1,12 +1,12 @@
OpenTelemetry.Exporter.PrometheusHttpListenerOptions
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.DisableTotalNameSuffixForCounters.get -> bool
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.DisableTotalNameSuffixForCounters.set -> void
-OpenTelemetry.Exporter.PrometheusHttpListenerOptions.UriPrefixes.get -> System.Collections.Generic.IReadOnlyCollection
+OpenTelemetry.Exporter.PrometheusHttpListenerOptions.UriPrefixes.get -> System.Collections.Generic.IReadOnlyCollection!
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.UriPrefixes.set -> void
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void
-OpenTelemetry.Exporter.PrometheusHttpListenerOptions.ScrapeEndpointPath.get -> string
+OpenTelemetry.Exporter.PrometheusHttpListenerOptions.ScrapeEndpointPath.get -> string?
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.ScrapeEndpointPath.set -> void
OpenTelemetry.Metrics.PrometheusHttpListenerMeterProviderBuilderExtensions
-static OpenTelemetry.Metrics.PrometheusHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.PrometheusHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder, string name, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder
-static OpenTelemetry.Metrics.PrometheusHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder
+static OpenTelemetry.Metrics.PrometheusHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder! builder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.PrometheusHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, string? name, System.Action? configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+static OpenTelemetry.Metrics.PrometheusHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder! builder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md
index abb4d7287f..5873577fb8 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md
@@ -1,7 +1,34 @@
# Changelog
+This file contains individual changes for the
+OpenTelemetry.Exporter.Prometheus.HttpListener package. For highlights and
+announcements covering all components see: [Release
+Notes](../../RELEASENOTES.md).
+
## Unreleased
+* Added meter-level tags to Prometheus exporter
+ ([#5837](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5837))
+
+## 1.9.0-beta.2
+
+Released 2024-Jun-24
+
+* Fixed a bug which lead to empty responses when the internal buffer is resized
+ processing a collection request
+ ([#5676](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5676))
+
+## 1.9.0-beta.1
+
+Released 2024-Jun-14
+
+## 1.9.0-alpha.2
+
+Released 2024-May-29
+
+* Fixed issue with OpenMetrics suffixes for Prometheus
+ ([#5646](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5646))
+
## 1.9.0-alpha.1
Released 2024-May-20
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs
index b93812176f..1c74e36bcf 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs
@@ -1,6 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
+using System.Diagnostics;
using System.Runtime.CompilerServices;
using OpenTelemetry.Metrics;
@@ -12,7 +13,7 @@ internal sealed class PrometheusCollectionManager
private readonly PrometheusExporter exporter;
private readonly int scrapeResponseCacheDurationMilliseconds;
- private readonly Func, ExportResult> onCollectRef;
+ private readonly PrometheusExporter.ExportFunc onCollectRef;
private readonly Dictionary metricsCache;
private readonly HashSet scopes;
private int metricsCacheCount;
@@ -26,7 +27,7 @@ internal sealed class PrometheusCollectionManager
private DateTime? previousOpenMetricsDataViewGeneratedAtUtc;
private int readerCount;
private bool collectionRunning;
- private TaskCompletionSource collectionTcs;
+ private TaskCompletionSource? collectionTcs;
public PrometheusCollectionManager(PrometheusExporter exporter)
{
@@ -37,7 +38,7 @@ public PrometheusCollectionManager(PrometheusExporter exporter)
this.scopes = new HashSet();
}
-#if NET6_0_OR_GREATER
+#if NET
public ValueTask EnterCollect(bool openMetricsRequested)
#else
public Task EnterCollect(bool openMetricsRequested)
@@ -57,7 +58,7 @@ public Task EnterCollect(bool openMetricsRequested)
{
Interlocked.Increment(ref this.readerCount);
this.ExitGlobalLock();
-#if NET6_0_OR_GREATER
+#if NET
return new ValueTask(new CollectionResponse(this.previousOpenMetricsDataView, this.previousPlainTextDataView, previousDataViewGeneratedAtUtc.Value, fromCache: true));
#else
return Task.FromResult(new CollectionResponse(this.previousOpenMetricsDataView, this.previousPlainTextDataView, previousDataViewGeneratedAtUtc.Value, fromCache: true));
@@ -74,7 +75,7 @@ public Task EnterCollect(bool openMetricsRequested)
Interlocked.Increment(ref this.readerCount);
this.ExitGlobalLock();
-#if NET6_0_OR_GREATER
+#if NET
return new ValueTask(this.collectionTcs.Task);
#else
return this.collectionTcs.Task;
@@ -115,7 +116,7 @@ public Task EnterCollect(bool openMetricsRequested)
? this.previousOpenMetricsDataViewGeneratedAtUtc
: this.previousPlainTextDataViewGeneratedAtUtc;
- response = new CollectionResponse(this.previousOpenMetricsDataView, this.previousPlainTextDataView, previousDataViewGeneratedAtUtc.Value, fromCache: false);
+ response = new CollectionResponse(this.previousOpenMetricsDataView, this.previousPlainTextDataView, previousDataViewGeneratedAtUtc!.Value, fromCache: false);
}
else
{
@@ -134,7 +135,7 @@ public Task EnterCollect(bool openMetricsRequested)
this.ExitGlobalLock();
-#if NET6_0_OR_GREATER
+#if NET
return new ValueTask(response);
#else
return Task.FromResult(response);
@@ -188,23 +189,25 @@ private void WaitForReadersToComplete()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool ExecuteCollect(bool openMetricsRequested)
{
+ Debug.Assert(this.exporter.Collect != null, "this.exporter.Collect was null");
+
this.exporter.OnExport = this.onCollectRef;
this.exporter.OpenMetricsRequested = openMetricsRequested;
- var result = this.exporter.Collect(Timeout.Infinite);
+ var result = this.exporter.Collect!(Timeout.Infinite);
this.exporter.OnExport = null;
return result;
}
- private ExportResult OnCollect(Batch metrics)
+ private ExportResult OnCollect(in Batch metrics)
{
var cursor = 0;
- var buffer = this.exporter.OpenMetricsRequested ? this.openMetricsBuffer : this.plainTextBuffer;
+ ref byte[] buffer = ref (this.exporter.OpenMetricsRequested ? ref this.openMetricsBuffer : ref this.plainTextBuffer);
try
{
if (this.exporter.OpenMetricsRequested)
{
- cursor = this.WriteTargetInfo();
+ cursor = this.WriteTargetInfo(ref buffer);
this.scopes.Clear();
@@ -291,11 +294,11 @@ private ExportResult OnCollect(Batch metrics)
if (this.exporter.OpenMetricsRequested)
{
- this.previousOpenMetricsDataView = new ArraySegment(this.openMetricsBuffer, 0, cursor);
+ this.previousOpenMetricsDataView = new ArraySegment(buffer, 0, cursor);
}
else
{
- this.previousPlainTextDataView = new ArraySegment(this.plainTextBuffer, 0, cursor);
+ this.previousPlainTextDataView = new ArraySegment(buffer, 0, cursor);
}
return ExportResult.Success;
@@ -315,7 +318,7 @@ private ExportResult OnCollect(Batch metrics)
}
}
- private int WriteTargetInfo()
+ private int WriteTargetInfo(ref byte[] buffer)
{
if (this.targetInfoBufferLength < 0)
{
@@ -323,13 +326,13 @@ private int WriteTargetInfo()
{
try
{
- this.targetInfoBufferLength = PrometheusSerializer.WriteTargetInfo(this.openMetricsBuffer, 0, this.exporter.Resource);
+ this.targetInfoBufferLength = PrometheusSerializer.WriteTargetInfo(buffer, 0, this.exporter.Resource);
break;
}
catch (IndexOutOfRangeException)
{
- if (!this.IncreaseBufferSize(ref this.openMetricsBuffer))
+ if (!this.IncreaseBufferSize(ref buffer))
{
throw;
}
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporter.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporter.cs
index 292b0aa7c3..c5b0e0e64d 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporter.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporter.cs
@@ -1,6 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
+using System.Diagnostics;
using OpenTelemetry.Internal;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
@@ -13,9 +14,9 @@ namespace OpenTelemetry.Exporter.Prometheus;
[ExportModes(ExportModes.Pull)]
internal sealed class PrometheusExporter : BaseExporter, IPullMetricExporter
{
- private Func funcCollect;
- private Func, ExportResult> funcExport;
- private Resource resource;
+ private Func? funcCollect;
+ private ExportFunc? funcExport;
+ private Resource? resource;
private bool disposed;
///
@@ -32,22 +33,24 @@ public PrometheusExporter(PrometheusExporterOptions options)
this.CollectionManager = new PrometheusCollectionManager(this);
}
+ public delegate ExportResult ExportFunc(in Batch batch);
+
///
/// Gets or sets the Collect delegate.
///
- public Func Collect
+ public Func? Collect
{
get => this.funcCollect;
set => this.funcCollect = value;
}
- internal Func, ExportResult> OnExport
+ internal ExportFunc? OnExport
{
get => this.funcExport;
set => this.funcExport = value;
}
- internal Action OnDispose { get; set; }
+ internal Action? OnDispose { get; set; }
internal PrometheusCollectionManager CollectionManager { get; }
@@ -62,7 +65,9 @@ internal Func, ExportResult> OnExport
///
public override ExportResult Export(in Batch metrics)
{
- return this.OnExport(metrics);
+ Debug.Assert(this.OnExport != null, "this.OnExport was null");
+
+ return this.OnExport!(in metrics);
}
///
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusHeadersParser.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusHeadersParser.cs
index 81576b723d..2c2c8f5b7d 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusHeadersParser.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusHeadersParser.cs
@@ -7,7 +7,7 @@ internal static class PrometheusHeadersParser
{
private const string OpenMetricsMediaType = "application/openmetrics-text";
- internal static bool AcceptsOpenMetrics(string contentType)
+ internal static bool AcceptsOpenMetrics(string? contentType)
{
var value = contentType.AsSpan();
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusMetric.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusMetric.cs
index a39a426136..800963454a 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusMetric.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusMetric.cs
@@ -1,6 +1,8 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Text;
using OpenTelemetry.Metrics;
@@ -27,47 +29,60 @@ public PrometheusMetric(string name, string unit, PrometheusType type, bool disa
// consecutive `_` characters MUST be replaced with a single `_` character.
// https://github.com/open-telemetry/opentelemetry-specification/blob/b2f923fb1650dde1f061507908b834035506a796/specification/compatibility/prometheus_and_openmetrics.md#L230-L233
var sanitizedName = SanitizeMetricName(name);
+ var openMetricsName = SanitizeOpenMetricsName(sanitizedName);
- string sanitizedUnit = null;
+ string? sanitizedUnit = null;
if (!string.IsNullOrEmpty(unit))
{
sanitizedUnit = GetUnit(unit);
// The resulting unit SHOULD be added to the metric as
// [OpenMetrics UNIT metadata](https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#metricfamily)
- // and as a suffix to the metric name unless the metric name already contains the
- // unit, or the unit MUST be omitted. The unit suffix comes before any
- // type-specific suffixes.
- // https://github.com/open-telemetry/opentelemetry-specification/blob/b2f923fb1650dde1f061507908b834035506a796/specification/compatibility/prometheus_and_openmetrics.md#L242-L246
- if (!sanitizedName.Contains(sanitizedUnit))
+ // and as a suffix to the metric name. The unit suffix comes before any type-specific suffixes.
+ // https://github.com/open-telemetry/opentelemetry-specification/blob/3dfb383fe583e3b74a2365c5a1d90256b273ee76/specification/compatibility/prometheus_and_openmetrics.md#metric-metadata-1
+ if (!sanitizedName.EndsWith(sanitizedUnit))
{
- sanitizedName = sanitizedName + "_" + sanitizedUnit;
+ sanitizedName += $"_{sanitizedUnit}";
+ openMetricsName += $"_{sanitizedUnit}";
}
}
// If the metric name for monotonic Sum metric points does not end in a suffix of `_total` a suffix of `_total` MUST be added by default, otherwise the name MUST remain unchanged.
// Exporters SHOULD provide a configuration option to disable the addition of `_total` suffixes.
// https://github.com/open-telemetry/opentelemetry-specification/blob/b2f923fb1650dde1f061507908b834035506a796/specification/compatibility/prometheus_and_openmetrics.md#L286
+ // Note that we no longer append '_ratio' for units that are '1', see: https://github.com/open-telemetry/opentelemetry-specification/issues/4058
if (type == PrometheusType.Counter && !sanitizedName.EndsWith("_total") && !disableTotalNameSuffixForCounters)
{
sanitizedName += "_total";
}
- // Special case: Converting "1" to "ratio".
- // https://github.com/open-telemetry/opentelemetry-specification/blob/b2f923fb1650dde1f061507908b834035506a796/specification/compatibility/prometheus_and_openmetrics.md#L239
- if (type == PrometheusType.Gauge && unit == "1" && !sanitizedName.Contains("ratio"))
+ // For counters requested using OpenMetrics format, the MetricFamily name MUST be suffixed with '_total', regardless of the setting to disable the 'total' suffix.
+ // https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#counter-1
+ if (type == PrometheusType.Counter && !openMetricsName.EndsWith("_total"))
{
- sanitizedName += "_ratio";
+ openMetricsName += "_total";
}
+ // In OpenMetrics format, the UNIT, TYPE and HELP metadata must be suffixed with the unit (handled above), and not the '_total' suffix, as in the case for counters.
+ // https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#unit
+ var openMetricsMetadataName = type == PrometheusType.Counter
+ ? SanitizeOpenMetricsName(openMetricsName)
+ : sanitizedName;
+
this.Name = sanitizedName;
+ this.OpenMetricsName = openMetricsName;
+ this.OpenMetricsMetadataName = openMetricsMetadataName;
this.Unit = sanitizedUnit;
this.Type = type;
}
public string Name { get; }
- public string Unit { get; }
+ public string OpenMetricsName { get; }
+
+ public string OpenMetricsMetadataName { get; }
+
+ public string? Unit { get; }
public PrometheusType Type { get; }
@@ -78,7 +93,7 @@ public static PrometheusMetric Create(Metric metric, bool disableTotalNameSuffix
internal static string SanitizeMetricName(string metricName)
{
- StringBuilder sb = null;
+ StringBuilder? sb = null;
var lastCharUnderscore = false;
for (var i = 0; i < metricName.Length; i++)
@@ -121,7 +136,7 @@ internal static string RemoveAnnotations(string unit)
// https://ucum.org/ucum#section-Character-Set-and-Lexical-Rules
// What should happen if they are nested isn't defined.
// Right now the remove annotations code doesn't attempt to balance multiple start and end braces.
- StringBuilder sb = null;
+ StringBuilder? sb = null;
var hasOpenBrace = false;
var startOpenBraceIndex = 0;
@@ -155,10 +170,23 @@ internal static string RemoveAnnotations(string unit)
return unit;
}
- sb.Append(unit, lastWriteIndex, unit.Length - lastWriteIndex);
+ Debug.Assert(sb != null, "sb was null");
+
+ sb!.Append(unit, lastWriteIndex, unit.Length - lastWriteIndex);
+
return sb.ToString();
}
+ private static string SanitizeOpenMetricsName(string metricName)
+ {
+ if (metricName.EndsWith("_total"))
+ {
+ return metricName.Substring(0, metricName.Length - 6);
+ }
+
+ return metricName;
+ }
+
private static string GetUnit(string unit)
{
// Dropping the portions of the Unit within brackets (e.g. {packet}). Brackets MUST NOT be included in the resulting unit. A "count of foo" is considered unitless in Prometheus.
@@ -181,7 +209,7 @@ private static string GetUnit(string unit)
return updatedUnit;
}
- private static bool TryProcessRateUnits(string updatedUnit, out string updatedPerUnit)
+ private static bool TryProcessRateUnits(string updatedUnit, [NotNullWhen(true)] out string? updatedPerUnit)
{
updatedPerUnit = null;
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs
index 719f21a0c6..b182b52150 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs
@@ -28,7 +28,7 @@ public static int WriteDouble(byte[] buffer, int cursor, double value)
{
if (MathHelper.IsFinite(value))
{
-#if NET6_0_OR_GREATER
+#if NET
Span span = stackalloc char[128];
var result = value.TryFormat(span, out var cchWritten, "G", CultureInfo.InvariantCulture);
@@ -62,7 +62,7 @@ public static int WriteDouble(byte[] buffer, int cursor, double value)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int WriteLong(byte[] buffer, int cursor, long value)
{
-#if NET6_0_OR_GREATER
+#if NET
Span span = stackalloc char[20];
var result = value.TryFormat(span, out var cchWritten, "G", CultureInfo.InvariantCulture);
@@ -177,7 +177,7 @@ public static int WriteLabelValue(byte[] buffer, int cursor, string value)
{
Debug.Assert(value != null, $"{nameof(value)} should not be null.");
- for (int i = 0; i < value.Length; i++)
+ for (int i = 0; i < value!.Length; i++)
{
var ordinal = (ushort)value[i];
switch (ordinal)
@@ -204,7 +204,7 @@ public static int WriteLabelValue(byte[] buffer, int cursor, string value)
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int WriteLabel(byte[] buffer, int cursor, string labelKey, object labelValue)
+ public static int WriteLabel(byte[] buffer, int cursor, string labelKey, object? labelValue)
{
cursor = WriteLabelKey(buffer, cursor, labelKey);
buffer[cursor++] = unchecked((byte)'=');
@@ -216,7 +216,7 @@ public static int WriteLabel(byte[] buffer, int cursor, string labelKey, object
return cursor;
- static string GetLabelValueString(object labelValue)
+ static string GetLabelValueString(object? labelValue)
{
// TODO: Attribute values should be written as their JSON representation. Extra logic may need to be added here to correctly convert other .NET types.
// More detail: https://github.com/open-telemetry/opentelemetry-dotnet/issues/4822#issuecomment-1707328495
@@ -230,12 +230,33 @@ static string GetLabelValueString(object labelValue)
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int WriteMetricName(byte[] buffer, int cursor, PrometheusMetric metric)
+ public static int WriteMetricName(byte[] buffer, int cursor, PrometheusMetric metric, bool openMetricsRequested)
+ {
+ // Metric name has already been escaped.
+ var name = openMetricsRequested ? metric.OpenMetricsName : metric.Name;
+
+ Debug.Assert(!string.IsNullOrWhiteSpace(name), "name was null or whitespace");
+
+ for (int i = 0; i < name.Length; i++)
+ {
+ var ordinal = (ushort)name[i];
+ buffer[cursor++] = unchecked((byte)ordinal);
+ }
+
+ return cursor;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int WriteMetricMetadataName(byte[] buffer, int cursor, PrometheusMetric metric, bool openMetricsRequested)
{
// Metric name has already been escaped.
- for (int i = 0; i < metric.Name.Length; i++)
+ var name = openMetricsRequested ? metric.OpenMetricsMetadataName : metric.Name;
+
+ Debug.Assert(!string.IsNullOrWhiteSpace(name), "name was null or whitespace");
+
+ for (int i = 0; i < name.Length; i++)
{
- var ordinal = (ushort)metric.Name[i];
+ var ordinal = (ushort)name[i];
buffer[cursor++] = unchecked((byte)ordinal);
}
@@ -252,7 +273,7 @@ public static int WriteEof(byte[] buffer, int cursor)
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int WriteHelpMetadata(byte[] buffer, int cursor, PrometheusMetric metric, string metricDescription)
+ public static int WriteHelpMetadata(byte[] buffer, int cursor, PrometheusMetric metric, string metricDescription, bool openMetricsRequested)
{
if (string.IsNullOrEmpty(metricDescription))
{
@@ -260,7 +281,7 @@ public static int WriteHelpMetadata(byte[] buffer, int cursor, PrometheusMetric
}
cursor = WriteAsciiStringNoEscape(buffer, cursor, "# HELP ");
- cursor = WriteMetricName(buffer, cursor, metric);
+ cursor = WriteMetricMetadataName(buffer, cursor, metric, openMetricsRequested);
if (!string.IsNullOrEmpty(metricDescription))
{
@@ -274,14 +295,14 @@ public static int WriteHelpMetadata(byte[] buffer, int cursor, PrometheusMetric
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int WriteTypeMetadata(byte[] buffer, int cursor, PrometheusMetric metric)
+ public static int WriteTypeMetadata(byte[] buffer, int cursor, PrometheusMetric metric, bool openMetricsRequested)
{
var metricType = MapPrometheusType(metric.Type);
Debug.Assert(!string.IsNullOrEmpty(metricType), $"{nameof(metricType)} should not be null or empty.");
cursor = WriteAsciiStringNoEscape(buffer, cursor, "# TYPE ");
- cursor = WriteMetricName(buffer, cursor, metric);
+ cursor = WriteMetricMetadataName(buffer, cursor, metric, openMetricsRequested);
buffer[cursor++] = unchecked((byte)' ');
cursor = WriteAsciiStringNoEscape(buffer, cursor, metricType);
@@ -291,7 +312,7 @@ public static int WriteTypeMetadata(byte[] buffer, int cursor, PrometheusMetric
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int WriteUnitMetadata(byte[] buffer, int cursor, PrometheusMetric metric)
+ public static int WriteUnitMetadata(byte[] buffer, int cursor, PrometheusMetric metric, bool openMetricsRequested)
{
if (string.IsNullOrEmpty(metric.Unit))
{
@@ -299,12 +320,12 @@ public static int WriteUnitMetadata(byte[] buffer, int cursor, PrometheusMetric
}
cursor = WriteAsciiStringNoEscape(buffer, cursor, "# UNIT ");
- cursor = WriteMetricName(buffer, cursor, metric);
+ cursor = WriteMetricMetadataName(buffer, cursor, metric, openMetricsRequested);
buffer[cursor++] = unchecked((byte)' ');
// Unit name has already been escaped.
- for (int i = 0; i < metric.Unit.Length; i++)
+ for (int i = 0; i < metric.Unit!.Length; i++)
{
var ordinal = (ushort)metric.Unit[i];
buffer[cursor++] = unchecked((byte)ordinal);
@@ -383,6 +404,15 @@ public static int WriteTags(byte[] buffer, int cursor, Metric metric, ReadOnlyTa
buffer[cursor++] = unchecked((byte)',');
}
+ if (metric.MeterTags != null)
+ {
+ foreach (var tag in metric.MeterTags)
+ {
+ cursor = WriteLabel(buffer, cursor, tag.Key, tag.Value);
+ buffer[cursor++] = unchecked((byte)',');
+ }
+ }
+
foreach (var tag in tags)
{
cursor = WriteLabel(buffer, cursor, tag.Key, tag.Value);
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializerExt.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializerExt.cs
index 1523ef7c16..70d67f468b 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializerExt.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializerExt.cs
@@ -24,9 +24,9 @@ public static bool CanWriteMetric(Metric metric)
public static int WriteMetric(byte[] buffer, int cursor, Metric metric, PrometheusMetric prometheusMetric, bool openMetricsRequested = false)
{
- cursor = WriteTypeMetadata(buffer, cursor, prometheusMetric);
- cursor = WriteUnitMetadata(buffer, cursor, prometheusMetric);
- cursor = WriteHelpMetadata(buffer, cursor, prometheusMetric, metric.Description);
+ cursor = WriteTypeMetadata(buffer, cursor, prometheusMetric, openMetricsRequested);
+ cursor = WriteUnitMetadata(buffer, cursor, prometheusMetric, openMetricsRequested);
+ cursor = WriteHelpMetadata(buffer, cursor, prometheusMetric, metric.Description, openMetricsRequested);
if (!metric.MetricType.IsHistogram())
{
@@ -35,7 +35,7 @@ public static int WriteMetric(byte[] buffer, int cursor, Metric metric, Promethe
var timestamp = metricPoint.EndTime.ToUnixTimeMilliseconds();
// Counter and Gauge
- cursor = WriteMetricName(buffer, cursor, prometheusMetric);
+ cursor = WriteMetricName(buffer, cursor, prometheusMetric, openMetricsRequested);
cursor = WriteTags(buffer, cursor, metric, metricPoint.Tags);
buffer[cursor++] = unchecked((byte)' ');
@@ -85,7 +85,7 @@ public static int WriteMetric(byte[] buffer, int cursor, Metric metric, Promethe
{
totalCount += histogramMeasurement.BucketCount;
- cursor = WriteMetricName(buffer, cursor, prometheusMetric);
+ cursor = WriteMetricName(buffer, cursor, prometheusMetric, openMetricsRequested);
cursor = WriteAsciiStringNoEscape(buffer, cursor, "_bucket{");
cursor = WriteTags(buffer, cursor, metric, tags, writeEnclosingBraces: false);
@@ -111,7 +111,7 @@ public static int WriteMetric(byte[] buffer, int cursor, Metric metric, Promethe
}
// Histogram sum
- cursor = WriteMetricName(buffer, cursor, prometheusMetric);
+ cursor = WriteMetricName(buffer, cursor, prometheusMetric, openMetricsRequested);
cursor = WriteAsciiStringNoEscape(buffer, cursor, "_sum");
cursor = WriteTags(buffer, cursor, metric, metricPoint.Tags);
@@ -125,7 +125,7 @@ public static int WriteMetric(byte[] buffer, int cursor, Metric metric, Promethe
buffer[cursor++] = ASCII_LINEFEED;
// Histogram count
- cursor = WriteMetricName(buffer, cursor, prometheusMetric);
+ cursor = WriteMetricName(buffer, cursor, prometheusMetric, openMetricsRequested);
cursor = WriteAsciiStringNoEscape(buffer, cursor, "_count");
cursor = WriteTags(buffer, cursor, metric, metricPoint.Tags);
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj
index 3766816a7e..4e087919be 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj
@@ -5,9 +5,6 @@
Stand-alone HttpListener for hosting OpenTelemetry .NET Prometheus Exporter
$(PackageTags);prometheus;metrics
coreunstable-
-
-
- disable
@@ -19,9 +16,11 @@
+
-
+
+
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs
index 8576873f52..cecda73f7c 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs
@@ -11,10 +11,10 @@ internal sealed class PrometheusHttpListener : IDisposable
{
private readonly PrometheusExporter exporter;
private readonly HttpListener httpListener = new();
- private readonly object syncObject = new();
+ private readonly Lock syncObject = new();
- private CancellationTokenSource tokenSource;
- private Task workerThread;
+ private CancellationTokenSource? tokenSource;
+ private Task? workerThread;
///
/// Initializes a new instance of the class.
@@ -28,7 +28,7 @@ public PrometheusHttpListener(PrometheusExporter exporter, PrometheusHttpListene
this.exporter = exporter;
- string path = options.ScrapeEndpointPath;
+ string path = options.ScrapeEndpointPath ?? PrometheusHttpListenerOptions.DefaultScrapeEndpointPath;
if (!path.StartsWith("/"))
{
@@ -83,7 +83,7 @@ public void Stop()
}
this.tokenSource.Cancel();
- this.workerThread.Wait();
+ this.workerThread!.Wait();
this.tokenSource = null;
}
}
@@ -116,7 +116,7 @@ private void WorkerProc()
try
{
using var scope = SuppressInstrumentationScope.Begin();
- while (!this.tokenSource.IsCancellationRequested)
+ while (!this.tokenSource!.IsCancellationRequested)
{
var ctxTask = this.httpListener.GetContextAsync();
ctxTask.Wait(this.tokenSource.Token);
@@ -164,7 +164,7 @@ private async Task ProcessRequestAsync(HttpListenerContext context)
? "application/openmetrics-text; version=1.0.0; charset=utf-8"
: "text/plain; charset=utf-8; version=0.0.4";
- await context.Response.OutputStream.WriteAsync(dataView.Array, 0, dataView.Count).ConfigureAwait(false);
+ await context.Response.OutputStream.WriteAsync(dataView.Array!, 0, dataView.Count).ConfigureAwait(false);
}
else
{
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs
index 929774a11f..7289432cdc 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs
@@ -37,13 +37,13 @@ public static MeterProviderBuilder AddPrometheusHttpListener(
/// Adds PrometheusHttpListener to MeterProviderBuilder.
///
/// builder to use.
- /// Name which is used when retrieving options.
- /// Callback action for configuring .
+ /// Optional name which is used when retrieving options.
+ /// Optional callback action for configuring .
/// The instance of to chain calls.
public static MeterProviderBuilder AddPrometheusHttpListener(
this MeterProviderBuilder builder,
- string name,
- Action configure)
+ string? name,
+ Action? configure)
{
Guard.ThrowIfNull(builder);
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs
index d0c6bd2edf..dbe20b726c 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs
@@ -10,12 +10,14 @@ namespace OpenTelemetry.Exporter;
///
public class PrometheusHttpListenerOptions
{
+ internal const string DefaultScrapeEndpointPath = "/metrics";
+
private IReadOnlyCollection uriPrefixes = new[] { "http://localhost:9464/" };
///
/// Gets or sets the path to use for the scraping endpoint. Default value: "/metrics".
///
- public string ScrapeEndpointPath { get; set; } = "/metrics";
+ public string? ScrapeEndpointPath { get; set; } = DefaultScrapeEndpointPath;
///
/// Gets or sets a value indicating whether addition of _total suffix for counter metric names is disabled. Default value: .
diff --git a/src/OpenTelemetry.Exporter.Zipkin/.publicApi/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Zipkin/.publicApi/PublicAPI.Shipped.txt
index 9e2e613e19..2e1bf086dc 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/.publicApi/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Exporter.Zipkin/.publicApi/PublicAPI.Shipped.txt
@@ -1,13 +1,14 @@
+#nullable enable
OpenTelemetry.Exporter.ZipkinExporter
-OpenTelemetry.Exporter.ZipkinExporter.ZipkinExporter(OpenTelemetry.Exporter.ZipkinExporterOptions options, System.Net.Http.HttpClient client = null) -> void
+OpenTelemetry.Exporter.ZipkinExporter.ZipkinExporter(OpenTelemetry.Exporter.ZipkinExporterOptions! options, System.Net.Http.HttpClient? client = null) -> void
OpenTelemetry.Exporter.ZipkinExporterOptions
-OpenTelemetry.Exporter.ZipkinExporterOptions.BatchExportProcessorOptions.get -> OpenTelemetry.BatchExportProcessorOptions
OpenTelemetry.Exporter.ZipkinExporterOptions.BatchExportProcessorOptions.set -> void
-OpenTelemetry.Exporter.ZipkinExporterOptions.Endpoint.get -> System.Uri
+OpenTelemetry.Exporter.ZipkinExporterOptions.BatchExportProcessorOptions.get -> OpenTelemetry.BatchExportProcessorOptions!
+OpenTelemetry.Exporter.ZipkinExporterOptions.HttpClientFactory.get -> System.Func!
+OpenTelemetry.Exporter.ZipkinExporterOptions.Endpoint.get -> System.Uri!
OpenTelemetry.Exporter.ZipkinExporterOptions.Endpoint.set -> void
OpenTelemetry.Exporter.ZipkinExporterOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType
OpenTelemetry.Exporter.ZipkinExporterOptions.ExportProcessorType.set -> void
-OpenTelemetry.Exporter.ZipkinExporterOptions.HttpClientFactory.get -> System.Func
OpenTelemetry.Exporter.ZipkinExporterOptions.HttpClientFactory.set -> void
OpenTelemetry.Exporter.ZipkinExporterOptions.MaxPayloadSizeInBytes.get -> int?
OpenTelemetry.Exporter.ZipkinExporterOptions.MaxPayloadSizeInBytes.set -> void
@@ -15,7 +16,7 @@ OpenTelemetry.Exporter.ZipkinExporterOptions.UseShortTraceIds.get -> bool
OpenTelemetry.Exporter.ZipkinExporterOptions.UseShortTraceIds.set -> void
OpenTelemetry.Exporter.ZipkinExporterOptions.ZipkinExporterOptions() -> void
OpenTelemetry.Trace.ZipkinExporterHelperExtensions
-override OpenTelemetry.Exporter.ZipkinExporter.Export(in OpenTelemetry.Batch batch) -> OpenTelemetry.ExportResult
-static OpenTelemetry.Trace.ZipkinExporterHelperExtensions.AddZipkinExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder) -> OpenTelemetry.Trace.TracerProviderBuilder
-static OpenTelemetry.Trace.ZipkinExporterHelperExtensions.AddZipkinExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, string name, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder
-static OpenTelemetry.Trace.ZipkinExporterHelperExtensions.AddZipkinExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder
+override OpenTelemetry.Exporter.ZipkinExporter.Export(in OpenTelemetry.Batch batch) -> OpenTelemetry.ExportResult
+static OpenTelemetry.Trace.ZipkinExporterHelperExtensions.AddZipkinExporter(this OpenTelemetry.Trace.TracerProviderBuilder! builder) -> OpenTelemetry.Trace.TracerProviderBuilder!
+static OpenTelemetry.Trace.ZipkinExporterHelperExtensions.AddZipkinExporter(this OpenTelemetry.Trace.TracerProviderBuilder! builder, string? name, System.Action? configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
+static OpenTelemetry.Trace.ZipkinExporterHelperExtensions.AddZipkinExporter(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
diff --git a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md
index 15dcc2f339..617098116d 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md
+++ b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md
@@ -1,7 +1,38 @@
# Changelog
+This file contains individual changes for the OpenTelemetry.Exporter.Zipkin
+package. For highlights and announcements covering all components see: [Release
+Notes](../../RELEASENOTES.md).
+
## Unreleased
+* Added direct reference to `System.Text.Json` for the `net8.0` target with
+ minimum version of `8.0.5` in response to
+ [CVE-2024-30105](https://github.com/advisories/GHSA-hh2w-p6rv-4g7w) &
+ [CVE-2024-43485](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-43485).
+ ([#5874](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5874),
+ [#5891](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5891))
+
+## 1.10.0-beta.1
+
+Released 2024-Sep-30
+
+* **Breaking change**: Non-primitive tag values converted using
+ `Convert.ToString` will now format using `CultureInfo.InvariantCulture`.
+ ([#5700](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5700))
+
+* Fixed `PlatformNotSupportedException`s being thrown during export when running
+ on mobile platforms which caused telemetry to be dropped silently.
+ ([#5821](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/5821))
+
+## 1.9.0
+
+Released 2024-Jun-14
+
+## 1.9.0-rc.1
+
+Released 2024-Jun-07
+
## 1.9.0-alpha.1
Released 2024-May-20
diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinActivityConversionExtensions.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinActivityConversionExtensions.cs
index 802591d052..2753f51f50 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinActivityConversionExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinActivityConversionExtensions.cs
@@ -21,13 +21,13 @@ internal static ZipkinSpan ToZipkinSpan(this Activity activity, ZipkinEndpoint l
{
var context = activity.Context;
- string parentId = activity.ParentSpanId == default ?
+ string? parentId = activity.ParentSpanId == default ?
null
: EncodeSpanId(activity.ParentSpanId);
var tagState = new TagEnumerationState
{
- Tags = PooledList>.Create(),
+ Tags = PooledList>.Create(),
};
tagState.EnumerateTags(activity);
@@ -38,9 +38,9 @@ internal static ZipkinSpan ToZipkinSpan(this Activity activity, ZipkinEndpoint l
{
if (activity.Status == ActivityStatusCode.Ok)
{
- PooledList>.Add(
+ PooledList>.Add(
ref tagState.Tags,
- new KeyValuePair(
+ new KeyValuePair(
SpanAttributeConstants.StatusCodeKey,
"OK"));
}
@@ -48,16 +48,16 @@ internal static ZipkinSpan ToZipkinSpan(this Activity activity, ZipkinEndpoint l
// activity.Status is Error
else
{
- PooledList>.Add(
+ PooledList>.Add(
ref tagState.Tags,
- new KeyValuePair(
+ new KeyValuePair(
SpanAttributeConstants.StatusCodeKey,
"ERROR"));
// Error flag rule from https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/zipkin.md#status
- PooledList>.Add(
+ PooledList>.Add(
ref tagState.Tags,
- new KeyValuePair(
+ new KeyValuePair(
ZipkinErrorFlagTagName,
activity.StatusDescription ?? string.Empty));
}
@@ -67,18 +67,18 @@ internal static ZipkinSpan ToZipkinSpan(this Activity activity, ZipkinEndpoint l
// activity status takes precedence over status tag.
else if (tagState.StatusCode.HasValue && tagState.StatusCode != StatusCode.Unset)
{
- PooledList>.Add(
+ PooledList>.Add(
ref tagState.Tags,
- new KeyValuePair(
+ new KeyValuePair(
SpanAttributeConstants.StatusCodeKey,
StatusHelper.GetTagValueForStatusCode(tagState.StatusCode.Value)));
// Error flag rule from https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/zipkin.md#status
if (tagState.StatusCode == StatusCode.Error)
{
- PooledList>.Add(
+ PooledList>.Add(
ref tagState.Tags,
- new KeyValuePair(
+ new KeyValuePair(
ZipkinErrorFlagTagName,
tagState.StatusDescription ?? string.Empty));
}
@@ -87,30 +87,30 @@ internal static ZipkinSpan ToZipkinSpan(this Activity activity, ZipkinEndpoint l
var activitySource = activity.Source;
if (!string.IsNullOrEmpty(activitySource.Name))
{
- PooledList>.Add(ref tagState.Tags, new KeyValuePair("otel.scope.name", activitySource.Name));
+ PooledList>.Add(ref tagState.Tags, new KeyValuePair("otel.scope.name", activitySource.Name));
// otel.library.name is deprecated, but has to be propagated according to https://github.com/open-telemetry/opentelemetry-specification/blob/v1.31.0/specification/common/mapping-to-non-otlp.md#instrumentationscope
- PooledList>.Add(ref tagState.Tags, new KeyValuePair("otel.library.name", activitySource.Name));
+ PooledList>.Add(ref tagState.Tags, new KeyValuePair("otel.library.name", activitySource.Name));
if (!string.IsNullOrEmpty(activitySource.Version))
{
- PooledList>.Add(ref tagState.Tags, new KeyValuePair("otel.scope.version", activitySource.Version));
+ PooledList>.Add(ref tagState.Tags, new KeyValuePair("otel.scope.version", activitySource.Version));
// otel.library.version is deprecated, but has to be propagated according to https://github.com/open-telemetry/opentelemetry-specification/blob/v1.31.0/specification/common/mapping-to-non-otlp.md#instrumentationscope
- PooledList>.Add(ref tagState.Tags, new KeyValuePair("otel.library.version", activitySource.Version));
+ PooledList>.Add(ref tagState.Tags, new KeyValuePair("otel.library.version", activitySource.Version));
}
}
- ZipkinEndpoint remoteEndpoint = null;
+ ZipkinEndpoint? remoteEndpoint = null;
if (activity.Kind == ActivityKind.Client || activity.Kind == ActivityKind.Producer)
{
- PeerServiceResolver.Resolve(ref tagState, out string peerServiceName, out bool addAsTag);
+ PeerServiceResolver.Resolve(ref tagState, out string? peerServiceName, out bool addAsTag);
if (peerServiceName != null)
{
remoteEndpoint = RemoteEndpointCache.GetOrAdd((peerServiceName, default), ZipkinEndpoint.Create);
if (addAsTag)
{
- PooledList>.Add(ref tagState.Tags, new KeyValuePair(SemanticConventions.AttributePeerService, peerServiceName));
+ PooledList>.Add(ref tagState.Tags, new KeyValuePair(SemanticConventions.AttributePeerService, peerServiceName));
}
}
}
@@ -172,7 +172,7 @@ private static string EncodeTraceId(ActivityTraceId traceId, bool useShortTraceI
return id;
}
- private static string ToActivityKind(Activity activity)
+ private static string? ToActivityKind(Activity activity)
{
return activity.Kind switch
{
@@ -186,15 +186,15 @@ private static string ToActivityKind(Activity activity)
internal struct TagEnumerationState : PeerServiceResolver.IPeerServiceState
{
- public PooledList> Tags;
+ public PooledList> Tags;
- public string PeerService { get; set; }
+ public string? PeerService { get; set; }
public int? PeerServicePriority { get; set; }
- public string HostName { get; set; }
+ public string? HostName { get; set; }
- public string IpAddress { get; set; }
+ public string? IpAddress { get; set; }
public long Port { get; set; }
@@ -239,7 +239,7 @@ public void EnumerateTags(Activity activity)
PeerServiceResolver.InspectTag(ref this, key, intVal);
}
- PooledList>.Add(ref this.Tags, tag);
+ PooledList>.Add(ref this.Tags, tag);
}
}
}
diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinEndpoint.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinEndpoint.cs
index c6c9908b38..cec7cc7156 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinEndpoint.cs
+++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinEndpoint.cs
@@ -13,11 +13,11 @@ public ZipkinEndpoint(string serviceName)
}
public ZipkinEndpoint(
- string serviceName,
- string ipv4,
- string ipv6,
+ string? serviceName,
+ string? ipv4,
+ string? ipv6,
int? port,
- Dictionary tags)
+ Dictionary? tags)
{
this.ServiceName = serviceName;
this.Ipv4 = ipv4;
@@ -26,15 +26,15 @@ public ZipkinEndpoint(
this.Tags = tags;
}
- public string ServiceName { get; }
+ public string? ServiceName { get; }
- public string Ipv4 { get; }
+ public string? Ipv4 { get; }
- public string Ipv6 { get; }
+ public string? Ipv6 { get; }
public int? Port { get; }
- public Dictionary Tags { get; }
+ public Dictionary? Tags { get; }
public static ZipkinEndpoint Create(string serviceName)
{
diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs
index 8038492a0b..a6ea86f6ce 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs
+++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs
@@ -11,16 +11,16 @@ internal readonly struct ZipkinSpan
{
public ZipkinSpan(
string traceId,
- string parentId,
+ string? parentId,
string id,
- string kind,
+ string? kind,
string name,
long? timestamp,
long? duration,
ZipkinEndpoint localEndpoint,
- ZipkinEndpoint remoteEndpoint,
+ ZipkinEndpoint? remoteEndpoint,
in PooledList annotations,
- in PooledList> tags,
+ in PooledList> tags,
bool? debug,
bool? shared)
{
@@ -44,11 +44,11 @@ public ZipkinSpan(
public string TraceId { get; }
- public string ParentId { get; }
+ public string? ParentId { get; }
public string Id { get; }
- public string Kind { get; }
+ public string? Kind { get; }
public string Name { get; }
@@ -58,11 +58,11 @@ public ZipkinSpan(
public ZipkinEndpoint LocalEndpoint { get; }
- public ZipkinEndpoint RemoteEndpoint { get; }
+ public ZipkinEndpoint? RemoteEndpoint { get; }
public PooledList Annotations { get; }
- public PooledList> Tags { get; }
+ public PooledList> Tags { get; }
public bool? Debug { get; }
@@ -148,7 +148,7 @@ public void Write(Utf8JsonWriter writer)
writer.WriteEndArray();
}
- if (!this.Tags.IsEmpty || this.LocalEndpoint.Tags != null)
+ if (!this.Tags.IsEmpty || this.LocalEndpoint!.Tags != null)
{
writer.WritePropertyName(ZipkinSpanJsonHelper.TagsPropertyName);
writer.WriteStartObject();
@@ -161,7 +161,7 @@ public void Write(Utf8JsonWriter writer)
try
{
- foreach (var tag in this.LocalEndpoint.Tags ?? Enumerable.Empty>())
+ foreach (var tag in this.LocalEndpoint!.Tags! ?? Enumerable.Empty>())
{
ZipkinTagWriter.Instance.TryWriteTag(ref writer, tag);
}
diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagWriter.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagWriter.cs
index d40d126b92..30e1eb112e 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagWriter.cs
+++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagWriter.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Buffers.Text;
using System.Globalization;
using System.Text.Json;
diff --git a/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj b/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj
index 3ca65ced4d..78d44fd3ee 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj
+++ b/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj
@@ -1,12 +1,11 @@
+
$(TargetFrameworksForLibraries)
Zipkin exporter for OpenTelemetry .NET
$(PackageTags);Zipkin;distributed-tracing
core-
-
-
- disable
+ true
@@ -30,11 +29,6 @@
-
-
-
-
-
diff --git a/src/OpenTelemetry.Exporter.Zipkin/README.md b/src/OpenTelemetry.Exporter.Zipkin/README.md
index aa277b7fdc..ededcf9b07 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/README.md
+++ b/src/OpenTelemetry.Exporter.Zipkin/README.md
@@ -15,7 +15,7 @@ dotnet add package OpenTelemetry.Exporter.Zipkin
## Enable/Add Zipkin as a tracing exporter
-You can enable the the `ZipkinExporter` with the `AddZipkinExporter()` extension
+You can enable the `ZipkinExporter` with the `AddZipkinExporter()` extension
method on `TracerProviderBuilder`.
## Configuration
diff --git a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs
index e7a9e0ebcc..c65f145428 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs
+++ b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs
@@ -24,22 +24,35 @@ public class ZipkinExporter : BaseExporter
private readonly ZipkinExporterOptions options;
private readonly int maxPayloadSizeInBytes;
private readonly HttpClient httpClient;
+#if NET
+ private readonly bool synchronousSendSupportedByCurrentPlatform;
+#endif
///
/// Initializes a new instance of the class.
///
/// Configuration options.
/// Http client to use to upload telemetry.
- public ZipkinExporter(ZipkinExporterOptions options, HttpClient client = null)
+ public ZipkinExporter(ZipkinExporterOptions options, HttpClient? client = null)
{
Guard.ThrowIfNull(options);
this.options = options;
- this.maxPayloadSizeInBytes = (!options.MaxPayloadSizeInBytes.HasValue || options.MaxPayloadSizeInBytes <= 0) ? ZipkinExporterOptions.DefaultMaxPayloadSizeInBytes : options.MaxPayloadSizeInBytes.Value;
+ this.maxPayloadSizeInBytes = (!options.MaxPayloadSizeInBytes.HasValue || options.MaxPayloadSizeInBytes <= 0)
+ ? ZipkinExporterOptions.DefaultMaxPayloadSizeInBytes
+ : options.MaxPayloadSizeInBytes.Value;
this.httpClient = client ?? options.HttpClientFactory?.Invoke() ?? throw new InvalidOperationException("ZipkinExporter was missing HttpClientFactory or it returned null.");
+
+#if NET
+ // See: https://github.com/dotnet/runtime/blob/280f2a0c60ce0378b8db49adc0eecc463d00fe5d/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs#L767
+ this.synchronousSendSupportedByCurrentPlatform = !OperatingSystem.IsAndroid()
+ && !OperatingSystem.IsIOS()
+ && !OperatingSystem.IsTvOS()
+ && !OperatingSystem.IsBrowser();
+#endif
}
- internal ZipkinEndpoint LocalEndpoint { get; private set; }
+ internal ZipkinEndpoint? LocalEndpoint { get; private set; }
///
public override ExportResult Export(in Batch batch)
@@ -61,8 +74,10 @@ public override ExportResult Export(in Batch batch)
Content = new JsonContent(this, batch),
};
-#if NET6_0_OR_GREATER
- using var response = this.httpClient.Send(request, CancellationToken.None);
+#if NET
+ using var response = this.synchronousSendSupportedByCurrentPlatform
+ ? this.httpClient.Send(request, CancellationToken.None)
+ : this.httpClient.SendAsync(request, CancellationToken.None).GetAwaiter().GetResult();
#else
using var response = this.httpClient.SendAsync(request, CancellationToken.None).GetAwaiter().GetResult();
#endif
@@ -83,15 +98,15 @@ internal void SetLocalEndpointFromResource(Resource resource)
{
var hostName = ResolveHostName();
- string ipv4 = null;
- string ipv6 = null;
+ string? ipv4 = null;
+ string? ipv6 = null;
if (!string.IsNullOrEmpty(hostName))
{
- ipv4 = ResolveHostAddress(hostName, AddressFamily.InterNetwork);
- ipv6 = ResolveHostAddress(hostName, AddressFamily.InterNetworkV6);
+ ipv4 = ResolveHostAddress(hostName!, AddressFamily.InterNetwork);
+ ipv6 = ResolveHostAddress(hostName!, AddressFamily.InterNetworkV6);
}
- string serviceName = null;
+ string? serviceName = null;
foreach (var label in resource.Attributes)
{
if (label.Key == ResourceSemanticConventions.AttributeServiceName)
@@ -115,9 +130,9 @@ internal void SetLocalEndpointFromResource(Resource resource)
tags: null);
}
- private static string ResolveHostAddress(string hostName, AddressFamily family)
+ private static string? ResolveHostAddress(string hostName, AddressFamily family)
{
- string result = null;
+ string? result = null;
try
{
@@ -145,9 +160,9 @@ private static string ResolveHostAddress(string hostName, AddressFamily family)
return result;
}
- private static string ResolveHostName()
+ private static string? ResolveHostName()
{
- string result = null;
+ string? result = null;
try
{
@@ -180,7 +195,7 @@ private sealed class JsonContent : HttpContent
private readonly ZipkinExporter exporter;
private readonly Batch batch;
- private Utf8JsonWriter writer;
+ private Utf8JsonWriter? writer;
public JsonContent(ZipkinExporter exporter, in Batch batch)
{
@@ -190,14 +205,14 @@ public JsonContent(ZipkinExporter exporter, in Batch batch)
this.Headers.ContentType = JsonHeader;
}
-#if NET6_0_OR_GREATER
- protected override void SerializeToStream(Stream stream, TransportContext context, CancellationToken cancellationToken)
+#if NET
+ protected override void SerializeToStream(Stream stream, TransportContext? context, CancellationToken cancellationToken)
{
this.SerializeToStreamInternal(stream);
}
#endif
- protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
+ protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context)
{
this.SerializeToStreamInternal(stream);
return Task.CompletedTask;
@@ -226,7 +241,7 @@ private void SerializeToStreamInternal(Stream stream)
foreach (var activity in this.batch)
{
- var zipkinSpan = activity.ToZipkinSpan(this.exporter.LocalEndpoint, this.exporter.options.UseShortTraceIds);
+ var zipkinSpan = activity.ToZipkinSpan(this.exporter.LocalEndpoint!, this.exporter.options.UseShortTraceIds);
zipkinSpan.Write(this.writer);
diff --git a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs
index ca858c649a..b7142b985a 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs
@@ -39,13 +39,13 @@ public static TracerProviderBuilder AddZipkinExporter(this TracerProviderBuilder
/// Adds Zipkin exporter to the TracerProvider.
///
/// builder to use.
- /// Name which is used when retrieving options.
- /// Callback action for configuring .
+ /// Optional name which is used when retrieving options.
+ /// Optional callback action for configuring .
/// The instance of to chain the calls.
public static TracerProviderBuilder AddZipkinExporter(
this TracerProviderBuilder builder,
- string name,
- Action configure)
+ string? name,
+ Action? configure)
{
Guard.ThrowIfNull(builder);
@@ -81,13 +81,13 @@ private static BaseProcessor BuildZipkinExporterProcessor(
{
options.HttpClientFactory = () =>
{
- Type httpClientFactoryType = Type.GetType("System.Net.Http.IHttpClientFactory, Microsoft.Extensions.Http", throwOnError: false);
+ Type? httpClientFactoryType = Type.GetType("System.Net.Http.IHttpClientFactory, Microsoft.Extensions.Http", throwOnError: false);
if (httpClientFactoryType != null)
{
- object httpClientFactory = serviceProvider.GetService(httpClientFactoryType);
+ object? httpClientFactory = serviceProvider.GetService(httpClientFactoryType);
if (httpClientFactory != null)
{
- MethodInfo createClientMethod = httpClientFactoryType.GetMethod(
+ MethodInfo? createClientMethod = httpClientFactoryType.GetMethod(
"CreateClient",
BindingFlags.Public | BindingFlags.Instance,
binder: null,
@@ -95,7 +95,9 @@ private static BaseProcessor BuildZipkinExporterProcessor(
modifiers: null);
if (createClientMethod != null)
{
- return (HttpClient)createClientMethod.Invoke(httpClientFactory, new object[] { "ZipkinExporter" });
+ var parameters = new object[] { "ZipkinExporter" };
+ var client = (HttpClient?)createClientMethod.Invoke(httpClientFactory, parameters);
+ return client ?? new HttpClient();
}
}
}
diff --git a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterOptions.cs b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterOptions.cs
index bc94307351..1f4bcd1468 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterOptions.cs
+++ b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterOptions.cs
@@ -40,12 +40,12 @@ internal ZipkinExporterOptions(
Debug.Assert(configuration != null, "configuration was null");
Debug.Assert(defaultBatchOptions != null, "defaultBatchOptions was null");
- if (configuration.TryGetUriValue(ZipkinExporterEventSource.Log, ZipkinEndpointEnvVar, out var endpoint))
+ if (configuration!.TryGetUriValue(ZipkinExporterEventSource.Log, ZipkinEndpointEnvVar, out var endpoint))
{
- this.Endpoint = endpoint;
+ this.Endpoint = endpoint!;
}
- this.BatchExportProcessorOptions = defaultBatchOptions;
+ this.BatchExportProcessorOptions = defaultBatchOptions!;
}
///
diff --git a/src/OpenTelemetry.Extensions.Hosting/.publicApi/Experimental/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Extensions.Hosting/.publicApi/Experimental/PublicAPI.Unshipped.txt
index f83d7ca4a0..e69de29bb2 100644
--- a/src/OpenTelemetry.Extensions.Hosting/.publicApi/Experimental/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry.Extensions.Hosting/.publicApi/Experimental/PublicAPI.Unshipped.txt
@@ -1,3 +0,0 @@
-OpenTelemetry.OpenTelemetryBuilder.WithLogging() -> OpenTelemetry.OpenTelemetryBuilder!
-OpenTelemetry.OpenTelemetryBuilder.WithLogging(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder!
-OpenTelemetry.OpenTelemetryBuilder.WithLogging(System.Action? configureBuilder, System.Action? configureOptions) -> OpenTelemetry.OpenTelemetryBuilder!
diff --git a/src/OpenTelemetry.Extensions.Hosting/.publicApi/Stable/PublicAPI.Shipped.txt b/src/OpenTelemetry.Extensions.Hosting/.publicApi/Stable/PublicAPI.Shipped.txt
index b0f847bf1e..57bce9162b 100644
--- a/src/OpenTelemetry.Extensions.Hosting/.publicApi/Stable/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Extensions.Hosting/.publicApi/Stable/PublicAPI.Shipped.txt
@@ -3,6 +3,9 @@ Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions
OpenTelemetry.OpenTelemetryBuilder
OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
+OpenTelemetry.OpenTelemetryBuilder.WithLogging() -> OpenTelemetry.OpenTelemetryBuilder!
+OpenTelemetry.OpenTelemetryBuilder.WithLogging(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder!
+OpenTelemetry.OpenTelemetryBuilder.WithLogging(System.Action? configureBuilder, System.Action? configureOptions) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder!
diff --git a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md
index a5921a6dd9..65cd938384 100644
--- a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md
+++ b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md
@@ -1,7 +1,32 @@
# Changelog
+This file contains individual changes for the OpenTelemetry.Extensions.Hosting
+package. For highlights and announcements covering all components see: [Release
+Notes](../../RELEASENOTES.md).
+
## Unreleased
+## 1.10.0-beta.1
+
+Released 2024-Sep-30
+
+* Updated `Microsoft.Extensions.Hosting.Abstractions` package
+ version to `9.0.0-rc.1.24431.7`.
+ ([#5853](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5853))
+
+## 1.9.0
+
+Released 2024-Jun-14
+
+## 1.9.0-rc.1
+
+Released 2024-Jun-07
+
+* The experimental APIs previously covered by `OTEL1000`
+ (`OpenTelemetryBuilder.WithLogging` method) are now be part of the public API
+ and supported in stable builds.
+ ([#5648](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5648))
+
## 1.9.0-alpha.1
Released 2024-May-20
diff --git a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryBuilder.cs b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryBuilder.cs
index 042a211e76..5512befb59 100644
--- a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryBuilder.cs
+++ b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryBuilder.cs
@@ -1,9 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#if EXPOSE_EXPERIMENTAL_FEATURES && NET8_0_OR_GREATER
-using System.Diagnostics.CodeAnalysis;
-#endif
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.Metrics;
using Microsoft.Extensions.Logging;
@@ -112,13 +109,10 @@ public OpenTelemetryBuilder WithTracing(Action configure)
return this;
}
-#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Adds logging services into the builder.
///
///
- /// WARNING: This is an experimental API which might change or
- /// be removed in the future. Use at your own risk.
/// Notes:
///
/// - This is safe to be called multiple times and by library authors.
@@ -131,33 +125,9 @@ public OpenTelemetryBuilder WithTracing(Action configure)
///
/// The supplied for chaining
/// calls.
-#if NET8_0_OR_GREATER
- [Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
- public
-#else
- ///
- /// Adds logging services into the builder.
- ///
- ///
- /// Notes:
- ///
- /// - This is safe to be called multiple times and by library authors.
- /// Only a single will be created for a given
- /// .
- /// - This method automatically registers an named 'OpenTelemetry' into the .
- ///
- ///
- /// The supplied for chaining
- /// calls.
- internal
-#endif
- OpenTelemetryBuilder WithLogging()
+ public OpenTelemetryBuilder WithLogging()
=> this.WithLogging(configureBuilder: null, configureOptions: null);
-#if EXPOSE_EXPERIMENTAL_FEATURES
///
/// Adds logging services into the builder.
///
@@ -166,44 +136,13 @@ OpenTelemetryBuilder WithLogging()
/// configuration callback.
/// The supplied for chaining
/// calls.
-#if NET8_0_OR_GREATER
- [Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
- public
-#else
- ///
- /// Adds logging services into the builder.
- ///
- ///
- ///
- /// configuration callback.
- /// The supplied for chaining
- /// calls.
- internal
-#endif
- OpenTelemetryBuilder WithLogging(Action configure)
+ public OpenTelemetryBuilder WithLogging(Action configure)
{
Guard.ThrowIfNull(configure);
return this.WithLogging(configureBuilder: configure, configureOptions: null);
}
-#if EXPOSE_EXPERIMENTAL_FEATURES
- ///
- /// Adds logging services into the builder.
- ///
- ///
- /// Optional configuration callback.
- /// Optional configuration callback.
- /// The supplied for chaining
- /// calls.
-#if NET8_0_OR_GREATER
- [Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
- public
-#else
///
/// Adds logging services into the builder.
///
@@ -211,14 +150,15 @@ OpenTelemetryBuilder WithLogging(Action configure)
/// Optional configuration callback.
/// Optional configuration callback.
+ /// cref="OpenTelemetryLoggerOptions"/> configuration callback. are used by the named 'OpenTelemetry' automatically registered
+ /// by this method.
/// The supplied for chaining
/// calls.
- internal
-#endif
- OpenTelemetryBuilder WithLogging(
- Action? configureBuilder,
- Action? configureOptions)
+ public OpenTelemetryBuilder WithLogging(
+ Action? configureBuilder,
+ Action? configureOptions)
{
OpenTelemetryBuilderSdkExtensions.WithLogging(this, configureBuilder, configureOptions);
diff --git a/src/OpenTelemetry.Extensions.Propagators/.publicApi/PublicAPI.Shipped.txt b/src/OpenTelemetry.Extensions.Propagators/.publicApi/PublicAPI.Shipped.txt
index eadd932c93..3379641fda 100644
--- a/src/OpenTelemetry.Extensions.Propagators/.publicApi/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Extensions.Propagators/.publicApi/PublicAPI.Shipped.txt
@@ -1,11 +1,12 @@
+#nullable enable
OpenTelemetry.Extensions.Propagators.B3Propagator
OpenTelemetry.Extensions.Propagators.B3Propagator.B3Propagator() -> void
OpenTelemetry.Extensions.Propagators.B3Propagator.B3Propagator(bool singleHeader) -> void
OpenTelemetry.Extensions.Propagators.JaegerPropagator
OpenTelemetry.Extensions.Propagators.JaegerPropagator.JaegerPropagator() -> void
-override OpenTelemetry.Extensions.Propagators.B3Propagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func> getter) -> OpenTelemetry.Context.Propagation.PropagationContext
-override OpenTelemetry.Extensions.Propagators.B3Propagator.Fields.get -> System.Collections.Generic.ISet
-override OpenTelemetry.Extensions.Propagators.B3Propagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action setter) -> void
-override OpenTelemetry.Extensions.Propagators.JaegerPropagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func> getter) -> OpenTelemetry.Context.Propagation.PropagationContext
-override OpenTelemetry.Extensions.Propagators.JaegerPropagator.Fields.get -> System.Collections.Generic.ISet
-override OpenTelemetry.Extensions.Propagators.JaegerPropagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action setter) -> void
+override OpenTelemetry.Extensions.Propagators.B3Propagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func?>! getter) -> OpenTelemetry.Context.Propagation.PropagationContext
+override OpenTelemetry.Extensions.Propagators.B3Propagator.Fields.get -> System.Collections.Generic.ISet!
+override OpenTelemetry.Extensions.Propagators.B3Propagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action! setter) -> void
+override OpenTelemetry.Extensions.Propagators.JaegerPropagator.Extract(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func?>! getter) -> OpenTelemetry.Context.Propagation.PropagationContext
+override OpenTelemetry.Extensions.Propagators.JaegerPropagator.Fields.get -> System.Collections.Generic.ISet!
+override OpenTelemetry.Extensions.Propagators.JaegerPropagator.Inject(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action! setter) -> void
diff --git a/src/OpenTelemetry.Extensions.Propagators/B3Propagator.cs b/src/OpenTelemetry.Extensions.Propagators/B3Propagator.cs
index 37ced1218e..45239981f0 100644
--- a/src/OpenTelemetry.Extensions.Propagators/B3Propagator.cs
+++ b/src/OpenTelemetry.Extensions.Propagators/B3Propagator.cs
@@ -62,7 +62,7 @@ public B3Propagator(bool singleHeader)
public override ISet Fields => AllFields;
///
- public override PropagationContext Extract(PropagationContext context, T carrier, Func> getter)
+ public override PropagationContext Extract(PropagationContext context, T carrier, Func?> getter)
{
if (context.ActivityContext.IsValid())
{
@@ -138,7 +138,7 @@ public override void Inject(PropagationContext context, T carrier, Action(PropagationContext context, T carrier, Func> getter)
+ private static PropagationContext ExtractFromMultipleHeaders(PropagationContext context, T carrier, Func?> getter)
{
try
{
@@ -171,7 +171,8 @@ private static PropagationContext ExtractFromMultipleHeaders(PropagationConte
}
var traceOptions = ActivityTraceFlags.None;
- if (SampledValues.Contains(getter(carrier, XB3Sampled)?.FirstOrDefault())
+ var xb3Sampled = getter(carrier, XB3Sampled)?.FirstOrDefault();
+ if ((xb3Sampled != null && SampledValues.Contains(xb3Sampled))
|| FlagsValue.Equals(getter(carrier, XB3Flags)?.FirstOrDefault(), StringComparison.Ordinal))
{
traceOptions |= ActivityTraceFlags.Recorded;
@@ -188,7 +189,7 @@ private static PropagationContext ExtractFromMultipleHeaders(PropagationConte
}
}
- private static PropagationContext ExtractFromSingleHeader(PropagationContext context, T carrier, Func> getter)
+ private static PropagationContext ExtractFromSingleHeader(PropagationContext context, T carrier, Func?> getter)
{
try
{
@@ -198,7 +199,7 @@ private static PropagationContext ExtractFromSingleHeader(PropagationContext
return context;
}
- var parts = header.Split(XB3CombinedDelimiter);
+ var parts = header!.Split(XB3CombinedDelimiter);
if (parts.Length < 2 || parts.Length > 4)
{
return context;
diff --git a/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md b/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md
index 68d9cd7747..60128b5a7d 100644
--- a/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md
+++ b/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md
@@ -1,7 +1,23 @@
# Changelog
+This file contains individual changes for the
+OpenTelemetry.Extensions.Propagators package. For highlights and announcements
+covering all components see: [Release Notes](../../RELEASENOTES.md).
+
## Unreleased
+## 1.10.0-beta.1
+
+Released 2024-Sep-30
+
+## 1.9.0
+
+Released 2024-Jun-14
+
+## 1.9.0-rc.1
+
+Released 2024-Jun-07
+
## 1.9.0-alpha.1
Released 2024-May-20
diff --git a/src/OpenTelemetry.Extensions.Propagators/JaegerPropagator.cs b/src/OpenTelemetry.Extensions.Propagators/JaegerPropagator.cs
index 472b719ded..045fd93e58 100644
--- a/src/OpenTelemetry.Extensions.Propagators/JaegerPropagator.cs
+++ b/src/OpenTelemetry.Extensions.Propagators/JaegerPropagator.cs
@@ -26,7 +26,7 @@ public class JaegerPropagator : TextMapPropagator
public override ISet Fields => new HashSet { JaegerHeader };
///
- public override PropagationContext Extract(PropagationContext context, T carrier, Func> getter)
+ public override PropagationContext Extract(PropagationContext context, T carrier, Func?> getter)
{
if (context.ActivityContext.IsValid())
{
@@ -56,7 +56,7 @@ public override PropagationContext Extract(PropagationContext context, T carr
return context;
}
- var jaegerHeaderParsed = TryExtractTraceContext(jaegerHeader, out var traceId, out var spanId, out var traceOptions);
+ var jaegerHeaderParsed = TryExtractTraceContext(jaegerHeader!, out var traceId, out var spanId, out var traceOptions);
if (!jaegerHeaderParsed)
{
diff --git a/src/OpenTelemetry.Extensions.Propagators/OpenTelemetry.Extensions.Propagators.csproj b/src/OpenTelemetry.Extensions.Propagators/OpenTelemetry.Extensions.Propagators.csproj
index c099b609a2..01ae76f4a1 100644
--- a/src/OpenTelemetry.Extensions.Propagators/OpenTelemetry.Extensions.Propagators.csproj
+++ b/src/OpenTelemetry.Extensions.Propagators/OpenTelemetry.Extensions.Propagators.csproj
@@ -5,9 +5,6 @@
$(PackageTags);distributed-tracing;AspNet;AspNetCore;B3
core-
true
-
-
- disable
diff --git a/src/OpenTelemetry.Shims.OpenTracing/.publicApi/PublicAPI.Shipped.txt b/src/OpenTelemetry.Shims.OpenTracing/.publicApi/PublicAPI.Shipped.txt
index e69de29bb2..7dc5c58110 100644
--- a/src/OpenTelemetry.Shims.OpenTracing/.publicApi/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Shims.OpenTracing/.publicApi/PublicAPI.Shipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/OpenTelemetry.Shims.OpenTracing/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Shims.OpenTracing/.publicApi/PublicAPI.Unshipped.txt
index 90f671f8a1..c5d387112f 100644
--- a/src/OpenTelemetry.Shims.OpenTracing/.publicApi/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry.Shims.OpenTracing/.publicApi/PublicAPI.Unshipped.txt
@@ -1,8 +1,8 @@
OpenTelemetry.Shims.OpenTracing.TracerShim
-OpenTelemetry.Shims.OpenTracing.TracerShim.ActiveSpan.get -> OpenTracing.ISpan
-OpenTelemetry.Shims.OpenTracing.TracerShim.BuildSpan(string operationName) -> OpenTracing.ISpanBuilder
-OpenTelemetry.Shims.OpenTracing.TracerShim.Extract(OpenTracing.Propagation.IFormat format, TCarrier carrier) -> OpenTracing.ISpanContext
-OpenTelemetry.Shims.OpenTracing.TracerShim.Inject(OpenTracing.ISpanContext spanContext, OpenTracing.Propagation.IFormat format, TCarrier carrier) -> void
-OpenTelemetry.Shims.OpenTracing.TracerShim.ScopeManager.get -> OpenTracing.IScopeManager
-OpenTelemetry.Shims.OpenTracing.TracerShim.TracerShim(OpenTelemetry.Trace.TracerProvider tracerProvider) -> void
-OpenTelemetry.Shims.OpenTracing.TracerShim.TracerShim(OpenTelemetry.Trace.TracerProvider tracerProvider, OpenTelemetry.Context.Propagation.TextMapPropagator textFormat) -> void
+OpenTelemetry.Shims.OpenTracing.TracerShim.ActiveSpan.get -> OpenTracing.ISpan?
+OpenTelemetry.Shims.OpenTracing.TracerShim.BuildSpan(string! operationName) -> OpenTracing.ISpanBuilder!
+OpenTelemetry.Shims.OpenTracing.TracerShim.Extract(OpenTracing.Propagation.IFormat! format, TCarrier carrier) -> OpenTracing.ISpanContext?
+OpenTelemetry.Shims.OpenTracing.TracerShim.Inject(OpenTracing.ISpanContext! spanContext, OpenTracing.Propagation.IFormat! format, TCarrier carrier) -> void
+OpenTelemetry.Shims.OpenTracing.TracerShim.ScopeManager.get -> OpenTracing.IScopeManager!
+OpenTelemetry.Shims.OpenTracing.TracerShim.TracerShim(OpenTelemetry.Trace.TracerProvider! tracerProvider) -> void
+OpenTelemetry.Shims.OpenTracing.TracerShim.TracerShim(OpenTelemetry.Trace.TracerProvider! tracerProvider, OpenTelemetry.Context.Propagation.TextMapPropagator? textFormat) -> void
diff --git a/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md b/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md
index b0cb58b6b5..23775d1cdd 100644
--- a/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md
+++ b/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md
@@ -1,7 +1,27 @@
# Changelog
+This file contains individual changes for the OpenTelemetry.Shims.OpenTracing
+package. For highlights and announcements covering all components see: [Release
+Notes](../../RELEASENOTES.md).
+
## Unreleased
+* Fixed an issue causing all tag values added via the `ISpanBuilder` API to be
+ converted to strings on the `ISpan` started from the builder.
+ ([#5797](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5797))
+
+## 1.9.0-beta.2
+
+Released 2024-Jun-24
+
+## 1.9.0-beta.1
+
+Released 2024-Jun-14
+
+## 1.9.0-alpha.2
+
+Released 2024-May-29
+
## 1.9.0-alpha.1
Released 2024-May-20
diff --git a/src/OpenTelemetry.Shims.OpenTracing/OpenTelemetry.Shims.OpenTracing.csproj b/src/OpenTelemetry.Shims.OpenTracing/OpenTelemetry.Shims.OpenTracing.csproj
index 645c9e49e5..127cbfb3aa 100644
--- a/src/OpenTelemetry.Shims.OpenTracing/OpenTelemetry.Shims.OpenTracing.csproj
+++ b/src/OpenTelemetry.Shims.OpenTracing/OpenTelemetry.Shims.OpenTracing.csproj
@@ -4,9 +4,6 @@
OpenTracing shim for OpenTelemetry .NET
$(PackageTags);distributed-tracing;OpenTracing
coreunstable-
-
-
- disable
@@ -22,7 +19,9 @@
+
+
diff --git a/src/OpenTelemetry.Shims.OpenTracing/ScopeManagerShim.cs b/src/OpenTelemetry.Shims.OpenTracing/ScopeManagerShim.cs
index f9464d966a..6b2fb78335 100644
--- a/src/OpenTelemetry.Shims.OpenTracing/ScopeManagerShim.cs
+++ b/src/OpenTelemetry.Shims.OpenTracing/ScopeManagerShim.cs
@@ -19,7 +19,7 @@ internal sealed class ScopeManagerShim : IScopeManager
#endif
///
- public IScope Active
+ public IScope? Active
{
get
{
@@ -56,7 +56,7 @@ public IScope Activate(ISpan span, bool finishSpanOnDispose)
Interlocked.Decrement(ref this.spanScopeTableCount);
}
#endif
- scope.Dispose();
+ scope!.Dispose();
});
SpanScopeTable.Add(shim.Span, instrumentation);
@@ -69,9 +69,9 @@ public IScope Activate(ISpan span, bool finishSpanOnDispose)
private sealed class ScopeInstrumentation : IScope
{
- private readonly Action disposeAction;
+ private readonly Action? disposeAction;
- public ScopeInstrumentation(TelemetrySpan span, Action disposeAction = null)
+ public ScopeInstrumentation(TelemetrySpan span, Action? disposeAction = null)
{
this.Span = new SpanShim(span);
this.disposeAction = disposeAction;
diff --git a/src/OpenTelemetry.Shims.OpenTracing/SpanBuilderShim.cs b/src/OpenTelemetry.Shims.OpenTracing/SpanBuilderShim.cs
index 0359762ac3..f95b1b77be 100644
--- a/src/OpenTelemetry.Shims.OpenTracing/SpanBuilderShim.cs
+++ b/src/OpenTelemetry.Shims.OpenTracing/SpanBuilderShim.cs
@@ -32,12 +32,12 @@ internal sealed class SpanBuilderShim : ISpanBuilder
///
/// The OpenTelemetry attributes. These correspond to OpenTracing Tags.
///
- private readonly List> attributes = new();
+ private readonly SpanAttributes attributes = new();
///
/// The parent as an TelemetrySpan, if any.
///
- private TelemetrySpan parentSpan;
+ private TelemetrySpan? parentSpan;
///
/// The parent as an SpanContext, if any.
@@ -70,7 +70,7 @@ public SpanBuilderShim(Tracer tracer, string spanName)
private bool ParentSet => this.parentSpan != null || this.parentSpanContext.IsValid;
///
- public ISpanBuilder AsChildOf(ISpanContext parent)
+ public ISpanBuilder AsChildOf(ISpanContext? parent)
{
if (parent == null)
{
@@ -81,7 +81,7 @@ public ISpanBuilder AsChildOf(ISpanContext parent)
}
///
- public ISpanBuilder AsChildOf(ISpan parent)
+ public ISpanBuilder AsChildOf(ISpan? parent)
{
if (parent == null)
{
@@ -98,7 +98,7 @@ public ISpanBuilder AsChildOf(ISpan parent)
}
///
- public ISpanBuilder AddReference(string referenceType, ISpanContext referencedContext)
+ public ISpanBuilder AddReference(string referenceType, ISpanContext? referencedContext)
{
if (referencedContext == null)
{
@@ -132,30 +132,25 @@ public ISpanBuilder IgnoreActiveSpan()
///
public ISpan Start()
{
- TelemetrySpan span = null;
+ TelemetrySpan? span = null;
// If specified, this takes precedence.
if (this.ignoreActiveSpan)
{
- span = this.tracer.StartRootSpan(this.spanName, this.spanKind, default, this.links, this.explicitStartTime ?? default);
+ span = this.tracer.StartRootSpan(this.spanName, this.spanKind, this.attributes, this.links, this.explicitStartTime ?? default);
}
else if (this.parentSpan != null)
{
- span = this.tracer.StartSpan(this.spanName, this.spanKind, this.parentSpan, default, this.links, this.explicitStartTime ?? default);
+ span = this.tracer.StartSpan(this.spanName, this.spanKind, this.parentSpan, this.attributes, this.links, this.explicitStartTime ?? default);
}
else if (this.parentSpanContext.IsValid)
{
- span = this.tracer.StartSpan(this.spanName, this.spanKind, this.parentSpanContext, default, this.links, this.explicitStartTime ?? default);
+ span = this.tracer.StartSpan(this.spanName, this.spanKind, this.parentSpanContext, this.attributes, this.links, this.explicitStartTime ?? default);
}
if (span == null)
{
- span = this.tracer.StartSpan(this.spanName, this.spanKind, default(SpanContext), default, null, this.explicitStartTime ?? default);
- }
-
- foreach (var kvp in this.attributes)
- {
- span.SetAttribute(kvp.Key, kvp.Value.ToString());
+ span = this.tracer.StartSpan(this.spanName, this.spanKind, default(SpanContext), this.attributes, null, this.explicitStartTime ?? default);
}
if (this.error)
@@ -184,8 +179,13 @@ public ISpanBuilder WithStartTimestamp(DateTimeOffset timestamp)
}
///
- public ISpanBuilder WithTag(string key, string value)
+ public ISpanBuilder WithTag(string key, string? value)
{
+ if (key == null)
+ {
+ return this;
+ }
+
// see https://opentracing.io/specification/conventions/ for special key handling.
if (global::OpenTracing.Tag.Tags.SpanKind.Key.Equals(key, StringComparison.Ordinal))
{
@@ -204,12 +204,7 @@ public ISpanBuilder WithTag(string key, string value)
}
else
{
- // Keys must be non-null.
- // Null values => string.Empty.
- if (key != null)
- {
- this.attributes.Add(new KeyValuePair(key, value ?? string.Empty));
- }
+ this.attributes.Add(key, value);
}
return this;
@@ -224,7 +219,7 @@ public ISpanBuilder WithTag(string key, bool value)
}
else
{
- this.attributes.Add(new KeyValuePair(key, value));
+ this.attributes.Add(key, value);
}
return this;
@@ -233,31 +228,31 @@ public ISpanBuilder WithTag(string key, bool value)
///
public ISpanBuilder WithTag(string key, int value)
{
- this.attributes.Add(new KeyValuePair(key, value));
+ this.attributes.Add(key, value);
return this;
}
///
public ISpanBuilder WithTag(string key, double value)
{
- this.attributes.Add(new KeyValuePair(key, value));
+ this.attributes.Add(key, value);
return this;
}
///
public ISpanBuilder WithTag(global::OpenTracing.Tag.BooleanTag tag, bool value)
{
- Guard.ThrowIfNull(tag?.Key);
+ Guard.ThrowIfNull(tag);
return this.WithTag(tag.Key, value);
}
///
- public ISpanBuilder WithTag(global::OpenTracing.Tag.IntOrStringTag tag, string value)
+ public ISpanBuilder WithTag(global::OpenTracing.Tag.IntOrStringTag tag, string? value)
{
- Guard.ThrowIfNull(tag?.Key);
+ Guard.ThrowIfNull(tag);
- if (int.TryParse(value, out var result))
+ if (value != null && int.TryParse(value, out var result))
{
return this.WithTag(tag.Key, result);
}
@@ -268,15 +263,15 @@ public ISpanBuilder WithTag(global::OpenTracing.Tag.IntOrStringTag tag, string v
///
public ISpanBuilder WithTag(global::OpenTracing.Tag.IntTag tag, int value)
{
- Guard.ThrowIfNull(tag?.Key);
+ Guard.ThrowIfNull(tag);
return this.WithTag(tag.Key, value);
}
///
- public ISpanBuilder WithTag(global::OpenTracing.Tag.StringTag tag, string value)
+ public ISpanBuilder WithTag(global::OpenTracing.Tag.StringTag tag, string? value)
{
- Guard.ThrowIfNull(tag?.Key);
+ Guard.ThrowIfNull(tag);
return this.WithTag(tag.Key, value);
}
diff --git a/src/OpenTelemetry.Shims.OpenTracing/SpanShim.cs b/src/OpenTelemetry.Shims.OpenTracing/SpanShim.cs
index 2ab6fee4fe..c1bde927a1 100644
--- a/src/OpenTelemetry.Shims.OpenTracing/SpanShim.cs
+++ b/src/OpenTelemetry.Shims.OpenTracing/SpanShim.cs
@@ -39,7 +39,7 @@ public SpanShim(TelemetrySpan span)
///
public ISpanContext Context => this.spanContextShim;
- public TelemetrySpan Span { get; private set; }
+ public TelemetrySpan Span { get; }
///
public void Finish()
@@ -54,7 +54,7 @@ public void Finish(DateTimeOffset finishTimestamp)
}
///
- public string GetBaggageItem(string key)
+ public string? GetBaggageItem(string key)
=> Baggage.GetBaggage(key);
///
@@ -137,7 +137,7 @@ public ISpan Log(DateTimeOffset timestamp, string @event)
}
///
- public ISpan SetBaggageItem(string key, string value)
+ public ISpan SetBaggageItem(string key, string? value)
{
Baggage.SetBaggage(key, value);
return this;
@@ -153,7 +153,7 @@ public ISpan SetOperationName(string operationName)
}
///
- public ISpan SetTag(string key, string value)
+ public ISpan SetTag(string key, string? value)
{
Guard.ThrowIfNull(key);
@@ -201,30 +201,38 @@ public ISpan SetTag(string key, double value)
///
public ISpan SetTag(global::OpenTracing.Tag.BooleanTag tag, bool value)
{
- return this.SetTag(tag?.Key, value);
+ Guard.ThrowIfNull(tag);
+
+ return this.SetTag(tag.Key, value);
}
///
- public ISpan SetTag(global::OpenTracing.Tag.IntOrStringTag tag, string value)
+ public ISpan SetTag(global::OpenTracing.Tag.IntOrStringTag tag, string? value)
{
- if (int.TryParse(value, out var result))
+ Guard.ThrowIfNull(tag);
+
+ if (value != null && int.TryParse(value, out var result))
{
- return this.SetTag(tag?.Key, result);
+ return this.SetTag(tag.Key, result);
}
- return this.SetTag(tag?.Key, value);
+ return this.SetTag(tag.Key, value);
}
///
public ISpan SetTag(global::OpenTracing.Tag.IntTag tag, int value)
{
- return this.SetTag(tag?.Key, value);
+ Guard.ThrowIfNull(tag);
+
+ return this.SetTag(tag.Key, value);
}
///
- public ISpan SetTag(global::OpenTracing.Tag.StringTag tag, string value)
+ public ISpan SetTag(global::OpenTracing.Tag.StringTag tag, string? value)
{
- return this.SetTag(tag?.Key, value);
+ Guard.ThrowIfNull(tag);
+
+ return this.SetTag(tag.Key, value);
}
///
@@ -234,7 +242,7 @@ public ISpan SetTag(global::OpenTracing.Tag.StringTag tag, string value)
/// A 2-Tuple containing the event name and payload information.
private static Tuple> ConvertToEventPayload(IEnumerable> fields)
{
- string eventName = null;
+ string? eventName = null;
var attributes = new Dictionary();
foreach (var field in fields)
@@ -268,7 +276,7 @@ private static Tuple> ConvertToEventPayload(
else
{
// TODO should we completely ignore unsupported types?
- attributes.Add(field.Key, field.Value.ToString());
+ attributes.Add(field.Key, field.Value.ToString()!);
}
}
diff --git a/src/OpenTelemetry.Shims.OpenTracing/TracerShim.cs b/src/OpenTelemetry.Shims.OpenTracing/TracerShim.cs
index 3ed448da94..504b28c5a5 100644
--- a/src/OpenTelemetry.Shims.OpenTracing/TracerShim.cs
+++ b/src/OpenTelemetry.Shims.OpenTracing/TracerShim.cs
@@ -14,7 +14,7 @@ namespace OpenTelemetry.Shims.OpenTracing;
public class TracerShim : global::OpenTracing.ITracer
{
private readonly Trace.Tracer tracer;
- private readonly TextMapPropagator definedPropagator;
+ private readonly TextMapPropagator? definedPropagator;
///
/// Initializes a new instance of the class.
@@ -30,7 +30,7 @@ public TracerShim(Trace.TracerProvider tracerProvider)
///
/// .
/// .
- public TracerShim(Trace.TracerProvider tracerProvider, TextMapPropagator textFormat)
+ public TracerShim(Trace.TracerProvider tracerProvider, TextMapPropagator? textFormat)
{
Guard.ThrowIfNull(tracerProvider);
@@ -46,7 +46,7 @@ public TracerShim(Trace.TracerProvider tracerProvider, TextMapPropagator textFor
public global::OpenTracing.IScopeManager ScopeManager { get; }
///
- public global::OpenTracing.ISpan ActiveSpan => this.ScopeManager.Active?.Span;
+ public global::OpenTracing.ISpan? ActiveSpan => this.ScopeManager.Active?.Span;
private TextMapPropagator Propagator
{
@@ -63,7 +63,7 @@ private TextMapPropagator Propagator
}
///
- public global::OpenTracing.ISpanContext Extract(IFormat format, TCarrier carrier)
+ public global::OpenTracing.ISpanContext? Extract(IFormat format, TCarrier carrier)
{
Guard.ThrowIfNull(format);
Guard.ThrowIfNull(carrier);
@@ -79,7 +79,7 @@ private TextMapPropagator Propagator
carrierMap.Add(entry.Key, new[] { entry.Value });
}
- static IEnumerable GetCarrierKeyValue(Dictionary> source, string key)
+ static IEnumerable? GetCarrierKeyValue(Dictionary> source, string key)
{
if (key == null || !source.TryGetValue(key, out var value))
{
diff --git a/src/OpenTelemetry/.publicApi/Experimental/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/Experimental/PublicAPI.Unshipped.txt
index 22a73f5d6b..7c9a6d046a 100644
--- a/src/OpenTelemetry/.publicApi/Experimental/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry/.publicApi/Experimental/PublicAPI.Unshipped.txt
@@ -1,8 +1,6 @@
abstract OpenTelemetry.Metrics.ExemplarReservoir.Collect() -> OpenTelemetry.Metrics.ReadOnlyExemplarCollection
abstract OpenTelemetry.Metrics.ExemplarReservoir.Offer(in OpenTelemetry.Metrics.ExemplarMeasurement measurement) -> void
abstract OpenTelemetry.Metrics.ExemplarReservoir.Offer(in OpenTelemetry.Metrics.ExemplarMeasurement measurement) -> void
-OpenTelemetry.Logs.LoggerProviderBuilderExtensions
-OpenTelemetry.Logs.LoggerProviderExtensions
OpenTelemetry.Logs.LogRecord.Logger.get -> OpenTelemetry.Logs.Logger!
OpenTelemetry.Logs.LogRecord.Severity.get -> OpenTelemetry.Logs.LogRecordSeverity?
OpenTelemetry.Logs.LogRecord.Severity.set -> void
@@ -19,25 +17,11 @@ OpenTelemetry.Metrics.FixedSizeExemplarReservoir.Capacity.get -> int
OpenTelemetry.Metrics.FixedSizeExemplarReservoir.FixedSizeExemplarReservoir(int capacity) -> void
OpenTelemetry.Metrics.FixedSizeExemplarReservoir.UpdateExemplar(int exemplarIndex, in OpenTelemetry.Metrics.ExemplarMeasurement measurement) -> void
OpenTelemetry.Metrics.FixedSizeExemplarReservoir.UpdateExemplar(int exemplarIndex, in OpenTelemetry.Metrics.ExemplarMeasurement measurement) -> void
-OpenTelemetry.Metrics.MetricStreamConfiguration.CardinalityLimit.get -> int?
-OpenTelemetry.Metrics.MetricStreamConfiguration.CardinalityLimit.set -> void
OpenTelemetry.Metrics.MetricStreamConfiguration.ExemplarReservoirFactory.get -> System.Func?
OpenTelemetry.Metrics.MetricStreamConfiguration.ExemplarReservoirFactory.set -> void
override sealed OpenTelemetry.Metrics.FixedSizeExemplarReservoir.Collect() -> OpenTelemetry.Metrics.ReadOnlyExemplarCollection
-static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddProcessor(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, OpenTelemetry.BaseProcessor! processor) -> OpenTelemetry.Logs.LoggerProviderBuilder!
-static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddProcessor(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, System.Func