diff --git a/.clomonitor.yml b/.clomonitor.yml
new file mode 100644
index 00000000000..4bc35d87f7d
--- /dev/null
+++ b/.clomonitor.yml
@@ -0,0 +1,4 @@
+# see https://github.com/cncf/clomonitor/blob/main/docs/checks.md#exemptions
+exemptions:
+ - check: artifacthub_badge
+ reason: "Artifact Hub doesn't support .NET packages"
diff --git a/.editorconfig b/.editorconfig
index 5bc89604c76..e3f693c1d13 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -10,6 +10,9 @@ indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
+[*.sh]
+end_of_line = lf
+
[*.{cs,cshtml,htm,html,md,py,sln,xml}]
indent_size = 4
@@ -41,7 +44,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 +56,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 +78,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 +86,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 +119,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 +135,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
@@ -152,7 +159,14 @@ dotnet_diagnostic.IDE0005.severity = warning
# RS0041: Public members should not use oblivious types
dotnet_diagnostic.RS0041.severity = suggestion
-[obj/**.cs]
+[*Tests.cs]
+# CA1515: Disable making types internal for Tests classes. It is required by xunit
+dotnet_diagnostic.CA1515.severity = none
+
+# CA2007: Disable Consider calling ConfigureAwait on the awaited task. It is not working with xunit
+dotnet_diagnostic.CA2007.severity = none
+
+[**/obj/**.cs]
generated_code = true
[*.csproj]
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000000..50ca329f24b
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+*.sh eol=lf
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 3bad5b876a7..1d9f2dd277a 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
@@ -61,7 +62,7 @@ body:
- type: textarea
attributes:
label: Steps to Reproduce
- description: Provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). We will close the issue if the repro project you share with us is complex or we cannot reproduce the behavior you are reporting. We cannot investigate custom projects, so don't point us to such, please.
+ description: Provide a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). We will close the issue if the repro project you share with us is complex or we cannot reproduce the behavior you are reporting. We cannot investigate custom projects, so don't point us to such, please.
validations:
required: true
@@ -83,3 +84,11 @@ body:
attributes:
label: Additional Context
description: Any additional information you think may be relevant to this issue.
+
+ - type: dropdown
+ attributes:
+ label: Tip
+ description: This element is static, used to render a helpful sub-heading for end-users and community members to help prioritize issues. Please leave as is.
+ options:
+ - "[React](https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/) with :+1: to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. Learn more [here](https://opentelemetry.io/community/end-user/issue-participation/)."
+ default: 0
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000000..3104c7c9769
--- /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 7fd9b2f4eda..9ca53fe8e7e 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:
@@ -52,3 +53,11 @@ body:
attributes:
label: Additional context
description: Any additional information you think may be relevant to this feature request.
+
+ - type: dropdown
+ attributes:
+ label: Tip
+ description: This element is static, used to render a helpful sub-heading for end-users and community members to help prioritize issues. Please leave as is.
+ options:
+ - "[React](https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/) with :+1: to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. Learn more [here](https://opentelemetry.io/community/end-user/issue-participation/)."
+ default: 0
diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml
deleted file mode 100644
index 76eea553517..00000000000
--- 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/dependabot.yml b/.github/dependabot.yml
index 2ac5ee67846..dda94ddd1f0 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,8 +1,10 @@
+# This file is retained solely for automated tooling to see we do automated
+# dependency updates as not all such scanners recognize the use of Renovate.
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
- interval: "daily"
+ interval: yearly
labels:
- "infra"
diff --git a/.github/renovate.json b/.github/renovate.json
new file mode 100644
index 00000000000..996d775ec7f
--- /dev/null
+++ b/.github/renovate.json
@@ -0,0 +1,70 @@
+{
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+ "additionalBranchPrefix": "{{manager}}/",
+ "automerge": false,
+ "commitBodyTable": true,
+ "commitMessageAction": "Bump",
+ "dependencyDashboard": false,
+ "extends": [
+ "config:best-practices",
+ "customManagers:dockerfileVersions",
+ "customManagers:githubActionsVersions",
+ ":automergeRequireAllStatusChecks",
+ ":disableRateLimiting",
+ ":enableVulnerabilityAlerts",
+ ":gitSignOff",
+ ":ignoreUnstable"
+ ],
+ "ignorePresets": [
+ ":ignoreModulesAndTests"
+ ],
+ "ignorePaths": [
+ "**/node_modules/**",
+ "**/bower_components/**",
+ "**/vendor/**",
+ "**/__tests__/**",
+ "**/__fixtures__/**"
+ ],
+ "labels": ["dependencies", "infra"],
+ "packageRules": [
+ {
+ "matchManagers": ["dockerfile"],
+ "addLabels": ["docker"]
+ },
+ {
+ "matchManagers": ["github-actions"],
+ "addLabels": ["github_actions"]
+ },
+ {
+ "matchManagers": ["nuget"],
+ "addLabels": [".NET"]
+ },
+ {
+ "matchManagers": ["pypi"],
+ "addLabels": ["python"]
+ },
+ {
+ "description": ["Skip pinned NuGet package versions"],
+ "matchManagers": ["nuget"],
+ "matchCurrentValue": "^\\[[^,]+,\\)$",
+ "enabled": false
+ },
+ {
+ "extends": ["monorepo:dotnet"],
+ "description": ["Disable major version updates for .NET"],
+ "matchUpdateTypes": ["major"],
+ "enabled": false
+ },
+ {
+ "matchDepNames": ["xunit"],
+ "description": ["Disable major version updates for xunit"],
+ "matchUpdateTypes": ["major"],
+ "enabled": false
+ }
+ ],
+ "schedule": ["* 8-17 * * 3"],
+ "timezone": "Etc/UTC",
+ "vulnerabilityAlerts": {
+ "addLabels": ["security"]
+ }
+}
diff --git a/.github/workflows/Component.BuildTest.yml b/.github/workflows/Component.BuildTest.yml
index f5ef85e0dc3..406be841884 100644
--- a/.github/workflows/Component.BuildTest.yml
+++ b/.github/workflows/Component.BuildTest.yml
@@ -20,14 +20,17 @@ on:
required: false
type: string
os-list:
- default: '[ "windows-latest", "ubuntu-latest" ]'
+ default: '[ "windows-latest", "windows-11-arm", "ubuntu-22.04", "ubuntu-22.04-arm" ]'
required: false
type: string
tfm-list:
- default: '[ "net462", "net6.0", "net7.0", "net8.0" ]'
+ default: '[ "net462", "net8.0", "net9.0" ]'
required: false
type: string
+permissions:
+ contents: read
+
jobs:
build-test:
@@ -37,20 +40,33 @@ jobs:
os: ${{ fromJSON(inputs.os-list) }}
version: ${{ fromJSON(inputs.tfm-list) }}
exclude:
- - os: ubuntu-latest
+ - os: ubuntu-22.04
+ version: net462
+ - os: ubuntu-22.04-arm
version: net462
+ - os: ubuntu-22.04-arm
+ version: net8.0
+ - os: windows-11-arm
+ version: net8.0
runs-on: ${{ matrix.os }}
+ timeout-minutes: 30
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Note: By default GitHub only fetches 1 commit. MinVer needs to find
# the version tag which is typically NOT on the first commit so we
# retrieve them all.
fetch-depth: 0
- - name: Setup dotnet
- uses: actions/setup-dotnet@v4
+ - name: Setup previous .NET runtimes
+ uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
+ with:
+ dotnet-version: |
+ 8.0.x
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
- name: dotnet restore ${{ inputs.project-name }}
run: dotnet restore ${{ inputs.project-name }} ${{ inputs.project-build-commands }}
@@ -59,7 +75,18 @@ jobs:
run: dotnet build ${{ inputs.project-name }} --configuration Release --no-restore ${{ inputs.project-build-commands }}
- name: dotnet test ${{ inputs.project-name }}
- run: dotnet test ${{ inputs.project-name }} --collect:"Code Coverage" --results-directory:TestResults --framework ${{ matrix.version }} --configuration Release --no-restore --no-build --logger:"console;verbosity=detailed" -- RunConfiguration.DisableAppDomain=true
+ run: >
+ dotnet test ${{ inputs.project-name }}
+ --collect:"Code Coverage"
+ --results-directory:TestResults
+ --framework ${{ matrix.version }}
+ --configuration Release
+ --no-restore
+ --no-build
+ --logger:"console;verbosity=detailed"
+ --logger:"GitHubActions;report-warnings=false"
+ --logger:"junit;LogFilePath=TestResults/junit.xml"
+ -- RunConfiguration.DisableAppDomain=true
- name: Install coverage tool
run: dotnet tool install -g dotnet-coverage
@@ -68,15 +95,24 @@ jobs:
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
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
continue-on-error: true # Note: Don't fail for upload failures
env:
OS: ${{ matrix.os }}
TFM: ${{ matrix.version }}
- token: ${{ secrets.CODECOV_TOKEN }}
with:
- file: TestResults/Cobertura.xml
+ files: TestResults/Cobertura.xml
env_vars: OS,TFM
flags: ${{ inputs.code-cov-prefix }}-${{ inputs.code-cov-name }}
name: Code Coverage for ${{ inputs.code-cov-prefix }}-${{ inputs.code-cov-name }} on [${{ matrix.os }}.${{ matrix.version }}]
codecov_yml_path: .github/codecov.yml
+ token: ${{ secrets.CODECOV_TOKEN }}
+
+ - name: Upload test results ${{ inputs.code-cov-prefix }}-${{ inputs.code-cov-name }}
+ if: ${{ !cancelled() && hashFiles('./**/TestResults/junit.xml') != '' }}
+ uses: codecov/test-results-action@47f89e9acb64b76debcd5ea40642d25a4adced9f # v1.1.1
+ with:
+ env_vars: OS,TFM
+ flags: ${{ inputs.code-cov-prefix }}-${{ inputs.code-cov-name }}
+ name: Test results for ${{ inputs.code-cov-prefix }}-${{ inputs.code-cov-name }} on [${{ matrix.os }}.${{ matrix.version }}]
+ token: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/add-labels.yml b/.github/workflows/add-labels.yml
index cae26b876b4..19d25be7e44 100644
--- a/.github/workflows/add-labels.yml
+++ b/.github/workflows/add-labels.yml
@@ -7,18 +7,19 @@ on:
branches: [ 'main*' ]
permissions:
- issues: write
- pull-requests: write
+ contents: read
jobs:
add-labels-on-issues:
+ permissions:
+ issues: write
if: github.event_name == 'issues' && !github.event.issue.pull_request
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- name: check out code
- uses: actions/checkout@v4
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Add labels for package found in bug issue descriptions
shell: pwsh
@@ -33,13 +34,15 @@ jobs:
ISSUE_BODY: ${{ github.event.issue.body }}
add-labels-on-pull-requests:
+ permissions:
+ pull-requests: write
if: github.event_name == 'pull_request_target'
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- name: check out code
- uses: actions/checkout@v4
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
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
diff --git a/.github/workflows/automation.yml b/.github/workflows/automation.yml
index 1385474892a..2daa116be62 100644
--- a/.github/workflows/automation.yml
+++ b/.github/workflows/automation.yml
@@ -5,30 +5,33 @@ on:
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 }}
+ application-name:
+ value: ${{ vars.AUTOMATION_APPLICATION_NAME }}
+ application-username:
+ value: ${{ vars.AUTOMATION_APPLICATION_USERNAME }}
secrets:
- OPENTELEMETRYBOT_GITHUB_TOKEN:
+ OTELBOT_DOTNET_PRIVATE_KEY:
required: false
+permissions:
+ contents: read
+
jobs:
resolve-automation:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
outputs:
enabled: ${{ steps.evaluate.outputs.enabled }}
- token-secret-name: ${{ steps.evaluate.outputs.token-secret-name }}
env:
- OPENTELEMETRYBOT_GITHUB_TOKEN_EXISTS: ${{ secrets.OPENTELEMETRYBOT_GITHUB_TOKEN != '' }}
+ OTELBOT_DOTNET_PRIVATE_KEY_EXISTS: ${{ secrets.OTELBOT_DOTNET_PRIVATE_KEY != '' }}
steps:
- id: evaluate
run: |
- echo "enabled=${{ env.OPENTELEMETRYBOT_GITHUB_TOKEN_EXISTS == 'true' }}" >> "$GITHUB_OUTPUT"
- echo "token-secret-name=OPENTELEMETRYBOT_GITHUB_TOKEN" >> "$GITHUB_OUTPUT"
+ echo "enabled=${{ env.OTELBOT_DOTNET_PRIVATE_KEY_EXISTS == 'true' }}" >> "$GITHUB_OUTPUT"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7f222b07cc3..3110eef0cc6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -9,22 +9,32 @@ on:
pull_request:
branches: [ 'main*' ]
+permissions:
+ contents: read
+
jobs:
lint-misspell-sanitycheck:
uses: ./.github/workflows/sanitycheck.yml
+ code-ql:
+ uses: ./.github/workflows/codeql-analysis-steps.yml
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
detect-changes:
runs-on: windows-latest
outputs:
changes: ${{ steps.changes.outputs.changes }}
steps:
- - uses: actions/checkout@v4
- - uses: AurorNZ/paths-filter@v4
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ - uses: AurorNZ/paths-filter@3b1f3abc3371cca888d8eb03dfa70bc8a9867629 # v4.0.0
id: changes
with:
filters: |
md: ['**.md']
- build: ['build/**', '.github/**/*.yml', '**/*.targets', '**/*.props']
+ build: ['build/**', '.github/**/*.yml', '**/*.targets', '**/*.props', 'global.json']
shared: ['src/Shared/**']
code: ['**.cs', '**.csproj', '.editorconfig']
solution: ['OpenTelemetry.sln']
@@ -107,13 +117,13 @@ jobs:
|| contains(needs.detect-changes.outputs.changes, 'otlp')
|| contains(needs.detect-changes.outputs.changes, 'build')
|| contains(needs.detect-changes.outputs.changes, 'shared')
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
- version: [ net6.0, net7.0, net8.0 ]
+ version: [ net8.0, net9.0 ]
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Run OTLP Exporter docker compose
run: docker compose --file=test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTest/docker-compose.yml --file=build/docker-compose.${{ matrix.version }}.yml --project-directory=. up --exit-code-from=tests --build
@@ -125,13 +135,13 @@ jobs:
|| contains(needs.detect-changes.outputs.changes, 'instrumentation')
|| contains(needs.detect-changes.outputs.changes, 'build')
|| contains(needs.detect-changes.outputs.changes, 'shared')
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
- version: [ net6.0, net7.0 ]
+ version: [ net8.0, net9.0 ]
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Run W3C Trace Context docker compose
run: docker compose --file=test/OpenTelemetry.Instrumentation.W3cTraceContext.Tests/docker-compose.yml --file=build/docker-compose.${{ matrix.version }}.yml --project-directory=. up --exit-code-from=tests --build
@@ -171,8 +181,9 @@ jobs:
build-test:
needs: [
- lint-misspell-sanitycheck,
detect-changes,
+ code-ql,
+ lint-misspell-sanitycheck,
lint-md,
lint-dotnet-format,
build-test-solution,
@@ -186,7 +197,18 @@ jobs:
verify-aot-compat,
concurrency-tests
]
- if: always() && !cancelled() && !contains(needs.*.result, 'failure')
- runs-on: windows-latest
+ if: always() && !cancelled()
+ runs-on: ubuntu-24.04
steps:
- - run: echo 'build complete'
+ - name: Report CI status
+ shell: bash
+ env:
+ CI_SUCCESS: ${{ !contains(needs.*.result, 'failure') }}
+ run: |
+ if [ "${CI_SUCCESS}" == "true" ]
+ then
+ echo 'Build complete'
+ else
+ echo 'Build failed'
+ exit 1
+ fi
diff --git a/.github/workflows/codeql-analysis-steps.yml b/.github/workflows/codeql-analysis-steps.yml
new file mode 100644
index 00000000000..47a6ba61535
--- /dev/null
+++ b/.github/workflows/codeql-analysis-steps.yml
@@ -0,0 +1,65 @@
+name: codeql-analysis-steps
+
+on:
+ workflow_call:
+
+permissions: {}
+
+jobs:
+ analyze:
+ permissions:
+ actions: read # for github/codeql-action/init to get workflow details
+ contents: read # for actions/checkout to fetch code
+ security-events: write # for github/codeql-action/analyze to upload SARIF results
+ runs-on: windows-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: ['actions', 'csharp']
+
+ steps:
+ - name: Configure Pagefile
+ if: matrix.language == 'csharp'
+ uses: al-cheb/configure-pagefile-action@a3b6ebd6b634da88790d9c58d4b37a7f4a7b8708 # v1.4
+ with:
+ minimum-size: 8GB
+ maximum-size: 32GB
+ disk-root: "D:"
+
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ with:
+ filter: 'tree:0'
+ persist-credentials: false
+ show-progress: false
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3.30.4
+ with:
+ build-mode: none
+ languages: ${{ matrix.language }}
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3.30.4
+ with:
+ category: '/language:${{ matrix.language }}'
+
+ results:
+ if: ${{ !cancelled() }}
+ needs: [ analyze ]
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Report status
+ shell: bash
+ env:
+ SCAN_SUCCESS: ${{ !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }}
+ run: |
+ if [ "${SCAN_SUCCESS}" == "true" ]
+ then
+ echo 'CodeQL analysis successful'
+ else
+ echo 'CodeQL analysis failed'
+ exit 1
+ fi
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 3cdd6a57b6d..44fc56c2444 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -1,8 +1,3 @@
-# For most projects, this workflow file will not need changing; you simply need
-# to commit it to your repository.
-#
-# You may wish to alter this file to override the set of languages analyzed,
-# or to provide custom queries or build logic.
name: "CodeQL"
on:
@@ -10,37 +5,12 @@ on:
- cron: '0 0 * * *' # once in a day at 00:00
workflow_dispatch:
-jobs:
- analyze:
- name: Analyze
- runs-on: windows-latest
-
- strategy:
- fail-fast: false
- matrix:
- language: ['csharp']
-
- steps:
- - name: configure Pagefile
- uses: al-cheb/configure-pagefile-action@v1.4
- with:
- minimum-size: 8GB
- maximum-size: 32GB
- disk-root: "D:"
-
- - name: Checkout repository
- uses: actions/checkout@v4
+permissions: {}
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v3
- with:
- languages: ${{ matrix.language }}
-
- - name: Setup dotnet
- uses: actions/setup-dotnet@v4
-
- - name: dotnet pack
- run: dotnet pack ./build/OpenTelemetry.proj --configuration Release
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v3
+jobs:
+ code-ql:
+ uses: ./.github/workflows/codeql-analysis-steps.yml
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
diff --git a/.github/workflows/concurrency-tests.yml b/.github/workflows/concurrency-tests.yml
index 4ff616911ce..ae1e64bfcf9 100644
--- a/.github/workflows/concurrency-tests.yml
+++ b/.github/workflows/concurrency-tests.yml
@@ -5,22 +5,25 @@ name: Concurrency Tests
on:
workflow_call:
+permissions:
+ contents: read
+
jobs:
run-concurrency-tests:
strategy:
fail-fast: false # ensures the entire test matrix is run, even if one permutation fails
matrix:
- os: [ windows-latest, ubuntu-latest ]
+ os: [ windows-latest, ubuntu-22.04 ]
version: [ net8.0 ]
project: [ OpenTelemetry.Tests, OpenTelemetry.Api.Tests ]
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup dotnet
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
- name: Run Coyote Tests
shell: pwsh
@@ -28,7 +31,7 @@ jobs:
- name: Publish Artifacts
if: always() && !cancelled()
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ matrix.os }}-${{ matrix.project }}-${{ matrix.version }}-coyoteoutput
path: '**/*_CoyoteOutput.*'
diff --git a/.github/workflows/docfx.yml b/.github/workflows/docfx.yml
index 4c2031c9303..fcf07c097b3 100644
--- a/.github/workflows/docfx.yml
+++ b/.github/workflows/docfx.yml
@@ -5,13 +5,19 @@ name: Build docfx
on:
workflow_call:
+permissions:
+ contents: read
+
jobs:
run-docfx-build:
runs-on: windows-latest
steps:
- name: check out code
- uses: actions/checkout@v4
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
- name: install docfx
run: dotnet tool install -g docfx
diff --git a/.github/workflows/dotnet-format.yml b/.github/workflows/dotnet-format.yml
index 2ea4834570f..dc72da32565 100644
--- a/.github/workflows/dotnet-format.yml
+++ b/.github/workflows/dotnet-format.yml
@@ -5,16 +5,19 @@ name: Lint - dotnet format
on:
workflow_call:
+permissions:
+ contents: read
+
jobs:
run-dotnet-format-stable:
runs-on: windows-latest
steps:
- name: check out code
- uses: actions/checkout@v4
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup dotnet
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
- name: dotnet restore
run: dotnet restore OpenTelemetry.sln
@@ -29,10 +32,10 @@ jobs:
steps:
- name: check out code
- uses: actions/checkout@v4
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup dotnet
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
- name: dotnet restore
run: dotnet restore OpenTelemetry.sln
diff --git a/.github/workflows/fossa.yml b/.github/workflows/fossa.yml
new file mode 100644
index 00000000000..f86b5a99322
--- /dev/null
+++ b/.github/workflows/fossa.yml
@@ -0,0 +1,20 @@
+name: FOSSA scanning
+
+on:
+ push:
+ branches:
+ - main
+
+permissions:
+ contents: read
+
+jobs:
+ fossa:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - uses: fossas/fossa-action@3ebcea1862c6ffbd5cf1b4d0bd6b3fe7bd6f2cac # v1.7.0
+ with:
+ api-key: ${{secrets.FOSSA_API_KEY}}
+ team: OpenTelemetry
diff --git a/.github/workflows/markdownlint.yml b/.github/workflows/markdownlint.yml
index 2764b8cc937..2ce6431d9cc 100644
--- a/.github/workflows/markdownlint.yml
+++ b/.github/workflows/markdownlint.yml
@@ -5,16 +5,19 @@ name: Lint - Markdown
on:
workflow_call:
+permissions:
+ contents: read
+
jobs:
run-markdownlint:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- name: check out code
- uses: actions/checkout@v4
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: run markdownlint
- uses: DavidAnson/markdownlint-cli2-action@v16.0.0
+ uses: DavidAnson/markdownlint-cli2-action@992badcdf24e3b8eb7e87ff9287fe931bcb00c6e # v20.0.0
with:
globs: |
**/*.md
diff --git a/.github/workflows/ossf-scorecard.yml b/.github/workflows/ossf-scorecard.yml
new file mode 100644
index 00000000000..3d950859b51
--- /dev/null
+++ b/.github/workflows/ossf-scorecard.yml
@@ -0,0 +1,47 @@
+name: OSSF Scorecard
+
+on:
+ push:
+ branches:
+ - main
+ schedule:
+ - cron: "24 5 * * 0" # once a week
+ workflow_dispatch:
+
+permissions: read-all
+
+jobs:
+ analysis:
+ runs-on: ubuntu-latest
+ permissions:
+ # Needed for Code scanning upload
+ security-events: write
+ # Needed for GitHub OIDC token if publish_results is true
+ id-token: write
+ steps:
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ with:
+ persist-credentials: false
+
+ - uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
+ with:
+ results_file: results.sarif
+ results_format: sarif
+ publish_results: true
+
+ # Upload the results as artifacts (optional). Commenting out will disable
+ # uploads of run results in SARIF format to the repository Actions tab.
+ # https://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts
+ - name: "Upload artifact"
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ with:
+ name: SARIF file
+ path: results.sarif
+ retention-days: 5
+
+ # Upload the results to GitHub's code scanning dashboard (optional).
+ # Commenting out will disable upload of results to your repo's Code Scanning dashboard
+ - name: "Upload to code-scanning"
+ uses: github/codeql-action/upload-sarif@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3.30.4
+ with:
+ sarif_file: results.sarif
diff --git a/.github/workflows/package-validation.yml b/.github/workflows/package-validation.yml
index d1f7658ee2d..3216646f45c 100644
--- a/.github/workflows/package-validation.yml
+++ b/.github/workflows/package-validation.yml
@@ -5,12 +5,15 @@ name: Package Validation
on:
workflow_call:
+permissions:
+ contents: read
+
jobs:
run-package-validation-stable:
runs-on: windows-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Note: By default GitHub only fetches 1 commit. MinVer needs to find
# the version tag which is typically NOT on the first commit so we
@@ -18,16 +21,23 @@ jobs:
fetch-depth: 0
- name: Setup dotnet
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
- name: dotnet pack
run: dotnet pack ./build/OpenTelemetry.proj --configuration Release /p:EnablePackageValidation=true /p:ExposeExperimentalFeatures=false /p:RunningDotNetPack=true
+ - name: Publish stable NuGet packages to Artifacts
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ with:
+ name: packages-stable
+ path: ./artifacts/package/release
+ if-no-files-found: error
+
run-package-validation-experimental:
runs-on: windows-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Note: By default GitHub only fetches 1 commit. MinVer needs to find
# the version tag which is typically NOT on the first commit so we
@@ -35,7 +45,14 @@ jobs:
fetch-depth: 0
- name: Setup dotnet
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
- name: dotnet pack
run: dotnet pack ./build/OpenTelemetry.proj --configuration Release /p:EnablePackageValidation=true /p:ExposeExperimentalFeatures=true /p:RunningDotNetPack=true
+
+ - name: Publish experimental NuGet packages to Artifacts
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ with:
+ name: packages-experimental
+ path: ./artifacts/package/release
+ if-no-files-found: error
diff --git a/.github/workflows/post-release.yml b/.github/workflows/post-release.yml
index e824e87d724..7a06a0c6580 100644
--- a/.github/workflows/post-release.yml
+++ b/.github/workflows/post-release.yml
@@ -16,104 +16,148 @@ on:
types:
- created
+permissions:
+ contents: read
+
jobs:
automation:
uses: ./.github/workflows/automation.yml
- secrets: inherit
+ secrets:
+ OTELBOT_DOTNET_PRIVATE_KEY: ${{ secrets.OTELBOT_DOTNET_PRIVATE_KEY }}
push-packages-and-publish-release:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
needs: automation
+ permissions:
+ id-token: write
+
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] }}
+ github.event_name == 'issue_comment' &&
+ github.event.issue.pull_request &&
+ github.event.issue.locked == true &&
+ github.event.comment.user.login != needs.automation.outputs.application-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
steps:
- - name: check out code
- uses: actions/checkout@v4
+ - uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
+ id: otelbot-token
+ with:
+ app-id: ${{ vars.OTELBOT_DOTNET_APP_ID }}
+ private-key: ${{ secrets.OTELBOT_DOTNET_PRIVATE_KEY }}
+
+ - name: Check out code
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
- token: ${{ secrets[needs.automation.outputs.token-secret-name] }}
+ token: ${{ steps.otelbot-token.outputs.token }}
ref: ${{ github.event.repository.default_branch }}
+ - name: Setup .NET
+ uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
+
+ - name: NuGet log in
+ uses: NuGet/login@d22cc5f58ff5b88bf9bd452535b4335137e24544 # v1.1.0
+ id: nuget-login
+ with:
+ user: ${{ secrets.NUGET_USER }}
+
- name: Push packages and publish release
shell: pwsh
env:
- NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
+ GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
+ EXPECTED_PR_AUTHOR_USER_NAME: ${{ needs.automation.outputs.application-name }}
+ COMMENT_USER_NAME: ${{ github.event.comment.user.login }}
+ ISSUE_NUMBER: ${{ github.event.issue.number }}
+ NUGET_TOKEN: ${{ steps.nuget-login.outputs.NUGET_API_KEY }}
run: |
Import-Module .\build\scripts\post-release.psm1
+ $HasToken = -Not [string]::IsNullOrEmpty($env:NUGET_TOKEN)
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 != '' }}'
+ -gitRepository ${env:GITHUB_REPOSITORY} `
+ -pullRequestNumber ${env:ISSUE_NUMBER} `
+ -expectedPrAuthorUserName ${env:EXPECTED_PR_AUTHOR_USER_NAME} `
+ -commentUserName ${env:COMMENT_USER_NAME} `
+ -artifactDownloadPath "${env:GITHUB_WORKSPACE}/artifacts" `
+ -pushToNuget $HasToken
post-release-published:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
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] }}
+ needs.automation.outputs.enabled &&
+ (github.event_name == 'release' || github.event_name == 'workflow_dispatch')
steps:
- - uses: actions/checkout@v4
+ - uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
+ id: otelbot-token
+ with:
+ app-id: ${{ vars.OTELBOT_DOTNET_APP_ID }}
+ private-key: ${{ secrets.OTELBOT_DOTNET_PRIVATE_KEY }}
+
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
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] }}
+ token: ${{ steps.otelbot-token.outputs.token }}
+
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
- 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
+ env:
+ GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
+ BOT_USER_EMAIL: ${{ needs.automation.outputs.email }}
+ BOT_USER_NAME: ${{ needs.automation.outputs.username }}
+ TAG: ${{ inputs.tag || github.ref_name }}
+ TARGET_BRANCH: ${{ github.event.repository.default_branch }}
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 }}'
+ -gitRepository ${env:GITHUB_REPOSITORY} `
+ -tag ${env:TAG} `
+ -targetBranch ${env:TARGET_BRANCH} `
+ -gitUserName ${env:BOT_USER_NAME} `
+ -gitUserEmail ${env:BOT_USER_EMAIL}
- name: Invoke core version update workflow in opentelemetry-dotnet-contrib repository
if: vars.CONTRIB_REPO
shell: pwsh
+ env:
+ GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
+ CONTRIB_REPO: ${{ vars.CONTRIB_REPO }}
+ TAG: ${{ inputs.tag || github.ref_name }}
run: |
Import-Module .\build\scripts\post-release.psm1
InvokeCoreVersionUpdateWorkflowInRemoteRepository `
- -remoteGitRepository '${{ vars.CONTRIB_REPO }}' `
- -tag '${{ inputs.tag || github.ref_name }}'
+ -remoteGitRepository ${env:CONTRIB_REPO} `
+ -tag ${env:TAG}
- name: Post notice when release is published
shell: pwsh
+ env:
+ GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
+ EXPECTED_PR_AUTHOR_USER_NAME: ${{ needs.automation.outputs.application-name }}
+ TAG: ${{ inputs.tag || github.ref_name }}
run: |
Import-Module .\build\scripts\post-release.psm1
TryPostReleasePublishedNoticeOnPrepareReleasePullRequest `
- -gitRepository '${{ github.repository }}' `
- -botUserName '${{ needs.automation.outputs.username }}' `
- -tag '${{ inputs.tag || github.ref_name }}'
+ -gitRepository ${env:GITHUB_REPOSITORY} `
+ -expectedPrAuthorUserName ${env:EXPECTED_PR_AUTHOR_USER_NAME} `
+ -tag ${env:TAG}
diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml
index bd8211e645e..5d8eb56ae39 100644
--- a/.github/workflows/prepare-release.yml
+++ b/.github/workflows/prepare-release.yml
@@ -23,108 +23,238 @@ on:
types:
- created
+permissions:
+ contents: read
+
jobs:
automation:
uses: ./.github/workflows/automation.yml
- secrets: inherit
+ secrets:
+ OTELBOT_DOTNET_PRIVATE_KEY: ${{ secrets.OTELBOT_DOTNET_PRIVATE_KEY }}
prepare-release-pr:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
needs: automation
if: github.event_name == 'workflow_dispatch' && needs.automation.outputs.enabled
- env:
- GH_TOKEN: ${{ secrets[needs.automation.outputs.token-secret-name] }}
-
steps:
- - name: check out code
- uses: actions/checkout@v4
+ - uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
+ id: otelbot-token
+ with:
+ app-id: ${{ vars.OTELBOT_DOTNET_APP_ID }}
+ private-key: ${{ secrets.OTELBOT_DOTNET_PRIVATE_KEY }}
+
+ - name: Check out code
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
- token: ${{ secrets[needs.automation.outputs.token-secret-name] }}
+ token: ${{ steps.otelbot-token.outputs.token }}
- name: Create GitHub Pull Request to prepare release
shell: pwsh
+ env:
+ GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
+ BOT_USER_EMAIL: ${{ needs.automation.outputs.email }}
+ BOT_USER_NAME: ${{ needs.automation.outputs.username }}
+ COMMENT_USER_NAME: ${{ github.event.sender.login }}
+ TAG_PREFIX: ${{ inputs.tag-prefix }}
+ VERSION: ${{ inputs.version }}
run: |
Import-Module .\build\scripts\prepare-release.psm1
CreatePullRequestToUpdateChangelogsAndPublicApis `
- -gitRepository '${{ github.repository }}' `
- -minVerTagPrefix '${{ inputs.tag-prefix }}' `
- -version '${{ inputs.version }}' `
- -targetBranch '${{ github.ref_name }}' `
- -gitUserName '${{ needs.automation.outputs.username }}' `
- -gitUserEmail '${{ needs.automation.outputs.email }}'
+ -gitRepository ${env:GITHUB_REPOSITORY} `
+ -minVerTagPrefix ${env:TAG_PREFIX} `
+ -version ${env:VERSION} `
+ -requestedByUserName ${env:COMMENT_USER_NAME} `
+ -targetBranch ${env:GITHUB_REF_NAME} `
+ -gitUserName ${env:BOT_USER_NAME} `
+ -gitUserEmail ${env:BOT_USER_EMAIL}
lock-pr-and-post-notice-to-create-release-tag:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
needs: automation
if: |
- github.event_name == 'pull_request'
- && github.event.action == 'closed'
- && github.event.pull_request.user.login == needs.automation.outputs.username
- && github.event.pull_request.merged == true
- && startsWith(github.event.pull_request.title, '[release] Prepare release ')
- && needs.automation.outputs.enabled
-
- env:
- GH_TOKEN: ${{ secrets[needs.automation.outputs.token-secret-name] }}
+ github.event_name == 'pull_request' &&
+ github.event.action == 'closed' &&
+ github.event.pull_request.user.login == needs.automation.outputs.application-username &&
+ github.event.pull_request.merged == true &&
+ startsWith(github.event.pull_request.title, '[release] Prepare release ') &&
+ needs.automation.outputs.enabled
steps:
- - name: check out code
- uses: actions/checkout@v4
+ - uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
+ id: otelbot-token
with:
- token: ${{ secrets[needs.automation.outputs.token-secret-name] }}
+ app-id: ${{ vars.OTELBOT_DOTNET_APP_ID }}
+ private-key: ${{ secrets.OTELBOT_DOTNET_PRIVATE_KEY }}
+
+ - name: Check out code
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ with:
+ token: ${{ steps.otelbot-token.outputs.token }}
- name: Lock GitHub Pull Request to prepare release
shell: pwsh
+ env:
+ GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
+ EXPECTED_PR_AUTHOR_USER_NAME: ${{ needs.automation.outputs.application-name }}
+ ISSUE_NUMBER: ${{ github.event.pull_request.number }}
run: |
Import-Module .\build\scripts\prepare-release.psm1
LockPullRequestAndPostNoticeToCreateReleaseTag `
- -gitRepository '${{ github.repository }}' `
- -pullRequestNumber '${{ github.event.pull_request.number }}' `
- -botUserName '${{ needs.automation.outputs.username }}'
+ -gitRepository ${env:GITHUB_REPOSITORY} `
+ -pullRequestNumber ${env:ISSUE_NUMBER} `
+ -expectedPrAuthorUserName ${env:EXPECTED_PR_AUTHOR_USER_NAME}
create-release-tag-pr-post-notice:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
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, '/CreateReleaseTag')
- && 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] }}
+ github.event_name == 'issue_comment' &&
+ github.event.issue.pull_request &&
+ github.event.issue.locked == true &&
+ github.event.comment.user.login != needs.automation.outputs.application-username &&
+ contains(github.event.comment.body, '/CreateReleaseTag') &&
+ startsWith(github.event.issue.title, '[release] Prepare release ') &&
+ github.event.issue.pull_request.merged_at &&
+ needs.automation.outputs.enabled
steps:
- - name: check out code
- uses: actions/checkout@v4
+ - uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
+ id: otelbot-token
+ with:
+ app-id: ${{ vars.OTELBOT_DOTNET_APP_ID }}
+ private-key: ${{ secrets.OTELBOT_DOTNET_PRIVATE_KEY }}
+
+ - name: Check out code
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
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] }}
+ token: ${{ steps.otelbot-token.outputs.token }}
- name: Create release tag
id: create-tag
shell: pwsh
+ env:
+ GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
+ BOT_USER_EMAIL: ${{ needs.automation.outputs.email }}
+ BOT_USER_NAME: ${{ needs.automation.outputs.username }}
+ EXPECTED_PR_AUTHOR_USER_NAME: ${{ needs.automation.outputs.application-name }}
+ ISSUE_NUMBER: ${{ github.event.issue.number }}
run: |
Import-Module .\build\scripts\prepare-release.psm1
CreateReleaseTagAndPostNoticeOnPullRequest `
- -gitRepository '${{ github.repository }}' `
- -pullRequestNumber '${{ github.event.issue.number }}' `
- -botUserName '${{ needs.automation.outputs.username }}' `
- -gitUserName '${{ needs.automation.outputs.username }}' `
- -gitUserEmail '${{ needs.automation.outputs.email }}'
+ -gitRepository ${env:GITHUB_REPOSITORY} `
+ -pullRequestNumber ${env:ISSUE_NUMBER} `
+ -expectedPrAuthorUserName ${env:EXPECTED_PR_AUTHOR_USER_NAME} `
+ -gitUserName ${env:BOT_USER_NAME} `
+ -gitUserEmail ${env:BOT_USER_EMAIL}
+
+ update-changelog-release-dates-on-prepare-pr-post-notice:
+ runs-on: ubuntu-24.04
+
+ 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.application-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
+
+ steps:
+ - uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
+ id: otelbot-token
+ with:
+ app-id: ${{ vars.OTELBOT_DOTNET_APP_ID }}
+ private-key: ${{ secrets.OTELBOT_DOTNET_PRIVATE_KEY }}
+
+ - name: Check out code
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ with:
+ # Note: By default GitHub only fetches 1 commit which fails the git tag operation below
+ fetch-depth: 0
+ token: ${{ steps.otelbot-token.outputs.token }}
+
+ - name: Update release date
+ shell: pwsh
+ env:
+ GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
+ BOT_USER_EMAIL: ${{ needs.automation.outputs.email }}
+ BOT_USER_NAME: ${{ needs.automation.outputs.username }}
+ EXPECTED_PR_AUTHOR_USER_NAME: ${{ needs.automation.outputs.application-name }}
+ COMMENT_USER_NAME: ${{ github.event.comment.user.login }}
+ ISSUE_NUMBER: ${{ github.event.issue.number }}
+ run: |
+ Import-Module .\build\scripts\prepare-release.psm1
+
+ UpdateChangelogReleaseDatesAndPostNoticeOnPullRequest `
+ -gitRepository ${env:GITHUB_REPOSITORY} `
+ -pullRequestNumber ${env:ISSUE_NUMBER} `
+ -expectedPrAuthorUserName ${env:EXPECTED_PR_AUTHOR_USER_NAME} `
+ -commentUserName ${env:COMMENT_USER_NAME} `
+ -gitUserName ${env:BOT_USER_NAME} `
+ -gitUserEmail ${env:BOT_USER_EMAIL}
+
+ update-releasenotes-on-prepare-pr-post-notice:
+ runs-on: ubuntu-24.04
+
+ 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.application-username &&
+ contains(github.event.comment.body, '/UpdateReleaseNotes') &&
+ startsWith(github.event.issue.title, '[release] Prepare release ') &&
+ github.event.issue.pull_request.merged_at == null &&
+ needs.automation.outputs.enabled
+
+ steps:
+ - uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
+ id: otelbot-token
+ with:
+ app-id: ${{ vars.OTELBOT_DOTNET_APP_ID }}
+ private-key: ${{ secrets.OTELBOT_DOTNET_PRIVATE_KEY }}
+
+ - name: Check out code
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ with:
+ # Note: By default GitHub only fetches 1 commit which fails the git tag operation below
+ fetch-depth: 0
+ token: ${{ steps.otelbot-token.outputs.token }}
+
+ - name: Update release notes
+ env:
+ GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
+ BOT_USER_EMAIL: ${{ needs.automation.outputs.email }}
+ BOT_USER_NAME: ${{ needs.automation.outputs.username }}
+ EXPECTED_PR_AUTHOR_USER_NAME: ${{ needs.automation.outputs.application-name }}
+ COMMENT_BODY: ${{ github.event.comment.body }}
+ COMMENT_USER_NAME: ${{ github.event.comment.user.login }}
+ ISSUE_NUMBER: ${{ github.event.issue.number }}
+ shell: pwsh
+ run: |
+ Import-Module .\build\scripts\prepare-release.psm1
+ UpdateReleaseNotesAndPostNoticeOnPullRequest `
+ -gitRepository ${env:GITHUB_REPOSITORY} `
+ -pullRequestNumber ${env:ISSUE_NUMBER} `
+ -expectedPrAuthorUserName ${env:EXPECTED_PR_AUTHOR_USER_NAME} `
+ -commentUserName ${env:COMMENT_USER_NAME} `
+ -commentBody $Env:COMMENT_BODY `
+ -gitUserName ${env:BOT_USER_NAME} `
+ -gitUserEmail ${env:BOT_USER_EMAIL}
diff --git a/.github/workflows/publish-packages-1.0.yml b/.github/workflows/publish-packages-1.0.yml
index 7553bd66627..86661100080 100644
--- a/.github/workflows/publish-packages-1.0.yml
+++ b/.github/workflows/publish-packages-1.0.yml
@@ -16,20 +16,30 @@ on:
schedule:
- cron: '0 0 * * *' # once in a day at 00:00
+permissions:
+ contents: read
+
jobs:
automation:
uses: ./.github/workflows/automation.yml
- secrets: inherit
+ secrets:
+ OTELBOT_DOTNET_PRIVATE_KEY: ${{ secrets.OTELBOT_DOTNET_PRIVATE_KEY }}
build-pack-publish:
runs-on: windows-latest
+ permissions:
+ contents: read
+ id-token: write
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ COSIGN_YES: "yes"
outputs:
artifact-url: ${{ steps.upload-artifacts.outputs.artifact-url }}
artifact-id: ${{ steps.upload-artifacts.outputs.artifact-id }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Note: By default GitHub only fetches 1 commit. MinVer needs to find
# the version tag which is typically NOT on the first commit so we
@@ -37,34 +47,62 @@ jobs:
fetch-depth: 0
- name: Setup dotnet
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
+
+ - name: Install Cosign
+ uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
+ with:
+ cosign-release: v2.5.3
- name: dotnet restore
run: dotnet restore ./build/OpenTelemetry.proj -p:RunningDotNetPack=true
- name: dotnet build
- run: dotnet build ./build/OpenTelemetry.proj --configuration Release --no-restore -p:Deterministic=true -p:BuildNumber=${{ github.run_number }} -p:RunningDotNetPack=true
+ shell: pwsh
+ run: dotnet build ./build/OpenTelemetry.proj --configuration Release --no-restore -p:Deterministic=true -p:"BuildNumber=${env: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 artifacts/bin/$projectName/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 ./build/OpenTelemetry.proj --configuration Release --no-restore --no-build -p:PackTag=${{ github.ref_type == 'tag' && github.ref_name || '' }}
+ shell: pwsh
+ env:
+ PACK_TAG: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
+ run: dotnet pack ./build/OpenTelemetry.proj --configuration Release --no-restore --no-build -p:"PackTag=${env:PACK_TAG}"
- name: Publish Artifacts
id: upload-artifacts
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ github.ref_name }}-packages
- path: 'src/**/*.*nupkg'
+ path: ./artifacts/package/release
+ if-no-files-found: error
- name: Publish MyGet
+ working-directory: ./artifacts/package/release
env:
MYGET_TOKEN_EXISTS: ${{ secrets.MYGET_TOKEN != '' }}
+ API_KEY: ${{ secrets.MYGET_TOKEN }}
+ SOURCE: https://www.myget.org/F/opentelemetry/api/v2/package
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 src/**/*.nupkg -Source https://www.myget.org/F/opentelemetry/api/v2/package
+ shell: pwsh
+ run: dotnet nuget push *.nupkg --api-key ${env:API_KEY} --skip-duplicate --source ${env:SOURCE}
post-build:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
needs:
- automation
@@ -72,45 +110,55 @@ jobs:
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
+ - uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
+ id: otelbot-token
+ with:
+ app-id: ${{ vars.OTELBOT_DOTNET_APP_ID }}
+ private-key: ${{ secrets.OTELBOT_DOTNET_PRIVATE_KEY }}
+
+ - name: Check out code
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
- token: ${{ secrets[needs.automation.outputs.token-secret-name] }}
+ token: ${{ steps.otelbot-token.outputs.token }}
- name: Download Artifacts
+ env:
+ ARTIFACT_ID: ${{ needs.build-pack-publish.outputs.artifact-id }}
+ ARTIFACT_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
curl \
-H "Accept: application/vnd.github+json" \
- -H "Authorization: token ${{ github.token }}" \
+ -H "Authorization: token ${ARTIFACT_TOKEN}" \
-L \
- -o '${{ github.workspace }}/artifacts/${{ github.ref_name }}-packages.zip' \
+ -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"
+ "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/artifacts/${ARTIFACT_ID}/zip"
- name: Create GitHub Release draft
shell: pwsh
+ env:
+ GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
run: |
Import-Module .\build\scripts\post-release.psm1
CreateDraftRelease `
- -gitRepository '${{ github.repository }}' `
- -tag '${{ github.ref_name }}' `
- -releaseFiles '${{ github.workspace }}/artifacts/${{ github.ref_name }}-packages.zip#Packages'
+ -gitRepository ${env:GITHUB_REPOSITORY} `
+ -tag ${env:GITHUB_REF_NAME} `
+ -releaseFiles "${env:GITHUB_WORKSPACE}/artifacts/${env:GITHUB_REF_NAME}-packages.zip"
- name: Post notice when packages are ready
shell: pwsh
+ env:
+ GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
+ EXPECTED_PR_AUTHOR_USER_NAME: ${{ needs.automation.outputs.application-name }}
+ PACKAGES_URL: ${{ needs.build-pack-publish.outputs.artifact-url }}
run: |
Import-Module .\build\scripts\post-release.psm1
TryPostPackagesReadyNoticeOnPrepareReleasePullRequest `
- -gitRepository '${{ github.repository }}' `
- -tag '${{ github.ref_name }}' `
- -tagSha '${{ github.sha }}' `
- -packagesUrl '${{ needs.build-pack-publish.outputs.artifact-url }}' `
- -botUserName '${{ needs.automation.outputs.username }}'
-
-
+ -gitRepository ${env:GITHUB_REPOSITORY} `
+ -tag ${env:GITHUB_REF_NAME} `
+ -tagSha ${env:GITHUB_SHA} `
+ -packagesUrl ${env:PACKAGES_URL} `
+ -expectedPrAuthorUserName ${env:EXPECTED_PR_AUTHOR_USER_NAME}
diff --git a/.github/workflows/sanitycheck.yml b/.github/workflows/sanitycheck.yml
index d98f3fea2c9..54f89668af6 100644
--- a/.github/workflows/sanitycheck.yml
+++ b/.github/workflows/sanitycheck.yml
@@ -5,13 +5,16 @@ name: Lint - Spelling & Encoding
on:
workflow_call:
+permissions:
+ contents: read
+
jobs:
run-misspell:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- name: check out code
- uses: actions/checkout@v4
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: install misspell
run: |
@@ -22,11 +25,11 @@ jobs:
run: ./bin/misspell -error .
run-sanitycheck:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- name: check out code
- uses: actions/checkout@v4
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: detect non-ASCII encoding and trailing space
run: python3 ./build/scripts/sanitycheck.py
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index f5657aa9f54..16b246d66aa 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -1,21 +1,32 @@
# 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
+permissions:
+ contents: read
+
jobs:
stale:
- runs-on: ubuntu-latest
+ permissions:
+ issues: write # for actions/stale to close stale issues
+ pull-requests: write # for actions/stale to close stale PRs
+ runs-on: ubuntu-24.04
steps:
- - uses: actions/stale@v9
+ - uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
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: 'keep-open,needs-triage'
+ exempt-pr-labels: 'keep-open'
diff --git a/.github/workflows/survey-on-merged-pr.yml b/.github/workflows/survey-on-merged-pr.yml
new file mode 100644
index 00000000000..3b3c80be6c5
--- /dev/null
+++ b/.github/workflows/survey-on-merged-pr.yml
@@ -0,0 +1,29 @@
+name: Survey on Merged PR by Non-Member
+
+on:
+ pull_request_target:
+ branches: [main]
+ types: [closed]
+
+permissions: {}
+
+jobs:
+ comment-on-pr:
+ name: Add survey to PR if author is not a member
+ permissions:
+ pull-requests: write
+ runs-on: ubuntu-latest
+ # Only run for merged pull requests by non-members users (i.e. not bots)
+ if: |
+ github.event.pull_request.merged &&
+ github.event.pull_request.user.type == 'User' &&
+ contains(fromJson('["CONTRIBUTOR", "FIRST_TIME_CONTRIBUTOR", "FIRST_TIMER"]'), github.event.pull_request.author_association)
+ steps:
+ - name: Add comment
+ run: |
+ gh pr comment "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" --body "Thank you for your contribution @${USERNAME}! :tada: We would like to hear from you about your experience contributing to OpenTelemetry by taking a few minutes to fill out this [survey](${SURVEY_URL})."
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ PR_NUMBER: ${{ github.event.pull_request.number }}
+ SURVEY_URL: https://docs.google.com/forms/d/e/1FAIpQLSf2FfCsW-DimeWzdQgfl0KDzT2UEAqu69_f7F2BVPSxVae1cQ/viewform?entry.1540511742=${{ github.repository }}
+ USERNAME: ${{ github.event.pull_request.user.login }}
diff --git a/.github/workflows/verifyaotcompat.yml b/.github/workflows/verifyaotcompat.yml
index 24991b9fe3c..affabafaf72 100644
--- a/.github/workflows/verifyaotcompat.yml
+++ b/.github/workflows/verifyaotcompat.yml
@@ -5,21 +5,24 @@ name: Publish & Verify AOT Compatibility
on:
workflow_call:
+permissions:
+ contents: read
+
jobs:
run-verify-aot-compat:
strategy:
fail-fast: false # ensures the entire test matrix is run, even if one permutation fails
matrix:
- os: [ ubuntu-latest, windows-latest ]
- version: [ net8.0 ]
+ os: [ ubuntu-22.04, windows-latest ]
+ version: [ net8.0, net9.0 ]
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup dotnet
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
- name: publish AOT testApp, assert static analysis warning count, and run the app
shell: pwsh
diff --git a/.gitignore b/.gitignore
index e06229e460f..851ee867e69 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@
x64/
x86/
bld/
+[Aa]rtifacts/
[Bb]in/
[Oo]bj/
[Ll]og/
@@ -351,3 +352,6 @@ tempo-data/
# Coyote Rewrite Files
rewrite.coyote.json
+
+# Test results
+TestResults/
diff --git a/.markdownlint.yaml b/.markdownlint.yaml
index c388b69fd5f..6efb6aeb05c 100644
--- a/.markdownlint.yaml
+++ b/.markdownlint.yaml
@@ -10,3 +10,6 @@ MD013:
MD033:
# Allowed elements
allowed_elements: [ 'details', 'summary' ]
+
+# MD059/link-text-should-be-descriptive : Inline HTML : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md059.md
+MD059: false
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7a9590b068a..9ca8868d46a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -10,16 +10,39 @@ 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),
-[**Approver**](https://github.com/open-telemetry/community/blob/main/community-membership.md#approver)
+[**Member**](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#member),
+[**Triager**](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#triager),
+[**Approver**](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver),
and
-[**Maintainer**](https://github.com/open-telemetry/community/blob/main/community-membership.md#maintainer).
+[**Maintainer**](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer).
-## Find a Buddy and Get Started Quickly
+## Give feedback
+
+We are always looking for your feedback.
+
+You can do this by [submitting a GitHub issue](https://github.com/open-telemetry/opentelemetry-dotnet/issues/new).
+
+You may also prefer writing on [#otel-dotnet Slack channel](https://cloud-native.slack.com/archives/C01N3BC2W7Q).
+
+### Report a bug
+
+Reporting bugs is an important contribution. Please make sure to include:
+
+* Expected and actual behavior;
+* OpenTelemetry, OS, and .NET versions you are using;
+* Steps to reproduce;
+* [Minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example).
+
+### Request a feature
+
+If you would like to work on something that is not listed as an issue
+(e.g. a new feature or enhancement) please create an issue and describe your proposal.
+
+## 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 +57,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 +89,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 +210,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 +221,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 +248,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 +277,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 +285,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 +299,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.
@@ -229,31 +323,11 @@ types](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-type
* Pass [static
analysis](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/overview).
- New projects MUST enable static analysis by specifying
- `latest-all` in the project file (`.csproj`).
-
> [!NOTE]
> There are other project-level features enabled automatically via
[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.Build.props b/Directory.Build.props
new file mode 100644
index 00000000000..e157295e687
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,6 @@
+
+
+ $([System.IO.Path]::Combine('$(MSBuildThisFileDirectory)', 'artifacts'))
+ true
+
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 032d5eb04a2..0e3f4ce78a8 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,7 +1,8 @@
+
true
- 1.8.1
+ 1.12.0
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
+
-
-
+
+
-
+
+
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/NuGet.config b/NuGet.config
index ca17f1b8088..ec945cd0620 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -3,19 +3,14 @@
-
-
-
-
-
diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln
index 61963889e01..0384bcce8aa 100644
--- a/OpenTelemetry.sln
+++ b/OpenTelemetry.sln
@@ -12,12 +12,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.dockerignore = .dockerignore
.editorconfig = .editorconfig
.gitignore = .gitignore
- .github\workflows\ci-concurrency.yml = .github\workflows\ci-concurrency.yml
CONTRIBUTING.md = CONTRIBUTING.md
global.json = global.json
LICENSE.TXT = LICENSE.TXT
NuGet.config = NuGet.config
README.md = README.md
+ RELEASENOTES.md = RELEASENOTES.md
THIRD-PARTY-NOTICES.TXT = THIRD-PARTY-NOTICES.TXT
VERSIONING.md = VERSIONING.md
EndProjectSection
@@ -27,12 +27,12 @@ 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
@@ -73,6 +73,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{F1D0
ProjectSection(SolutionItems) = preProject
.github\codecov.yml = .github\codecov.yml
.github\CODEOWNERS = .github\CODEOWNERS
+ .github\dependabot.yml = .github\dependabot.yml
.github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md
EndProjectSection
EndProject
@@ -80,7 +81,6 @@ 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}"
@@ -113,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}"
@@ -123,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
@@ -249,9 +254,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A49299
src\Shared\ExceptionExtensions.cs = src\Shared\ExceptionExtensions.cs
src\Shared\Guard.cs = src\Shared\Guard.cs
src\Shared\MathHelper.cs = src\Shared\MathHelper.cs
- src\Shared\PeerServiceResolver.cs = src\Shared\PeerServiceResolver.cs
src\Shared\PeriodicExportingMetricReaderHelper.cs = src\Shared\PeriodicExportingMetricReaderHelper.cs
- src\Shared\PooledList.cs = src\Shared\PooledList.cs
src\Shared\ResourceSemanticConventions.cs = src\Shared\ResourceSemanticConventions.cs
src\Shared\SemanticConventions.cs = src\Shared\SemanticConventions.cs
src\Shared\SpanAttributeConstants.cs = src\Shared\SpanAttributeConstants.cs
@@ -275,7 +278,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Options", "Options", "{4949
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shims", "Shims", "{A0CB9A10-F22D-4E66-A449-74B3D0361A9C}"
ProjectSection(SolutionItems) = preProject
+ src\Shared\Shims\ExperimentalAttribute.cs = src\Shared\Shims\ExperimentalAttribute.cs
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
@@ -299,7 +304,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
@@ -340,6 +344,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{4498
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "exemplars", "docs\metrics\exemplars\exemplars.csproj", "{79C12C80-B27B-41FB-AE79-A3BB74CFA782}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Proto", "Proto", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
+ ProjectSection(SolutionItems) = preProject
+ src\Shared\Proto\README.md = src\Shared\Proto\README.md
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -656,6 +665,7 @@ Global
{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}
+ {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521}
diff --git a/README.md b/README.md
index 06490b1eeb3..303f2ce3f79 100644
--- a/README.md
+++ b/README.md
@@ -6,9 +6,32 @@
[](https://www.nuget.org/profiles/OpenTelemetry)
[](https://github.com/open-telemetry/opentelemetry-dotnet/actions/workflows/ci.yml)
-The .NET [OpenTelemetry](https://opentelemetry.io/) client.
+[](https://scorecard.dev/viewer/?uri=github.com/open-telemetry/opentelemetry-dotnet)
+[](https://www.bestpractices.dev/projects/10017)
+[](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fopen-telemetry%2Fopentelemetry-dotnet?ref=badge_shield&issueType=license)
+[](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fopen-telemetry%2Fopentelemetry-dotnet?ref=badge_shield&issueType=security)
-## Supported .NET Versions
+The .NET [OpenTelemetry](https://opentelemetry.io/) implementation.
+
+
+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 +40,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 i.e. `Logs`, `Metrics`, and `Traces`.
+**Stable** across all 3 signals (`Logs`, `Metrics`, and `Traces`).
-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.
+> [!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.
-## Getting Started
+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).
-If you are new here, please read the getting started docs:
+## Getting started
-* [Logs](./docs/logs/README.md)
-* [Metrics](./docs/metrics/README.md)
-* [Traces](./docs/trace/README.md)
+If you are new here, please read the getting started docs:
-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 +134,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 +158,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,9 +166,59 @@ 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.
+
+### Digital signing
+
+Starting with the `1.10.0` release the DLLs included in the packages pushed to
+NuGet are digitally signed using [Sigstore](https://www.sigstore.dev/). Within
+each NuGet package the digital signature and its corresponding certificate file
+are placed alongside the shipped DLL(s) in the `/lib` folder. When a project
+targets multiple frameworks each target outputs a dedicated DLL and signing
+artifacts into a sub folder based on the
+[TFM](https://learn.microsoft.com/dotnet/standard/frameworks).
+
+The digitial signature and certificate files share the same name prefix as the
+DLL to ensure easy identification and association.
+
+To verify the integrity of a DLL inside a NuGet package use the
+[cosign](https://github.com/sigstore/cosign) tool from Sigstore:
+
+```bash
+cosign verify-blob \
+ --signature OpenTelemetry.dll-keyless.sig \
+ --certificate OpenTelemetry.dll-keyless.pem.cer \
+ --certificate-identity "https://github.com/open-telemetry/opentelemetry-dotnet/.github/workflows/publish-packages-1.0.yml@refs/tags/core-1.10.0-rc.1" \
+ --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
+ OpenTelemetry.dll
+```
+
+> [!NOTE]
+> A successful verification outputs `Verify OK`.
+
+For more verification options please refer to the [cosign
+documentation](https://github.com/sigstore/cosign/blob/main/doc/cosign_verify-blob.md).
+
## 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'
@@ -108,59 +236,60 @@ 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)
-([@open-telemetry/dotnet-maintainers](https://github.com/orgs/open-telemetry/teams/dotnet-maintainers)):
+### Maintainers
* [Alan West](https://github.com/alanwest), New Relic
-* [Mikel Blanchard](https://github.com/CodeBlanch), Microsoft
+* [Piotr Kiełkowicz](https://github.com/Kielek), Splunk
+* [Rajkumar Rangaraj](https://github.com/rajkumar-rangaraj), Microsoft
+
+For more information about the maintainer role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer).
-[Approvers](https://github.com/open-telemetry/community/blob/main/community-membership.md#approver)
-([@open-telemetry/dotnet-approvers](https://github.com/orgs/open-telemetry/teams/dotnet-approvers)):
+### Approvers
* [Cijo Thomas](https://github.com/cijothomas), Microsoft
-* [Reiley Yang](https://github.com/reyang), Microsoft
-* [Utkarsh Umesan Pillai](https://github.com/utpilla), Microsoft
-* [Vishwesh Bankwar](https://github.com/vishweshbankwar), Microsoft
+* [Martin Costello](https://github.com/martincostello), Grafana Labs
+* [Mikel Blanchard](https://github.com/CodeBlanch), Microsoft
+
+For more information about the approver role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver).
-[Triagers](https://github.com/open-telemetry/community/blob/main/community-membership.md#triager)
-([@open-telemetry/dotnet-triagers](https://github.com/orgs/open-telemetry/teams/dotnet-triagers)):
+### Triagers
* [Martin Thwaites](https://github.com/martinjt), Honeycomb
-* [Piotr Kiełkowicz](https://github.com/Kielek), Splunk
+* [Timothy "Mothra" Lee](https://github.com/TimothyMothra)
+
+For more information about the triager role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#triager).
-[Emeritus
-Maintainer/Approver/Triager](https://github.com/open-telemetry/community/blob/main/community-membership.md#emeritus-maintainerapprovertriager):
+### Emeritus Maintainers
+
+* [Mike Goldsmith](https://github.com/MikeGoldsmith)
+* [Sergey Kanzhelev](https://github.com/SergeyKanzhelev)
+* [Utkarsh Umesan Pillai](https://github.com/utpilla)
+
+For more information about the emeritus role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager).
+
+### Emeritus Approvers
* [Bruno Garcia](https://github.com/bruno-garcia)
* [Eddy Nakamura](https://github.com/eddynaka)
* [Liudmila Molkova](https://github.com/lmolkova)
-* [Mike Goldsmith](https://github.com/MikeGoldsmith)
* [Paulo Janotti](https://github.com/pjanotti)
+* [Reiley Yang](https://github.com/reyang)
* [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
+For more information about the emeritus role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager).
-[](https://github.com/open-telemetry/opentelemetry-dotnet/graphs/contributors)
+### Emeritus Triagers
-## Release Schedule
+* [Victor Lu](https://github.com/victlu)
-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.
+For more information about the emeritus role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager).
-See the [release
-notes](https://github.com/open-telemetry/opentelemetry-dotnet/releases) for
-existing releases.
+### Thanks to all the people who have contributed
-> [!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.
+[](https://github.com/open-telemetry/opentelemetry-dotnet/graphs/contributors)
+
+## 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 00000000000..3a26d50aec8
--- /dev/null
+++ b/RELEASENOTES.md
@@ -0,0 +1,143 @@
+# 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.13.0
+
+Release details: [1.13.0](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/core-1.13.0)
+
+* gRPC calls to export traces, logs, and metrics using `OtlpExportProtocol.Grpc`
+ now set the `TE=trailers` HTTP request header to improve interoperability.
+* `EventName` is now exported by default as `EventName` instead of
+ `logrecord.event.name` when specified through `ILogger` or the experimental
+ log bridge API.
+
+## 1.12.0
+
+Release details: [1.12.0](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/core-1.12.0)
+
+* **Breaking Change**: `OpenTelemetry.Exporter.OpenTelemetryProtocol` now
+ defaults to using OTLP/HTTP instead of OTLP/gRPC when targeting .NET Framework
+ and .NET Standard. This change may cause telemetry export to fail unless
+ appropriate adjustments are made. Explicitly setting OTLP/gRPC may result in a
+ `NotSupportedException` unless further configuration is applied. See
+ [#6209](https://github.com/open-telemetry/opentelemetry-dotnet/issues/6209) for
+ full details and mitigation guidance. [#6229](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6229)
+
+## 1.11.1
+
+Release details: [1.11.1](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/core-1.11.1)
+
+* Fixed a bug preventing `OpenTelemetry.Exporter.OpenTelemetryProtocol` from
+ exporting telemetry on .NET Framework.
+
+## 1.11.0
+
+Release details: [1.11.0](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/core-1.11.0)
+
+* `OpenTelemetry.Exporter.OpenTelemetryProtocol` no longer depends on the
+ `Google.Protobuf`, `Grpc`, or `Grpc.Net.Client` packages. Serialization and
+ transmission of outgoing data is now performed manually to improve the overall
+ performance.
+
+## 1.10.0
+
+Release details: [1.10.0](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/core-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)
+
+ For details see: [Explicit bucket histogram
+ aggregation](./docs/metrics/customizing-the-sdk/README.md#explicit-bucket-histogram-aggregation).
+
+ * [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).
+
+ * The MetricPoint reclaim behavior is now enabled by default when Delta
+ aggregation temporality is used. The
+ `OTEL_DOTNET_EXPERIMENTAL_METRICS_RECLAIM_UNUSED_METRIC_POINTS` 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
+
+Release details: [1.9.0](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/core-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
+
+Release details: [1.8.0](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/core-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
+
+Release details: [1.7.0](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/core-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/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT
index b65f5723308..38eb675f542 100644
--- a/THIRD-PARTY-NOTICES.TXT
+++ b/THIRD-PARTY-NOTICES.TXT
@@ -29,3 +29,20 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+
+License notice for gRPC for .NET (https://github.com/grpc/grpc-dotnet)
+----------------------------------------------------------------------------------------------
+
+Copyright 2019 The gRPC Authors
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/build/Common.nonprod.props b/build/Common.nonprod.props
index 6de6e014c88..d5a959fd253 100644
--- a/build/Common.nonprod.props
+++ b/build/Common.nonprod.props
@@ -2,13 +2,13 @@
- $(NoWarn),1574,1591
+ $(NoWarn),CS1574,CS1591
false
$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), 'OpenTelemetry.sln'))\build\OpenTelemetry.test.ruleset
- net8.0
+ net9.0
@@ -21,6 +21,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/Common.prod.props b/build/Common.prod.props
index 2f7b7cc900f..5a13bf20617 100644
--- a/build/Common.prod.props
+++ b/build/Common.prod.props
@@ -3,6 +3,9 @@
$(MSBuildThisFileDirectory)/OpenTelemetry.prod.ruleset
+
+
+
true
false
@@ -15,13 +18,15 @@
https://opentelemetry.io
OpenTelemetry Authors
Copyright The OpenTelemetry Authors
- $(Build_ArtifactStagingDirectory)
true
snupkg
Apache-2.0
true
$(RepoRoot)\LICENSE.TXT
$(RepoRoot)\THIRD-PARTY-NOTICES.TXT
+ README.md
+ CHANGELOG.md
+ $(RepoRoot)\RELEASENOTES.md
@@ -32,7 +37,6 @@
-
@@ -47,7 +51,20 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ \[([^]]+?)\]\(\.(.+?)\)
+ $(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).
+
+
+
+
+
+
+
+
- $(NoWarn);OTEL1000;OTEL1001;OTEL1002;OTEL1003;OTEL1004
-
-
+ $(NoWarn);OTEL1000;OTEL1001;OTEL1002;OTEL1004
+ latest-All
+
+
+
+ 002400000480000094000000060200000024000052534131000400000100010051C1562A090FB0C9F391012A32198B5E5D9A60E9B80FA2D7B434C9E5CCB7259BD606E66F9660676AFC6692B8CDC6793D190904551D2103B7B22FA636DCBB8208839785BA402EA08FC00C8F1500CCEF28BBF599AA64FFB1E1D5DC1BF3420A3777BADFE697856E9D52070A50C3EA5821C80BEF17CA3ACFFA28F89DD413F096F898
+
+
+
+ false
@@ -21,18 +30,19 @@
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 00000000000..63286efffbf
--- /dev/null
+++ b/build/Common.targets
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
diff --git a/build/RELEASING.md b/build/RELEASING.md
index f9075727bd6..bb430aaf9e8 100644
--- a/build/RELEASING.md
+++ b/build/RELEASING.md
@@ -80,11 +80,21 @@ Maintainers (admins) are needed to merge PRs and for the push to NuGet.**
for the projects being released.
- 5. :stop_sign: Wait for the [Build, pack, and publish to
+ 6. :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. When complete a trigger will automatically add a
comment on the PR opened by [Prepare for a
@@ -187,14 +197,14 @@ Maintainers (admins) are needed to merge PRs and for the push to NuGet.**
draft Release and click `Publish release`.
- 6. If a new stable version of the core packages was released, a PR should have
+ 7. 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. Merge that
PR once the build passes (this requires the packages be available on NuGet).
- 7. The [Complete
+ 8. 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)
@@ -203,6 +213,6 @@ Maintainers (admins) are needed to merge PRs and for the push to NuGet.**
repository which opens a PR to update dependencies. Verify this PR was
opened successfully.
- 8. 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.
+ 9. For stable releases post an announcement in the [Slack
+ channel](https://cloud-native.slack.com/archives/C01N3BC2W7Q) announcing the
+ release and link to the release notes.
diff --git a/build/docker-compose.net6.0.yml b/build/docker-compose.net6.0.yml
deleted file mode 100644
index 099f1007277..00000000000
--- 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 48a2589cda9..00000000000
--- 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 a5ac999e43e..b93fc24655e 100644
--- a/build/docker-compose.net8.0.yml
+++ b/build/docker-compose.net8.0.yml
@@ -1,9 +1,7 @@
-version: '3.7'
-
services:
tests:
build:
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 00000000000..94176258b24
--- /dev/null
+++ b/build/docker-compose.net9.0.yml
@@ -0,0 +1,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.psm1 b/build/scripts/add-labels.psm1
index 60c07bc4637..1b14854adb5 100644
--- a/build/scripts/add-labels.psm1
+++ b/build/scripts/add-labels.psm1
@@ -38,7 +38,7 @@ function AddLabelsOnPullRequestsBasedOnFilesChanged {
# 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'
+ $documentationFiles = 'readme.md', 'contributing.md', 'releasing.md', 'versioning.md', 'releasenotes.md'
foreach ($fileChanged in $filesChangedOnPullRequest)
{
@@ -99,12 +99,12 @@ function AddLabelsOnPullRequestsBasedOnFilesChanged {
$rootInfraFiles.Contains($fullFileName) -or
$fileExtension -eq ".props" -or
$fileExtension -eq ".targets" -or
- $fileChanged.StartsWith('test\openTelemetry.aotcompatibility'))
+ $fileChanged.StartsWith('test/openTelemetry.aotcompatibility'))
{
$added = $labelsToAdd.Add("infra")
}
- if ($fileChanged.StartsWith('test\benchmarks'))
+ if ($fileChanged.StartsWith('test/benchmarks'))
{
$added = $labelsToAdd.Add("perf")
}
diff --git a/build/scripts/post-release.psm1 b/build/scripts/post-release.psm1
index 57f0f341c8f..6edbe955474 100644
--- a/build/scripts/post-release.psm1
+++ b/build/scripts/post-release.psm1
@@ -13,6 +13,7 @@ function CreateDraftRelease {
$tagPrefix = $match.Groups[1].Value
$version = $match.Groups[2].Value
+ $isPrerelease = $version -match '-alpha' -or $version -match '-beta' -or $version -match '-rc'
$projects = @(Get-ChildItem -Path src/**/*.csproj | Select-String "$tagPrefix" -List | Select Path)
@@ -22,6 +23,7 @@ function CreateDraftRelease {
}
$notes = ''
+ $previousVersion = ''
foreach ($project in $projects)
{
@@ -44,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
@@ -57,7 +64,7 @@ function CreateDraftRelease {
if ([string]::IsNullOrWhitespace($content) -eq $true)
{
- $content = " No notable changes."
+ $content = " No notable changes."
}
$content = $content.trimend()
@@ -70,11 +77,19 @@ $content
See [CHANGELOG](https://github.com/$gitRepository/blob/$tag/src/$projectName/CHANGELOG.md) for details.
+
"@
}
- if ($version -match '-alpha' -or $version -match '-beta' -or $version -match '-rc')
+ if ($isPrerelease -eq $true)
{
+ $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 `
@@ -84,6 +99,15 @@ $content
}
else
{
+ $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 `
@@ -101,7 +125,7 @@ function TryPostPackagesReadyNoticeOnPrepareReleasePullRequest {
[Parameter(Mandatory=$true)][string]$tag,
[Parameter(Mandatory=$true)][string]$tagSha,
[Parameter(Mandatory=$true)][string]$packagesUrl,
- [Parameter(Mandatory=$true)][string]$botUserName
+ [Parameter(Mandatory=$true)][string]$expectedPrAuthorUserName
)
$prListResponse = gh pr list --search $tagSha --state merged --json number,author,title,comments | ConvertFrom-Json
@@ -114,7 +138,7 @@ function TryPostPackagesReadyNoticeOnPrepareReleasePullRequest {
foreach ($pr in $prListResponse)
{
- if ($pr.author.login -ne $botUserName -or $pr.title -ne "[release] Prepare release $tag")
+ if ($pr.author.login -ne $expectedPrAuthorUserName -or $pr.title -ne "[release] Prepare release $tag")
{
continue
}
@@ -122,7 +146,7 @@ function TryPostPackagesReadyNoticeOnPrepareReleasePullRequest {
$foundComment = $false
foreach ($comment in $pr.comments)
{
- if ($comment.author.login -eq $botUserName -and $comment.body.StartsWith("I just pushed the [$tag]"))
+ if ($comment.author.login -eq $expectedPrAuthorUserName -and $comment.body.StartsWith("I just pushed the [$tag]"))
{
$foundComment = $true
break
@@ -156,15 +180,15 @@ function PushPackagesPublishReleaseUnlockAndPostNoticeOnPrepareReleasePullReques
param(
[Parameter(Mandatory=$true)][string]$gitRepository,
[Parameter(Mandatory=$true)][string]$pullRequestNumber,
- [Parameter(Mandatory=$true)][string]$botUserName,
+ [Parameter(Mandatory=$true)][string]$expectedPrAuthorUserName,
[Parameter(Mandatory=$true)][string]$commentUserName,
[Parameter(Mandatory=$true)][string]$artifactDownloadPath,
- [Parameter(Mandatory=$true)][string]$pushToNuget
+ [Parameter(Mandatory=$true)][bool]$pushToNuget
)
$prViewResponse = gh pr view $pullRequestNumber --json author,title,comments | ConvertFrom-Json
- if ($prViewResponse.author.login -ne $botUserName)
+ if ($prViewResponse.author.login -ne $expectedPrAuthorUserName)
{
throw 'PR author was unexpected'
}
@@ -189,7 +213,7 @@ function PushPackagesPublishReleaseUnlockAndPostNoticeOnPrepareReleasePullReques
$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:"))
+ if ($comment.author.login -eq $expectedPrAuthorUserName -and $comment.body.StartsWith("The packages for [$tag](https://github.com/$gitRepository/releases/tag/$tag) are now available:"))
{
$foundComment = $true
break
@@ -207,12 +231,12 @@ function PushPackagesPublishReleaseUnlockAndPostNoticeOnPrepareReleasePullReques
Expand-Archive -LiteralPath "$artifactDownloadPath/$tag-packages.zip" -DestinationPath "$artifactDownloadPath\"
- if ($pushToNuget -eq 'true')
+ if ($pushToNuget)
{
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"
+ dotnet nuget push "$artifactDownloadPath/**/*.nupkg" --source https://api.nuget.org/v3/index.json --api-key "$env:NUGET_TOKEN" --symbol-api-key "$env:NUGET_TOKEN"
if ($LASTEXITCODE -gt 0)
{
@@ -239,6 +263,7 @@ function CreateStableVersionUpdatePullRequest {
[Parameter(Mandatory=$true)][string]$gitRepository,
[Parameter(Mandatory=$true)][string]$tag,
[Parameter()][string]$targetBranch="main",
+ [Parameter()][string]$lineEnding="`n",
[Parameter()][string]$gitUserName,
[Parameter()][string]$gitUserEmail
)
@@ -249,9 +274,9 @@ 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"
+ $branch="otelbot/post-stable-${tag}-update"
if ([string]::IsNullOrEmpty($gitUserName) -eq $false)
{
@@ -268,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'
@@ -298,19 +344,177 @@ 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 "[release] Core stable release $packageVersion updates" `
+ $createPullRequestResponse = gh pr create `
+ --title "[release] Core stable release $version updates" `
--body $body `
--base $targetBranch `
--head $branch `
--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,
@@ -335,7 +539,7 @@ Export-ModuleMember -Function InvokeCoreVersionUpdateWorkflowInRemoteRepository
function TryPostReleasePublishedNoticeOnPrepareReleasePullRequest {
param(
[Parameter(Mandatory=$true)][string]$gitRepository,
- [Parameter(Mandatory=$true)][string]$botUserName,
+ [Parameter(Mandatory=$true)][string]$expectedPrAuthorUserName,
[Parameter(Mandatory=$true)][string]$tag
)
@@ -355,7 +559,7 @@ function TryPostReleasePublishedNoticeOnPrepareReleasePullRequest {
foreach ($pr in $prListResponse)
{
- if ($pr.author.login -ne $botUserName -or $pr.title -ne "[release] Prepare release $tag")
+ if ($pr.author.login -ne $expectedPrAuthorUserName -or $pr.title -ne "[release] Prepare release $tag")
{
continue
}
@@ -363,7 +567,7 @@ function TryPostReleasePublishedNoticeOnPrepareReleasePullRequest {
$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:"))
+ if ($comment.author.login -eq $expectedPrAuthorUserName -and $comment.body.StartsWith("The packages for [$tag](https://github.com/$gitRepository/releases/tag/$tag) are now available:"))
{
$foundComment = $true
break
diff --git a/build/scripts/prepare-release.psm1 b/build/scripts/prepare-release.psm1
index 88e6f7ad11f..4a6ee4678f4 100644
--- a/build/scripts/prepare-release.psm1
+++ b/build/scripts/prepare-release.psm1
@@ -3,13 +3,21 @@ function CreatePullRequestToUpdateChangelogsAndPublicApis {
[Parameter(Mandatory=$true)][string]$gitRepository,
[Parameter(Mandatory=$true)][string]$minVerTagPrefix,
[Parameter(Mandatory=$true)][string]$version,
+ [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'
+ }
+
+ $isPrerelease = $version -match '-alpha' -or $version -match '-beta' -or $version -match '-rc'
$tag="${minVerTagPrefix}${version}"
- $branch="release/prepare-${tag}-release"
+ $branch="otelbot/prepare-${tag}-release"
if ([string]::IsNullOrEmpty($gitUserName) -eq $false)
{
@@ -30,6 +38,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.
@@ -39,13 +49,37 @@ Note: This PR was opened automatically by the [prepare release workflow](https:/
& ./build/scripts/update-changelogs.ps1 -minVerTagPrefix $minVerTagPrefix -version $version
# Update publicApi files for stable releases
- if ($version -notlike "*-alpha*" -and $version -notlike "*-beta*" -and $version -notlike "*-rc*")
+ if ($isPrerelease -ne $true)
{
& ./build/scripts/finalize-publicapi.ps1 -minVerTagPrefix $minVerTagPrefix
$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``]
+"@
+
+ if ($minVerTagPrefix -eq 'core-' -and $isPrerelease -ne $true)
+ {
+ $body +=
+@"
+
+``/UpdateReleaseNotes``: Use to update ``RELEASENOTES.md`` before merging [``approvers``, ``maintainers``]
+"@
+ }
+
+ $body +=
+@"
+
+``/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)
{
@@ -58,12 +92,42 @@ Note: This PR was opened automatically by the [prepare release workflow](https:/
throw 'git push failure'
}
- gh pr create `
+ $createPullRequestResponse = gh pr create `
--title "[release] Prepare release $tag" `
--body $body `
--base $targetBranch `
--head $branch `
--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 ($minVerTagPrefix -eq 'core-' -and $isPrerelease -ne $true)
+ {
+ $found = Select-String -Path "RELEASENOTES.md" -Pattern "## $version" -Quiet
+ if ($found -eq $false)
+ {
+ $body =
+@"
+I noticed this PR is releasing a stable version of core packages but there isn't any content in ``RELEASENOTES.md`` for the version being released.
+
+It is important to update ``RELEASENOTES.md`` before creating the release tag because a permalink will become part of the package(s).
+
+Post a comment with "/UpdateReleaseNotes" in the body if you would like me to update release notes.
+
+Note: In the comment everything below "/UpdateReleaseNotes" will be added to ``RELEASENOTES.md`` for the version being released. If something is already there it will be replaced.
+"@
+
+ gh pr comment $pullRequestNumber --body $body
+ }
+ }
}
Export-ModuleMember -Function CreatePullRequestToUpdateChangelogsAndPublicApis
@@ -72,12 +136,12 @@ function LockPullRequestAndPostNoticeToCreateReleaseTag {
param(
[Parameter(Mandatory=$true)][string]$gitRepository,
[Parameter(Mandatory=$true)][string]$pullRequestNumber,
- [Parameter(Mandatory=$true)][string]$botUserName
+ [Parameter(Mandatory=$true)][string]$expectedPrAuthorUserName
)
$prViewResponse = gh pr view $pullRequestNumber --json mergeCommit,author,title | ConvertFrom-Json
- if ($prViewResponse.author.login -ne $botUserName)
+ if ($prViewResponse.author.login -ne $expectedPrAuthorUserName)
{
throw 'PR author was unexpected'
}
@@ -114,14 +178,14 @@ function CreateReleaseTagAndPostNoticeOnPullRequest {
param(
[Parameter(Mandatory=$true)][string]$gitRepository,
[Parameter(Mandatory=$true)][string]$pullRequestNumber,
- [Parameter(Mandatory=$true)][string]$botUserName,
+ [Parameter(Mandatory=$true)][string]$expectedPrAuthorUserName,
[Parameter()][string]$gitUserName,
[Parameter()][string]$gitUserEmail
)
$prViewResponse = gh pr view $pullRequestNumber --json mergeCommit,author,title | ConvertFrom-Json
- if ($prViewResponse.author.login -ne $botUserName)
+ if ($prViewResponse.author.login -ne $expectedPrAuthorUserName)
{
throw 'PR author was unexpected'
}
@@ -172,3 +236,228 @@ The [package workflow](https://github.com/$gitRepository/actions/workflows/publi
}
Export-ModuleMember -Function CreateReleaseTagAndPostNoticeOnPullRequest
+
+function UpdateChangelogReleaseDatesAndPostNoticeOnPullRequest {
+ param(
+ [Parameter(Mandatory=$true)][string]$gitRepository,
+ [Parameter(Mandatory=$true)][string]$pullRequestNumber,
+ [Parameter(Mandatory=$true)][string]$expectedPrAuthorUserName,
+ [Parameter(Mandatory=$true)][string]$commentUserName,
+ [Parameter()][string]$gitUserName,
+ [Parameter()][string]$gitUserEmail
+ )
+
+ $prViewResponse = gh pr view $pullRequestNumber --json headRefName,author,title | ConvertFrom-Json
+
+ if ($prViewResponse.author.login -ne $expectedPrAuthorUserName)
+ {
+ 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 =
+@"
+## $version
+
+Released $(Get-Date -UFormat '%Y-%b-%d')
+"@
+
+ $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 UpdateChangelogReleaseDatesAndPostNoticeOnPullRequest
+
+function UpdateReleaseNotesAndPostNoticeOnPullRequest {
+ param(
+ [Parameter(Mandatory=$true)][string]$gitRepository,
+ [Parameter(Mandatory=$true)][string]$pullRequestNumber,
+ [Parameter(Mandatory=$true)][string]$expectedPrAuthorUserName,
+ [Parameter(Mandatory=$true)][string]$commentUserName,
+ [Parameter(Mandatory=$true)][string]$commentBody,
+ [Parameter()][string]$gitUserName,
+ [Parameter()][string]$gitUserEmail
+ )
+
+ $prViewResponse = gh pr view $pullRequestNumber --json headRefName,author,title | ConvertFrom-Json
+
+ if ($prViewResponse.author.login -ne $expectedPrAuthorUserName)
+ {
+ 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
+ $isPrerelease = $version -match '-alpha' -or $version -match '-beta' -or $version -match '-rc'
+
+ $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 ($tagPrefix -ne 'core-' -or $isPrerelease -eq $true)
+ {
+ gh pr comment $pullRequestNumber `
+ --body "I'm sorry @$commentUserName but we don't typically add release notes for prereleases or unstable packages."
+ 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'
+ }
+
+ $releaseNotesContent = (Get-Content -Path "RELEASENOTES.md" -Raw)
+
+ $match = [regex]::Match($commentBody, '[\w\W\s]*\/UpdateReleaseNotes.*$([\w\W\s]*)', [Text.RegularExpressions.RegexOptions]::Multiline)
+ if ($match.Success -eq $false)
+ {
+ throw 'Could not find release notes content'
+ }
+
+ $content = $match.Groups[1].Value.Trim() -replace "`r`n", "`n"
+
+ $body =
+@"
+## $version
+
+Release details: [$version](https://github.com/$gitRepository/releases/tag/$tagPrefix$version)
+
+$content
+
+##
+"@
+
+ $match = [regex]::Match($releaseNotesContent, "(## $version[\w\W\s]*?)##", [Text.RegularExpressions.RegexOptions]::Multiline)
+ if ($match.Success -eq $true)
+ {
+ $content = [regex]::Replace($releaseNotesContent, "(## $version[\w\W\s]*?)##", $body, [Text.RegularExpressions.RegexOptions]::Multiline)
+ Set-Content -Path "RELEASENOTES.md" -Value $content.TrimEnd()
+ }
+ else {
+ $match = [regex]::Match($releaseNotesContent, '(# Release Notes[\w\W\s]*?)##', [Text.RegularExpressions.RegexOptions]::Multiline)
+ if ($match.Success -eq $false)
+ {
+ throw 'Could not find release notes header'
+ }
+
+ $body = $match.Groups[1].Value + $body
+ $content = [regex]::Replace($releaseNotesContent, '(# Release Notes[\w\W\s]*?)##', $body, [Text.RegularExpressions.RegexOptions]::Multiline)
+ Set-Content -Path "RELEASENOTES.md" -Value $content.TrimEnd()
+ }
+
+ git commit -a -m "Update RELEASENOTES 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 ``RELEASENOTES.md``."
+}
+
+Export-ModuleMember -Function UpdateReleaseNotesAndPostNoticeOnPullRequest
diff --git a/build/scripts/test-aot-compatibility.ps1 b/build/scripts/test-aot-compatibility.ps1
index 895055a1b48..99def7badd5 100644
--- a/build/scripts/test-aot-compatibility.ps1
+++ b/build/scripts/test-aot-compatibility.ps1
@@ -24,10 +24,9 @@ if ($LastExitCode -ne 0)
Write-Host $publishOutput
}
-$runtime = $IsWindows ? "win-x64" : ($IsMacOS ? "macos-x64" : "linux-x64")
$app = $IsWindows ? "./OpenTelemetry.AotCompatibility.TestApp.exe" : "./OpenTelemetry.AotCompatibility.TestApp"
-Push-Location $rootDirectory/test/OpenTelemetry.AotCompatibility.TestApp/bin/Release/$targetNetFramework/$runtime
+Push-Location $rootDirectory/artifacts/publish/OpenTelemetry.AotCompatibility.TestApp/release_$targetNetFramework
Write-Host "Executing test App..."
$app
diff --git a/build/scripts/test-threadSafety.ps1 b/build/scripts/test-threadSafety.ps1
index 73cc1f27d27..6fbaba60e5c 100644
--- a/build/scripts/test-threadSafety.ps1
+++ b/build/scripts/test-threadSafety.ps1
@@ -1,22 +1,32 @@
param(
- [Parameter()][string]$coyoteVersion="1.7.10",
+ [Parameter()][string]$coyoteVersion="1.7.11",
[Parameter(Mandatory=$true)][string]$testProjectName,
[Parameter(Mandatory=$true)][string]$targetFramework,
[Parameter()][string]$categoryName="CoyoteConcurrencyTests",
[Parameter()][string]$configuration="Release"
)
+$ErrorActionPreference = "Stop"
+
$env:OTEL_RUN_COYOTE_TESTS = 'true'
$rootDirectory = Get-Location
Write-Host "Install Coyote CLI."
-dotnet tool install --global Microsoft.Coyote.CLI
+dotnet tool install --global Microsoft.Coyote.CLI --version $coyoteVersion
+
+if ($LASTEXITCODE -ne 0) {
+ throw "Microsoft.Coyote.CLI installation failed with exit code $LASTEXITCODE"
+}
Write-Host "Build $testProjectName project."
dotnet build "$rootDirectory/test/$testProjectName/$testProjectName.csproj" --configuration $configuration
-$artifactsPath = Join-Path $rootDirectory "test/$testProjectName/bin/$configuration/$targetFramework"
+if ($LASTEXITCODE -ne 0) {
+ throw "dotnet build failed with exit code $LASTEXITCODE"
+}
+
+$artifactsPath = Join-Path $rootDirectory "artifacts/bin/$testProjectName/$($configuration.ToLowerInvariant())_$targetFramework"
Write-Host "Generate Coyote rewriting options JSON file."
$assemblies = Get-ChildItem $artifactsPath -Filter OpenTelemetry*.dll | ForEach-Object {$_.Name}
@@ -29,6 +39,13 @@ $RewriteOptionsJson | ConvertTo-Json -Compress | Set-Content -Path "$rootDirecto
Write-Host "Run Coyote rewrite."
coyote rewrite "$rootDirectory/test/$testProjectName/rewrite.coyote.json"
+if ($LASTEXITCODE -ne 0) {
+ throw "coyote rewrite failed with exit code $LASTEXITCODE"
+}
+
Write-Host "Execute re-written binary."
dotnet test "$artifactsPath/$testProjectName.dll" --framework $targetFramework --filter CategoryName=$categoryName
+if ($LASTEXITCODE -ne 0) {
+ throw "dotnet test failed with exit code $LASTEXITCODE"
+}
diff --git a/docs/Directory.Build.props b/docs/Directory.Build.props
index 942eea5974c..9bc6a965577 100644
--- a/docs/Directory.Build.props
+++ b/docs/Directory.Build.props
@@ -1,8 +1,11 @@
+
Exe
$(TargetFrameworksForDocs)
+
+ false
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 00000000000..23d80c8a577
--- /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/OTEL1003.md b/docs/diagnostics/experimental-apis/OTEL1003.md
deleted file mode 100644
index 5f62f03575f..00000000000
--- 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 6c581030b4c..daa80d34b38 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/README.md b/docs/logs/README.md
index 55c6c06c0b2..d5a6064c310 100644
--- a/docs/logs/README.md
+++ b/docs/logs/README.md
@@ -25,33 +25,17 @@ OpenTelemetry .NET:
* [Getting Started - Console Application](./getting-started-console/README.md)
* [Logging with Complex Objects](./complex-objects/README.md)
-## Structured Logging
-
-:heavy_check_mark: You should use structured logging.
-
-* Structured logging is more efficient than unstructured logging.
- * Filtering and redaction can happen on individual key-value pairs instead of
- the entire log message.
- * Storage and indexing are more efficient.
-* Structured logging makes it easier to manage and consume logs.
-
-:stop_sign: You should avoid string interpolation.
-
-> [!WARNING]
-> The following code has bad performance due to [string
- interpolation](https://learn.microsoft.com/dotnet/csharp/tutorials/string-interpolation):
-
-```csharp
-var food = "tomato";
-var price = 2.99;
+## Logging API
-logger.LogInformation($"Hello from {food} {price}.");
-```
+### ILogger
-Refer to the [logging performance
-benchmark](../../test/Benchmarks/Logs/LogBenchmarks.cs) for more details.
+.NET supports high performance, structured logging via the
+[`Microsoft.Extensions.Logging.ILogger`](https://docs.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger)
+interface (including
+[`ILogger`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger-1))
+to help monitor application behavior and diagnose issues.
-## Package Version
+#### Package Version
:heavy_check_mark: You should always use the
[`ILogger`](https://docs.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger)
@@ -69,16 +53,6 @@ package, regardless of the .NET runtime version being used:
backward compatibility on `Microsoft.Extensions.Logging` even during major
version bumps, so compatibility is not a concern here.
-## Logging API
-
-### ILogger
-
-.NET supports high performance, structured logging via the
-[`Microsoft.Extensions.Logging.ILogger`](https://docs.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger)
-interface (including
-[`ILogger`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger-1))
-to help monitor application behavior and diagnose issues.
-
#### Get Logger
In order to use the `ILogger` interface, you need to first get a logger. How to
@@ -125,7 +99,38 @@ are not super expensive, they still come with CPU and memory cost, and are meant
to be reused throughout the application. Refer to the [logging performance
benchmark](../../test/Benchmarks/Logs/LogBenchmarks.cs) for more details.
-#### Use Logger
+#### Write log messages
+
+:heavy_check_mark: You should use structured logging.
+
+* Structured logging is more efficient than unstructured logging.
+ * Filtering and redaction can happen on individual key-value pairs instead of
+ the entire log message.
+ * Storage and indexing are more efficient.
+* Structured logging makes it easier to manage and consume logs.
+
+```csharp
+var food = "tomato";
+var price = 2.99;
+
+logger.LogInformation("Hello from {food} {price}.", food, price);
+```
+
+:stop_sign: You should avoid string interpolation.
+
+> [!WARNING]
+> The following code has bad performance due to [string
+ interpolation](https://learn.microsoft.com/dotnet/csharp/tutorials/string-interpolation):
+
+```csharp
+var food = "tomato";
+var price = 2.99;
+
+logger.LogInformation($"Hello from {food} {price}.");
+```
+
+Refer to the [logging performance
+benchmark](../../test/Benchmarks/Logs/LogBenchmarks.cs) for more details.
:heavy_check_mark: You should use [compile-time logging source
generation](https://docs.microsoft.com/dotnet/core/extensions/logger-message-generator)
@@ -222,6 +227,111 @@ code is now depending on which logger is being enabled, not to mention the
argument evaluation might have significant side effects that are now depending
on the logging configuration.
+:heavy_check_mark: You should use a dedicated parameter to log exceptions when
+using the compile-time source generator.
+
+```csharp
+var food = "tomato";
+var price = 2.99;
+
+try
+{
+ // Execute some logic
+
+ logger.SayHello(food, price);
+}
+catch (Exception ex)
+{
+ logger.SayHelloFailure(ex, food, price);
+}
+
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(Level = LogLevel.Information, Message = "Hello from {food} {price}.")]
+ public static partial void SayHello(this ILogger logger, string food, double price);
+
+ [LoggerMessage(Level = LogLevel.Error, Message = "Could not say hello from {food} {price}.")]
+ public static partial void SayHelloFailure(this ILogger logger, Exception exception, string food, double price);
+}
+```
+
+> [!NOTE]
+> When using the compile-time source generator the first `Exception` parameter
+> detected is automatically given special handling. It **SHOULD NOT** be part of
+> the message template. For details see: [Log method
+> anatomy](https://learn.microsoft.com/dotnet/core/extensions/logger-message-generator#log-method-anatomy).
+
+:heavy_check_mark: You should use the dedicated overloads to log exceptions when
+using the logging extensions methods.
+
+```csharp
+var food = "tomato";
+var price = 2.99;
+
+try
+{
+ // Execute some logic
+
+ logger.LogInformation("Hello from {food} {price}.", food, price);
+}
+catch (Exception ex)
+{
+ logger.LogError(ex, "Could not say hello from {food} {price}.", food, price);
+}
+```
+
+:stop_sign: You should avoid adding exception details into the message template.
+
+You want to use the correct `Exception` APIs because the OpenTelemetry
+Specification [defines dedicated
+attributes](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/exceptions/exceptions-logs.md)
+for `Exception` details. The following examples show what **NOT** to do. In
+these cases the details won't be lost, but the dedicated attributes also won't
+be added.
+
+```csharp
+var food = "tomato";
+var price = 2.99;
+
+try
+{
+ // Execute some logic
+
+ logger.SayHello(food, price);
+}
+catch (Exception ex)
+{
+ logger.SayHelloFailure(food, price, ex.Message);
+}
+
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(Level = LogLevel.Information, Message = "Hello from {food} {price}.")]
+ public static partial void SayHello(this ILogger logger, string food, double price);
+
+ // BAD - Exception should not be part of the message template. Use the dedicated parameter.
+ [LoggerMessage(Level = LogLevel.Error, Message = "Could not say hello from {food} {price} {message}.")]
+ public static partial void SayHelloFailure(this ILogger logger, string food, double price, string message);
+}
+```
+
+```csharp
+var food = "tomato";
+var price = 2.99;
+
+try
+{
+ // Execute some logic
+
+ logger.LogInformation("Hello from {food} {price}.", food, price);
+}
+catch (Exception ex)
+{
+ // BAD - Exception should not be part of the message template. Use the dedicated parameter.
+ logger.LogError("Could not say hello from {food} {price} {message}.", food, price, ex.Message);
+}
+```
+
## LoggerFactory
In many cases, you can use [ILogger](#ilogger) without having to interact with
diff --git a/docs/logs/complex-objects/FoodRecallNotice.cs b/docs/logs/complex-objects/FoodRecallNotice.cs
index 40ca59e3b8d..e771fc7adc4 100644
--- a/docs/logs/complex-objects/FoodRecallNotice.cs
+++ b/docs/logs/complex-objects/FoodRecallNotice.cs
@@ -1,7 +1,9 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-public struct FoodRecallNotice
+namespace ComplexObjects;
+
+internal struct FoodRecallNotice
{
public string? BrandName { get; set; }
diff --git a/docs/logs/complex-objects/Program.cs b/docs/logs/complex-objects/Program.cs
index c09cfc5c772..d4aa278f89e 100644
--- a/docs/logs/complex-objects/Program.cs
+++ b/docs/logs/complex-objects/Program.cs
@@ -1,6 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
+using ComplexObjects;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;
diff --git a/docs/logs/correlation/Program.cs b/docs/logs/correlation/Program.cs
index b1a3284fbcc..6eee75f3657 100644
--- a/docs/logs/correlation/Program.cs
+++ b/docs/logs/correlation/Program.cs
@@ -7,7 +7,9 @@
using OpenTelemetry.Logs;
using OpenTelemetry.Trace;
-public class Program
+namespace Correlation;
+
+internal sealed class Program
{
private static readonly ActivitySource MyActivitySource = new("MyCompany.MyProduct.MyLibrary");
diff --git a/docs/logs/dedicated-pipeline/DedicatedLogging/DedicatedLoggingServiceCollectionExtensions.cs b/docs/logs/dedicated-pipeline/DedicatedLogging/DedicatedLoggingServiceCollectionExtensions.cs
index c9343185e21..6652c195586 100644
--- a/docs/logs/dedicated-pipeline/DedicatedLogging/DedicatedLoggingServiceCollectionExtensions.cs
+++ b/docs/logs/dedicated-pipeline/DedicatedLogging/DedicatedLoggingServiceCollectionExtensions.cs
@@ -6,7 +6,7 @@
namespace DedicatedLogging;
-public static class DedicatedLoggingServiceCollectionExtensions
+internal static class DedicatedLoggingServiceCollectionExtensions
{
public static IServiceCollection AddDedicatedLogging(
this IServiceCollection services,
diff --git a/docs/logs/dedicated-pipeline/DedicatedLogging/IDedicatedLogger.cs b/docs/logs/dedicated-pipeline/DedicatedLogging/IDedicatedLogger.cs
index ba09f27e271..975300a60e0 100644
--- a/docs/logs/dedicated-pipeline/DedicatedLogging/IDedicatedLogger.cs
+++ b/docs/logs/dedicated-pipeline/DedicatedLogging/IDedicatedLogger.cs
@@ -3,10 +3,10 @@
namespace DedicatedLogging;
-public interface IDedicatedLogger : ILogger
+internal interface IDedicatedLogger : ILogger
{
}
-public interface IDedicatedLogger : IDedicatedLogger
+internal interface IDedicatedLogger : IDedicatedLogger
{
}
diff --git a/docs/logs/dedicated-pipeline/dedicated-pipeline.csproj b/docs/logs/dedicated-pipeline/dedicated-pipeline.csproj
index cebc8460c42..6426d0f7ddd 100644
--- a/docs/logs/dedicated-pipeline/dedicated-pipeline.csproj
+++ b/docs/logs/dedicated-pipeline/dedicated-pipeline.csproj
@@ -1,4 +1,8 @@
+
+ $(NoWarn);CA1812;CA2213
+
+
diff --git a/docs/logs/extending-the-sdk/MyExporter.cs b/docs/logs/extending-the-sdk/MyExporter.cs
index 6093f57394b..25b2d9809e1 100644
--- a/docs/logs/extending-the-sdk/MyExporter.cs
+++ b/docs/logs/extending-the-sdk/MyExporter.cs
@@ -5,7 +5,7 @@
using OpenTelemetry;
using OpenTelemetry.Logs;
-internal class MyExporter : BaseExporter
+internal sealed class MyExporter : BaseExporter
{
private readonly string name;
@@ -59,6 +59,7 @@ protected override bool OnShutdown(int timeoutMilliseconds)
protected override void Dispose(bool disposing)
{
+ base.Dispose(disposing);
Console.WriteLine($"{this.name}.Dispose({disposing})");
}
}
diff --git a/docs/logs/extending-the-sdk/MyProcessor.cs b/docs/logs/extending-the-sdk/MyProcessor.cs
index 5fcd34e1d8d..739f9f6f232 100644
--- a/docs/logs/extending-the-sdk/MyProcessor.cs
+++ b/docs/logs/extending-the-sdk/MyProcessor.cs
@@ -4,7 +4,7 @@
using OpenTelemetry;
using OpenTelemetry.Logs;
-internal class MyProcessor : BaseProcessor
+internal sealed class MyProcessor : BaseProcessor
{
private readonly string name;
@@ -32,6 +32,7 @@ protected override bool OnShutdown(int timeoutMilliseconds)
protected override void Dispose(bool disposing)
{
+ base.Dispose(disposing);
Console.WriteLine($"{this.name}.Dispose({disposing})");
}
}
diff --git a/docs/logs/extending-the-sdk/Program.cs b/docs/logs/extending-the-sdk/Program.cs
index cada6ec1f5d..1de67683841 100644
--- a/docs/logs/extending-the-sdk/Program.cs
+++ b/docs/logs/extending-the-sdk/Program.cs
@@ -6,7 +6,7 @@
namespace ExtendingTheSdk;
-public class Program
+internal sealed class Program
{
public static void Main()
{
@@ -29,16 +29,16 @@ public static void Main()
// logger.LogInformation($"Hello from potato {0.99}.");
// structured log with template
- logger.LogInformation("Hello from {name} {price}.", "tomato", 2.99);
+ logger.LogInformation("Hello from {Name} {Price}.", "tomato", 2.99);
// structured log with strong type
- logger.LogInformation("{food}", new Food { Name = "artichoke", Price = 3.99 });
+ logger.LogInformation("{Food}", new Food { Name = "artichoke", Price = 3.99 });
// structured log with anonymous type
- logger.LogInformation("{food}", new { Name = "pumpkin", Price = 5.99 });
+ logger.LogInformation("{Food}", new { Name = "pumpkin", Price = 5.99 });
// structured log with general type
- logger.LogInformation("{food}", new Dictionary
+ logger.LogInformation("{Food}", new Dictionary
{
["Name"] = "truffle",
["Price"] = 299.99,
@@ -48,11 +48,11 @@ public static void Main()
using (logger.BeginScope("[operation]"))
using (logger.BeginScope("[hardware]"))
{
- logger.LogError("{name} is broken.", "refrigerator");
+ logger.LogError("{Name} is broken.", "refrigerator");
}
// message will be redacted by MyRedactionProcessor
- logger.LogInformation("OpenTelemetry {sensitiveString}.", "");
+ logger.LogInformation("OpenTelemetry {SensitiveString}.", "");
}
internal struct Food
diff --git a/docs/logs/extending-the-sdk/extending-the-sdk.csproj b/docs/logs/extending-the-sdk/extending-the-sdk.csproj
index 4d96c349671..e775de84b5d 100644
--- a/docs/logs/extending-the-sdk/extending-the-sdk.csproj
+++ b/docs/logs/extending-the-sdk/extending-the-sdk.csproj
@@ -1,4 +1,8 @@
+
+ $(NoWarn);CA2000;CA1848;CA1510;CA1305
+
+
diff --git a/docs/logs/redaction/MyRedactionProcessor.cs b/docs/logs/redaction/MyRedactionProcessor.cs
index 7959faf3d60..cec1edc4504 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 2dc5d8deb63..f9c04fa7bff 100644
--- a/docs/logs/redaction/redaction.csproj
+++ b/docs/logs/redaction/redaction.csproj
@@ -1,8 +1,8 @@
-
- disable
+ $(NoWarn);CA2213;CA1812;CA1307
+
diff --git a/docs/metrics/README.md b/docs/metrics/README.md
index a96ade061b3..a51c76319bb 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)
@@ -57,7 +59,7 @@ too frequently. `Meter` is fairly expensive and meant to be reused throughout
the application. For most applications, it can be modeled as static readonly
field (e.g. [Program.cs](./getting-started-console/Program.cs)) or singleton via
dependency injection (e.g.
-[Instrumentation.cs](../../examples/AspNetCore/Instrumentation.cs)).
+[InstrumentationSource.cs](../../examples/AspNetCore/InstrumentationSource.cs)).
:heavy_check_mark: You should use dot-separated
[UpperCamelCase](https://en.wikipedia.org/wiki/Camel_case) as the
@@ -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) |
@@ -95,7 +97,7 @@ frequently. Instruments are fairly expensive and meant to be reused throughout
the application. For most applications, instruments can be modeled as static
readonly fields (e.g. [Program.cs](./getting-started-console/Program.cs)) or
singleton via dependency injection (e.g.
-[Instrumentation.cs](../../examples/AspNetCore/Instrumentation.cs)).
+[InstrumentationSource.cs](../../examples/AspNetCore/InstrumentationSource.cs)).
:stop_sign: You should avoid invalid instrument names.
@@ -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,37 +388,25 @@ 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
+As of `1.10.0` once a metric has reached the cardinality limit, any new
+measurement that could not be independently aggregated will be automatically
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.
+attribute](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#overflow-attribute).
> [!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.
-
-When [Delta Aggregation
+> In SDK versions `1.6.0` - `1.9.0` the overflow attribute was an experimental
+ feature that could be enabled by setting the environment variable
+ `OTEL_DOTNET_EXPERIMENTAL_METRICS_EMIT_OVERFLOW_ATTRIBUTE=true`.
+
+As of `1.10.0` when [Delta Aggregation
Temporality](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#temporality)
-is used, it is possible to choose a smaller cardinality limit by allowing the
-SDK to reclaim unused metric points.
+is used, it is possible to choose a smaller cardinality limit because the SDK
+will reclaim unused metric points.
> [!NOTE]
-> Reclaim unused metric points feature was introduced in OpenTelemetry .NET
- [1.7.0-alpha.1](../../src/OpenTelemetry/CHANGELOG.md#170-alpha1). It is
- currently an experimental feature which can be turned on by setting the
- environment variable
- `OTEL_DOTNET_EXPERIMENTAL_METRICS_RECLAIM_UNUSED_METRIC_POINTS=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.
+> In SDK versions `1.7.0` - `1.9.0`, metric point reclaim was an experimental
+ feature that could be enabled by setting the environment variable
+ `OTEL_DOTNET_EXPERIMENTAL_METRICS_RECLAIM_UNUSED_METRIC_POINTS=true`.
### Memory Preallocation
diff --git a/docs/metrics/customizing-the-sdk/Program.cs b/docs/metrics/customizing-the-sdk/Program.cs
index c88a295fdd7..cdcb6dcbbaf 100644
--- a/docs/metrics/customizing-the-sdk/Program.cs
+++ b/docs/metrics/customizing-the-sdk/Program.cs
@@ -8,7 +8,7 @@
namespace CustomizingTheSdk;
-public class Program
+internal static class Program
{
private static readonly Meter Meter1 = new("CompanyA.ProductA.Library1", "1.0");
private static readonly Meter Meter2 = new("CompanyA.ProductB.Library2", "1.0");
@@ -29,17 +29,23 @@ public static void Main()
.AddView(instrumentName: "MyCounter", name: "MyCounterRenamed")
// Change Histogram boundaries using the Explicit Bucket Histogram aggregation.
- .AddView(instrumentName: "MyHistogram", new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 } })
+ .AddView(instrumentName: "MyHistogram", new ExplicitBucketHistogramConfiguration() { Boundaries = [10.0, 20.0] })
// Change Histogram to use the Base2 Exponential Bucket Histogram aggregation.
.AddView(instrumentName: "MyExponentialBucketHistogram", new Base2ExponentialBucketHistogramConfiguration())
// For the instrument "MyCounterCustomTags", aggregate with only the keys "tag1", "tag2".
- .AddView(instrumentName: "MyCounterCustomTags", new MetricStreamConfiguration() { TagKeys = new string[] { "tag1", "tag2" } })
+ .AddView(instrumentName: "MyCounterCustomTags", new MetricStreamConfiguration() { TagKeys = ["tag1", "tag2"] })
// 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 = [10.0, 20.0], 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 830ad66957c..75d55077a15 100644
--- a/docs/metrics/customizing-the-sdk/README.md
+++ b/docs/metrics/customizing-the-sdk/README.md
@@ -200,29 +200,56 @@ used.
##### Explicit bucket histogram aggregation
-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
-default boundaries. This requires the use of
-`ExplicitBucketHistogramConfiguration`.
+By default, the [OpenTelemetry
+Specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.14.0/specification/metrics/sdk.md#explicit-bucket-histogram-aggregation)
+defines explicit buckets (aka boundaries) for Histograms as: `[ 0, 5, 10, 25,
+50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000 ]`.
-```csharp
- // Change Histogram boundaries to count measurements under the following buckets:
- // (-inf, 10]
- // (10, 20]
- // (20, +inf)
- .AddView(
- instrumentName: "MyHistogram",
- new ExplicitBucketHistogramConfiguration { Boundaries = new double[] { 10, 20 } })
+###### Customizing explicit buckets when using histogram aggregation
- // If you provide an empty `double` array as `Boundaries` to the `ExplicitBucketHistogramConfiguration`,
- // the SDK will only export the sum, count, min and max for the measurements.
- // There are no buckets exported in this case.
- .AddView(
- instrumentName: "MyHistogram",
- new ExplicitBucketHistogramConfiguration { Boundaries = Array.Empty() })
-```
+There are two mechanisms available to configure explicit buckets when using
+histogram aggregation:
+
+* View API - Part of the OpenTelemetry .NET SDK.
+* Advice API - Part of the `System.Diagnostics.DiagnosticSource` package
+ starting with version `9.0.0`.
+
+> [!IMPORTANT]
+> When both the View API and Advice API are used, the View API takes precedence.
+ If explicit buckets are not provided by either the View API or the Advice API
+ then the SDK defaults apply.
+
+* View API
+
+ Views can be used to provide custom explicit buckets for a Histogram. This
+ requires the use of `ExplicitBucketHistogramConfiguration`.
+
+ ```csharp
+ // Change Histogram boundaries to count measurements under the following buckets:
+ // (-inf, 10]
+ // (10, 20]
+ // (20, +inf)
+ .AddView(
+ instrumentName: "MyHistogram",
+ new ExplicitBucketHistogramConfiguration { Boundaries = new double[] { 10, 20 } })
+
+ // If you provide an empty `double` array as `Boundaries` to the `ExplicitBucketHistogramConfiguration`,
+ // the SDK will only export the sum, count, min and max for the measurements.
+ // There are no buckets exported in this case.
+ .AddView(
+ instrumentName: "MyHistogram",
+ new ExplicitBucketHistogramConfiguration { Boundaries = Array.Empty() })
+ ```
+
+* Advice API
+
+ Starting with the `1.10.0` SDK, explicit buckets for a Histogram may be provided
+ by instrumentation authors when the instrument is created. This is generally
+ recommended to be used by library authors when the SDK defaults don't match the
+ required granularity for the histogram being emitted.
+
+ See: [Using Advice to customize Histogram
+ instruments](https://learn.microsoft.com/dotnet/core/diagnostics/metrics-instrumentation#using-advice-to-customize-histogram-instruments).
##### Base2 exponential bucket histogram aggregation
@@ -245,6 +272,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 +430,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 +447,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/customizing-the-sdk/customizing-the-sdk.csproj b/docs/metrics/customizing-the-sdk/customizing-the-sdk.csproj
index 19aa9791432..97876c06b9c 100644
--- a/docs/metrics/customizing-the-sdk/customizing-the-sdk.csproj
+++ b/docs/metrics/customizing-the-sdk/customizing-the-sdk.csproj
@@ -1,4 +1,8 @@
+
+ $(NoWarn);CA5394
+
+
diff --git a/docs/metrics/exemplars/Program.cs b/docs/metrics/exemplars/Program.cs
index cd63ac77ecc..d54e0ff6a2b 100644
--- a/docs/metrics/exemplars/Program.cs
+++ b/docs/metrics/exemplars/Program.cs
@@ -8,7 +8,9 @@
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
-public class Program
+namespace Exemplars;
+
+internal static class Program
{
private static readonly ActivitySource MyActivitySource = new("OpenTelemetry.Demo.Exemplar");
private static readonly Meter MyMeter = new("OpenTelemetry.Demo.Exemplar");
diff --git a/docs/metrics/exemplars/README.md b/docs/metrics/exemplars/README.md
index 89f88866560..1f532c2ff0e 100644
--- a/docs/metrics/exemplars/README.md
+++ b/docs/metrics/exemplars/README.md
@@ -58,7 +58,7 @@ and
enabled:
```sh
-./prometheus --enable-feature=exemplar-storage --enable-feature=otlp-write-receiver
+./prometheus --enable-feature=exemplar-storage --web.enable-otlp-receiver
```
## Install and configure Grafana
diff --git a/docs/metrics/exemplars/exemplars.csproj b/docs/metrics/exemplars/exemplars.csproj
index cce12eec60d..686278e7a42 100644
--- a/docs/metrics/exemplars/exemplars.csproj
+++ b/docs/metrics/exemplars/exemplars.csproj
@@ -1,4 +1,8 @@
+
+ $(NoWarn);CA5394
+
+
diff --git a/docs/metrics/extending-the-sdk/MyExporter.cs b/docs/metrics/extending-the-sdk/MyExporter.cs
index 228d3e0c342..376fa2f5b97 100644
--- a/docs/metrics/extending-the-sdk/MyExporter.cs
+++ b/docs/metrics/extending-the-sdk/MyExporter.cs
@@ -5,7 +5,7 @@
using OpenTelemetry;
using OpenTelemetry.Metrics;
-internal class MyExporter : BaseExporter
+internal sealed class MyExporter : BaseExporter
{
private readonly string name;
@@ -28,7 +28,7 @@ public override ExportResult Export(in Batch batch)
sb.Append(", ");
}
- sb.Append($"{metric.Name}");
+ sb.Append(metric.Name);
foreach (ref readonly var metricPoint in metric.GetMetricPoints())
{
@@ -52,6 +52,7 @@ protected override bool OnShutdown(int timeoutMilliseconds)
protected override void Dispose(bool disposing)
{
+ base.Dispose(disposing);
Console.WriteLine($"{this.name}.Dispose({disposing})");
}
}
diff --git a/docs/metrics/extending-the-sdk/Program.cs b/docs/metrics/extending-the-sdk/Program.cs
index a2952062261..0a7cf838cd1 100644
--- a/docs/metrics/extending-the-sdk/Program.cs
+++ b/docs/metrics/extending-the-sdk/Program.cs
@@ -8,7 +8,7 @@
namespace ExtendingTheSdk;
-public class Program
+internal static class Program
{
private static readonly Meter MyMeter = new("MyCompany.MyProduct.MyLibrary", "1.0");
private static readonly Counter MyFruitCounter = MyMeter.CreateCounter("MyFruitCounter");
diff --git a/docs/metrics/extending-the-sdk/extending-the-sdk.csproj b/docs/metrics/extending-the-sdk/extending-the-sdk.csproj
index 4d96c349671..98a53a13c5a 100644
--- a/docs/metrics/extending-the-sdk/extending-the-sdk.csproj
+++ b/docs/metrics/extending-the-sdk/extending-the-sdk.csproj
@@ -1,4 +1,8 @@
+
+ $(NoWarn);CA2000;CA1510;CA1305
+
+
diff --git a/docs/metrics/getting-started-console/Program.cs b/docs/metrics/getting-started-console/Program.cs
index 89425c6d41c..dbc42339877 100644
--- a/docs/metrics/getting-started-console/Program.cs
+++ b/docs/metrics/getting-started-console/Program.cs
@@ -5,7 +5,9 @@
using OpenTelemetry;
using OpenTelemetry.Metrics;
-public class Program
+namespace GettingStartedConsole;
+
+internal static class Program
{
private static readonly Meter MyMeter = new("MyCompany.MyProduct.MyLibrary", "1.0");
private static readonly Counter MyFruitCounter = MyMeter.CreateCounter("MyFruitCounter");
diff --git a/docs/metrics/getting-started-prometheus-grafana/Program.cs b/docs/metrics/getting-started-prometheus-grafana/Program.cs
index 0fd2437eefd..848116636c0 100644
--- a/docs/metrics/getting-started-prometheus-grafana/Program.cs
+++ b/docs/metrics/getting-started-prometheus-grafana/Program.cs
@@ -6,7 +6,9 @@
using OpenTelemetry.Exporter;
using OpenTelemetry.Metrics;
-public class Program
+namespace GettingStartedPrometheusGrafana;
+
+internal static class Program
{
private static readonly Meter MyMeter = new("MyCompany.MyProduct.MyLibrary", "1.0");
private static readonly Counter MyFruitCounter = MyMeter.CreateCounter("MyFruitCounter");
diff --git a/docs/metrics/getting-started-prometheus-grafana/README.md b/docs/metrics/getting-started-prometheus-grafana/README.md
index dfc3e09c1a3..75a09cb1226 100644
--- a/docs/metrics/getting-started-prometheus-grafana/README.md
+++ b/docs/metrics/getting-started-prometheus-grafana/README.md
@@ -88,7 +88,7 @@ access. Run the `prometheus(.exe)` server executable with feature flag
enabled:
```sh
-./prometheus --enable-feature=otlp-write-receiver
+./prometheus --web.enable-otlp-receiver
```
### View results in Prometheus
diff --git a/docs/metrics/learning-more-instruments/Program.cs b/docs/metrics/learning-more-instruments/Program.cs
index c887e281461..9acbcac5639 100644
--- a/docs/metrics/learning-more-instruments/Program.cs
+++ b/docs/metrics/learning-more-instruments/Program.cs
@@ -8,7 +8,7 @@
namespace LearningMoreInstruments;
-public class Program
+internal static class Program
{
private static readonly Meter MyMeter = new("MyCompany.MyProduct.MyLibrary", "1.0");
private static readonly Histogram MyHistogram = MyMeter.CreateHistogram("MyHistogram");
diff --git a/docs/metrics/learning-more-instruments/learning-more-instruments.csproj b/docs/metrics/learning-more-instruments/learning-more-instruments.csproj
index 9f5b6b79bc3..001e041f0f7 100644
--- a/docs/metrics/learning-more-instruments/learning-more-instruments.csproj
+++ b/docs/metrics/learning-more-instruments/learning-more-instruments.csproj
@@ -1,4 +1,8 @@
+
+ $(NoWarn);CA5394
+
+
diff --git a/docs/resources/extending-the-sdk/LoggerExtensions.cs b/docs/resources/extending-the-sdk/LoggerExtensions.cs
new file mode 100644
index 00000000000..a57502fc0f8
--- /dev/null
+++ b/docs/resources/extending-the-sdk/LoggerExtensions.cs
@@ -0,0 +1,12 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using Microsoft.Extensions.Logging;
+
+namespace ExtendingTheSdk;
+
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(LogLevel.Information, "Hello from {Name} {Price}")]
+ public static partial void HelloFrom(this ILogger logger, string name, double price);
+}
diff --git a/docs/resources/extending-the-sdk/MyResourceDetector.cs b/docs/resources/extending-the-sdk/MyResourceDetector.cs
index df40d9b3302..978e4a7edb6 100644
--- a/docs/resources/extending-the-sdk/MyResourceDetector.cs
+++ b/docs/resources/extending-the-sdk/MyResourceDetector.cs
@@ -3,7 +3,7 @@
using OpenTelemetry.Resources;
-internal class MyResourceDetector : IResourceDetector
+internal sealed class MyResourceDetector : IResourceDetector
{
public Resource Detect()
{
diff --git a/docs/resources/extending-the-sdk/Program.cs b/docs/resources/extending-the-sdk/Program.cs
index 849bdcc182b..6877d0c5cc7 100644
--- a/docs/resources/extending-the-sdk/Program.cs
+++ b/docs/resources/extending-the-sdk/Program.cs
@@ -11,7 +11,7 @@
namespace ExtendingTheSdk;
-public class Program
+internal static class Program
{
private static readonly ActivitySource DemoSource = new("OTel.Demo");
private static readonly Meter MeterDemoSource = new("OTel.Demo");
@@ -55,7 +55,6 @@ public static void Main()
}
var logger = loggerFactory.CreateLogger("OTel.Demo");
- logger
- .LogInformation("Hello from {Name} {Price}", "tomato", 2.99);
+ logger.HelloFrom("tomato", 2.99);
}
}
diff --git a/docs/trace/README.md b/docs/trace/README.md
index f0cdb973e1e..80f7c48978e 100644
--- a/docs/trace/README.md
+++ b/docs/trace/README.md
@@ -49,7 +49,7 @@ too frequently. `ActivitySource` is fairly expensive and meant to be reused
throughout the application. For most applications, it can be modeled as static
readonly field (e.g. [Program.cs](./getting-started-console/Program.cs)) or
singleton via dependency injection (e.g.
-[Instrumentation.cs](../../examples/AspNetCore/Instrumentation.cs)).
+[InstrumentationSource.cs](../../examples/AspNetCore/InstrumentationSource.cs)).
:heavy_check_mark: You should use dot-separated
[UpperCamelCase](https://en.wikipedia.org/wiki/Camel_case) as the
diff --git a/docs/trace/customizing-the-sdk/Program.cs b/docs/trace/customizing-the-sdk/Program.cs
index fead3aa0be2..1cc63b0fcc5 100644
--- a/docs/trace/customizing-the-sdk/Program.cs
+++ b/docs/trace/customizing-the-sdk/Program.cs
@@ -8,7 +8,7 @@
namespace CustomizingTheSdk;
-public class Program
+internal static class Program
{
private static readonly ActivitySource MyLibraryActivitySource = new(
"MyCompany.MyProduct.MyLibrary");
diff --git a/docs/trace/customizing-the-sdk/README.md b/docs/trace/customizing-the-sdk/README.md
index d78ed1cd569..b9cec40e949 100644
--- a/docs/trace/customizing-the-sdk/README.md
+++ b/docs/trace/customizing-the-sdk/README.md
@@ -477,8 +477,8 @@ When using the `AddOpenTelemetry` & `WithTracing` extension methods the
into an existing collection (typically the collection used is the one managed by
the application host). The `TracerProviderBuilder` will be able to access all
services registered into that collection. For lifecycle management, the
-`AddOpenTelemetry` registers an [IHostedService
-](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice)
+`AddOpenTelemetry` registers an
+[IHostedService](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice)
which is used to automatically start the `TracerProvider` when the host starts
and the host will automatically shutdown and dispose the `TracerProvider` when
it is shutdown.
diff --git a/docs/trace/customizing-the-sdk/customizing-the-sdk.csproj b/docs/trace/customizing-the-sdk/customizing-the-sdk.csproj
index 2dc5d8deb63..19aa9791432 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/MyEnrichingProcessor.cs b/docs/trace/extending-the-sdk/MyEnrichingProcessor.cs
index a6107330485..4372f9e59f3 100644
--- a/docs/trace/extending-the-sdk/MyEnrichingProcessor.cs
+++ b/docs/trace/extending-the-sdk/MyEnrichingProcessor.cs
@@ -4,7 +4,7 @@
using System.Diagnostics;
using OpenTelemetry;
-internal class MyEnrichingProcessor : BaseProcessor
+internal sealed class MyEnrichingProcessor : BaseProcessor
{
public override void OnEnd(Activity activity)
{
diff --git a/docs/trace/extending-the-sdk/MyExporter.cs b/docs/trace/extending-the-sdk/MyExporter.cs
index d37b9daac46..f00674d1ffc 100644
--- a/docs/trace/extending-the-sdk/MyExporter.cs
+++ b/docs/trace/extending-the-sdk/MyExporter.cs
@@ -5,7 +5,7 @@
using System.Text;
using OpenTelemetry;
-internal class MyExporter : BaseExporter
+internal sealed class MyExporter : BaseExporter
{
private readonly string name;
@@ -43,6 +43,7 @@ protected override bool OnShutdown(int timeoutMilliseconds)
protected override void Dispose(bool disposing)
{
+ base.Dispose(disposing);
Console.WriteLine($"{this.name}.Dispose({disposing})");
}
}
diff --git a/docs/trace/extending-the-sdk/MyProcessor.cs b/docs/trace/extending-the-sdk/MyProcessor.cs
index 4171821d49a..d6ab394ce03 100644
--- a/docs/trace/extending-the-sdk/MyProcessor.cs
+++ b/docs/trace/extending-the-sdk/MyProcessor.cs
@@ -4,7 +4,7 @@
using System.Diagnostics;
using OpenTelemetry;
-internal class MyProcessor : BaseProcessor
+internal sealed class MyProcessor : BaseProcessor
{
private readonly string name;
@@ -37,6 +37,7 @@ protected override bool OnShutdown(int timeoutMilliseconds)
protected override void Dispose(bool disposing)
{
+ base.Dispose(disposing);
Console.WriteLine($"{this.name}.Dispose({disposing})");
}
}
diff --git a/docs/trace/extending-the-sdk/MyResourceDetector.cs b/docs/trace/extending-the-sdk/MyResourceDetector.cs
index df40d9b3302..978e4a7edb6 100644
--- a/docs/trace/extending-the-sdk/MyResourceDetector.cs
+++ b/docs/trace/extending-the-sdk/MyResourceDetector.cs
@@ -3,7 +3,7 @@
using OpenTelemetry.Resources;
-internal class MyResourceDetector : IResourceDetector
+internal sealed class MyResourceDetector : IResourceDetector
{
public Resource Detect()
{
diff --git a/docs/trace/extending-the-sdk/MySampler.cs b/docs/trace/extending-the-sdk/MySampler.cs
index bbb4ae04793..2d733aed25d 100644
--- a/docs/trace/extending-the-sdk/MySampler.cs
+++ b/docs/trace/extending-the-sdk/MySampler.cs
@@ -3,7 +3,7 @@
using OpenTelemetry.Trace;
-internal class MySampler : Sampler
+internal sealed class MySampler : Sampler
{
public override SamplingResult ShouldSample(in SamplingParameters param)
{
diff --git a/docs/trace/extending-the-sdk/Program.cs b/docs/trace/extending-the-sdk/Program.cs
index ce001aee3e3..e051d4ed71a 100644
--- a/docs/trace/extending-the-sdk/Program.cs
+++ b/docs/trace/extending-the-sdk/Program.cs
@@ -8,7 +8,7 @@
namespace ExtendingTheSdk;
-public class Program
+internal static class Program
{
private static readonly ActivitySource DemoSource = new("OTel.Demo");
diff --git a/docs/trace/extending-the-sdk/README.md b/docs/trace/extending-the-sdk/README.md
index 4f7380ee64b..db75bad7131 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/extending-the-sdk/extending-the-sdk.csproj b/docs/trace/extending-the-sdk/extending-the-sdk.csproj
index 85aab7a7ed3..2f56fd33163 100644
--- a/docs/trace/extending-the-sdk/extending-the-sdk.csproj
+++ b/docs/trace/extending-the-sdk/extending-the-sdk.csproj
@@ -1,4 +1,8 @@
+
+ $(NoWarn);CA2000;CA1812;CA1510
+
+
diff --git a/docs/trace/getting-started-aspnetcore/README.md b/docs/trace/getting-started-aspnetcore/README.md
index a9b7adf0b3d..7febcf4d55f 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-console/Program.cs b/docs/trace/getting-started-console/Program.cs
index 4acaf7b8a80..3ab95d4d24f 100644
--- a/docs/trace/getting-started-console/Program.cs
+++ b/docs/trace/getting-started-console/Program.cs
@@ -5,7 +5,9 @@
using OpenTelemetry;
using OpenTelemetry.Trace;
-public class Program
+namespace GettingStartedConsole;
+
+internal static class Program
{
private static readonly ActivitySource MyActivitySource = new("MyCompany.MyProduct.MyLibrary");
@@ -18,9 +20,10 @@ public static void Main()
using (var activity = MyActivitySource.StartActivity("SayHello"))
{
+ int[] intArray = [1, 2, 3];
activity?.SetTag("foo", 1);
activity?.SetTag("bar", "Hello, World!");
- activity?.SetTag("baz", new int[] { 1, 2, 3 });
+ activity?.SetTag("baz", intArray);
activity?.SetStatus(ActivityStatusCode.Ok);
}
diff --git a/docs/trace/getting-started-jaeger/Program.cs b/docs/trace/getting-started-jaeger/Program.cs
index d4603a71bd0..bff8079f132 100644
--- a/docs/trace/getting-started-jaeger/Program.cs
+++ b/docs/trace/getting-started-jaeger/Program.cs
@@ -11,7 +11,7 @@
namespace GettingStartedJaeger;
-public class Program
+internal static class Program
{
private static readonly ActivitySource MyActivitySource = new("OpenTelemetry.Demo.Jaeger");
@@ -33,13 +33,13 @@ public static async Task Main()
{
using (var slow = MyActivitySource.StartActivity("SomethingSlow"))
{
- await client.GetStringAsync("https://httpstat.us/200?sleep=1000");
- await client.GetStringAsync("https://httpstat.us/200?sleep=1000");
+ await client.GetStringAsync(new Uri("https://httpstat.us/200?sleep=1000")).ConfigureAwait(false);
+ await client.GetStringAsync(new Uri("https://httpstat.us/200?sleep=1000")).ConfigureAwait(false);
}
using (var fast = MyActivitySource.StartActivity("SomethingFast"))
{
- await client.GetStringAsync("https://httpstat.us/301");
+ await client.GetStringAsync(new Uri("https://httpstat.us/301")).ConfigureAwait(false);
}
}
}
diff --git a/docs/trace/getting-started-jaeger/README.md b/docs/trace/getting-started-jaeger/README.md
index b291933df00..92752ff66da 100644
--- a/docs/trace/getting-started-jaeger/README.md
+++ b/docs/trace/getting-started-jaeger/README.md
@@ -47,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
...
```
diff --git a/docs/trace/links-based-sampler/LinksAndParentBasedSampler.cs b/docs/trace/links-based-sampler/LinksAndParentBasedSampler.cs
index bca076a2734..af44cb92072 100644
--- a/docs/trace/links-based-sampler/LinksAndParentBasedSampler.cs
+++ b/docs/trace/links-based-sampler/LinksAndParentBasedSampler.cs
@@ -13,7 +13,7 @@ namespace LinksAndParentBasedSamplerExample;
/// links based sampler. If either of these samplers decide to sample,
/// this composite sampler decides to sample.
///
-internal class LinksAndParentBasedSampler : Sampler
+internal sealed class LinksAndParentBasedSampler : Sampler
{
private readonly ParentBasedSampler parentBasedSampler;
private readonly LinksBasedSampler linksBasedSampler;
diff --git a/docs/trace/links-based-sampler/LinksBasedSampler.cs b/docs/trace/links-based-sampler/LinksBasedSampler.cs
index b9306fab232..226b6591693 100644
--- a/docs/trace/links-based-sampler/LinksBasedSampler.cs
+++ b/docs/trace/links-based-sampler/LinksBasedSampler.cs
@@ -10,7 +10,7 @@ namespace LinksAndParentBasedSamplerExample;
/// A non-probabilistic sampler that samples an activity if ANY of the linked activities
/// is sampled.
///
-internal class LinksBasedSampler : Sampler
+internal sealed class LinksBasedSampler : Sampler
{
public override SamplingResult ShouldSample(in SamplingParameters samplingParameters)
{
diff --git a/docs/trace/links-based-sampler/Program.cs b/docs/trace/links-based-sampler/Program.cs
index 7ef89aa5fdb..03827633820 100644
--- a/docs/trace/links-based-sampler/Program.cs
+++ b/docs/trace/links-based-sampler/Program.cs
@@ -7,7 +7,7 @@
namespace LinksAndParentBasedSamplerExample;
-internal class Program
+internal static class Program
{
private static readonly ActivitySource MyActivitySource = new("LinksAndParentBasedSampler.Example");
@@ -37,7 +37,7 @@ public static void Main(string[] args)
/// Generates a list of activity links. A linked activity is sampled with a probability of 0.1.
///
/// A list of links.
- private static IEnumerable GetActivityLinks(int seed)
+ private static List GetActivityLinks(int seed)
{
var random = new Random(seed);
var linkedActivitiesList = new List();
diff --git a/docs/trace/links-based-sampler/links-sampler.csproj b/docs/trace/links-based-sampler/links-sampler.csproj
index 19aa9791432..97876c06b9c 100644
--- a/docs/trace/links-based-sampler/links-sampler.csproj
+++ b/docs/trace/links-based-sampler/links-sampler.csproj
@@ -1,4 +1,8 @@
+
+ $(NoWarn);CA5394
+
+
diff --git a/docs/trace/links-creation-with-new-activities/Program.cs b/docs/trace/links-creation-with-new-activities/Program.cs
index c03af7bcc82..1568930d998 100644
--- a/docs/trace/links-creation-with-new-activities/Program.cs
+++ b/docs/trace/links-creation-with-new-activities/Program.cs
@@ -7,7 +7,7 @@
namespace LinksCreationWithNewRootActivitiesDemo;
-internal class Program
+internal static class Program
{
private static readonly ActivitySource MyActivitySource = new("LinksCreationWithNewRootActivities");
@@ -21,7 +21,7 @@ public static async Task Main(string[] args)
using (var activity = MyActivitySource.StartActivity("OrchestratingActivity"))
{
activity?.SetTag("foo", 1);
- await DoFanoutAsync();
+ await DoFanoutAsync().ConfigureAwait(false);
using (var nestedActivity = MyActivitySource.StartActivity("WrapUp"))
{
@@ -77,7 +77,7 @@ public static async Task DoFanoutAsync()
}
// Wait for all tasks to complete
- await Task.WhenAll(tasks);
+ await Task.WhenAll(tasks).ConfigureAwait(false);
// Reset to the previous activity now that we are done with the fanout
// This will ensure that the rest of the code executes in the context of the original activity.
diff --git a/docs/trace/reporting-exceptions/Program.cs b/docs/trace/reporting-exceptions/Program.cs
index 62f2a11914e..a6e4997ff79 100644
--- a/docs/trace/reporting-exceptions/Program.cs
+++ b/docs/trace/reporting-exceptions/Program.cs
@@ -7,7 +7,7 @@
namespace ReportingExceptions;
-public class Program
+internal static class Program
{
private static readonly ActivitySource MyActivitySource = new(
"MyCompany.MyProduct.MyLibrary");
@@ -27,7 +27,7 @@ public static void Main()
{
using (MyActivitySource.StartActivity("Bar"))
{
- throw new Exception("Oops!");
+ throw new InvalidOperationException("Oops!");
}
}
}
diff --git a/docs/trace/stratified-sampling-example/Program.cs b/docs/trace/stratified-sampling-example/Program.cs
index 49d8e1b7e7b..8063dd4f046 100644
--- a/docs/trace/stratified-sampling-example/Program.cs
+++ b/docs/trace/stratified-sampling-example/Program.cs
@@ -7,7 +7,7 @@
namespace StratifiedSamplingByQueryTypeDemo;
-internal class Program
+internal sealed class Program
{
private static readonly ActivitySource MyActivitySource = new("StratifiedSampling.POC");
diff --git a/docs/trace/stratified-sampling-example/StratifiedSampler.cs b/docs/trace/stratified-sampling-example/StratifiedSampler.cs
index cb01a23dee0..64cbe8a4c84 100644
--- a/docs/trace/stratified-sampling-example/StratifiedSampler.cs
+++ b/docs/trace/stratified-sampling-example/StratifiedSampler.cs
@@ -5,7 +5,7 @@
namespace StratifiedSamplingByQueryTypeDemo;
-internal class StratifiedSampler : Sampler
+internal sealed class StratifiedSampler : Sampler
{
// For this POC, we have two groups.
// 0 is the group corresponding to user-initiated queries where we want a 100% sampling rate.
diff --git a/docs/trace/stratified-sampling-example/stratified-sampling-example.csproj b/docs/trace/stratified-sampling-example/stratified-sampling-example.csproj
index 19aa9791432..97876c06b9c 100644
--- a/docs/trace/stratified-sampling-example/stratified-sampling-example.csproj
+++ b/docs/trace/stratified-sampling-example/stratified-sampling-example.csproj
@@ -1,4 +1,8 @@
+
+ $(NoWarn);CA5394
+
+
diff --git a/docs/trace/tail-based-sampling-span-level/ParentBasedElseAlwaysRecordSampler.cs b/docs/trace/tail-based-sampling-span-level/ParentBasedElseAlwaysRecordSampler.cs
index bce691b0c16..4d933dbf2ec 100644
--- a/docs/trace/tail-based-sampling-span-level/ParentBasedElseAlwaysRecordSampler.cs
+++ b/docs/trace/tail-based-sampling-span-level/ParentBasedElseAlwaysRecordSampler.cs
@@ -15,7 +15,7 @@ namespace SDKBasedSpanLevelTailSamplingSample;
/// changed later by a span processor based on span attributes (e.g., failure) that become
/// available only by the end of the span.
///
-internal class ParentBasedElseAlwaysRecordSampler : Sampler
+internal sealed class ParentBasedElseAlwaysRecordSampler : Sampler
{
private const double DefaultSamplingProbabilityForRootSpan = 0.1;
private readonly ParentBasedSampler parentBasedSampler;
diff --git a/docs/trace/tail-based-sampling-span-level/Program.cs b/docs/trace/tail-based-sampling-span-level/Program.cs
index de4f8ea9f17..d2114248442 100644
--- a/docs/trace/tail-based-sampling-span-level/Program.cs
+++ b/docs/trace/tail-based-sampling-span-level/Program.cs
@@ -7,7 +7,7 @@
namespace SDKBasedSpanLevelTailSamplingSample;
-internal class Program
+internal static class Program
{
private static readonly ActivitySource MyActivitySource = new("SDK.TailSampling.POC");
diff --git a/docs/trace/tail-based-sampling-span-level/TailSamplingProcessor.cs b/docs/trace/tail-based-sampling-span-level/TailSamplingProcessor.cs
index 5aa22092e75..10aee54e38d 100644
--- a/docs/trace/tail-based-sampling-span-level/TailSamplingProcessor.cs
+++ b/docs/trace/tail-based-sampling-span-level/TailSamplingProcessor.cs
@@ -26,7 +26,7 @@ public override void OnEnd(Activity activity)
}
else
{
- this.IncludeForExportIfFailedActivity(activity);
+ IncludeForExportIfFailedActivity(activity);
}
base.OnEnd(activity);
@@ -42,7 +42,7 @@ public override void OnEnd(Activity activity)
// 2. Traces will not be complete: Since this sampling is at a span level, the generated trace will be partial and won't be complete.
// For example, if another part of the call tree is successful, those spans may not be sampled in leading to a partial trace.
// 3. If multiple exporters are used, this decision will impact all of them: https://github.com/open-telemetry/opentelemetry-dotnet/issues/3861.
- private void IncludeForExportIfFailedActivity(Activity activity)
+ private static void IncludeForExportIfFailedActivity(Activity activity)
{
if (activity.Status == ActivityStatusCode.Error)
{
diff --git a/docs/trace/tail-based-sampling-span-level/tail-based-sampling-example.csproj b/docs/trace/tail-based-sampling-span-level/tail-based-sampling-example.csproj
index 19aa9791432..b7947e79e17 100644
--- a/docs/trace/tail-based-sampling-span-level/tail-based-sampling-example.csproj
+++ b/docs/trace/tail-based-sampling-span-level/tail-based-sampling-example.csproj
@@ -1,4 +1,8 @@
+
+ $(NoWarn);CA5394;CA2000
+
+
diff --git a/examples/AspNetCore/Controllers/WeatherForecastController.cs b/examples/AspNetCore/Controllers/WeatherForecastController.cs
index 3d09fe9ed61..bbb257334e7 100644
--- a/examples/AspNetCore/Controllers/WeatherForecastController.cs
+++ b/examples/AspNetCore/Controllers/WeatherForecastController.cs
@@ -5,6 +5,7 @@ namespace Examples.AspNetCore.Controllers;
using System.Diagnostics;
using System.Diagnostics.Metrics;
+using System.Security.Cryptography;
using Examples.AspNetCore;
using Microsoft.AspNetCore.Mvc;
@@ -12,10 +13,10 @@ namespace Examples.AspNetCore.Controllers;
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
- private static readonly string[] Summaries = new[]
- {
- "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching",
- };
+ private static readonly string[] Summaries =
+ [
+ "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
+ ];
private static readonly HttpClient HttpClient = new();
@@ -23,24 +24,24 @@ public class WeatherForecastController : ControllerBase
private readonly ActivitySource activitySource;
private readonly Counter freezingDaysCounter;
- public WeatherForecastController(ILogger logger, Instrumentation instrumentation)
+ public WeatherForecastController(ILogger logger, InstrumentationSource instrumentationSource)
{
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
- ArgumentNullException.ThrowIfNull(instrumentation);
- this.activitySource = instrumentation.ActivitySource;
- this.freezingDaysCounter = instrumentation.FreezingDaysCounter;
+ ArgumentNullException.ThrowIfNull(instrumentationSource);
+ this.activitySource = instrumentationSource.ActivitySource;
+ this.freezingDaysCounter = instrumentationSource.FreezingDaysCounter;
}
[HttpGet]
public IEnumerable Get()
{
- using var scope = this.logger.BeginScope("{Id}", Guid.NewGuid().ToString("N"));
+ using var scope = this.logger.BeginIdScope(Guid.NewGuid().ToString("N"));
- // Making an http call here to serve as an example of
+ // Making a http call here to serve as an example of
// how dependency calls will be captured and treated
// automatically as child of incoming request.
- var res = HttpClient.GetStringAsync("http://google.com").Result;
+ var res = HttpClient.GetStringAsync(new Uri("http://google.com")).Result;
// Optional: Manually create an activity. This will become a child of
// the activity created from the instrumentation library for AspNetCore.
@@ -52,22 +53,18 @@ public IEnumerable Get()
// a manual activity using Activity.Current?.SetTag()
using var activity = this.activitySource.StartActivity("calculate forecast");
- var rng = new Random();
var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
- TemperatureC = rng.Next(-20, 55),
- Summary = Summaries[rng.Next(Summaries.Length)],
+ TemperatureC = RandomNumberGenerator.GetInt32(-20, 55),
+ Summary = Summaries[RandomNumberGenerator.GetInt32(Summaries.Length)],
})
.ToArray();
// Optional: Count the freezing days
this.freezingDaysCounter.Add(forecast.Count(f => f.TemperatureC < 0));
- this.logger.LogInformation(
- "WeatherForecasts generated {count}: {forecasts}",
- forecast.Length,
- forecast);
+ this.logger.WeatherForecastGenerated(LogLevel.Information, forecast.Length, forecast);
return forecast;
}
diff --git a/examples/AspNetCore/Controllers/WeatherForecastControllerLog.cs b/examples/AspNetCore/Controllers/WeatherForecastControllerLog.cs
new file mode 100644
index 00000000000..eb6bc292673
--- /dev/null
+++ b/examples/AspNetCore/Controllers/WeatherForecastControllerLog.cs
@@ -0,0 +1,14 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+namespace Examples.AspNetCore.Controllers;
+
+internal static partial class WeatherForecastControllerLog
+{
+ private static readonly Func Scope = LoggerMessage.DefineScope("{Id}");
+
+ public static IDisposable? BeginIdScope(this ILogger logger, string id) => Scope(logger, id);
+
+ [LoggerMessage(EventId = 1, Message = "WeatherForecasts generated {Count}: {Forecasts}")]
+ public static partial void WeatherForecastGenerated(this ILogger logger, LogLevel logLevel, int count, WeatherForecast[] forecasts);
+}
diff --git a/examples/AspNetCore/Examples.AspNetCore.csproj b/examples/AspNetCore/Examples.AspNetCore.csproj
index e476b1ed4d8..459213fe2ba 100644
--- a/examples/AspNetCore/Examples.AspNetCore.csproj
+++ b/examples/AspNetCore/Examples.AspNetCore.csproj
@@ -2,6 +2,7 @@
$(DefaultTargetFrameworkForExampleApps)
+ $(NoWarn);CA1515
diff --git a/examples/AspNetCore/Instrumentation.cs b/examples/AspNetCore/InstrumentationSource.cs
similarity index 85%
rename from examples/AspNetCore/Instrumentation.cs
rename to examples/AspNetCore/InstrumentationSource.cs
index 4b0ede1157f..be6d5764033 100644
--- a/examples/AspNetCore/Instrumentation.cs
+++ b/examples/AspNetCore/InstrumentationSource.cs
@@ -11,15 +11,15 @@ namespace Examples.AspNetCore;
/// ActivitySource and Instruments. This avoids possible type collisions
/// with other components in the DI container.
///
-public class Instrumentation : IDisposable
+public sealed class InstrumentationSource : IDisposable
{
internal const string ActivitySourceName = "Examples.AspNetCore";
internal const string MeterName = "Examples.AspNetCore";
private readonly Meter meter;
- public Instrumentation()
+ public InstrumentationSource()
{
- string? version = typeof(Instrumentation).Assembly.GetName().Version?.ToString();
+ string? version = typeof(InstrumentationSource).Assembly.GetName().Version?.ToString();
this.ActivitySource = new ActivitySource(ActivitySourceName, version);
this.meter = new Meter(MeterName, version);
this.FreezingDaysCounter = this.meter.CreateCounter("weather.days.freezing", description: "The number of days where the temperature is below freezing");
diff --git a/examples/AspNetCore/Program.cs b/examples/AspNetCore/Program.cs
index 809534f5c76..afd59db31d7 100644
--- a/examples/AspNetCore/Program.cs
+++ b/examples/AspNetCore/Program.cs
@@ -13,20 +13,20 @@
var appBuilder = WebApplication.CreateBuilder(args);
// Note: Switch between Zipkin/OTLP/Console by setting UseTracingExporter in appsettings.json.
-var tracingExporter = appBuilder.Configuration.GetValue("UseTracingExporter", defaultValue: "console")!.ToLowerInvariant();
+var tracingExporter = appBuilder.Configuration.GetValue("UseTracingExporter", defaultValue: "CONSOLE").ToUpperInvariant();
// Note: Switch between Prometheus/OTLP/Console by setting UseMetricsExporter in appsettings.json.
-var metricsExporter = appBuilder.Configuration.GetValue("UseMetricsExporter", defaultValue: "console")!.ToLowerInvariant();
+var metricsExporter = appBuilder.Configuration.GetValue("UseMetricsExporter", defaultValue: "CONSOLE").ToUpperInvariant();
// Note: Switch between Console/OTLP by setting UseLogExporter in appsettings.json.
-var logExporter = appBuilder.Configuration.GetValue("UseLogExporter", defaultValue: "console")!.ToLowerInvariant();
+var logExporter = appBuilder.Configuration.GetValue("UseLogExporter", defaultValue: "CONSOLE").ToUpperInvariant();
// Note: Switch between Explicit/Exponential by setting HistogramAggregation in appsettings.json
-var histogramAggregation = appBuilder.Configuration.GetValue("HistogramAggregation", defaultValue: "explicit")!.ToLowerInvariant();
+var histogramAggregation = appBuilder.Configuration.GetValue("HistogramAggregation", defaultValue: "EXPLICIT").ToUpperInvariant();
// Create a service to expose ActivitySource, and Metric Instruments
// for manual instrumentation
-appBuilder.Services.AddSingleton();
+appBuilder.Services.AddSingleton();
// Clear default logging providers used by WebApplication host.
appBuilder.Logging.ClearProviders();
@@ -45,7 +45,7 @@
// Ensure the TracerProvider subscribes to any custom ActivitySources.
builder
- .AddSource(Instrumentation.ActivitySourceName)
+ .AddSource(InstrumentationSource.ActivitySourceName)
.SetSampler(new AlwaysOnSampler())
.AddHttpClientInstrumentation()
.AddAspNetCoreInstrumentation();
@@ -55,7 +55,7 @@
switch (tracingExporter)
{
- case "zipkin":
+ case "ZIPKIN":
builder.AddZipkinExporter();
builder.ConfigureServices(services =>
@@ -65,11 +65,11 @@
});
break;
- case "otlp":
+ 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")!);
+ otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue("Otlp:Endpoint", defaultValue: "http://localhost:4317"));
});
break;
@@ -84,7 +84,7 @@
// Ensure the MeterProvider subscribes to any custom Meters.
builder
- .AddMeter(Instrumentation.MeterName)
+ .AddMeter(InstrumentationSource.MeterName)
.SetExemplarFilter(ExemplarFilterType.TraceBased)
.AddRuntimeInstrumentation()
.AddHttpClientInstrumentation()
@@ -92,7 +92,7 @@
switch (histogramAggregation)
{
- case "exponential":
+ case "EXPONENTIAL":
builder.AddView(instrument =>
{
return instrument.GetType().GetGenericTypeDefinition() == typeof(Histogram<>)
@@ -108,10 +108,10 @@
switch (metricsExporter)
{
- case "prometheus":
+ case "PROMETHEUS":
builder.AddPrometheusExporter();
break;
- case "otlp":
+ case "OTLP":
builder.AddOtlpExporter(otlpOptions =>
{
// Use IConfiguration directly for Otlp exporter endpoint option.
@@ -129,11 +129,11 @@
switch (logExporter)
{
- case "otlp":
+ 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")!);
+ otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue("Otlp:Endpoint", defaultValue: "http://localhost:4317"));
});
break;
default:
diff --git a/examples/AspNetCore/README.md b/examples/AspNetCore/README.md
index 001d3cdea08..8ab5c23a0ad 100644
--- a/examples/AspNetCore/README.md
+++ b/examples/AspNetCore/README.md
@@ -1,6 +1,6 @@
-# OpenTelemetry ASP.NET Core 7 Web API Example
+# OpenTelemetry ASP.NET Core Web API Example
-This example uses the new WebApplication host that ships with .NET 7
+This example uses the new WebApplication host that ships with .NET
and shows how to setup
1. OpenTelemetry logging
@@ -13,7 +13,27 @@ service name, version and the machine on which this program is running.
The sample rate is set to emit all the traces using `AlwaysOnSampler`.
You can try out different samplers like `TraceIdRatioBasedSampler`.
+## Running Dependencies via Docker
+
+The example by default writes telemetry to stdout. To enable telemetry export
+via OTLP, update the `appsettings.json` file to replace `"console"` with
+`"otlp"`. Launching the application will then send telemetry data via OTLP.
+
+Use the provided "docker-compose.yaml" file to spin up the
+required dependencies, including:
+
+- **OTel Collector** Accept telemetry and forwards them to Tempo, Prometheus
+- **Prometheus** to store metrics
+- **Grafana (UI)** UI to view metrics, traces. (Exemplars can be used to jump
+ from metrics to traces)
+- **Tempo** to store traces // TODO: Add a logging store also.
+
+Once the Docker containers are running, you can access the **Grafana UI** at:
+[http://localhost:3000/](http://localhost:3000/)
+
## References
-* [ASP.NET Core 3.1 Example](https://github.com/open-telemetry/opentelemetry-dotnet/tree/98cb28974af43fc893ab80a8cead6e2d4163e144/examples/AspNetCore)
-* [OpenTelemetry Project](https://opentelemetry.io/)
+- [ASP.NET Core](https://learn.microsoft.com/aspnet/core/introduction-to-aspnet-core)
+- [Docker](http://docker.com)
+- [Prometheus](http://prometheus.io/docs)
+- [Tempo](https://github.com/grafana/tempo)
diff --git a/examples/AspNetCore/docker-compose.yaml b/examples/AspNetCore/docker-compose.yaml
index c8cc94fa4b1..444e79eca81 100644
--- a/examples/AspNetCore/docker-compose.yaml
+++ b/examples/AspNetCore/docker-compose.yaml
@@ -1,9 +1,8 @@
-version: "3"
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.136.0@sha256:98fd3b410ae8a939be9588f1580c4b7c3da6ebba49f5363df4259a827aabb779
command: [ "--config=/etc/otel-collector.yaml" ]
volumes:
- ./otel-collector.yaml:/etc/otel-collector.yaml
@@ -14,7 +13,7 @@ services:
# Exports Traces to Tempo
tempo:
- image: grafana/tempo:latest
+ image: grafana/tempo:2.8.2@sha256:0ef775495967cd5d7a6b2e146b6ea695d624803c8db8349fb8ce4164f719f9b7
command: [ "-config.file=/etc/tempo.yaml" ]
volumes:
- ./tempo.yaml:/etc/tempo.yaml
@@ -26,7 +25,7 @@ services:
# Exports Metrics to Prometheus
prometheus:
- image: prom/prometheus:latest
+ image: prom/prometheus:v3.6.0@sha256:76947e7ef22f8a698fc638f706685909be425dbe09bd7a2cd7aca849f79b5f64
command:
- --config.file=/etc/prometheus.yaml
- --web.enable-remote-write-receiver
@@ -38,7 +37,7 @@ services:
# UI to query traces and metrics
grafana:
- image: grafana/grafana:9.3.2
+ image: grafana/grafana:12.2.0@sha256:74144189b38447facf737dfd0f3906e42e0776212bf575dc3334c3609183adf7
volumes:
- ./grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml
environment:
diff --git a/examples/AspNetCore/otel-collector.yaml b/examples/AspNetCore/otel-collector.yaml
index 15df605c542..fa9999d66c9 100644
--- a/examples/AspNetCore/otel-collector.yaml
+++ b/examples/AspNetCore/otel-collector.yaml
@@ -2,7 +2,9 @@ receivers:
otlp:
protocols:
grpc:
+ endpoint: 0.0.0.0:4317
http:
+ endpoint: 0.0.0.0:4318
exporters:
debug:
diff --git a/examples/AspNetCore/tempo.yaml b/examples/AspNetCore/tempo.yaml
index 0d46d4718e8..1217bc05760 100644
--- a/examples/AspNetCore/tempo.yaml
+++ b/examples/AspNetCore/tempo.yaml
@@ -6,7 +6,9 @@ distributor:
otlp:
protocols:
http:
+ endpoint: 0.0.0.0:4318
grpc:
+ endpoint: 0.0.0.0:4317
storage:
trace:
diff --git a/examples/Console/Examples.Console.csproj b/examples/Console/Examples.Console.csproj
index d2b74f2e648..ade79a55665 100644
--- a/examples/Console/Examples.Console.csproj
+++ b/examples/Console/Examples.Console.csproj
@@ -1,12 +1,9 @@
-
+
Exe
$(DefaultTargetFrameworkForExampleApps)
- $(NoWarn),CS0618
-
-
- disable
+ $(NoWarn),CA1812
diff --git a/examples/Console/InstrumentationWithActivitySource.cs b/examples/Console/InstrumentationWithActivitySource.cs
index 240f58289d8..e591ea12505 100644
--- a/examples/Console/InstrumentationWithActivitySource.cs
+++ b/examples/Console/InstrumentationWithActivitySource.cs
@@ -8,7 +8,7 @@
namespace Examples.Console;
-internal class InstrumentationWithActivitySource : IDisposable
+internal sealed class InstrumentationWithActivitySource : IDisposable
{
private const string RequestPath = "/api/request";
private readonly SampleServer server = new();
@@ -27,7 +27,7 @@ public void Dispose()
this.server.Dispose();
}
- private class SampleServer : IDisposable
+ private sealed class SampleServer : IDisposable
{
private readonly HttpListener listener = new();
@@ -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,11 +62,11 @@ 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);
- activity?.SetTag("request.length", requestContent.Length.ToString());
+ activity?.SetTag("request.length", requestContent.Length);
var echo = Encoding.UTF8.GetBytes("echo: " + requestContent);
context.Response.ContentEncoding = Encoding.UTF8;
@@ -88,10 +88,10 @@ public void Dispose()
}
}
- private class SampleClient : IDisposable
+ private sealed class SampleClient : IDisposable
{
- private CancellationTokenSource cts;
- private Task requestTask;
+ private CancellationTokenSource? cts;
+ private Task? requestTask;
public void Start(string url)
{
@@ -114,7 +114,7 @@ public void Start(string url)
count++;
activity?.AddEvent(new ActivityEvent("PostAsync:Started"));
- using var response = await client.PostAsync(url, content, cancellationToken).ConfigureAwait(false);
+ using var response = await client.PostAsync(new Uri(url, UriKind.Absolute), content, cancellationToken).ConfigureAwait(false);
activity?.AddEvent(new ActivityEvent("PostAsync:Ended"));
activity?.SetTag("http.status_code", (int)response.StatusCode);
@@ -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 2b93979e071..a7d0e822f47 100644
--- a/examples/Console/Program.cs
+++ b/examples/Console/Program.cs
@@ -8,7 +8,7 @@ namespace Examples.Console;
///
/// Main samples entry point.
///
-public class Program
+internal static class Program
{
///
/// Main method - invoke this using command line.
@@ -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);
}
@@ -51,21 +51,21 @@ public static void Main(string[] args)
#pragma warning disable SA1402 // File may only contain a single type
[Verb("zipkin", HelpText = "Specify the options required to test Zipkin exporter")]
-internal class ZipkinOptions
+internal sealed 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")]
-internal class PrometheusOptions
+internal sealed class PrometheusOptions
{
[Option('p', "port", Default = 9464, HelpText = "The port to expose metrics. The endpoint will be http://localhost:port/metrics/ (this is the port from which your Prometheus server scraps metrics from.)", Required = false)]
public int Port { get; set; }
}
[Verb("metrics", HelpText = "Specify the options required to test Metrics")]
-internal class MetricsOptions
+internal sealed class MetricsOptions
{
[Option('d', "IsDelta", HelpText = "Export Delta metrics", Required = false, Default = false)]
public bool IsDelta { get; set; }
@@ -83,71 +83,71 @@ 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; }
}
[Verb("grpc", HelpText = "Specify the options required to test Grpc.Net.Client")]
-internal class GrpcNetClientOptions
+internal sealed class GrpcNetClientOptions
{
}
[Verb("httpclient", HelpText = "Specify the options required to test HttpClient")]
-internal class HttpClientOptions
+internal sealed class HttpClientOptions
{
}
[Verb("console", HelpText = "Specify the options required to test console exporter")]
-internal class ConsoleOptions
+internal sealed class ConsoleOptions
{
}
[Verb("otelshim", HelpText = "Specify the options required to test OpenTelemetry Shim with console exporter")]
-internal class OpenTelemetryShimOptions
+internal sealed class OpenTelemetryShimOptions
{
}
[Verb("opentracing", HelpText = "Specify the options required to test OpenTracing Shim with console exporter")]
-internal class OpenTracingShimOptions
+internal sealed class OpenTracingShimOptions
{
}
[Verb("otlp", HelpText = "Specify the options required to test OpenTelemetry Protocol (OTLP)")]
-internal class OtlpOptions
+internal sealed 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
+internal sealed 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; }
}
[Verb("inmemory", HelpText = "Specify the options required to test InMemory Exporter")]
-internal class InMemoryOptions
+internal sealed class InMemoryOptions
{
}
diff --git a/examples/Console/TestConsoleExporter.cs b/examples/Console/TestConsoleExporter.cs
index cf3f803c4fd..fa59c3a9954 100644
--- a/examples/Console/TestConsoleExporter.cs
+++ b/examples/Console/TestConsoleExporter.cs
@@ -8,49 +8,49 @@
namespace Examples.Console;
-internal class TestConsoleExporter
+internal sealed class TestConsoleExporter
{
// To run this example, run the following command from
// the reporoot\examples\Console\.
// (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"))
+#pragma warning disable CA2000 // Dispose objects before losing scope
+ .AddProcessor(new MyProcessor()) // This must be added before ConsoleExporter
+#pragma warning restore CA2000 // Dispose objects before losing scope
+ .AddConsoleExporter()
+ .Build();
// The above line is required only in applications
// which decide to use OpenTelemetry.
- using (var sample = new InstrumentationWithActivitySource())
- {
- sample.Start();
+ using var sample = new InstrumentationWithActivitySource();
+ sample.Start();
- System.Console.WriteLine("Traces are being created and exported " +
- "to Console in the background. " +
- "Press ENTER to stop.");
- System.Console.ReadLine();
- }
+ System.Console.WriteLine("Traces are being created and exported " +
+ "to Console in the background. " +
+ "Press ENTER to stop.");
+ System.Console.ReadLine();
- return null;
+ return 0;
}
///
/// An example of custom processor which
/// can be used to add more tags to an activity.
///
- internal class MyProcessor : BaseProcessor
+ internal sealed class MyProcessor : BaseProcessor
{
public override void OnStart(Activity activity)
{
diff --git a/examples/Console/TestGrpcNetClient.cs b/examples/Console/TestGrpcNetClient.cs
index d179d93913e..ab2e0378a6b 100644
--- a/examples/Console/TestGrpcNetClient.cs
+++ b/examples/Console/TestGrpcNetClient.cs
@@ -10,10 +10,12 @@
namespace Examples.Console;
-internal class TestGrpcNetClient
+internal sealed 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 27305a50523..5c72029378c 100644
--- a/examples/Console/TestHttpClient.cs
+++ b/examples/Console/TestHttpClient.cs
@@ -8,15 +8,17 @@
namespace Examples.Console;
-internal class TestHttpClient
+internal sealed class TestHttpClient
{
// To run this example, run the following command from
// the reporoot\examples\Console\.
// (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()
@@ -30,12 +32,12 @@ internal static object Run()
using (var parent = source.StartActivity("incoming request", ActivityKind.Server))
{
using var client = new HttpClient();
- client.GetStringAsync("http://bing.com").GetAwaiter().GetResult();
+ client.GetStringAsync(new Uri("http://bing.com", UriKind.Absolute)).GetAwaiter().GetResult();
}
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 53d3dd7f49e..d3b30db60ff 100644
--- a/examples/Console/TestInMemoryExporter.cs
+++ b/examples/Console/TestInMemoryExporter.cs
@@ -8,14 +8,14 @@
namespace Examples.Console;
-internal class TestInMemoryExporter
+internal sealed class TestInMemoryExporter
{
// To run this example, run the following command from
// the reporoot\examples\Console\.
// (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 4c88753ffd7..b38cc230217 100644
--- a/examples/Console/TestLogs.cs
+++ b/examples/Console/TestLogs.cs
@@ -7,9 +7,9 @@
namespace Examples.Console;
-internal class TestLogs
+internal sealed 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:
@@ -27,10 +28,10 @@ internal static object Run(LogsOptions options)
* launch the OpenTelemetry Collector with an OTLP receiver, by running:
*
* - On Unix based systems use:
- * docker run --rm -it -p 4317:4317 -p 4318:4318 -v $(pwd):/cfg otel/opentelemetry-collector:0.48.0 --config=/cfg/otlp-collector-example/config.yaml
+ * docker run --rm -it -p 4317:4317 -p 4318:4318 -v $(pwd):/cfg otel/opentelemetry-collector:0.123.0 --config=/cfg/otlp-collector-example/config.yaml
*
* - On Windows use:
- * docker run --rm -it -p 4317:4317 -p 4318:4318 -v "%cd%":/cfg otel/opentelemetry-collector:0.48.0 --config=/cfg/otlp-collector-example/config.yaml
+ * docker run --rm -it -p 4317:4317 -p 4318:4318 -v "%cd%":/cfg otel/opentelemetry-collector:0.123.0 --config=/cfg/otlp-collector-example/config.yaml
*
* Open another terminal window at the examples/Console/ directory and
* launch the OTLP example by running:
@@ -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) =>
@@ -96,13 +112,13 @@ internal static object Run(LogsOptions options)
});
});
- var logger = loggerFactory.CreateLogger();
- using (logger.BeginScope("{city}", "Seattle"))
- using (logger.BeginScope("{storeType}", "Physical"))
+ var logger = loggerFactory.CreateLogger();
+ using (logger.BeginCityScope("Seattle"))
+ using (logger.BeginStoreTypeScope("Physical"))
{
- logger.LogInformation("Hello from {name} {price}.", "tomato", 2.99);
+ logger.HelloFrom("tomato", 2.99);
}
- return null;
+ return 0;
}
}
diff --git a/examples/Console/TestLogsExtensions.cs b/examples/Console/TestLogsExtensions.cs
new file mode 100644
index 00000000000..f76eb03b3c8
--- /dev/null
+++ b/examples/Console/TestLogsExtensions.cs
@@ -0,0 +1,19 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using Microsoft.Extensions.Logging;
+
+namespace Examples.Console;
+
+internal static partial class TestLogsExtensions
+{
+ private static readonly Func CityScope = LoggerMessage.DefineScope("{City}");
+ private static readonly Func StoreTypeScope = LoggerMessage.DefineScope("{StoreType}");
+
+ public static IDisposable? BeginCityScope(this ILogger logger, string city) => CityScope(logger, city);
+
+ public static IDisposable? BeginStoreTypeScope(this ILogger logger, string storeType) => StoreTypeScope(logger, storeType);
+
+ [LoggerMessage(LogLevel.Information, "Hello from {Name} {Price}.")]
+ public static partial void HelloFrom(this ILogger logger, string name, double price);
+}
diff --git a/examples/Console/TestMetrics.cs b/examples/Console/TestMetrics.cs
index ba943e91775..308acee8d4c 100644
--- a/examples/Console/TestMetrics.cs
+++ b/examples/Console/TestMetrics.cs
@@ -10,12 +10,12 @@
namespace Examples.Console;
-internal class TestMetrics
+internal sealed 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:
@@ -37,10 +37,10 @@ internal static object Run(MetricsOptions options)
* launch the OpenTelemetry Collector with an OTLP receiver, by running:
*
* - On Unix based systems use:
- * docker run --rm -it -p 4317:4317 -v $(pwd):/cfg otel/opentelemetry-collector:0.33.0 --config=/cfg/otlp-collector-example/config.yaml
+ * docker run --rm -it -p 4317:4317 -v $(pwd):/cfg otel/opentelemetry-collector:0.123.0 --config=/cfg/otlp-collector-example/config.yaml
*
* - On Windows use:
- * docker run --rm -it -p 4317:4317 -v "%cd%":/cfg otel/opentelemetry-collector:0.33.0 --config=/cfg/otlp-collector-example/config.yaml
+ * docker run --rm -it -p 4317:4317 -v "%cd%":/cfg otel/opentelemetry-collector:0.123.0 --config=/cfg/otlp-collector-example/config.yaml
*
* Open another terminal window at the examples/Console/ directory and
* launch the OTLP example by running:
@@ -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");
@@ -97,9 +97,9 @@ internal static object Run(MetricsOptions options)
{
return new List>()
{
- new Measurement(
+ new(
(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 6557357a963..4dbb22ff9db 100644
--- a/examples/Console/TestOTelShimWithConsoleExporter.cs
+++ b/examples/Console/TestOTelShimWithConsoleExporter.cs
@@ -7,17 +7,17 @@
namespace Examples.Console;
-internal class TestOTelShimWithConsoleExporter
+internal sealed 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 0de2419b6ef..77ab8d6c7d0 100644
--- a/examples/Console/TestOpenTracingShim.cs
+++ b/examples/Console/TestOpenTracingShim.cs
@@ -10,17 +10,17 @@
namespace Examples.Console;
-internal class TestOpenTracingShim
+internal sealed 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 94d749eafef..c38ac518a18 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:
@@ -20,10 +20,10 @@ internal static object Run(string endpoint, string protocol)
* launch the OpenTelemetry Collector with an OTLP receiver, by running:
*
* - On Unix based systems use:
- * docker run --rm -it -p 4317:4317 -p 4318:4318 -v $(pwd):/cfg otel/opentelemetry-collector:latest --config=/cfg/otlp-collector-example/config.yaml
+ * docker run --rm -it -p 4317:4317 -p 4318:4318 -v $(pwd):/cfg otel/opentelemetry-collector:0.123.0 --config=/cfg/otlp-collector-example/config.yaml
*
* - On Windows use:
- * docker run --rm -it -p 4317:4317 -p 4318:4318 -v "%cd%":/cfg otel/opentelemetry-collector:latest --config=/cfg/otlp-collector-example/config.yaml
+ * docker run --rm -it -p 4317:4317 -p 4318:4318 -v "%cd%":/cfg otel/opentelemetry-collector:0.123.0 --config=/cfg/otlp-collector-example/config.yaml
*
* Open another terminal window at the examples/Console/ directory and
* launch the OTLP example by running:
@@ -36,57 +36,55 @@ 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.
- using (var sample = new InstrumentationWithActivitySource())
- {
- sample.Start();
+ using var sample = new InstrumentationWithActivitySource();
+ sample.Start();
- System.Console.WriteLine("Traces are being created and exported " +
- "to the OpenTelemetry Collector in the background. " +
- "Press ENTER to stop.");
- System.Console.ReadLine();
- }
+ System.Console.WriteLine("Traces are being created and exported " +
+ "to the OpenTelemetry Collector in the background. " +
+ "Press ENTER to stop.");
+ 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().ToUpperInvariant() switch
{
- "grpc" => OtlpExportProtocol.Grpc,
- "http/protobuf" => OtlpExportProtocol.HttpProtobuf,
+ "GRPC" => OtlpExportProtocol.Grpc,
+ "HTTP/PROTOBUF" => OtlpExportProtocol.HttpProtobuf,
_ => null,
};
}
diff --git a/examples/Console/TestPrometheusExporter.cs b/examples/Console/TestPrometheusExporter.cs
index 57f38c466df..3dc9ca0d89d 100644
--- a/examples/Console/TestPrometheusExporter.cs
+++ b/examples/Console/TestPrometheusExporter.cs
@@ -3,21 +3,20 @@
using System.Diagnostics;
using System.Diagnostics.Metrics;
+using System.Security.Cryptography;
using OpenTelemetry;
using OpenTelemetry.Metrics;
-using OpenTelemetry.Trace;
namespace Examples.Console;
-internal class TestPrometheusExporter
+internal sealed class TestPrometheusExporter
{
private static readonly Meter MyMeter = new("MyMeter");
private static readonly Meter MyMeter2 = new("MyMeter2");
private static readonly Counter Counter = MyMeter.CreateCounter("myCounter", description: "A counter for demonstration purpose.");
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 +34,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 = [$"http://localhost:{options.Port}/"])
.Build();
var process = Process.GetCurrentProcess();
@@ -57,12 +56,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(RandomNumberGenerator.GetInt32(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 +79,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 271826a7c2b..d7d579270f9 100644
--- a/examples/Console/TestZipkinExporter.cs
+++ b/examples/Console/TestZipkinExporter.cs
@@ -7,9 +7,9 @@
namespace Examples.Console;
-internal class TestZipkinExporter
+internal sealed 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,25 +23,24 @@ 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();
-
- using (var sample = new InstrumentationWithActivitySource())
- {
- sample.Start();
-
- System.Console.WriteLine("Traces are being created and exported " +
- "to Zipkin in the background. Use Zipkin to view them. " +
- "Press ENTER to stop.");
- System.Console.ReadLine();
- }
-
- return null;
+ .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();
+ sample.Start();
+
+ System.Console.WriteLine("Traces are being created and exported " +
+ "to Zipkin in the background. Use Zipkin to view them. " +
+ "Press ENTER to stop.");
+ System.Console.ReadLine();
+
+ return 0;
}
}
diff --git a/examples/Console/otlp-collector-example/config.yaml b/examples/Console/otlp-collector-example/config.yaml
index 8d0584b61fa..57e59398b7c 100644
--- a/examples/Console/otlp-collector-example/config.yaml
+++ b/examples/Console/otlp-collector-example/config.yaml
@@ -8,7 +8,9 @@ receivers:
otlp:
protocols:
grpc:
+ endpoint: 0.0.0.0:4317
http:
+ endpoint: 0.0.0.0:4318
exporters:
debug:
diff --git a/examples/Directory.Build.props b/examples/Directory.Build.props
index 032e1e27ec9..4c709d51681 100644
--- a/examples/Directory.Build.props
+++ b/examples/Directory.Build.props
@@ -1,3 +1,4 @@
+
diff --git a/examples/Directory.Build.targets b/examples/Directory.Build.targets
new file mode 100644
index 00000000000..a0db1462028
--- /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 902efc8cc04..00000000000
--- a/examples/Directory.Packages.props
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/examples/GrpcService/Program.cs b/examples/GrpcService/Program.cs
index 5ed8ceb4c34..5f80792c640 100644
--- a/examples/GrpcService/Program.cs
+++ b/examples/GrpcService/Program.cs
@@ -1,22 +1,58 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-namespace Examples.GrpcService;
+using Examples.GrpcService;
+using OpenTelemetry.Resources;
+using OpenTelemetry.Trace;
-public class Program
-{
- public static void Main(string[] args)
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+builder.Services.AddGrpc();
+
+builder.Services.AddOpenTelemetry()
+ .WithTracing(tracerBuilder =>
{
- CreateHostBuilder(args).Build().Run();
- }
-
- // Additional configuration is required to successfully run gRPC on macOS.
- // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup();
- webBuilder.UseUrls("https://localhost:44335");
- });
+ tracerBuilder.ConfigureResource(r => r.AddService(
+ builder.Configuration.GetValue("ServiceName", defaultValue: "otel-test")))
+ .AddAspNetCoreInstrumentation();
+
+ var exporter = builder.Configuration.GetValue("UseExporter", defaultValue: "console").ToUpperInvariant();
+ switch (exporter)
+ {
+ case "OTLP":
+ tracerBuilder.AddOtlpExporter(otlpOptions =>
+ {
+ otlpOptions.Endpoint = new Uri(builder.Configuration.GetValue("Otlp:Endpoint", defaultValue: "http://localhost:4317"));
+ });
+ break;
+ case "ZIPKIN":
+ tracerBuilder.AddZipkinExporter(zipkinOptions =>
+ {
+ zipkinOptions.Endpoint = new Uri(builder.Configuration.GetValue("Zipkin:Endpoint", defaultValue: "http://localhost:9411/api/v2/spans"));
+ });
+ break;
+ default:
+ tracerBuilder.AddConsoleExporter();
+ break;
+ }
+ });
+
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment())
+{
+ app.UseDeveloperExceptionPage();
}
+
+app.UseRouting();
+
+app.MapGrpcService();
+app.MapGet("/", () =>
+{
+ return Results.Text("Communication with gRPC endpoints must be made through a gRPC client. " +
+ "To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
+});
+
+app.Run();
diff --git a/examples/GrpcService/Services/GreeterService.cs b/examples/GrpcService/Services/GreeterService.cs
index 011439970fb..9963b7aeb35 100644
--- a/examples/GrpcService/Services/GreeterService.cs
+++ b/examples/GrpcService/Services/GreeterService.cs
@@ -5,15 +5,10 @@
namespace Examples.GrpcService;
-public class GreeterService : Greeter.GreeterBase
+#pragma warning disable CA1812 // Avoid uninstantiated internal classes
+internal sealed class GreeterService : Greeter.GreeterBase
+#pragma warning restore CA1812 // Avoid uninstantiated internal classes
{
- private readonly ILogger logger;
-
- public GreeterService(ILogger logger)
- {
- this.logger = logger;
- }
-
public override Task SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply
diff --git a/examples/GrpcService/Startup.cs b/examples/GrpcService/Startup.cs
deleted file mode 100644
index d23af73550f..00000000000
--- a/examples/GrpcService/Startup.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright The OpenTelemetry Authors
-// SPDX-License-Identifier: Apache-2.0
-
-using OpenTelemetry.Resources;
-using OpenTelemetry.Trace;
-
-namespace Examples.GrpcService;
-
-public class Startup
-{
- public Startup(IConfiguration configuration)
- {
- this.Configuration = configuration;
- }
-
- public IConfiguration Configuration { get; }
-
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddGrpc();
-
- services.AddOpenTelemetry()
- .WithTracing(builder =>
- {
- builder
- .ConfigureResource(r => r.AddService(this.Configuration.GetValue("ServiceName", defaultValue: "otel-test")!))
- .AddAspNetCoreInstrumentation();
-
- // Switch between Otlp/Zipkin/Console by setting UseExporter in appsettings.json.
- var exporter = this.Configuration.GetValue("UseExporter", defaultValue: "console")!.ToLowerInvariant();
- switch (exporter)
- {
- case "otlp":
- builder.AddOtlpExporter(otlpOptions =>
- {
- otlpOptions.Endpoint = new Uri(this.Configuration.GetValue("Otlp:Endpoint", defaultValue: "http://localhost:4317")!);
- });
- break;
- case "zipkin":
- builder.AddZipkinExporter(zipkinOptions =>
- {
- zipkinOptions.Endpoint = new Uri(this.Configuration.GetValue("Zipkin:Endpoint", defaultValue: "http://localhost:9411/api/v2/spans")!);
- });
- break;
- default:
- builder.AddConsoleExporter();
- break;
- }
- });
- }
-
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
-
- app.UseRouting();
-
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapGrpcService();
-
- endpoints.MapGet("/", async context =>
- {
- await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909").ConfigureAwait(false);
- });
- });
- }
-}
diff --git a/examples/MicroserviceExample/Utils/Messaging/MessageReceiver.cs b/examples/MicroserviceExample/Utils/Messaging/MessageReceiver.cs
index 09de208df21..e3137d987a4 100644
--- a/examples/MicroserviceExample/Utils/Messaging/MessageReceiver.cs
+++ b/examples/MicroserviceExample/Utils/Messaging/MessageReceiver.cs
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.Extensions.Logging;
using OpenTelemetry;
@@ -11,35 +12,39 @@
namespace Utils.Messaging;
-public class MessageReceiver : IDisposable
+public sealed class MessageReceiver : IDisposable
{
private static readonly ActivitySource ActivitySource = new(nameof(MessageReceiver));
private static readonly TextMapPropagator Propagator = Propagators.DefaultTextMapPropagator;
private readonly ILogger logger;
- private readonly IConnection connection;
- private readonly IModel channel;
+ private IConnection? connection;
+ private IChannel? channel;
public MessageReceiver(ILogger logger)
{
this.logger = logger;
- this.connection = RabbitMqHelper.CreateConnection();
- this.channel = RabbitMqHelper.CreateModelAndDeclareTestQueue(this.connection);
}
public void Dispose()
{
- this.channel.Dispose();
- this.connection.Dispose();
+ this.channel?.Dispose();
+ this.connection?.Dispose();
}
- public void StartConsumer()
+ public async Task StartConsumerAsync()
{
- RabbitMqHelper.StartConsumer(this.channel, this.ReceiveMessage);
+ this.connection = await RabbitMqHelper.CreateConnectionAsync().ConfigureAwait(false);
+ this.channel = await RabbitMqHelper.CreateModelAndDeclareTestQueueAsync(this.connection).ConfigureAwait(false);
+ await RabbitMqHelper.StartConsumerAsync(this.channel, this.ReceiveMessageAsync).ConfigureAwait(false);
}
- public void ReceiveMessage(BasicDeliverEventArgs ea)
+ public async Task ReceiveMessageAsync(BasicDeliverEventArgs ea)
{
+ this.EnsureStarted();
+
+ ArgumentNullException.ThrowIfNull(ea);
+
// Extract the PropagationContext of the upstream parent from the message headers.
var parentContext = Propagator.Extract(default, ea.BasicProperties, this.ExtractTraceContextFromBasicProperties);
Baggage.Current = parentContext.Baggage;
@@ -53,7 +58,7 @@ public void ReceiveMessage(BasicDeliverEventArgs ea)
{
var message = Encoding.UTF8.GetString(ea.Body.Span.ToArray());
- this.logger.LogInformation($"Message received: [{message}]");
+ this.logger.MessageReceived(message);
activity?.SetTag("message", message);
@@ -61,29 +66,38 @@ public void ReceiveMessage(BasicDeliverEventArgs ea)
RabbitMqHelper.AddMessagingTags(activity);
// Simulate some work
- Thread.Sleep(1000);
+ await Task.Delay(1_000).ConfigureAwait(false);
}
catch (Exception ex)
{
- this.logger.LogError(ex, "Message processing failed.");
+ this.logger.MessageProcessingFailed(ex);
}
}
- private IEnumerable ExtractTraceContextFromBasicProperties(IBasicProperties props, string key)
+ private IEnumerable ExtractTraceContextFromBasicProperties(IReadOnlyBasicProperties props, string key)
{
try
{
- if (props.Headers.TryGetValue(key, out var value))
+ if (props.Headers?.TryGetValue(key, out var value) is true)
{
- var bytes = value as byte[];
- return new[] { Encoding.UTF8.GetString(bytes) };
+ var bytes = (byte[])value!;
+ return [Encoding.UTF8.GetString(bytes)];
}
}
catch (Exception ex)
{
- this.logger.LogError(ex, "Failed to extract trace context.");
+ this.logger.FailedToExtractTraceContext(ex);
}
- return Enumerable.Empty();
+ return [];
+ }
+
+ [MemberNotNull(nameof(channel), nameof(connection))]
+ private void EnsureStarted()
+ {
+ if (this.channel == null || this.connection == null)
+ {
+ throw new InvalidOperationException("The message receiver has not been started.");
+ }
}
}
diff --git a/examples/MicroserviceExample/Utils/Messaging/MessageReceiverLog.cs b/examples/MicroserviceExample/Utils/Messaging/MessageReceiverLog.cs
new file mode 100644
index 00000000000..95a3e69a93a
--- /dev/null
+++ b/examples/MicroserviceExample/Utils/Messaging/MessageReceiverLog.cs
@@ -0,0 +1,18 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using Microsoft.Extensions.Logging;
+
+namespace Utils.Messaging;
+
+internal static partial class MessageReceiverLog
+{
+ [LoggerMessage(EventId = 1, Level = LogLevel.Information, Message = "Message received: [{Message}]")]
+ public static partial void MessageReceived(this ILogger logger, string message);
+
+ [LoggerMessage(EventId = 2, Level = LogLevel.Error, Message = "Message processing failed.")]
+ public static partial void MessageProcessingFailed(this ILogger logger, Exception exception);
+
+ [LoggerMessage(EventId = 3, Level = LogLevel.Error, Message = "Failed to extract trace context.")]
+ public static partial void FailedToExtractTraceContext(this ILogger logger, Exception exception);
+}
diff --git a/examples/MicroserviceExample/Utils/Messaging/MessageSender.cs b/examples/MicroserviceExample/Utils/Messaging/MessageSender.cs
index 969cf279cb4..e978cf01f3e 100644
--- a/examples/MicroserviceExample/Utils/Messaging/MessageSender.cs
+++ b/examples/MicroserviceExample/Utils/Messaging/MessageSender.cs
@@ -10,38 +10,42 @@
namespace Utils.Messaging;
-public class MessageSender : IDisposable
+public sealed class MessageSender : IDisposable
{
private static readonly ActivitySource ActivitySource = new(nameof(MessageSender));
private static readonly TextMapPropagator Propagator = Propagators.DefaultTextMapPropagator;
private readonly ILogger logger;
- private readonly IConnection connection;
- private readonly IModel channel;
+ private IConnection? connection;
+ private IChannel? channel;
public MessageSender(ILogger logger)
{
this.logger = logger;
- this.connection = RabbitMqHelper.CreateConnection();
- this.channel = RabbitMqHelper.CreateModelAndDeclareTestQueue(this.connection);
}
public void Dispose()
{
- this.channel.Dispose();
- this.connection.Dispose();
+ this.channel?.Dispose();
+ this.connection?.Dispose();
}
- public string SendMessage()
+ public async Task SendMessageAsync()
{
try
{
+ if (this.channel is null)
+ {
+ this.connection = await RabbitMqHelper.CreateConnectionAsync().ConfigureAwait(false);
+ this.channel = await RabbitMqHelper.CreateModelAndDeclareTestQueueAsync(this.connection).ConfigureAwait(false);
+ }
+
// Start an activity with a name following the semantic convention of the OpenTelemetry messaging specification.
// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/messaging/messaging-spans.md#span-name
var activityName = $"{RabbitMqHelper.TestQueueName} send";
using var activity = ActivitySource.StartActivity(activityName, ActivityKind.Producer);
- var props = this.channel.CreateBasicProperties();
+ var props = new BasicProperties();
// Depending on Sampling (and whether a listener is registered or not), the
// activity above may not be created.
@@ -65,19 +69,20 @@ public string SendMessage()
RabbitMqHelper.AddMessagingTags(activity);
var body = $"Published message: DateTime.Now = {DateTime.Now}.";
- this.channel.BasicPublish(
+ await this.channel.BasicPublishAsync(
exchange: RabbitMqHelper.DefaultExchangeName,
routingKey: RabbitMqHelper.TestQueueName,
+ mandatory: false,
basicProperties: props,
- body: Encoding.UTF8.GetBytes(body));
+ body: Encoding.UTF8.GetBytes(body)).ConfigureAwait(false);
- this.logger.LogInformation($"Message sent: [{body}]");
+ this.logger.MessageSent(body);
return body;
}
catch (Exception ex)
{
- this.logger.LogError(ex, "Message publishing failed.");
+ this.logger.MessagePublishingFailed(ex);
throw;
}
}
@@ -86,16 +91,13 @@ private void InjectTraceContextIntoBasicProperties(IBasicProperties props, strin
{
try
{
- if (props.Headers == null)
- {
- props.Headers = new Dictionary();
- }
+ props.Headers ??= new Dictionary();
props.Headers[key] = value;
}
catch (Exception ex)
{
- this.logger.LogError(ex, "Failed to inject trace context.");
+ this.logger.FailedToInjectTraceContext(ex);
}
}
}
diff --git a/examples/MicroserviceExample/Utils/Messaging/MessageSenderLog.cs b/examples/MicroserviceExample/Utils/Messaging/MessageSenderLog.cs
new file mode 100644
index 00000000000..f33eab31c37
--- /dev/null
+++ b/examples/MicroserviceExample/Utils/Messaging/MessageSenderLog.cs
@@ -0,0 +1,18 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using Microsoft.Extensions.Logging;
+
+namespace Utils.Messaging;
+
+internal static partial class MessageSenderLog
+{
+ [LoggerMessage(EventId = 1, Level = LogLevel.Information, Message = "Message sent: [{Body}]")]
+ public static partial void MessageSent(this ILogger logger, string body);
+
+ [LoggerMessage(EventId = 2, Level = LogLevel.Error, Message = "Message publishing failed.")]
+ public static partial void MessagePublishingFailed(this ILogger logger, Exception exception);
+
+ [LoggerMessage(EventId = 3, Level = LogLevel.Error, Message = "Failed to inject trace context.")]
+ public static partial void FailedToInjectTraceContext(this ILogger logger, Exception exception);
+}
diff --git a/examples/MicroserviceExample/Utils/Messaging/RabbitMqHelper.cs b/examples/MicroserviceExample/Utils/Messaging/RabbitMqHelper.cs
index 476bc26a853..a1a6569abbe 100644
--- a/examples/MicroserviceExample/Utils/Messaging/RabbitMqHelper.cs
+++ b/examples/MicroserviceExample/Utils/Messaging/RabbitMqHelper.cs
@@ -12,49 +12,44 @@ public static class RabbitMqHelper
public const string DefaultExchangeName = "";
public const string TestQueueName = "TestQueue";
- private static readonly ConnectionFactory ConnectionFactory;
-
- static RabbitMqHelper()
+ private static readonly ConnectionFactory ConnectionFactory = new()
{
- ConnectionFactory = new ConnectionFactory()
- {
- HostName = Environment.GetEnvironmentVariable("RABBITMQ_HOSTNAME") ?? "localhost",
- UserName = Environment.GetEnvironmentVariable("RABBITMQ_DEFAULT_USER") ?? "guest",
- Password = Environment.GetEnvironmentVariable("RABBITMQ_DEFAULT_PASS") ?? "guest",
- Port = 5672,
- RequestedConnectionTimeout = TimeSpan.FromMilliseconds(3000),
- };
- }
+ HostName = Environment.GetEnvironmentVariable("RABBITMQ_HOSTNAME") ?? "localhost",
+ UserName = Environment.GetEnvironmentVariable("RABBITMQ_DEFAULT_USER") ?? "guest",
+ Password = Environment.GetEnvironmentVariable("RABBITMQ_DEFAULT_PASS") ?? "guest",
+ Port = 5672,
+ RequestedConnectionTimeout = TimeSpan.FromMilliseconds(3000),
+ };
- public static IConnection CreateConnection()
- {
- return ConnectionFactory.CreateConnection();
- }
+ public static async Task CreateConnectionAsync() =>
+ await ConnectionFactory.CreateConnectionAsync().ConfigureAwait(false);
- public static IModel CreateModelAndDeclareTestQueue(IConnection connection)
+ public static async Task CreateModelAndDeclareTestQueueAsync(IConnection connection)
{
- var channel = connection.CreateModel();
+ ArgumentNullException.ThrowIfNull(connection);
+
+ var channel = await connection.CreateChannelAsync().ConfigureAwait(false);
- channel.QueueDeclare(
+ await channel.QueueDeclareAsync(
queue: TestQueueName,
durable: false,
exclusive: false,
autoDelete: false,
- arguments: null);
+ arguments: null).ConfigureAwait(false);
return channel;
}
- public static void StartConsumer(IModel channel, Action processMessage)
+ public static async Task StartConsumerAsync(IChannel channel, Func processMessage)
{
- var consumer = new EventingBasicConsumer(channel);
+ var consumer = new AsyncEventingBasicConsumer(channel);
- consumer.Received += (bc, ea) => processMessage(ea);
+ consumer.ReceivedAsync += async (bc, ea) => await processMessage(ea).ConfigureAwait(false);
- channel.BasicConsume(queue: TestQueueName, autoAck: true, consumer: consumer);
+ await channel.BasicConsumeAsync(queue: TestQueueName, autoAck: true, consumer: consumer).ConfigureAwait(false);
}
- 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 cc7382d4995..1c95380e4c9 100644
--- a/examples/MicroserviceExample/Utils/Utils.csproj
+++ b/examples/MicroserviceExample/Utils/Utils.csproj
@@ -1,9 +1,6 @@
- netstandard2.0
-
-
- disable
+ $(DefaultTargetFrameworkForExampleApps)
diff --git a/examples/MicroserviceExample/WebApi/Controllers/SendMessageController.cs b/examples/MicroserviceExample/WebApi/Controllers/SendMessageController.cs
index 6a8a5f9564a..e08009c5f8e 100644
--- a/examples/MicroserviceExample/WebApi/Controllers/SendMessageController.cs
+++ b/examples/MicroserviceExample/WebApi/Controllers/SendMessageController.cs
@@ -10,18 +10,14 @@ namespace WebApi.Controllers;
[Route("[controller]")]
public class SendMessageController : ControllerBase
{
- private readonly ILogger logger;
private readonly MessageSender messageSender;
- public SendMessageController(ILogger logger, MessageSender messageSender)
+ public SendMessageController(MessageSender messageSender)
{
- this.logger = logger;
this.messageSender = messageSender;
}
[HttpGet]
- public string Get()
- {
- return this.messageSender.SendMessage();
- }
+ public async Task Get() =>
+ await this.messageSender.SendMessageAsync().ConfigureAwait(false);
}
diff --git a/examples/MicroserviceExample/WebApi/Dockerfile b/examples/MicroserviceExample/WebApi/Dockerfile
index d74077a0a87..a11bc474dcf 100644
--- a/examples/MicroserviceExample/WebApi/Dockerfile
+++ b/examples/MicroserviceExample/WebApi/Dockerfile
@@ -1,12 +1,18 @@
-ARG SDK_VERSION=8.0
-FROM mcr.microsoft.com/dotnet/sdk:${SDK_VERSION} AS build
+ARG SDK_VERSION=9.0
+FROM mcr.microsoft.com/dotnet/sdk:8.0.414@sha256:3cef19377b2ef2a0171e930a24627677447c3e41b5f2eab84ff4895f1b15d254 AS dotnet-sdk-8.0
+FROM mcr.microsoft.com/dotnet/sdk:9.0.305@sha256:bb42ae2c058609d1746baf24fe6864ecab0686711dfca1f4b7a99e367ab17162 AS dotnet-sdk-9.0
+
+FROM dotnet-sdk-${SDK_VERSION} AS build
ARG PUBLISH_CONFIGURATION=Release
-ARG PUBLISH_FRAMEWORK=net8.0
+ARG PUBLISH_FRAMEWORK=net9.0
WORKDIR /app
COPY . ./
RUN dotnet publish ./examples/MicroserviceExample/WebApi -c "${PUBLISH_CONFIGURATION}" -f "${PUBLISH_FRAMEWORK}" -o /out -p:IntegrationBuild=true
-FROM mcr.microsoft.com/dotnet/aspnet:${SDK_VERSION} AS runtime
+FROM mcr.microsoft.com/dotnet/aspnet:8.0.20@sha256:e88f90b6d9fd7e9e0d8e231d068fccdbebd3c91892441a85ef35066aea9a4e1e AS dotnet-aspnet-8.0
+FROM mcr.microsoft.com/dotnet/aspnet:9.0.9@sha256:1af4114db9ba87542a3f23dbb5cd9072cad7fcc8505f6e9131d1feb580286a6f AS dotnet-aspnet-9.0
+
+FROM dotnet-aspnet-${SDK_VERSION} AS runtime
WORKDIR /app
COPY --from=build /out ./
ENTRYPOINT ["dotnet", "WebApi.dll"]
diff --git a/examples/MicroserviceExample/WebApi/Program.cs b/examples/MicroserviceExample/WebApi/Program.cs
index 9ed5a0b9c01..2dbc341f6d4 100644
--- a/examples/MicroserviceExample/WebApi/Program.cs
+++ b/examples/MicroserviceExample/WebApi/Program.cs
@@ -1,19 +1,36 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-namespace WebApi;
+using OpenTelemetry.Trace;
+using Utils.Messaging;
-public class Program
+var builder = WebApplication.CreateBuilder(args);
+
+builder.Services.AddControllers();
+
+builder.Services.AddSingleton();
+
+builder.Services.AddOpenTelemetry()
+ .WithTracing(b => b
+ .AddAspNetCoreInstrumentation()
+ .AddSource(nameof(MessageSender))
+ .AddZipkinExporter(o =>
+ {
+ var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost";
+ o.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans");
+ }));
+
+builder.WebHost.UseUrls("http://*:5000");
+
+var app = builder.Build();
+
+if (app.Environment.IsDevelopment())
{
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
-
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseUrls("http://*:5000").UseStartup();
- });
+ app.UseDeveloperExceptionPage();
}
+
+app.UseRouting();
+
+app.MapControllers();
+
+app.Run();
diff --git a/examples/MicroserviceExample/WebApi/Startup.cs b/examples/MicroserviceExample/WebApi/Startup.cs
deleted file mode 100644
index b77ea597c73..00000000000
--- a/examples/MicroserviceExample/WebApi/Startup.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright The OpenTelemetry Authors
-// SPDX-License-Identifier: Apache-2.0
-
-using OpenTelemetry.Trace;
-using Utils.Messaging;
-
-namespace WebApi;
-
-public class Startup
-{
- public Startup(IConfiguration configuration)
- {
- this.Configuration = configuration;
- }
-
- public IConfiguration Configuration { get; }
-
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddControllers();
-
- services.AddSingleton();
-
- services.AddOpenTelemetry()
- .WithTracing(builder => builder
- .AddAspNetCoreInstrumentation()
- .AddSource(nameof(MessageSender))
- .AddZipkinExporter(b =>
- {
- var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost";
- b.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans");
- }));
- }
-
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
-
- app.UseRouting();
-
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapControllers();
- });
- }
-}
diff --git a/examples/MicroserviceExample/WebApi/WebApi.csproj b/examples/MicroserviceExample/WebApi/WebApi.csproj
index 2d5846e580f..9c7ae7cf936 100644
--- a/examples/MicroserviceExample/WebApi/WebApi.csproj
+++ b/examples/MicroserviceExample/WebApi/WebApi.csproj
@@ -1,11 +1,11 @@
-
+
$(DefaultTargetFrameworkForExampleApps)
+ $(NoWarn);CA1515
-
diff --git a/examples/MicroserviceExample/WorkerService/Dockerfile b/examples/MicroserviceExample/WorkerService/Dockerfile
index dafc0049b46..07dde87f8b9 100644
--- a/examples/MicroserviceExample/WorkerService/Dockerfile
+++ b/examples/MicroserviceExample/WorkerService/Dockerfile
@@ -1,12 +1,19 @@
-ARG SDK_VERSION=8.0
-FROM mcr.microsoft.com/dotnet/sdk:${SDK_VERSION} AS build
+ARG SDK_VERSION=9.0
+
+FROM mcr.microsoft.com/dotnet/sdk:8.0.414@sha256:3cef19377b2ef2a0171e930a24627677447c3e41b5f2eab84ff4895f1b15d254 AS dotnet-sdk-8.0
+FROM mcr.microsoft.com/dotnet/sdk:9.0.305@sha256:bb42ae2c058609d1746baf24fe6864ecab0686711dfca1f4b7a99e367ab17162 AS dotnet-sdk-9.0
+
+FROM dotnet-sdk-${SDK_VERSION} AS build
ARG PUBLISH_CONFIGURATION=Release
-ARG PUBLISH_FRAMEWORK=net8.0
+ARG PUBLISH_FRAMEWORK=net9.0
WORKDIR /app
COPY . ./
RUN dotnet publish ./examples/MicroserviceExample/WorkerService -c "${PUBLISH_CONFIGURATION}" -f "${PUBLISH_FRAMEWORK}" -o /out -p:IntegrationBuild=true
-FROM mcr.microsoft.com/dotnet/aspnet:${SDK_VERSION} AS runtime
+FROM mcr.microsoft.com/dotnet/aspnet:8.0.20@sha256:e88f90b6d9fd7e9e0d8e231d068fccdbebd3c91892441a85ef35066aea9a4e1e AS dotnet-aspnet-8.0
+FROM mcr.microsoft.com/dotnet/aspnet:9.0.9@sha256:1af4114db9ba87542a3f23dbb5cd9072cad7fcc8505f6e9131d1feb580286a6f AS dotnet-aspnet-9.0
+
+FROM dotnet-aspnet-${SDK_VERSION} AS runtime
WORKDIR /app
COPY --from=build /out ./
ENTRYPOINT ["dotnet", "WorkerService.dll"]
diff --git a/examples/MicroserviceExample/WorkerService/Program.cs b/examples/MicroserviceExample/WorkerService/Program.cs
index 24e03322c12..118484d827b 100644
--- a/examples/MicroserviceExample/WorkerService/Program.cs
+++ b/examples/MicroserviceExample/WorkerService/Program.cs
@@ -3,31 +3,22 @@
using OpenTelemetry.Trace;
using Utils.Messaging;
+using WorkerService;
-namespace WorkerService;
+var builder = Host.CreateApplicationBuilder(args);
-public class Program
-{
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
+builder.Services.AddHostedService();
+builder.Services.AddSingleton();
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureServices((hostContext, services) =>
- {
- services.AddHostedService();
+builder.Services.AddOpenTelemetry()
+ .WithTracing(b => b
+ .AddSource(nameof(MessageReceiver))
+ .AddZipkinExporter(o =>
+ {
+ var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost";
+ o.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans");
+ }));
- services.AddSingleton();
+var app = builder.Build();
- services.AddOpenTelemetry()
- .WithTracing(builder => builder
- .AddSource(nameof(MessageReceiver))
- .AddZipkinExporter(b =>
- {
- var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost";
- b.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans");
- }));
- });
-}
+app.Run();
diff --git a/examples/MicroserviceExample/WorkerService/Worker.cs b/examples/MicroserviceExample/WorkerService/Worker.cs
index 9b3fa484d19..1292076399b 100644
--- a/examples/MicroserviceExample/WorkerService/Worker.cs
+++ b/examples/MicroserviceExample/WorkerService/Worker.cs
@@ -5,7 +5,7 @@
namespace WorkerService;
-public partial class Worker : BackgroundService
+internal sealed class Worker : BackgroundService
{
private readonly MessageReceiver messageReceiver;
@@ -14,22 +14,10 @@ public Worker(MessageReceiver messageReceiver)
this.messageReceiver = messageReceiver;
}
- public override Task StartAsync(CancellationToken cancellationToken)
- {
- return base.StartAsync(cancellationToken);
- }
-
- public override async Task StopAsync(CancellationToken cancellationToken)
- {
- await base.StopAsync(cancellationToken).ConfigureAwait(false);
- }
-
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
stoppingToken.ThrowIfCancellationRequested();
- this.messageReceiver.StartConsumer();
-
- await Task.CompletedTask.ConfigureAwait(false);
+ await this.messageReceiver.StartConsumerAsync().ConfigureAwait(false);
}
}
diff --git a/examples/MicroserviceExample/WorkerService/WorkerService.csproj b/examples/MicroserviceExample/WorkerService/WorkerService.csproj
index b9b1a680772..a1dc2dae9f4 100644
--- a/examples/MicroserviceExample/WorkerService/WorkerService.csproj
+++ b/examples/MicroserviceExample/WorkerService/WorkerService.csproj
@@ -1,15 +1,14 @@
$(DefaultTargetFrameworkForExampleApps)
+ $(NoWarn);CA1812
-
-
diff --git a/examples/MicroserviceExample/docker-compose.yml b/examples/MicroserviceExample/docker-compose.yml
index 35385fae591..ebbe2bbf345 100644
--- a/examples/MicroserviceExample/docker-compose.yml
+++ b/examples/MicroserviceExample/docker-compose.yml
@@ -1,13 +1,11 @@
-version: '3.8'
-
services:
zipkin:
- image: openzipkin/zipkin
+ image: openzipkin/zipkin:3.5.1@sha256:bb570eb45c2994eaf32da783cc098b3d51d1095b73ec92919863d73d0a9eaafb
ports:
- 9411:9411
rabbitmq:
- image: rabbitmq:3-management-alpine
+ image: rabbitmq:4-management-alpine@sha256:603089229e6060279f1b5db7fb5d844d1f259dd7a73fca8e3b15bb93713ad27c
ports:
- 5672:5672
- 15672:15672
diff --git a/global.json b/global.json
index 0aca8b12938..8c14264b61d 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
"rollForward": "latestFeature",
- "version": "8.0.100"
+ "version": "9.0.305"
}
}
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 93113cdc8e2..dfe83531769 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -1,3 +1,4 @@
+
diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets
index 3ee054532a9..6cef70da6c1 100644
--- a/src/Directory.Build.targets
+++ b/src/Directory.Build.targets
@@ -1,5 +1,7 @@
+
+
-
-
-
.
/// The supplied for chaining.
public static LoggerProviderBuilder AddInstrumentation<
-#if NET6_0_OR_GREATER
+#if NET
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(this LoggerProviderBuilder loggerProviderBuilder)
@@ -36,7 +36,7 @@ public static LoggerProviderBuilder AddInstrumentation<
loggerProviderBuilder.ConfigureBuilder((sp, builder) =>
{
- builder.AddInstrumentation(() => sp.GetRequiredService());
+ builder.AddInstrumentation(sp.GetRequiredService);
});
return loggerProviderBuilder;
diff --git a/src/OpenTelemetry.Api.ProviderBuilderExtensions/Metrics/OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Api.ProviderBuilderExtensions/Metrics/OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.cs
index 457ddc87663..ff52ee37cb3 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)
@@ -36,7 +36,7 @@ public static MeterProviderBuilder AddInstrumentation<
meterProviderBuilder.ConfigureBuilder((sp, builder) =>
{
- builder.AddInstrumentation(() => sp.GetRequiredService());
+ builder.AddInstrumentation(sp.GetRequiredService);
});
return meterProviderBuilder;
diff --git a/src/OpenTelemetry.Api.ProviderBuilderExtensions/OpenTelemetry.Api.ProviderBuilderExtensions.csproj b/src/OpenTelemetry.Api.ProviderBuilderExtensions/OpenTelemetry.Api.ProviderBuilderExtensions.csproj
index d057d595f43..8c28b1e5c44 100644
--- a/src/OpenTelemetry.Api.ProviderBuilderExtensions/OpenTelemetry.Api.ProviderBuilderExtensions.csproj
+++ b/src/OpenTelemetry.Api.ProviderBuilderExtensions/OpenTelemetry.Api.ProviderBuilderExtensions.csproj
@@ -5,7 +5,6 @@
Contains extensions to register OpenTelemetry in applications using Microsoft.Extensions.DependencyInjection
OpenTelemetry
core-
- latest-all
@@ -16,4 +15,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/OpenTelemetry.Api.ProviderBuilderExtensions/Trace/OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Api.ProviderBuilderExtensions/Trace/OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.cs
index 35088b2a5ef..939fd34b366 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)
@@ -36,7 +36,7 @@ public static TracerProviderBuilder AddInstrumentation<
tracerProviderBuilder.ConfigureBuilder((sp, builder) =>
{
- builder.AddInstrumentation(() => sp.GetRequiredService());
+ builder.AddInstrumentation(sp.GetRequiredService);
});
return tracerProviderBuilder;
diff --git a/src/OpenTelemetry.Api/.publicApi/Experimental/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Api/.publicApi/Experimental/PublicAPI.Unshipped.txt
index 4cb12fd2969..e4f616a9dca 100644
--- a/src/OpenTelemetry.Api/.publicApi/Experimental/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry.Api/.publicApi/Experimental/PublicAPI.Unshipped.txt
@@ -1,73 +1,75 @@
-abstract OpenTelemetry.Logs.Logger.EmitLog(in OpenTelemetry.Logs.LogRecordData data, in OpenTelemetry.Logs.LogRecordAttributeList attributes) -> void
-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.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.LogRecordAttributeList
-OpenTelemetry.Logs.LogRecordAttributeList.Add(string! key, object? value) -> void
-OpenTelemetry.Logs.LogRecordAttributeList.Add(System.Collections.Generic.KeyValuePair attribute) -> void
-OpenTelemetry.Logs.LogRecordAttributeList.Clear() -> void
-OpenTelemetry.Logs.LogRecordAttributeList.Count.get -> int
-OpenTelemetry.Logs.LogRecordAttributeList.Enumerator
-OpenTelemetry.Logs.LogRecordAttributeList.Enumerator.Current.get -> System.Collections.Generic.KeyValuePair
-OpenTelemetry.Logs.LogRecordAttributeList.Enumerator.Dispose() -> void
-OpenTelemetry.Logs.LogRecordAttributeList.Enumerator.Enumerator() -> void
-OpenTelemetry.Logs.LogRecordAttributeList.Enumerator.MoveNext() -> bool
-OpenTelemetry.Logs.LogRecordAttributeList.GetEnumerator() -> OpenTelemetry.Logs.LogRecordAttributeList.Enumerator
-OpenTelemetry.Logs.LogRecordAttributeList.LogRecordAttributeList() -> void
-OpenTelemetry.Logs.LogRecordAttributeList.RecordException(System.Exception! exception) -> void
-OpenTelemetry.Logs.LogRecordAttributeList.this[int index].get -> System.Collections.Generic.KeyValuePair
-OpenTelemetry.Logs.LogRecordAttributeList.this[int index].set -> void
-OpenTelemetry.Logs.LogRecordAttributeList.this[string! key].set -> void
-OpenTelemetry.Logs.LogRecordData
-OpenTelemetry.Logs.LogRecordData.Body.get -> string?
-OpenTelemetry.Logs.LogRecordData.Body.set -> void
-OpenTelemetry.Logs.LogRecordData.LogRecordData() -> void
-OpenTelemetry.Logs.LogRecordData.LogRecordData(in System.Diagnostics.ActivityContext activityContext) -> void
-OpenTelemetry.Logs.LogRecordData.LogRecordData(System.Diagnostics.Activity? activity) -> void
-OpenTelemetry.Logs.LogRecordData.Severity.get -> OpenTelemetry.Logs.LogRecordSeverity?
-OpenTelemetry.Logs.LogRecordData.Severity.set -> void
-OpenTelemetry.Logs.LogRecordData.SeverityText.get -> string?
-OpenTelemetry.Logs.LogRecordData.SeverityText.set -> void
-OpenTelemetry.Logs.LogRecordData.SpanId.get -> System.Diagnostics.ActivitySpanId
-OpenTelemetry.Logs.LogRecordData.SpanId.set -> void
-OpenTelemetry.Logs.LogRecordData.Timestamp.get -> System.DateTime
-OpenTelemetry.Logs.LogRecordData.Timestamp.set -> void
-OpenTelemetry.Logs.LogRecordData.TraceFlags.get -> System.Diagnostics.ActivityTraceFlags
-OpenTelemetry.Logs.LogRecordData.TraceFlags.set -> void
-OpenTelemetry.Logs.LogRecordData.TraceId.get -> System.Diagnostics.ActivityTraceId
-OpenTelemetry.Logs.LogRecordData.TraceId.set -> void
-OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Debug = 5 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Debug2 = 6 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Debug3 = 7 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Debug4 = 8 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Error = 17 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Error2 = 18 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Error3 = 19 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Error4 = 20 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Fatal = 21 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Fatal2 = 22 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Fatal3 = 23 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Fatal4 = 24 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Info = 9 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Info2 = 10 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Info3 = 11 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Info4 = 12 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Trace = 1 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Trace2 = 2 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Trace3 = 3 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Trace4 = 4 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Unspecified = 0 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Warn = 13 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Warn2 = 14 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Warn3 = 15 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverity.Warn4 = 16 -> OpenTelemetry.Logs.LogRecordSeverity
-OpenTelemetry.Logs.LogRecordSeverityExtensions
-static OpenTelemetry.Logs.LogRecordAttributeList.CreateFromEnumerable(System.Collections.Generic.IEnumerable>! attributes) -> OpenTelemetry.Logs.LogRecordAttributeList
-static OpenTelemetry.Logs.LogRecordSeverityExtensions.ToShortName(this OpenTelemetry.Logs.LogRecordSeverity logRecordSeverity) -> string!
-virtual OpenTelemetry.Logs.LoggerProvider.TryCreateLogger(string? name, out OpenTelemetry.Logs.Logger? logger) -> bool
+[OTEL1001]abstract OpenTelemetry.Logs.Logger.EmitLog(in OpenTelemetry.Logs.LogRecordData data, in OpenTelemetry.Logs.LogRecordAttributeList attributes) -> void
+[OTEL1001]OpenTelemetry.Logs.Logger
+[OTEL1001]OpenTelemetry.Logs.Logger.EmitLog(in OpenTelemetry.Logs.LogRecordData data) -> void
+[OTEL1001]OpenTelemetry.Logs.Logger.Logger(string? name) -> void
+[OTEL1001]OpenTelemetry.Logs.Logger.Name.get -> string!
+[OTEL1001]OpenTelemetry.Logs.Logger.Version.get -> string?
+[OTEL1001]OpenTelemetry.Logs.LoggerProvider.GetLogger() -> OpenTelemetry.Logs.Logger!
+[OTEL1001]OpenTelemetry.Logs.LoggerProvider.GetLogger(string? name) -> OpenTelemetry.Logs.Logger!
+[OTEL1001]OpenTelemetry.Logs.LoggerProvider.GetLogger(string? name, string? version) -> OpenTelemetry.Logs.Logger!
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.Add(string! key, object? value) -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.Add(System.Collections.Generic.KeyValuePair attribute) -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.Clear() -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.Count.get -> int
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.Enumerator
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.Enumerator.Current.get -> System.Collections.Generic.KeyValuePair
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.Enumerator.Dispose() -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.Enumerator.Enumerator() -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.Enumerator.MoveNext() -> bool
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.GetEnumerator() -> OpenTelemetry.Logs.LogRecordAttributeList.Enumerator
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.LogRecordAttributeList() -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.RecordException(System.Exception! exception) -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.this[int index].get -> System.Collections.Generic.KeyValuePair
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.this[int index].set -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordAttributeList.this[string! key].set -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordData
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.Body.get -> string?
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.Body.set -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.LogRecordData() -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.LogRecordData(in System.Diagnostics.ActivityContext activityContext) -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.LogRecordData(System.Diagnostics.Activity? activity) -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.Severity.get -> OpenTelemetry.Logs.LogRecordSeverity?
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.Severity.set -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.SeverityText.get -> string?
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.SeverityText.set -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.SpanId.get -> System.Diagnostics.ActivitySpanId
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.SpanId.set -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.Timestamp.get -> System.DateTime
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.Timestamp.set -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.TraceFlags.get -> System.Diagnostics.ActivityTraceFlags
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.TraceFlags.set -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.TraceId.get -> System.Diagnostics.ActivityTraceId
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.TraceId.set -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.EventName.get -> string?
+[OTEL1001]OpenTelemetry.Logs.LogRecordData.EventName.set -> void
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Debug = 5 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Debug2 = 6 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Debug3 = 7 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Debug4 = 8 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Error = 17 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Error2 = 18 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Error3 = 19 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Error4 = 20 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Fatal = 21 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Fatal2 = 22 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Fatal3 = 23 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Fatal4 = 24 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Info = 9 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Info2 = 10 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Info3 = 11 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Info4 = 12 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Trace = 1 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Trace2 = 2 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Trace3 = 3 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Trace4 = 4 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Unspecified = 0 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Warn = 13 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Warn2 = 14 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Warn3 = 15 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverity.Warn4 = 16 -> OpenTelemetry.Logs.LogRecordSeverity
+[OTEL1001]OpenTelemetry.Logs.LogRecordSeverityExtensions
+[OTEL1001]static OpenTelemetry.Logs.LogRecordAttributeList.CreateFromEnumerable(System.Collections.Generic.IEnumerable>! attributes) -> OpenTelemetry.Logs.LogRecordAttributeList
+[OTEL1001]static OpenTelemetry.Logs.LogRecordSeverityExtensions.ToShortName(this OpenTelemetry.Logs.LogRecordSeverity logRecordSeverity) -> string!
+[OTEL1001]virtual OpenTelemetry.Logs.LoggerProvider.TryCreateLogger(string? name, out OpenTelemetry.Logs.Logger? logger) -> bool
diff --git a/src/OpenTelemetry.Api/.publicApi/Stable/PublicAPI.Shipped.txt b/src/OpenTelemetry.Api/.publicApi/Stable/PublicAPI.Shipped.txt
index 7b02ca885de..a0742cbc241 100644
--- a/src/OpenTelemetry.Api/.publicApi/Stable/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Api/.publicApi/Stable/PublicAPI.Shipped.txt
@@ -1,56 +1,8 @@
#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
+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!
@@ -64,18 +16,31 @@ 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.BaggagePropagator
OpenTelemetry.Context.Propagation.BaggagePropagator.BaggagePropagator() -> void
OpenTelemetry.Context.Propagation.CompositeTextMapPropagator
+OpenTelemetry.Context.Propagation.CompositeTextMapPropagator.CompositeTextMapPropagator(System.Collections.Generic.IEnumerable! propagators) -> void
OpenTelemetry.Context.Propagation.PropagationContext
OpenTelemetry.Context.Propagation.PropagationContext.ActivityContext.get -> System.Diagnostics.ActivityContext
OpenTelemetry.Context.Propagation.PropagationContext.Baggage.get -> OpenTelemetry.Baggage
@@ -90,7 +55,12 @@ 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
@@ -156,6 +126,8 @@ OpenTelemetry.Trace.TelemetrySpan.AddEvent(string! name, OpenTelemetry.Trace.Spa
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.AddLink(OpenTelemetry.Trace.SpanContext spanContext, OpenTelemetry.Trace.SpanAttributes? attributes) -> OpenTelemetry.Trace.TelemetrySpan!
+OpenTelemetry.Trace.TelemetrySpan.AddLink(OpenTelemetry.Trace.SpanContext spanContext) -> OpenTelemetry.Trace.TelemetrySpan!
OpenTelemetry.Trace.TelemetrySpan.Context.get -> OpenTelemetry.Trace.SpanContext
OpenTelemetry.Trace.TelemetrySpan.Dispose() -> void
OpenTelemetry.Trace.TelemetrySpan.End() -> void
@@ -181,16 +153,31 @@ OpenTelemetry.Trace.Tracer.StartRootSpan(string! name, OpenTelemetry.Trace.SpanK
OpenTelemetry.Trace.Tracer.StartSpan(string! name, OpenTelemetry.Trace.SpanKind kind = OpenTelemetry.Trace.SpanKind.Internal, in OpenTelemetry.Trace.SpanContext parentContext = default(OpenTelemetry.Trace.SpanContext), OpenTelemetry.Trace.SpanAttributes? initialAttributes = null, System.Collections.Generic.IEnumerable? links = null, System.DateTimeOffset startTime = default(System.DateTimeOffset)) -> OpenTelemetry.Trace.TelemetrySpan!
OpenTelemetry.Trace.Tracer.StartSpan(string! name, OpenTelemetry.Trace.SpanKind kind, in OpenTelemetry.Trace.TelemetrySpan? parentSpan, OpenTelemetry.Trace.SpanAttributes? initialAttributes = null, System.Collections.Generic.IEnumerable? links = null, System.DateTimeOffset startTime = default(System.DateTimeOffset)) -> OpenTelemetry.Trace.TelemetrySpan!
OpenTelemetry.Trace.TracerProvider
-OpenTelemetry.Trace.TracerProvider.GetTracer(string! name, string? version = null) -> OpenTelemetry.Trace.Tracer!
+OpenTelemetry.Trace.TracerProvider.GetTracer(string! name, string? version = null, System.Collections.Generic.IEnumerable>? tags = null) -> OpenTelemetry.Trace.Tracer!
+OpenTelemetry.Trace.TracerProvider.GetTracer(string! name, string? version) -> OpenTelemetry.Trace.Tracer!
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.Equals(object? obj) -> bool
override OpenTelemetry.Context.Propagation.PropagationContext.GetHashCode() -> int
+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
@@ -202,16 +189,32 @@ 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, 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.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
+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 58383768cd8..378097ec65c 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 f50a9af8fee..fb630ae6613 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/AssemblyInfo.cs b/src/OpenTelemetry.Api/AssemblyInfo.cs
deleted file mode 100644
index b1e95ff67e6..00000000000
--- a/src/OpenTelemetry.Api/AssemblyInfo.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright The OpenTelemetry Authors
-// SPDX-License-Identifier: Apache-2.0
-
-using System.Runtime.CompilerServices;
-
-[assembly: InternalsVisibleTo("OpenTelemetry" + AssemblyInfo.PublicKey)]
-[assembly: InternalsVisibleTo("OpenTelemetry.Api.ProviderBuilderExtensions" + AssemblyInfo.PublicKey)]
-[assembly: InternalsVisibleTo("OpenTelemetry.Api.ProviderBuilderExtensions.Tests" + AssemblyInfo.PublicKey)]
-[assembly: InternalsVisibleTo("OpenTelemetry.Api.Tests" + AssemblyInfo.PublicKey)]
-[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Console" + AssemblyInfo.PublicKey)]
-[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.InMemory" + AssemblyInfo.PublicKey)]
-[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.OpenTelemetryProtocol" + AssemblyInfo.PublicKey)]
-[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests" + AssemblyInfo.PublicKey)]
-[assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Hosting" + AssemblyInfo.PublicKey)]
-[assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Hosting.Tests" + AssemblyInfo.PublicKey)]
-[assembly: InternalsVisibleTo("OpenTelemetry.Shims.OpenTracing.Tests" + AssemblyInfo.PublicKey)]
-[assembly: InternalsVisibleTo("OpenTelemetry.Tests" + AssemblyInfo.PublicKey)]
-
-#if SIGNED
-file static class AssemblyInfo
-{
- public const string PublicKey = ", PublicKey=002400000480000094000000060200000024000052534131000400000100010051C1562A090FB0C9F391012A32198B5E5D9A60E9B80FA2D7B434C9E5CCB7259BD606E66F9660676AFC6692B8CDC6793D190904551D2103B7B22FA636DCBB8208839785BA402EA08FC00C8F1500CCEF28BBF599AA64FFB1E1D5DC1BF3420A3777BADFE697856E9D52070A50C3EA5821C80BEF17CA3ACFFA28F89DD413F096F898";
-}
-#else
-file static class AssemblyInfo
-{
- public const string PublicKey = "";
-}
-#endif
diff --git a/src/OpenTelemetry.Api/Baggage.cs b/src/OpenTelemetry.Api/Baggage.cs
index 46cdedbd7d1..d69e0170ca4 100644
--- a/src/OpenTelemetry.Api/Baggage.cs
+++ b/src/OpenTelemetry.Api/Baggage.cs
@@ -16,7 +16,7 @@ namespace OpenTelemetry;
public readonly struct Baggage : IEquatable
{
private static readonly RuntimeContextSlot RuntimeContextSlot = RuntimeContext.RegisterSlot("otel.baggage");
- private static readonly Dictionary EmptyBaggage = new();
+ private static readonly Dictionary EmptyBaggage = [];
private readonly Dictionary baggage;
@@ -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!;
}
}
@@ -305,7 +305,9 @@ public Baggage RemoveBaggage(string name)
/// Returns a new with all the key/value pairs removed.
///
/// New with all the key/value pairs removed.
+#pragma warning disable CA1822 // Mark members as static
public Baggage ClearBaggage()
+#pragma warning restore CA1822 // Mark members as static
=> default;
///
@@ -325,11 +327,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);
///
@@ -343,7 +345,11 @@ public override int GetHashCode()
unchecked
{
hash = (hash * 23) + baggage.Comparer.GetHashCode(item.Key);
+#if NET
+ hash = (hash * 23) + item.Value.GetHashCode(StringComparison.Ordinal);
+#else
hash = (hash * 23) + item.Value.GetHashCode();
+#endif
}
}
diff --git a/src/OpenTelemetry.Api/BaseProvider.cs b/src/OpenTelemetry.Api/BaseProvider.cs
index ce8e30a46b7..117f18c3c6d 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 f39d81b108e..961b11de5b0 100644
--- a/src/OpenTelemetry.Api/CHANGELOG.md
+++ b/src/OpenTelemetry.Api/CHANGELOG.md
@@ -1,7 +1,97 @@
# 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.13.0
+
+Released 2025-Oct-01
+
+* Added `AddLink(SpanContext, SpanAttributes?)` to `TelemetrySpan` to support
+ linking spans and associating optional attributes for advanced trace relationships.
+ ([#6305](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6305))
+
+* Experimental (only in pre-release versions): Added the `EventName` property
+ to `LogRecordData`
+ ([#6306](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6306))
+
+## 1.12.0
+
+Released 2025-Apr-29
+
+* Added a new overload for `TracerProvider.GetTracer` which accepts an optional
+ `IEnumerable>? tags` parameter, allowing
+ additional attributes to be associated with the `Tracer`.
+ ([#6137](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6137))
+
+## 1.11.2
+
+Released 2025-Mar-04
+
+* Revert optimize performance of `TraceContextPropagator.Extract` introduced
+ in #5749 to resolve [GHSA-8785-wc3w-h8q6](https://github.com/open-telemetry/opentelemetry-dotnet/security/advisories/GHSA-8785-wc3w-h8q6).
+ ([#6161](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6161))
+
+## 1.11.1
+
+Released 2025-Jan-22
+
+## 1.11.0
+
+Released 2025-Jan-15
+
+## 1.11.0-rc.1
+
+Released 2024-Dec-11
+
+## 1.10.0
+
+Released 2024-Nov-12
+
+* Updated `System.Diagnostics.DiagnosticSource` package version to
+ `9.0.0`.
+ ([#5967](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5967))
+
+## 1.10.0-rc.1
+
+Released 2024-Nov-01
+
+## 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
@@ -15,8 +105,8 @@ Released 2024-Jun-14
Released 2024-Jun-07
* The experimental APIs previously covered by `OTEL1000` (`LoggerProvider`,
- `LoggerProviderBuilder`, & `IDeferredLoggerProviderBuilder`) will now be part
- of the public API and supported in stable builds.
+ `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
diff --git a/src/OpenTelemetry.Api/Context/AsyncLocalRuntimeContextSlot.cs b/src/OpenTelemetry.Api/Context/AsyncLocalRuntimeContextSlot.cs
index 15eb31d08c2..7bafc0e951d 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 1e16ea42601..19c02050cd8 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 10b4aee1d81..56c353f4a28 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/B3Propagator.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/B3Propagator.cs
@@ -27,6 +27,7 @@ public sealed class B3Propagator : TextMapPropagator
internal const string UpperTraceId = "0000000000000000";
// Sampled values via the X_B3_SAMPLED header.
+ internal const char SampledValueChar = '1';
internal const string SampledValue = "1";
// Some old zipkin implementations may send true/false for the sampled header. Only use this for checking incoming values.
@@ -35,7 +36,7 @@ public sealed class B3Propagator : TextMapPropagator
// "Debug" sampled value.
internal const string FlagsValue = "1";
- private static readonly HashSet AllFields = new() { XB3TraceId, XB3SpanId, XB3ParentSpanId, XB3Sampled, XB3Flags };
+ private static readonly HashSet AllFields = [XB3TraceId, XB3SpanId, XB3ParentSpanId, XB3Sampled, XB3Flags];
private static readonly HashSet SampledValues = new(StringComparer.Ordinal) { SampledValue, LegacySampledValue };
@@ -66,7 +67,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())
@@ -130,7 +131,7 @@ public override void Inject(PropagationContext context, T carrier, Action(PropagationContext context, T carrier, Action(PropagationContext context, T carrier, Func> getter)
+ private static PropagationContext ExtractFromMultipleHeaders(PropagationContext context, T carrier, Func?> getter)
{
try
{
@@ -179,7 +180,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 +198,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 +208,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 57bdb453b8f..3a0dca61219 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/BaggagePropagator.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/BaggagePropagator.cs
@@ -1,6 +1,9 @@
// 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;
@@ -17,14 +20,14 @@ public class BaggagePropagator : TextMapPropagator
private const int MaxBaggageLength = 8192;
private const int MaxBaggageItems = 180;
- private static readonly char[] EqualSignSeparator = new[] { '=' };
- private static readonly char[] CommaSignSeparator = new[] { ',' };
+ private static readonly char[] EqualSignSeparator = ['='];
+ private static readonly char[] CommaSignSeparator = [','];
///
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)
{
@@ -46,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], 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)
{
@@ -102,11 +105,16 @@ public override void Inject(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)
{
@@ -130,7 +138,11 @@ internal static bool TryExtractBaggage(string[] baggageCollection, out Dictionar
break;
}
+#if NET
+ if (pair.IndexOf('=', StringComparison.Ordinal) < 0)
+#else
if (pair.IndexOf('=') < 0)
+#endif
{
continue;
}
@@ -149,10 +161,7 @@ internal static bool TryExtractBaggage(string[] baggageCollection, out Dictionar
continue;
}
- if (baggageDictionary == null)
- {
- baggageDictionary = new Dictionary();
- }
+ baggageDictionary ??= [];
baggageDictionary[key] = value;
}
diff --git a/src/OpenTelemetry.Api/Context/Propagation/CompositeTextMapPropagator.cs b/src/OpenTelemetry.Api/Context/Propagation/CompositeTextMapPropagator.cs
index a6b12c3cd1b..d0375aadc71 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 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 03dd45785d4..0721ad52883 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/NoopTextMapPropagator.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/NoopTextMapPropagator.cs
@@ -5,11 +5,13 @@ namespace OpenTelemetry.Context.Propagation;
internal sealed class NoopTextMapPropagator : TextMapPropagator
{
+#pragma warning disable CA1805 // Do not initialize unnecessarily
private static readonly PropagationContext DefaultPropagationContext = default;
+#pragma warning restore CA1805 // Do not initialize unnecessarily
- 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 77b6c71e77a..0923ed45d6d 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 1000b317bf5..bb0432378b5 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 de711295428..a00f8e8beb1 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/TraceContextPropagator.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/TraceContextPropagator.cs
@@ -16,6 +16,12 @@ public class TraceContextPropagator : TextMapPropagator
private const string TraceParent = "traceparent";
private const string TraceState = "tracestate";
+ // The following length limits are from Trace Context v1 https://www.w3.org/TR/trace-context-1/#key
+ private const int TraceStateKeyMaxLength = 256;
+ private const int TraceStateKeyTenantMaxLength = 241;
+ private const int TraceStateKeyVendorMaxLength = 14;
+ private const int TraceStateValueMaxLength = 256;
+
private static readonly int VersionPrefixIdLength = "00-".Length;
private static readonly int TraceIdLength = "0af7651916cd43dd8448eb211c80319c".Length;
private static readonly int VersionAndTraceIdLength = "00-0af7651916cd43dd8448eb211c80319c-".Length;
@@ -24,17 +30,11 @@ public class TraceContextPropagator : TextMapPropagator
private static readonly int OptionsLength = "00".Length;
private static readonly int TraceparentLengthV0 = "00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-00".Length;
- // The following length limits are from Trace Context v1 https://www.w3.org/TR/trace-context-1/#key
- private static readonly int TraceStateKeyMaxLength = 256;
- private static readonly int TraceStateKeyTenantMaxLength = 241;
- private static readonly int TraceStateKeyVendorMaxLength = 14;
- private static readonly int TraceStateValueMaxLength = 256;
-
///
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);
@@ -173,7 +173,7 @@ internal static bool TryExtractTraceparent(string traceparent, out ActivityTrace
try
{
- traceId = ActivityTraceId.CreateFromString(traceparent.AsSpan().Slice(VersionPrefixIdLength, TraceIdLength));
+ traceId = ActivityTraceId.CreateFromString(traceparent.AsSpan(VersionPrefixIdLength, TraceIdLength));
}
catch (ArgumentOutOfRangeException)
{
@@ -189,7 +189,7 @@ internal static bool TryExtractTraceparent(string traceparent, out ActivityTrace
byte optionsLowByte;
try
{
- spanId = ActivitySpanId.CreateFromString(traceparent.AsSpan().Slice(VersionAndTraceIdLength, SpanIdLength));
+ spanId = ActivitySpanId.CreateFromString(traceparent.AsSpan(VersionAndTraceIdLength, SpanIdLength));
_ = HexCharToByte(traceparent[VersionAndTraceIdAndSpanIdLength]); // to verify if there is no bad chars on options position
optionsLowByte = HexCharToByte(traceparent[VersionAndTraceIdAndSpanIdLength + 1]);
}
@@ -297,7 +297,11 @@ internal static bool TryExtractTracestate(string[] tracestateCollection, out str
result.Append(',');
}
+#if NET
+ result.Append(listMember);
+#else
result.Append(listMember.ToString());
+#endif
}
}
@@ -430,7 +434,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/TraceStateUtils.cs
similarity index 94%
rename from src/OpenTelemetry.Api/Context/Propagation/TraceStateUtilsNew.cs
rename to src/OpenTelemetry.Api/Context/Propagation/TraceStateUtils.cs
index 717e1a94584..d81291b5052 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/TraceStateUtilsNew.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/TraceStateUtils.cs
@@ -10,7 +10,7 @@ namespace OpenTelemetry.Context.Propagation;
///
/// Extension methods to extract TraceState from string.
///
-internal static class TraceStateUtilsNew
+internal static class TraceStateUtils
{
private const int KeyMaxSize = 256;
private const int ValueMaxSize = 256;
@@ -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)
{
+#pragma warning disable CA1851 // Possible multiple enumerations of 'IEnumerable' collection
if (traceState == null || !traceState.Any())
{
return string.Empty;
@@ -125,6 +126,7 @@ internal static string GetString(IEnumerable> trace
.Append(',');
}
}
+#pragma warning restore CA1851 // Possible multiple enumerations of 'IEnumerable' collection
return sb.Remove(sb.Length - 1, 1).ToString();
}
@@ -153,7 +155,7 @@ private static bool TryParseKeyValue(ReadOnlySpan pair, out ReadOnlySpan
- 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 93c96299d2f..c984147bf49 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 918e4b79424..7502070ffc0 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,13 +31,17 @@ protected RuntimeContextSlot(string name)
/// Get the value from the context slot.
///
/// The value retrieved from the context slot.
- public abstract T Get();
+#pragma warning disable CA1716 // Identifiers should not match keywords
+ public abstract T? Get();
+#pragma warning restore CA1716 // Identifiers should not match keywords
///
/// Set the value to the context slot.
///
/// The value to be set.
+#pragma warning disable CA1716 // Identifiers should not match keywords
public abstract void Set(T value);
+#pragma warning restore CA1716 // Identifiers should not match keywords
///
public void Dispose()
diff --git a/src/OpenTelemetry.Api/Context/ThreadLocalRuntimeContextSlot.cs b/src/OpenTelemetry.Api/Context/ThreadLocalRuntimeContextSlot.cs
index c7724a842b4..360f9df564b 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 ea802a6ed15..c2e9cf9dfb2 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;
@@ -14,7 +12,7 @@ namespace OpenTelemetry.Internal;
[EventSource(Name = "OpenTelemetry-Api")]
internal sealed class OpenTelemetryApiEventSource : EventSource
{
- public static OpenTelemetryApiEventSource Log = new();
+ public static readonly OpenTelemetryApiEventSource Log = new();
[NonEvent]
public void ActivityContextExtractException(string format, Exception ex)
diff --git a/src/OpenTelemetry.Api/Logs/IDeferredLoggerProviderBuilder.cs b/src/OpenTelemetry.Api/Logs/IDeferredLoggerProviderBuilder.cs
index 7421a9df268..11397157cea 100644
--- a/src/OpenTelemetry.Api/Logs/IDeferredLoggerProviderBuilder.cs
+++ b/src/OpenTelemetry.Api/Logs/IDeferredLoggerProviderBuilder.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Logs;
///
diff --git a/src/OpenTelemetry.Api/Logs/LogRecordAttributeList.cs b/src/OpenTelemetry.Api/Logs/LogRecordAttributeList.cs
index e4367d41c6e..96621ee27ed 100644
--- a/src/OpenTelemetry.Api/Logs/LogRecordAttributeList.cs
+++ b/src/OpenTelemetry.Api/Logs/LogRecordAttributeList.cs
@@ -1,12 +1,10 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
-#if NET8_0_OR_GREATER && EXPOSE_EXPERIMENTAL_FEATURES
+#if EXPOSE_EXPERIMENTAL_FEATURES
using System.Diagnostics.CodeAnalysis;
#endif
using OpenTelemetry.Internal;
@@ -19,9 +17,7 @@ namespace OpenTelemetry.Logs;
/// Stores attributes to be added to a log message.
///
///
-#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
public
#else
///
@@ -29,12 +25,14 @@ namespace OpenTelemetry.Logs;
///
internal
#endif
+#pragma warning disable CA1815 // Override equals and operator equals on value types
struct LogRecordAttributeList : IReadOnlyList>
+#pragma warning restore CA1815 // Override equals and operator equals on value types
{
internal const int OverflowMaxCount = 8;
internal const int OverflowAdditionalCapacity = 16;
internal List>? OverflowAttributes;
- private static readonly IReadOnlyList> Empty = Array.Empty>();
+ private static readonly IReadOnlyList> Empty = [];
private KeyValuePair attribute1;
private KeyValuePair attribute2;
private KeyValuePair attribute3;
@@ -115,7 +113,9 @@ readonly get
/// Attribute name.
/// Attribute value.
[EditorBrowsable(EditorBrowsableState.Never)]
+#pragma warning disable CA1044 // Properties should not be write only
public object? this[string key]
+#pragma warning restore CA1044 // Properties should not be write only
{
// Note: This only exists to enable collection initializer syntax
// like { ["key"] = value }.
@@ -132,7 +132,7 @@ public static LogRecordAttributeList CreateFromEnumerable(IEnumerable> Export(ref List>? attributeStorage)
{
- int count = this.count;
- if (count <= 0)
+ int readonlyCount = this.count;
+ if (readonlyCount <= 0)
{
return Empty;
}
@@ -225,58 +225,55 @@ public readonly Enumerator GetEnumerator()
return overflowAttributes;
}
- Debug.Assert(count <= 8, "Invalid size detected.");
+ Debug.Assert(readonlyCount <= 8, "Invalid size detected.");
attributeStorage ??= new List>(OverflowAdditionalCapacity);
// TODO: Perf test this, adjust as needed.
- if (count > 0)
+ attributeStorage.Add(this.attribute1);
+ if (readonlyCount == 1)
{
- attributeStorage.Add(this.attribute1);
- if (count == 1)
- {
- return attributeStorage;
- }
-
- attributeStorage.Add(this.attribute2);
- if (count == 2)
- {
- return attributeStorage;
- }
+ return attributeStorage;
+ }
- attributeStorage.Add(this.attribute3);
- if (count == 3)
- {
- return attributeStorage;
- }
+ attributeStorage.Add(this.attribute2);
+ if (readonlyCount == 2)
+ {
+ return attributeStorage;
+ }
- attributeStorage.Add(this.attribute4);
- if (count == 4)
- {
- return attributeStorage;
- }
+ attributeStorage.Add(this.attribute3);
+ if (readonlyCount == 3)
+ {
+ return attributeStorage;
+ }
- attributeStorage.Add(this.attribute5);
- if (count == 5)
- {
- return attributeStorage;
- }
+ attributeStorage.Add(this.attribute4);
+ if (readonlyCount == 4)
+ {
+ return attributeStorage;
+ }
- attributeStorage.Add(this.attribute6);
- if (count == 6)
- {
- return attributeStorage;
- }
+ attributeStorage.Add(this.attribute5);
+ if (readonlyCount == 5)
+ {
+ return attributeStorage;
+ }
- attributeStorage.Add(this.attribute7);
- if (count == 7)
- {
- return attributeStorage;
- }
+ attributeStorage.Add(this.attribute6);
+ if (readonlyCount == 6)
+ {
+ return attributeStorage;
+ }
- attributeStorage.Add(this.attribute8);
+ attributeStorage.Add(this.attribute7);
+ if (readonlyCount == 7)
+ {
+ return attributeStorage;
}
+ attributeStorage.Add(this.attribute8);
+
return attributeStorage;
}
diff --git a/src/OpenTelemetry.Api/Logs/LogRecordData.cs b/src/OpenTelemetry.Api/Logs/LogRecordData.cs
index cb3c49292af..374b95d736a 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 EXPOSE_EXPERIMENTAL_FEATURES
using System.Diagnostics.CodeAnalysis;
using OpenTelemetry.Internal;
#endif
@@ -16,9 +14,7 @@ namespace OpenTelemetry.Logs;
/// Stores details about a log message.
///
///
-#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
public
#else
///
@@ -26,7 +22,9 @@ namespace OpenTelemetry.Logs;
///
internal
#endif
+#pragma warning disable CA1815 // Override equals and operator equals on value types
struct LogRecordData
+#pragma warning restore CA1815 // Override equals and operator equals on value types
{
internal DateTime TimestampBacking = DateTime.UtcNow;
@@ -125,6 +123,11 @@ public DateTime Timestamp
///
public string? Body { get; set; } = null;
+ ///
+ /// Gets or sets the name of the event associated with the log.
+ ///
+ public string? EventName { get; set; } = null;
+
internal static void SetActivityContext(ref LogRecordData data, Activity? activity)
{
if (activity != null)
diff --git a/src/OpenTelemetry.Api/Logs/LogRecordSeverity.cs b/src/OpenTelemetry.Api/Logs/LogRecordSeverity.cs
index 9f48e71e854..73d98881d0a 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 EXPOSE_EXPERIMENTAL_FEATURES
using System.Diagnostics.CodeAnalysis;
using OpenTelemetry.Internal;
#endif
@@ -15,9 +13,7 @@ namespace OpenTelemetry.Logs;
/// Describes the severity level of a log record.
///
///
-#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
public
#else
///
diff --git a/src/OpenTelemetry.Api/Logs/LogRecordSeverityExtensions.cs b/src/OpenTelemetry.Api/Logs/LogRecordSeverityExtensions.cs
index f171edbc9ca..14e6e846cdd 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 EXPOSE_EXPERIMENTAL_FEATURES
using System.Diagnostics.CodeAnalysis;
using OpenTelemetry.Internal;
#endif
@@ -15,9 +13,7 @@ namespace OpenTelemetry.Logs;
/// Contains extension methods for the enum.
///
///
-#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
public
#else
///
@@ -59,8 +55,8 @@ static class LogRecordSeverityExtensions
internal const string Fatal3ShortName = FatalShortName + "3";
internal const string Fatal4ShortName = FatalShortName + "4";
- private static readonly string[] LogRecordSeverityShortNames = new string[]
- {
+ private static readonly string[] LogRecordSeverityShortNames =
+ [
UnspecifiedShortName,
TraceShortName,
@@ -91,8 +87,8 @@ static class LogRecordSeverityExtensions
FatalShortName,
Fatal2ShortName,
Fatal3ShortName,
- Fatal4ShortName,
- };
+ Fatal4ShortName
+ ];
///
/// Returns the OpenTelemetry Specification short name for the
/// 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
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
public
#else
///
diff --git a/src/OpenTelemetry.Api/Logs/LoggerProvider.cs b/src/OpenTelemetry.Api/Logs/LoggerProvider.cs
index 01c341c0a5b..c01a9ffd923 100644
--- a/src/OpenTelemetry.Api/Logs/LoggerProvider.cs
+++ b/src/OpenTelemetry.Api/Logs/LoggerProvider.cs
@@ -1,12 +1,10 @@
// 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 || EXPOSE_EXPERIMENTAL_FEATURES
using System.Diagnostics.CodeAnalysis;
#endif
-#if EXPOSE_EXPERIMENTAL_FEATURES && NET8_0_OR_GREATER
+#if EXPOSE_EXPERIMENTAL_FEATURES
using OpenTelemetry.Internal;
#endif
@@ -32,9 +30,7 @@ protected LoggerProvider()
///
///
/// instance.
-#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
public
#else
internal
@@ -49,9 +45,7 @@ Logger GetLogger()
///
/// Optional name identifying the instrumentation library.
/// instance.
-#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
public
#else
internal
@@ -67,9 +61,7 @@ Logger GetLogger(string? name)
/// Optional name identifying the instrumentation library.
/// Optional version of the instrumentation library.
/// instance.
-#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
public
#else
internal
@@ -94,16 +86,14 @@ Logger GetLogger(string? name, string? version)
/// Optional name identifying the instrumentation library.
/// .
/// if the logger was created.
-#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LogsBridgeExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
-#endif
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 b0aec6bfca7..2bc69d1d0c6 100644
--- a/src/OpenTelemetry.Api/Logs/LoggerProviderBuilder.cs
+++ b/src/OpenTelemetry.Api/Logs/LoggerProviderBuilder.cs
@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Logs;
///
diff --git a/src/OpenTelemetry.Api/Logs/NoopLogger.cs b/src/OpenTelemetry.Api/Logs/NoopLogger.cs
index f33ec668aca..2c2b61c4185 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 c283219c431..5f0dc38d34e 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 a16fd88df93..64fcb5e8e52 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 95075dbe703..4fb6bb007dd 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 0a781a94173..a3a2895ee3e 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,7 +16,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/OpenTelemetry.Api/README.md b/src/OpenTelemetry.Api/README.md
index 5fd769f4461..fcaea931073 100644
--- a/src/OpenTelemetry.Api/README.md
+++ b/src/OpenTelemetry.Api/README.md
@@ -249,7 +249,7 @@ following sections describes more features.
### Activity creation options
Basic usage example above showed how `StartActivity` method can be used to start
-an `Activity`. The started activity will automatically becomes the `Current`
+an `Activity`. The started activity automatically becomes the `Current`
activity. It is important to note that the `StartActivity` returns `null`, if no
listeners are interested in the activity to be created. This happens when the
final application does not enable OpenTelemetry, or when OpenTelemetry samplers
@@ -332,11 +332,13 @@ chose not to sample this activity.
4. Activity Links
- Apart from the parent-child relation, activities can be linked using
- `ActivityLinks` which represent the OpenTelemetry
- [Links](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#links-between-spans).
- The linked activities must be provided during the creation time, as shown
- below.
+ In addition to parent-child relationships, activities can also be linked
+ using `ActivityLinks`, which represent
+ [Links](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#links-between-spans)
+ in OpenTelemetry. Providing activity links during creation is recommended, as
+ this allows samplers to consider them when deciding whether to sample an
+ activity. However, starting with `System.Diagnostics.DiagnosticSource` 9.0.0,
+ links can also be added after an activity is created.
```csharp
var activityLinks = new List();
@@ -359,12 +361,19 @@ chose not to sample this activity.
ActivityKind.Server,
default(ActivityContext),
initialTags,
- activityLinks);
+ activityLinks); // links provided at creation time.
+
+ // One may add links after activity is created too.
+ var linkedContext3 = new ActivityContext(
+ ActivityTraceId.CreateFromString("01260a70a81e1fa3ad5a8acfeaa0f711"),
+ ActivitySpanId.CreateFromString("34739aa9e2239da1"),
+ ActivityTraceFlags.None);
+ activity?.AddLink(linkedContext3);
```
- Note that `Activity` above is created with `default(ActivityContext)`
- parent, which makes it child of implicit `Activity.Current` or orphan if
- there is no `Current`.
+ Note that `Activity` above is created with `default(ActivityContext)`
+ parent, which makes it child of implicit `Activity.Current` or orphan if
+ there is no `Current`.
### Adding Events
@@ -539,4 +548,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 d8ac769b9c9..b22339267ba 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 8be46ae4432..7b0d3f71232 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 45af8791625..1972a624c25 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 84850ae048d..5975830c98c 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 b94f50cc5f6..9ebab851122 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;
@@ -36,7 +34,7 @@ public SpanContext(
bool isRemote = false,
IEnumerable>? traceState = null)
{
- this.ActivityContext = new ActivityContext(traceId, spanId, traceFlags, TraceStateUtilsNew.GetString(traceState), isRemote);
+ this.ActivityContext = new ActivityContext(traceId, spanId, traceFlags, TraceStateUtils.GetString(traceState), isRemote);
}
///
@@ -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>();
+ return [];
}
var traceStateResult = new List>();
- TraceStateUtilsNew.AppendTraceState(this.ActivityContext.TraceState, traceStateResult);
+ TraceStateUtils.AppendTraceState(traceState!, traceStateResult);
return traceStateResult;
}
}
@@ -100,7 +99,9 @@ public IEnumerable> TraceState
/// Converts a into an .
///
/// source.
+#pragma warning disable CA2225 // Operator overloads have named alternates
public static implicit operator ActivityContext(SpanContext spanContext)
+#pragma warning restore CA2225 // Operator overloads have named alternates
=> spanContext.ActivityContext;
///
diff --git a/src/OpenTelemetry.Api/Trace/SpanKind.cs b/src/OpenTelemetry.Api/Trace/SpanKind.cs
index f3237a6bd4a..65a6df7af9c 100644
--- a/src/OpenTelemetry.Api/Trace/SpanKind.cs
+++ b/src/OpenTelemetry.Api/Trace/SpanKind.cs
@@ -1,14 +1,14 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
namespace OpenTelemetry.Trace;
///
/// Span kind.
///
+#pragma warning disable CA1008 // Enums should have zero value
public enum SpanKind
+#pragma warning restore CA1008 // Enums should have zero value
{
///
/// Span kind was not specified.
diff --git a/src/OpenTelemetry.Api/Trace/Status.cs b/src/OpenTelemetry.Api/Trace/Status.cs
index b7d0eb35c32..679d663f4ef 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;
///
@@ -88,7 +86,11 @@ public override int GetHashCode()
unchecked
{
hash = (31 * hash) + this.StatusCode.GetHashCode();
+#if NET
+ hash = (31 * hash) + (this.Description?.GetHashCode(StringComparison.Ordinal) ?? 0);
+#else
hash = (31 * hash) + (this.Description?.GetHashCode() ?? 0);
+#endif
}
return hash;
diff --git a/src/OpenTelemetry.Api/Trace/StatusCode.cs b/src/OpenTelemetry.Api/Trace/StatusCode.cs
index 9332d708d06..28d691c10e6 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 f70598d078b..0b5ce40141f 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 CS0618 // Type or member is obsolete
+ this.Activity.SetStatus(value);
+#pragma warning restore CS0618 // Type or member is obsolete
}
///
@@ -226,6 +226,31 @@ public TelemetrySpan AddEvent(string name, DateTimeOffset timestamp, SpanAttribu
return this;
}
+ ///
+ /// Adds a link to another span.
+ ///
+ /// Span context to be linked.
+ /// The instance for chaining.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public TelemetrySpan AddLink(SpanContext spanContext)
+ {
+ this.AddLinkInternal(spanContext.ActivityContext);
+ return this;
+ }
+
+ ///
+ /// Adds a link to another span.
+ ///
+ /// Span context to be linked.
+ /// Attributes for the link.
+ /// The instance for chaining.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public TelemetrySpan AddLink(SpanContext spanContext, SpanAttributes? attributes)
+ {
+ this.AddLinkInternal(spanContext.ActivityContext, attributes?.Attributes);
+ return this;
+ }
+
///
/// End the span.
///
@@ -342,4 +367,12 @@ private void AddEventInternal(string name, DateTimeOffset timestamp = default, A
this.Activity!.AddEvent(new ActivityEvent(name, timestamp, tags));
}
}
+
+ private void AddLinkInternal(ActivityContext context, ActivityTagsCollection? tags = null)
+ {
+ if (this.IsRecording)
+ {
+ this.Activity!.AddLink(new ActivityLink(context, tags));
+ }
+ }
}
diff --git a/src/OpenTelemetry.Api/Trace/Tracer.cs b/src/OpenTelemetry.Api/Trace/Tracer.cs
index 44bf17e1f5c..d0fb906ec18 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 1dc0a5f2936..3246b2e4e7b 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
@@ -35,12 +33,29 @@ protected TracerProvider()
/// Name identifying the instrumentation library.
/// Version of the instrumentation library.
/// Tracer instance.
+ // 1.11.1 BACKCOMPAT OVERLOAD -- DO NOT TOUCH
+ public Tracer GetTracer(
+#if NET
+ [AllowNull]
+#endif
+ string name,
+ string? version) =>
+ this.GetTracer(name, version, null);
+
+ ///
+ /// Gets a tracer with given name, version and tags.
+ ///
+ /// Name identifying the instrumentation library.
+ /// Version of the instrumentation library.
+ /// Tags associated with the tracer.
+ /// Tracer instance.
public Tracer GetTracer(
-#if NET6_0_OR_GREATER
+#if NET
[AllowNull]
#endif
string name,
- string? version = null)
+ string? version = null,
+ IEnumerable>? tags = null)
{
var tracers = this.Tracers;
if (tracers == null)
@@ -49,7 +64,7 @@ public Tracer GetTracer(
return new(activitySource: null);
}
- var key = new TracerKey(name, version);
+ var key = new TracerKey(name, version, tags);
if (!tracers.TryGetValue(key, out var tracer))
{
@@ -62,12 +77,10 @@ public Tracer GetTracer(
return new(activitySource: null);
}
- tracer = new(new(key.Name, key.Version));
-#if DEBUG
+ tracer = new(new(key.Name, key.Version, key.Tags));
bool result = tracers.TryAdd(key, tracer);
+#if DEBUG
System.Diagnostics.Debug.Assert(result, "Write into tracers cache failed");
-#else
- tracers.TryAdd(key, tracer);
#endif
}
}
@@ -80,7 +93,7 @@ protected override void Dispose(bool disposing)
{
if (disposing)
{
- var tracers = Interlocked.CompareExchange(ref this.Tracers, null, this.Tracers);
+ var tracers = Interlocked.Exchange(ref this.Tracers, null);
if (tracers != null)
{
lock (tracers)
@@ -105,11 +118,154 @@ internal readonly record struct TracerKey
{
public readonly string Name;
public readonly string? Version;
+ public readonly KeyValuePair[]? Tags;
- public TracerKey(string? name, string? version)
+ public TracerKey(string? name, string? version, IEnumerable>? tags)
{
this.Name = name ?? string.Empty;
this.Version = version;
+ this.Tags = GetOrderedTags(tags);
+ }
+
+ public bool Equals(TracerKey other)
+ {
+ if (!string.Equals(this.Name, other.Name, StringComparison.Ordinal) ||
+ !string.Equals(this.Version, other.Version, StringComparison.Ordinal))
+ {
+ return false;
+ }
+
+ return AreTagsEqual(this.Tags, other.Tags);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ var hash = 17;
+#if NET
+ hash = (hash * 31) + (this.Name?.GetHashCode(StringComparison.Ordinal) ?? 0);
+ hash = (hash * 31) + (this.Version?.GetHashCode(StringComparison.Ordinal) ?? 0);
+#else
+ hash = (hash * 31) + (this.Name?.GetHashCode() ?? 0);
+ hash = (hash * 31) + (this.Version?.GetHashCode() ?? 0);
+#endif
+
+ hash = (hash * 31) + GetTagsHashCode(this.Tags);
+ return hash;
+ }
+ }
+
+ private static bool AreTagsEqual(
+ KeyValuePair[]? tags1,
+ KeyValuePair[]? tags2)
+ {
+ if (tags1 == null && tags2 == null)
+ {
+ return true;
+ }
+
+ if (tags1 == null || tags2 == null || tags1.Length != tags2.Length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < tags1.Length; i++)
+ {
+ var kvp1 = tags1[i];
+ var kvp2 = tags2[i];
+
+ if (!string.Equals(kvp1.Key, kvp2.Key, StringComparison.Ordinal))
+ {
+ return false;
+ }
+
+ // Compare values
+ if (kvp1.Value is null)
+ {
+ if (kvp2.Value is not null)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!kvp1.Value.Equals(kvp2.Value))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private static int GetTagsHashCode(
+ IEnumerable>? tags)
+ {
+ if (tags is null)
+ {
+ return 0;
+ }
+
+ var hash = 0;
+ unchecked
+ {
+ foreach (var kvp in tags)
+ {
+#if NET
+ hash = (hash * 31) + kvp.Key.GetHashCode(StringComparison.Ordinal);
+#else
+ hash = (hash * 31) + kvp.Key.GetHashCode();
+#endif
+ if (kvp.Value != null)
+ {
+ hash = (hash * 31) + kvp.Value.GetHashCode()!;
+ }
+ }
+ }
+
+ return hash;
+ }
+
+ private static KeyValuePair[]? GetOrderedTags(
+ IEnumerable>? tags)
+ {
+ if (tags is null)
+ {
+ return null;
+ }
+
+ var orderedTagList = new List>(tags);
+ orderedTagList.Sort((left, right) =>
+ {
+ // First compare by key
+ int keyComparison = string.Compare(left.Key, right.Key, StringComparison.Ordinal);
+ if (keyComparison != 0)
+ {
+ return keyComparison;
+ }
+
+ // If keys are equal, compare by value
+ if (left.Value == null && right.Value == null)
+ {
+ return 0;
+ }
+
+ if (left.Value == null)
+ {
+ return -1;
+ }
+
+ if (right.Value == null)
+ {
+ return 1;
+ }
+
+ // Both values are non-null, compare as strings
+ return string.Compare(left.Value.ToString(), right.Value.ToString(), StringComparison.Ordinal);
+ });
+ return [.. orderedTagList];
}
}
}
diff --git a/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs b/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs
index 0a8c3dae3da..ac9b7a2dbe2 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/Stable/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Console/.publicApi/Stable/PublicAPI.Shipped.txt
index 0e45009bac8..670e4b8a1c6 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,26 +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.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.LoggerProviderBuilder loggerProviderBuilder) -> OpenTelemetry.Logs.LoggerProviderBuilder
-static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions loggerOptions, System.Action configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions
-static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions loggerOptions) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions
-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.Metrics.ConsoleExporterMetricsExtensions.AddConsoleExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder) -> OpenTelemetry.Metrics.MeterProviderBuilder
-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
-static OpenTelemetry.Trace.ConsoleExporterHelperExtensions.AddConsoleExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder) -> 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, 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.LoggerProviderBuilder! loggerProviderBuilder) -> OpenTelemetry.Logs.LoggerProviderBuilder!
+static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions! loggerOptions, System.Action? configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions!
+static OpenTelemetry.Logs.ConsoleExporterLoggingExtensions.AddConsoleExporter(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions! loggerOptions) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions!
+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.Metrics.ConsoleExporterMetricsExtensions.AddConsoleExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
+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!
+static OpenTelemetry.Trace.ConsoleExporterHelperExtensions.AddConsoleExporter(this OpenTelemetry.Trace.TracerProviderBuilder! builder) -> OpenTelemetry.Trace.TracerProviderBuilder!
diff --git a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md
index 9e94df266e8..8e2ee12d281 100644
--- a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md
+++ b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md
@@ -1,7 +1,59 @@
# 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
+## 1.13.0
+
+Released 2025-Oct-01
+
+## 1.12.0
+
+Released 2025-Apr-29
+
+## 1.11.2
+
+Released 2025-Mar-04
+
+## 1.11.1
+
+Released 2025-Jan-22
+
+## 1.11.0
+
+Released 2025-Jan-15
+
+## 1.11.0-rc.1
+
+Released 2024-Dec-11
+
+## 1.10.0
+
+Released 2024-Nov-12
+
+## 1.10.0-rc.1
+
+Released 2024-Nov-01
+
+* 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
@@ -11,7 +63,7 @@ Released 2024-Jun-14
Released 2024-Jun-07
* The experimental APIs previously covered by `OTEL1000`
- (`LoggerProviderBuilder.AddConsoleExporter` extension) will now be part of the
+ (`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))
@@ -46,9 +98,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))
@@ -106,7 +158,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 9197cd1287c..c1b707b3e4d 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 b79aa0d9ed9..68a811669e3 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 80c767343b7..d8d04913496 100644
--- a/src/OpenTelemetry.Exporter.Console/ConsoleExporterLoggingExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Console/ConsoleExporterLoggingExtensions.cs
@@ -23,16 +23,18 @@ 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)
+ public static OpenTelemetryLoggerOptions AddConsoleExporter(this OpenTelemetryLoggerOptions loggerOptions, Action? configure)
{
Guard.ThrowIfNull(loggerOptions);
var options = new ConsoleExporterOptions();
configure?.Invoke(options);
+#pragma warning disable CA2000 // Dispose objects before losing scope
return loggerOptions.AddProcessor(new SimpleLogRecordExportProcessor(new ConsoleLogRecordExporter(options)));
+#pragma warning restore CA2000 // Dispose objects before losing scope
}
///
@@ -59,13 +61,13 @@ public static LoggerProviderBuilder AddConsoleExporter(
/// 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.
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 103593efddd..3d9bf9560f5 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);
@@ -104,11 +104,13 @@ public static MeterProviderBuilder AddConsoleExporter(
});
}
- private static MetricReader BuildConsoleExporterMetricReader(
+ private static PeriodicExportingMetricReader BuildConsoleExporterMetricReader(
ConsoleExporterOptions exporterOptions,
MetricReaderOptions metricReaderOptions)
{
+#pragma warning disable CA2000 // Dispose objects before losing scope
var metricExporter = new ConsoleMetricExporter(exporterOptions);
+#pragma warning restore CA2000 // Dispose objects before losing scope
return PeriodicExportingMetricReaderHelper.CreatePeriodicExportingMetricReader(
metricExporter,
diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs b/src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs
index 3ad90910954..84fd449532b 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)
@@ -38,8 +38,8 @@ 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($"{Environment.NewLine}Dispose was called on the following stack trace:");
+ this.WriteLine(this.disposedStackTrace!);
}
return ExportResult.Failure;
@@ -89,8 +89,8 @@ public override ExportResult Export(in Batch batch)
// Special casing {OriginalFormat}
// 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)
+ var valueToTransform = logRecord.Attributes[i].Key.Equals("{OriginalFormat}", StringComparison.Ordinal)
+ ? 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))
{
@@ -137,10 +137,10 @@ void ProcessScope(LogRecordScope scope, ConsoleLogRecordExporter exporter)
var resource = this.ParentProvider.GetResource();
if (resource != Resource.Empty)
{
- this.WriteLine("\nResource associated with LogRecord:");
+ this.WriteLine($"{Environment.NewLine}Resource 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 4bd9772b217..c47823b3ad6 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,54 +17,67 @@ public ConsoleMetricExporter(ConsoleExporterOptions options)
public override ExportResult Export(in Batch batch)
{
- if (this.resource == null)
+ // Print Resource information once at the beginning of the batch
+ var resource = this.ParentProvider.GetResource();
+ if (resource != Resource.Empty)
{
- this.resource = this.ParentProvider.GetResource();
- if (this.resource != Resource.Empty)
+ this.WriteLine("Resource associated with Metrics:");
+ foreach (var resourceAttribute in resource.Attributes)
{
- this.WriteLine("Resource associated with Metric:");
- foreach (var resourceAttribute in this.resource.Attributes)
+ if (this.TagWriter.TryTransformTag(resourceAttribute.Key, resourceAttribute.Value, out var result))
{
- if (this.TagWriter.TryTransformTag(resourceAttribute, out var result))
- {
- this.WriteLine($" {result.Key}: {result.Value}");
- }
+ this.WriteLine($"\t{result.Key}: {result.Value}");
}
}
}
foreach (var metric in batch)
{
- var msg = new StringBuilder($"\n");
+ var msg = new StringBuilder(Environment.NewLine);
+#if NET
+ msg.Append(CultureInfo.InvariantCulture, $"Metric Name: {metric.Name}");
+#else
msg.Append($"Metric Name: {metric.Name}");
- if (metric.Description != string.Empty)
+#endif
+ if (!string.IsNullOrEmpty(metric.Description))
{
- msg.Append(", ");
- msg.Append(metric.Description);
+#if NET
+ msg.Append(CultureInfo.InvariantCulture, $", Description: {metric.Description}");
+#else
+ msg.Append($", Description: {metric.Description}");
+#endif
}
- if (metric.Unit != string.Empty)
+ if (!string.IsNullOrEmpty(metric.Unit))
{
+#if NET
+ msg.Append(CultureInfo.InvariantCulture, $", Unit: {metric.Unit}");
+#else
msg.Append($", Unit: {metric.Unit}");
+#endif
}
- if (!string.IsNullOrEmpty(metric.MeterName))
- {
- msg.Append($", Meter: {metric.MeterName}");
-
- if (!string.IsNullOrEmpty(metric.MeterVersion))
- {
- msg.Append($"/{metric.MeterVersion}");
- }
- }
+#if NET
+ msg.Append(CultureInfo.InvariantCulture, $", Metric Type: {metric.MetricType}");
+#else
+ msg.Append($", Metric Type: {metric.MetricType}");
+#endif
this.WriteLine(msg.ToString());
- if (metric.MeterTags != null)
+ // Print Instrumentation scope (Meter) information once per metric
+ 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)
{
- this.WriteLine("\tMeter Tags:");
if (this.TagWriter.TryTransformTag(meterTag, out var result))
{
this.WriteLine($"\t\t{result.Key}: {result.Value}");
@@ -82,7 +93,11 @@ public override ExportResult Export(in Batch batch)
{
if (this.TagWriter.TryTransformTag(tag, out var result))
{
+#if NET
+ tagsBuilder.Append(CultureInfo.InvariantCulture, $"{result.Key}: {result.Value}");
+#else
tagsBuilder.Append($"{result.Key}: {result.Value}");
+#endif
tagsBuilder.Append(' ');
}
}
@@ -96,10 +111,18 @@ public override ExportResult Export(in Batch batch)
var bucketsBuilder = new StringBuilder();
var sum = metricPoint.GetHistogramSum();
var count = metricPoint.GetHistogramCount();
+#if NET
+ bucketsBuilder.Append(CultureInfo.InvariantCulture, $"Sum: {sum} Count: {count} ");
+#else
bucketsBuilder.Append($"Sum: {sum} Count: {count} ");
+#endif
if (metricPoint.TryGetHistogramMinMaxValues(out double min, out double max))
{
+#if NET
+ bucketsBuilder.Append(CultureInfo.InvariantCulture, $"Min: {min} Max: {max} ");
+#else
bucketsBuilder.Append($"Min: {min} Max: {max} ");
+#endif
}
bucketsBuilder.AppendLine();
@@ -150,7 +173,11 @@ public override ExportResult Export(in Batch batch)
if (exponentialHistogramData.ZeroCount != 0)
{
+#if NET
+ bucketsBuilder.AppendLine(CultureInfo.InvariantCulture, $"Zero Bucket:{exponentialHistogramData.ZeroCount}");
+#else
bucketsBuilder.AppendLine($"Zero Bucket:{exponentialHistogramData.ZeroCount}");
+#endif
}
var offset = exponentialHistogramData.PositiveBuckets.Offset;
@@ -158,7 +185,11 @@ public override ExportResult Export(in Batch batch)
{
var lowerBound = Base2ExponentialBucketHistogramHelper.CalculateLowerBoundary(offset, scale).ToString(CultureInfo.InvariantCulture);
var upperBound = Base2ExponentialBucketHistogramHelper.CalculateLowerBoundary(++offset, scale).ToString(CultureInfo.InvariantCulture);
+#if NET
+ bucketsBuilder.AppendLine(CultureInfo.InvariantCulture, $"({lowerBound}, {upperBound}]:{bucketCount}");
+#else
bucketsBuilder.AppendLine($"({lowerBound}, {upperBound}]:{bucketCount}");
+#endif
}
}
@@ -166,25 +197,11 @@ public override ExportResult Export(in Batch batch)
}
else if (metricType.IsDouble())
{
- if (metricType.IsSum())
- {
- valueDisplay = metricPoint.GetSumDouble().ToString(CultureInfo.InvariantCulture);
- }
- else
- {
- valueDisplay = metricPoint.GetGaugeLastValueDouble().ToString(CultureInfo.InvariantCulture);
- }
+ valueDisplay = metricType.IsSum() ? metricPoint.GetSumDouble().ToString(CultureInfo.InvariantCulture) : metricPoint.GetGaugeLastValueDouble().ToString(CultureInfo.InvariantCulture);
}
else if (metricType.IsLong())
{
- if (metricType.IsSum())
- {
- valueDisplay = metricPoint.GetSumLong().ToString(CultureInfo.InvariantCulture);
- }
- else
- {
- valueDisplay = metricPoint.GetGaugeLastValueLong().ToString(CultureInfo.InvariantCulture);
- }
+ valueDisplay = metricType.IsSum() ? metricPoint.GetSumLong().ToString(CultureInfo.InvariantCulture) : metricPoint.GetGaugeLastValueLong().ToString(CultureInfo.InvariantCulture);
}
var exemplarString = new StringBuilder();
@@ -220,11 +237,15 @@ public override ExportResult Export(in Batch batch)
{
if (!appendedTagString)
{
- exemplarString.Append(" Filtered Tags : ");
+ exemplarString.Append(" Filtered Tags: ");
appendedTagString = true;
}
+#if NET
+ exemplarString.Append(CultureInfo.InvariantCulture, $"{result.Key}: {result.Value}");
+#else
exemplarString.Append($"{result.Key}: {result.Value}");
+#endif
exemplarString.Append(' ');
}
}
@@ -240,20 +261,23 @@ public override ExportResult Export(in Batch batch)
msg.Append(metricPoint.EndTime.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ", CultureInfo.InvariantCulture));
msg.Append("] ");
msg.Append(tags);
- if (tags != string.Empty)
+ if (string.IsNullOrEmpty(tags))
{
msg.Append(' ');
}
- msg.Append(metric.MetricType);
msg.AppendLine();
+#if NET
+ msg.Append(CultureInfo.InvariantCulture, $"Value: {valueDisplay}");
+#else
msg.Append($"Value: {valueDisplay}");
+#endif
if (exemplarString.Length > 0)
{
msg.AppendLine();
msg.AppendLine("Exemplars");
- msg.Append(exemplarString.ToString());
+ msg.Append(exemplarString);
}
this.WriteLine(msg.ToString());
diff --git a/src/OpenTelemetry.Exporter.Console/Implementation/ConsoleTagWriter.cs b/src/OpenTelemetry.Exporter.Console/Implementation/ConsoleTagWriter.cs
index 2f36df00915..4950bd100e5 100644
--- a/src/OpenTelemetry.Exporter.Console/Implementation/ConsoleTagWriter.cs
+++ b/src/OpenTelemetry.Exporter.Console/Implementation/ConsoleTagWriter.cs
@@ -1,9 +1,8 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-#nullable enable
-
using System.Diagnostics;
+using System.Globalization;
using System.Text;
using OpenTelemetry.Internal;
@@ -21,9 +20,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;
@@ -36,13 +40,13 @@ public bool TryTransformTag(KeyValuePair tag, out KeyValuePair<
protected override void WriteIntegralTag(ref ConsoleTag consoleTag, string key, long value)
{
consoleTag.Key = key;
- consoleTag.Value = value.ToString();
+ consoleTag.Value = value.ToString(CultureInfo.InvariantCulture);
}
protected override void WriteFloatingPointTag(ref ConsoleTag consoleTag, string key, double value)
{
consoleTag.Key = key;
- consoleTag.Value = value.ToString();
+ consoleTag.Value = value.ToString(CultureInfo.InvariantCulture);
}
protected override void WriteBooleanTag(ref ConsoleTag consoleTag, string key, bool value)
@@ -70,6 +74,13 @@ protected override void OnUnsupportedTagDropped(
this.onUnsupportedTagDropped(tagKey, tagValueTypeFullName);
}
+ protected override bool TryWriteEmptyTag(ref ConsoleTag consoleTag, string key, object? value)
+ {
+ consoleTag.Key = key;
+ consoleTag.Value = null;
+ return true;
+ }
+
internal struct ConsoleTag
{
public string? Key;
diff --git a/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj b/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj
index 3e6d3b58284..2fc8d03e54b 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
+ $(NoWarn),CS1591
-
-
-
-
-
diff --git a/src/OpenTelemetry.Exporter.Console/README.md b/src/OpenTelemetry.Exporter.Console/README.md
index 07a51a29e52..ef7985bf7ef 100644
--- a/src/OpenTelemetry.Exporter.Console/README.md
+++ b/src/OpenTelemetry.Exporter.Console/README.md
@@ -7,8 +7,11 @@ The console exporter prints data to the Console window.
ConsoleExporter supports exporting logs, metrics and traces.
> [!WARNING]
-> This component is intended to be used while learning how telemetry data is
- created and exported. It is not recommended for any production environment.
+> This exporter is intended for debugging and learning purposes. It is not
+ recommended for production use. The output format is not standardized and can
+ change at any time.
+ If a standardized format for exporting telemetry to stdout is desired, upvote on
+ [this feature request](https://github.com/open-telemetry/opentelemetry-dotnet/issues/5920).
## Installation
diff --git a/src/OpenTelemetry.Exporter.InMemory/.publicApi/Stable/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.InMemory/.publicApi/Stable/PublicAPI.Shipped.txt
index a79ca4f2cf5..be3367f467f 100644
--- a/src/OpenTelemetry.Exporter.InMemory/.publicApi/Stable/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry.Exporter.InMemory/.publicApi/Stable/PublicAPI.Shipped.txt
@@ -1,25 +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.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, 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.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, 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.Trace.InMemoryExporterHelperExtensions.AddInMemoryExporter(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Collections.Generic.ICollection! exportedItems) -> OpenTelemetry.Trace.TracerProviderBuilder!
diff --git a/src/OpenTelemetry.Exporter.InMemory/AssemblyInfo.cs b/src/OpenTelemetry.Exporter.InMemory/AssemblyInfo.cs
deleted file mode 100644
index f7775c1b9b8..00000000000
--- a/src/OpenTelemetry.Exporter.InMemory/AssemblyInfo.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright The OpenTelemetry Authors
-// SPDX-License-Identifier: Apache-2.0
-
-#if !EXPOSE_EXPERIMENTAL_FEATURES
-using System.Runtime.CompilerServices;
-
-[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests" + AssemblyInfo.PublicKey)]
-#endif
-
-#if SIGNED
-file static class AssemblyInfo
-{
- public const string PublicKey = ", PublicKey=002400000480000094000000060200000024000052534131000400000100010051C1562A090FB0C9F391012A32198B5E5D9A60E9B80FA2D7B434C9E5CCB7259BD606E66F9660676AFC6692B8CDC6793D190904551D2103B7B22FA636DCBB8208839785BA402EA08FC00C8F1500CCEF28BBF599AA64FFB1E1D5DC1BF3420A3777BADFE697856E9D52070A50C3EA5821C80BEF17CA3ACFFA28F89DD413F096F898";
-}
-#else
-file static class AssemblyInfo
-{
- public const string PublicKey = "";
-}
-#endif
diff --git a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md
index fc2a00afb3c..4521a32b130 100644
--- a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md
+++ b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md
@@ -1,7 +1,47 @@
# 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.13.0
+
+Released 2025-Oct-01
+
+## 1.12.0
+
+Released 2025-Apr-29
+
+## 1.11.2
+
+Released 2025-Mar-04
+
+## 1.11.1
+
+Released 2025-Jan-22
+
+## 1.11.0
+
+Released 2025-Jan-15
+
+## 1.11.0-rc.1
+
+Released 2024-Dec-11
+
+## 1.10.0
+
+Released 2024-Nov-12
+
+## 1.10.0-rc.1
+
+Released 2024-Nov-01
+
+## 1.10.0-beta.1
+
+Released 2024-Sep-30
+
## 1.9.0
Released 2024-Jun-14
@@ -11,8 +51,8 @@ Released 2024-Jun-14
Released 2024-Jun-07
* The experimental APIs previously covered by `OTEL1000`
- (`LoggerProviderBuilder.AddInMemoryExporter` extension) will now be part of
- the public API and supported in stable builds.
+ (`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
diff --git a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporter.cs b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporter.cs
index dedcf65b37c..8533108ce86 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