diff --git a/.editorconfig b/.editorconfig
index dd065ed451c..5bc89604c76 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -13,6 +13,12 @@ trim_trailing_whitespace = true
[*.{cs,cshtml,htm,html,md,py,sln,xml}]
indent_size = 4
+###############################
+# Copyright header #
+###############################
+[*.cs]
+file_header_template = Copyright The OpenTelemetry Authors\nSPDX-License-Identifier: Apache-2.0
+
###############################
# .NET Coding Conventions #
###############################
@@ -34,7 +40,7 @@ csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
# Modifier preferences
-csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
+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
# this. preferences
@@ -106,6 +112,7 @@ csharp_style_prefer_index_operator = false:none
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
# Space preferences
csharp_space_after_cast = false
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 39203dabfb6..0ff333446eb 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -7,7 +7,7 @@ Please provide a brief description of the changes here.
## Merge requirement checklist
-* [ ] [CONTRIBUTING](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/CONTRIBUTING.md) guidelines followed (nullable enabled, static analysis, etc.)
+* [ ] [CONTRIBUTING](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/CONTRIBUTING.md) guidelines followed (license requirements, nullable enabled, static analysis, etc.)
* [ ] Unit tests added/updated
* [ ] Appropriate `CHANGELOG.md` files updated for non-trivial changes
* [ ] Changes in public API reviewed (if applicable)
diff --git a/.github/codecov.yml b/.github/codecov.yml
index 1abd5d69c37..b20bf1b2972 100644
--- a/.github/codecov.yml
+++ b/.github/codecov.yml
@@ -23,7 +23,32 @@ comment:
require_changes: no
ignore:
- - "docs/**/*"
- - "examples/**/*"
- - "test/**/*"
- "**.md"
+ - ".github"
+ - ".vscode"
+ - "build"
+ - "docs"
+ - "examples"
+ - "src/Shared"
+ - "test"
+
+flags:
+ unittests-Solution-Stable:
+ carryforward: true
+ paths:
+ - src
+
+ unittests-Solution-Experimental:
+ carryforward: true
+ paths:
+ - src
+
+ unittests-Instrumentation-Stable:
+ carryforward: true
+ paths:
+ - src
+
+ unittests-Instrumentation-Experimental:
+ carryforward: true
+ paths:
+ - src
diff --git a/.github/workflows/Component.BuildTest.yml b/.github/workflows/Component.BuildTest.yml
new file mode 100644
index 00000000000..f97c8b94f9b
--- /dev/null
+++ b/.github/workflows/Component.BuildTest.yml
@@ -0,0 +1,82 @@
+# Called by ci.yml to build & test project files
+# See: https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow
+name: Build Component
+
+on:
+ workflow_call:
+ inputs:
+ project-name:
+ required: true
+ type: string
+ project-build-commands:
+ default: ''
+ required: false
+ type: string
+ code-cov-name:
+ required: true
+ type: string
+ code-cov-prefix:
+ default: 'unittests'
+ required: false
+ type: string
+ os-list:
+ default: '[ "windows-latest", "ubuntu-latest" ]'
+ required: false
+ type: string
+ tfm-list:
+ default: '[ "net462", "net6.0", "net7.0", "net8.0" ]'
+ required: false
+ type: string
+
+jobs:
+ build-test:
+
+ strategy:
+ fail-fast: false # ensures the entire test matrix is run, even if one permutation fails
+ matrix:
+ os: ${{ fromJSON(inputs.os-list) }}
+ version: ${{ fromJSON(inputs.tfm-list) }}
+ exclude:
+ - os: ubuntu-latest
+ version: net462
+
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v4
+ 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: dotnet restore ${{ inputs.project-name }}
+ run: dotnet restore ${{ inputs.project-name }} ${{ inputs.project-build-commands }}
+
+ - name: dotnet build ${{ inputs.project-name }}
+ 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
+
+ - name: Install coverage tool
+ run: dotnet tool install -g dotnet-coverage
+
+ - name: Merging test results
+ run: dotnet-coverage merge -r -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
+ 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
+ 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
diff --git a/.github/workflows/apicompatibility.yml b/.github/workflows/apicompatibility.yml
deleted file mode 100644
index ec6706fdfab..00000000000
--- a/.github/workflows/apicompatibility.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-name: API Compatibility
-
-on:
- pull_request:
- branches: [ 'main*' ]
- paths-ignore:
- - '**.md'
-
-jobs:
- build-test:
- runs-on: windows-latest
- env:
- CheckAPICompatibility: true
-
- steps:
- - uses: actions/checkout@v3
- with:
- fetch-depth: 0 # fetching all
-
- - name: Install dependencies
- run: dotnet restore
-
- - name: Build
- run: dotnet build --configuration Release --no-restore
diff --git a/.github/workflows/ci-md.yml b/.github/workflows/ci-md.yml
deleted file mode 100644
index 1dde2355a3e..00000000000
--- a/.github/workflows/ci-md.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-# Syntax: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
-# See also: https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks
-
-# Description: This workflow exists to unblock documentation-only PRs.
-
-# IMPORTANT: This workflow MUST use the same 'name' as the non -md workflow.
-
-name: Build
-
-on:
- pull_request:
- branches: [ 'main*' ]
- paths:
- - '**.md'
-
-jobs:
- build-test:
- strategy:
- matrix:
- os: [ windows-latest, ubuntu-latest ]
- version: [ net462, net6.0, net7.0 ]
- exclude:
- - os: ubuntu-latest
- version: net462
-
- runs-on: ubuntu-latest
- steps:
- - run: 'echo "No build required"'
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 734959b70de..dc3494d93cc 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,37 +1,193 @@
name: Build
on:
+ workflow_dispatch:
+ # The push trigger would run the CI workflow when any changes get merged to main branch.
+ # The build badge on the main README uses the CI results on the main branch to report the build status.
push:
branches: [ 'main*' ]
- paths-ignore:
- - '**.md'
pull_request:
branches: [ 'main*' ]
- paths-ignore:
- - '**.md'
jobs:
- build-test:
+ lint-misspell-sanitycheck:
+ uses: ./.github/workflows/sanitycheck.yml
+
+ detect-changes:
+ runs-on: windows-latest
+ outputs:
+ changes: ${{ steps.changes.outputs.changes }}
+ steps:
+ - uses: actions/checkout@v4
+ - uses: AurorNZ/paths-filter@v4
+ id: changes
+ with:
+ filters: |
+ md: ['**.md']
+ build: ['build/**', '.github/**/*.yml', '**/*.targets', '**/*.props']
+ shared: ['src/Shared/**']
+ code: ['**.cs', '**.csproj', '.editorconfig']
+ packaged-code: ['src/**', '!**/*.md']
+ api-code: ['*/OpenTelemetry.Api*/**', '!**/*.md']
+ api-packages: ['src/OpenTelemetry.Api*/**', '!**/*.md']
+ instrumentation: ['*/OpenTelemetry.Instrumentation*/**', 'test/TestApp.AspNetCore/**', '!**/*.md']
+ instrumentation-packages: ['src/OpenTelemetry.Instrumentation*/**', '!**/*.md']
+ sdk-code: ['src/OpenTelemetry/**', 'test/OpenTelemetry.Tests/**', '!**/*.md']
+ sdk-package: ['src/OpenTelemetry/**', '!**/*.md']
+ otlp: ['*/OpenTelemetry.Exporter.OpenTelemetryProtocol*/**', '!**/*.md']
+
+ lint-md:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'md')
+ || contains(needs.detect-changes.outputs.changes, 'build')
+ uses: ./.github/workflows/markdownlint.yml
+
+ lint-dotnet-format:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'code')
+ || contains(needs.detect-changes.outputs.changes, 'build')
+ uses: ./.github/workflows/dotnet-format.yml
+
+ build-test-solution-stable:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'code')
+ || contains(needs.detect-changes.outputs.changes, 'build')
+ || contains(needs.detect-changes.outputs.changes, 'shared')
+ uses: ./.github/workflows/Component.BuildTest.yml
+ with:
+ project-name: 'OpenTelemetry.sln'
+ project-build-commands: '-p:ExposeExperimentalFeatures=false'
+ code-cov-name: 'Solution-Stable'
+
+ build-test-solution-experimental:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'code')
+ || contains(needs.detect-changes.outputs.changes, 'build')
+ || contains(needs.detect-changes.outputs.changes, 'shared')
+ uses: ./.github/workflows/Component.BuildTest.yml
+ with:
+ project-name: 'OpenTelemetry.sln'
+ project-build-commands: '-p:ExposeExperimentalFeatures=true'
+ code-cov-name: 'Solution-Experimental'
+
+ # Build instrumentation libraries using stable packages released to NuGet
+ build-test-instrumentation-stable:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'instrumentation-packages')
+ || contains(needs.detect-changes.outputs.changes, 'build')
+ || contains(needs.detect-changes.outputs.changes, 'shared')
+ uses: ./.github/workflows/Component.BuildTest.yml
+ with:
+ project-name: './build/InstrumentationLibraries.proj'
+ project-build-commands: '-p:RunningDotNetPack=true -p:ExposeExperimentalFeatures=false'
+ code-cov-name: 'Instrumentation-Stable'
+
+ # Build instrumentation libraries using stable packages released to NuGet
+ build-test-instrumentation-experimental:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'instrumentation-packages')
+ || contains(needs.detect-changes.outputs.changes, 'build')
+ || contains(needs.detect-changes.outputs.changes, 'shared')
+ uses: ./.github/workflows/Component.BuildTest.yml
+ with:
+ project-name: './build/InstrumentationLibraries.proj'
+ project-build-commands: '-p:RunningDotNetPack=true -p:ExposeExperimentalFeatures=true'
+ code-cov-name: 'Instrumentation-Experimental'
+
+ otlp-integration-test:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'api-packages')
+ || contains(needs.detect-changes.outputs.changes, 'sdk-package')
+ || 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
strategy:
- fail-fast: false # ensures the entire test matrix is run, even if one permutation fails
+ fail-fast: false
matrix:
- os: [ windows-latest, ubuntu-latest ]
- version: [ net462, net6.0, net7.0 ]
- exclude:
- - os: ubuntu-latest
- version: net462
+ version: [ net6.0, net7.0, net8.0 ]
+ steps:
+ - uses: actions/checkout@v4
+ - 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
- runs-on: ${{ matrix.os }}
+ w3c-trace-context-integration-test:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'api-packages')
+ || contains(needs.detect-changes.outputs.changes, 'sdk-package')
+ || 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
+ strategy:
+ fail-fast: false
+ matrix:
+ version: [ net6.0, net7.0 ]
steps:
- - uses: actions/checkout@v3
- with:
- fetch-depth: 0 # fetching all
+ - uses: actions/checkout@v4
+ - 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
- - name: Install dependencies
- run: dotnet restore
+ validate-packages:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'packaged-code')
+ || contains(needs.detect-changes.outputs.changes, 'build')
+ || contains(needs.detect-changes.outputs.changes, 'shared')
+ uses: ./.github/workflows/package-validation.yml
- - name: Build
- run: dotnet build --configuration Release --no-restore
+ generate-docs:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'packaged-code')
+ || contains(needs.detect-changes.outputs.changes, 'md')
+ || contains(needs.detect-changes.outputs.changes, 'build')
+ || contains(needs.detect-changes.outputs.changes, 'shared')
+ uses: ./.github/workflows/docfx.yml
- - name: Test ${{ matrix.version }}
- run: dotnet test **/bin/**/${{ matrix.version }}/*.Tests.dll --logger:"console;verbosity=detailed"
+ verify-aot-compat:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'packaged-code')
+ || contains(needs.detect-changes.outputs.changes, 'build')
+ || contains(needs.detect-changes.outputs.changes, 'shared')
+ uses: ./.github/workflows/verifyaotcompat.yml
+
+ concurrency-tests:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'api-code')
+ || contains(needs.detect-changes.outputs.changes, 'sdk-code')
+ || contains(needs.detect-changes.outputs.changes, 'build')
+ || contains(needs.detect-changes.outputs.changes, 'shared')
+ uses: ./.github/workflows/concurrency-tests.yml
+
+ build-test:
+ needs: [
+ lint-misspell-sanitycheck,
+ detect-changes,
+ lint-md,
+ lint-dotnet-format,
+ build-test-solution-stable,
+ build-test-solution-experimental,
+ build-test-instrumentation-stable,
+ build-test-instrumentation-experimental,
+ otlp-integration-test,
+ w3c-trace-context-integration-test,
+ validate-packages,
+ generate-docs,
+ verify-aot-compat,
+ concurrency-tests
+ ]
+ if: always() && !cancelled() && !contains(needs.*.result, 'failure')
+ runs-on: windows-latest
+ steps:
+ - run: echo 'build complete'
diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml
deleted file mode 100644
index 4a68cb93e41..00000000000
--- a/.github/workflows/code-coverage.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-name: Code Coverage
-
-on:
- push:
- branches: [ 'main*' ]
- paths-ignore:
- - '**.md'
- pull_request:
- branches: [ 'main*' ]
- paths-ignore:
- - '**.md'
-
-jobs:
- build-test-report:
- runs-on: ${{ matrix.os }}
-
- strategy:
- fail-fast: false
- matrix:
- os: [windows-latest]
-
- steps:
- - uses: actions/checkout@v3
- with:
- fetch-depth: 0 # fetching all
-
- - name: Install dependencies
- run: dotnet restore
-
- - name: dotnet build
- run: dotnet build --configuration Release --no-restore
-
-# - name: dotnet test
-# run: dotnet test --collect:"XPlat Code Coverage" --results-directory:"TestResults" --configuration Release --no-build -- RunConfiguration.DisableAppDomain=true
-
- - name: dotnet test
- run: dotnet test --collect:"Code Coverage" --results-directory:"TestResults" --configuration Release --no-build -- RunConfiguration.DisableAppDomain=true
-
- - name: Process code coverage
- run: .\build\process-codecoverage.ps1
- shell: powershell
-
- - name: Install report tool
- run: dotnet tool install -g dotnet-reportgenerator-globaltool
-
- - name: Merging test results
- run: reportgenerator -reports:TestResults/**/*.xml -targetdir:TestResults -reporttypes:Cobertura -assemblyFilters:"-microsoft.data.sqlclient*;-grpc.core*;-opentracing*"
-
- - uses: codecov/codecov-action@v3.1.4
- with:
- file: TestResults/Cobertura.xml
- env_vars: OS
- name: Code Coverage for ${{ matrix.os }}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 2b6d32c3ead..c091dc85184 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -8,6 +8,7 @@ name: "CodeQL"
on:
schedule:
- cron: '0 0 * * *' # once in a day at 00:00
+ workflow_dispatch:
jobs:
analyze:
@@ -17,48 +18,29 @@ jobs:
strategy:
fail-fast: false
matrix:
- # Override automatic language detection by changing the below list
- # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['csharp']
- # Learn more...
- # https://docs.github.com/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: configure Pagefile
- uses: al-cheb/configure-pagefile-action@v1.3
+ uses: al-cheb/configure-pagefile-action@v1.4
with:
minimum-size: 8GB
maximum-size: 32GB
disk-root: "D:"
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
- # If you wish to specify custom queries, you can do so here or in a config file.
- # By default, queries listed here will override any specified in a config file.
- # Prefix the list here with "+" to use these queries and those in the config file.
- # queries: ./path/to/local/query, your-org/your-repo/queries@main
- # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
- # If this step fails, then you should remove it and run the build manually (see below)
- - name: Autobuild
- uses: github/codeql-action/autobuild@v2
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v4
- # Command-line programs to run using the OS shell.
- # https://git.io/JvXDl
-
- # If the Autobuild fails above, remove it and uncomment the following three lines
- # and modify them (or add more) to build your code if your project
- # uses a compiled language
-
- #- run: |
- # make bootstrap
- # make release
+ - name: dotnet pack OpenTelemetry.proj
+ run: dotnet pack OpenTelemetry.proj --configuration Release
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
diff --git a/.github/workflows/concurrency-tests.yml b/.github/workflows/concurrency-tests.yml
new file mode 100644
index 00000000000..43c438ef2d9
--- /dev/null
+++ b/.github/workflows/concurrency-tests.yml
@@ -0,0 +1,34 @@
+# Called by ci.yml to run coyote concurrency tests
+# See: https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow
+name: Concurrency Tests
+
+on:
+ workflow_call:
+
+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 ]
+ version: [ net8.0 ]
+ project: [ OpenTelemetry.Tests, OpenTelemetry.Api.Tests ]
+
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v4
+
+ - name: Run Coyote Tests
+ shell: pwsh
+ run: .\build\test-threadSafety.ps1 -testProjectName ${{ matrix.project }} -targetFramework ${{ matrix.version }}
+
+ - name: Publish Artifacts
+ if: always() && !cancelled()
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ matrix.os }}-${{ matrix.project }}-${{ matrix.version }}-coyoteoutput
+ path: '**/*_CoyoteOutput.*'
diff --git a/.github/workflows/docfx.yml b/.github/workflows/docfx.yml
index 53e13b5b4e8..34a94672acf 100644
--- a/.github/workflows/docfx.yml
+++ b/.github/workflows/docfx.yml
@@ -1,18 +1,17 @@
-name: docfx
+# Called by ci.yml to run documentation build
+# See: https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow
+name: Build docfx
on:
- push:
- branches: [ 'main*' ]
- pull_request:
- branches: [ 'main*' ]
+ workflow_call:
jobs:
- build:
+ run-docfx-build:
runs-on: windows-latest
steps:
- name: check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: install docfx
run: choco install docfx -y
diff --git a/.github/workflows/dotnet-format-md.yml b/.github/workflows/dotnet-format-md.yml
deleted file mode 100644
index d35d16849bb..00000000000
--- a/.github/workflows/dotnet-format-md.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-# Syntax: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
-# See also: https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks
-
-# Description: This workflow exists to unblock documentation-only PRs.
-
-# IMPORTANT: This workflow MUST use the same 'name' and 'matrix' as the non -md workflow.
-
-name: dotnet format
-
-on:
- pull_request:
- branches: [ 'main*' ]
- paths-ignore:
- - '**.cs'
- - '.editorconfig'
-
-jobs:
- check-format:
- runs-on: ubuntu-latest
-
- steps:
- - run: 'echo "No build required"'
diff --git a/.github/workflows/dotnet-format.yml b/.github/workflows/dotnet-format.yml
index 73c2cde0bdc..b6baf18aab0 100644
--- a/.github/workflows/dotnet-format.yml
+++ b/.github/workflows/dotnet-format.yml
@@ -1,27 +1,43 @@
-name: dotnet format
+# Called by ci.yml to perform dotnet format linting
+# See: https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow
+name: Lint - dotnet format
on:
- push:
- branches: [ 'main*' ]
- paths:
- - '**.cs'
- - '.editorconfig'
- pull_request:
- branches: [ 'main*' ]
- paths:
- - '**.cs'
- - '.editorconfig'
+ workflow_call:
jobs:
- check-format:
+ run-dotnet-format-stable:
runs-on: windows-latest
steps:
- name: check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- - name: Install format tool
- run: dotnet tool install -g dotnet-format
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v4
+
+ - name: dotnet restore
+ run: dotnet restore
+
+ - name: dotnet format
+ run: dotnet format OpenTelemetry.sln --no-restore --verify-no-changes
+ env:
+ ExposeExperimentalFeatures: false
+
+ run-dotnet-format-experimental:
+ runs-on: windows-latest
+
+ steps:
+ - name: check out code
+ uses: actions/checkout@v4
+
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v4
+
+ - name: dotnet restore
+ run: dotnet restore
- name: dotnet format
- run: dotnet-format --folder --check
+ run: dotnet format OpenTelemetry.sln --no-restore --verify-no-changes
+ env:
+ ExposeExperimentalFeatures: true
diff --git a/.github/workflows/integration-md.yml b/.github/workflows/integration-md.yml
deleted file mode 100644
index 516bcbb7f53..00000000000
--- a/.github/workflows/integration-md.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-# Syntax: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
-# See also: https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks
-
-# Description: This workflow exists to unblock documentation-only PRs.
-
-# IMPORTANT: This workflow MUST use the same 'name' and 'matrix' as the non -md workflow.
-
-name: Integration Tests
-
-on:
- pull_request:
- branches: [ 'main*' ]
- paths:
- - '**.md'
-
-jobs:
- sql-test:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- version: [net6.0,net7.0]
- steps:
- - run: 'echo "No build required"'
-
- w3c-trace-context-test:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- version: [net6.0,net7.0]
- steps:
- - run: 'echo "No build required"'
-
- otlp-exporter-test:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- version: [net6.0,net7.0]
- steps:
- - run: 'echo "No build required"'
diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
deleted file mode 100644
index 3127c132789..00000000000
--- a/.github/workflows/integration.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-name: Integration Tests
-
-on:
- push:
- branches: [ 'main*' ]
- paths-ignore:
- - '**.md'
- pull_request:
- branches: [ 'main*' ]
- paths-ignore:
- - '**.md'
-
-jobs:
- w3c-trace-context-test:
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- matrix:
- version: [net6.0,net7.0]
- steps:
- - uses: actions/checkout@v3
-
- - name: Run W3C Trace Context docker-compose.integration
- 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
-
- otlp-exporter-test:
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- matrix:
- version: [net6.0,net7.0]
- steps:
- - uses: actions/checkout@v3
-
- - name: Run OTLP Exporter docker-compose.integration
- run: docker-compose --file=test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/docker-compose.yml --file=build/docker-compose.${{ matrix.version }}.yml --project-directory=. up --exit-code-from=tests --build
diff --git a/.github/workflows/markdownlint.yml b/.github/workflows/markdownlint.yml
index 643c5f6f1d8..462832652d5 100644
--- a/.github/workflows/markdownlint.yml
+++ b/.github/workflows/markdownlint.yml
@@ -1,25 +1,21 @@
-name: markdownlint
+# Called by ci.yml to perform markdown linting
+# See: https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow
+name: Lint - Markdown
on:
- push:
- branches: [ 'main*' ]
- paths:
- - '**.md'
- pull_request:
- branches: [ 'main*' ]
- paths:
- - '**.md'
+ workflow_call:
jobs:
- build:
+ run-markdownlint:
runs-on: ubuntu-latest
steps:
- name: check out code
- uses: actions/checkout@v3
-
- - name: install markdownlint-cli
- run: sudo npm install -g markdownlint-cli
+ uses: actions/checkout@v4
- name: run markdownlint
- run: markdownlint .
+ uses: DavidAnson/markdownlint-cli2-action@v15.0.0
+ with:
+ globs: |
+ **/*.md
+ !.github/**/*.md
diff --git a/.github/workflows/package-validation.yml b/.github/workflows/package-validation.yml
new file mode 100644
index 00000000000..5fc56716624
--- /dev/null
+++ b/.github/workflows/package-validation.yml
@@ -0,0 +1,41 @@
+# Called by ci.yml to perform package validation
+# See: https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow
+name: Package Validation
+
+on:
+ workflow_call:
+
+jobs:
+ run-package-validation-stable:
+ runs-on: windows-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ 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: Pack
+ run: dotnet pack OpenTelemetry.proj --configuration Release /p:EnablePackageValidation=true /p:ExposeExperimentalFeatures=false
+
+ run-package-validation-experimental:
+ runs-on: windows-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ 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: Pack
+ run: dotnet pack OpenTelemetry.proj --configuration Release /p:EnablePackageValidation=true /p:ExposeExperimentalFeatures=true
diff --git a/.github/workflows/publish-packages-1.0.yml b/.github/workflows/publish-packages-1.0.yml
index e479ec186b4..3fa6ad549a3 100644
--- a/.github/workflows/publish-packages-1.0.yml
+++ b/.github/workflows/publish-packages-1.0.yml
@@ -5,7 +5,7 @@
################### IMPORTANT ###################
#################################################
-name: Pack and publish to MyGet
+name: Build, pack, and publish to MyGet
on:
release:
@@ -14,26 +14,32 @@ on:
- cron: '0 0 * * *' # once in a day at 00:00
jobs:
- build-pack:
+ build-pack-publish:
runs-on: windows-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
- fetch-depth: 0 # fetching all
+ # 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
ref: ${{ github.ref || 'main' }}
- - name: Install dependencies
- run: dotnet restore
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v4
+
+ - name: dotnet restore
+ run: dotnet restore OpenTelemetry.proj -p:RunningDotNetPack=true
- name: dotnet build
- run: dotnet build --configuration Release --no-restore -p:Deterministic=true -p:BuildNumber=${{ github.run_number }}
+ run: dotnet build OpenTelemetry.proj --configuration Release --no-restore -p:Deterministic=true -p:BuildNumber=${{ github.run_number }} -p:RunningDotNetPack=true
- name: dotnet pack
- run: dotnet pack OpenTelemetry.proj --configuration Release --no-build
+ run: dotnet pack OpenTelemetry.proj --configuration Release --no-restore --no-build
- name: Publish Artifacts
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ github.ref_name }}-packages
path: '**/bin/**/*.*nupkg'
diff --git a/.github/workflows/sanitycheck.yml b/.github/workflows/sanitycheck.yml
index d452206e4bf..1c01e5a8235 100644
--- a/.github/workflows/sanitycheck.yml
+++ b/.github/workflows/sanitycheck.yml
@@ -1,18 +1,17 @@
-name: sanitycheck
+# Called by ci.yml to perform general linting
+# See: https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow
+name: Lint - Spelling & Encoding
on:
- push:
- branches: [ 'main*' ]
- pull_request:
- branches: [ 'main*' ]
+ workflow_call:
jobs:
- misspell:
+ run-misspell:
runs-on: ubuntu-latest
steps:
- name: check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: install misspell
run: |
@@ -22,12 +21,12 @@ jobs:
- name: run misspell
run: ./bin/misspell -error .
- encoding:
+ run-sanitycheck:
runs-on: ubuntu-latest
steps:
- name: check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: detect non-ASCII encoding and trailing space
run: python3 ./build/sanitycheck.py
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index 95287991b18..f5657aa9f54 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -10,7 +10,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v8
+ - uses: actions/stale@v9
with:
stale-pr-message: 'This PR was marked stale due to lack of activity and will be closed in 7 days. Commenting or Pushing will instruct the bot to automatically remove the label. This bot runs once per day.'
close-pr-message: 'Closed as inactive. Feel free to reopen if this PR is still being worked on.'
diff --git a/.github/workflows/verifyaotcompat.yml b/.github/workflows/verifyaotcompat.yml
new file mode 100644
index 00000000000..6a599bb5369
--- /dev/null
+++ b/.github/workflows/verifyaotcompat.yml
@@ -0,0 +1,27 @@
+# Called by ci.yml to perform AOT validation
+# See: https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow
+name: Publish & Verify AOT Compatibility
+
+on:
+ workflow_call:
+
+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 ]
+ version: [ net8.0 ]
+
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v4
+
+ - name: publish AOT testApp, assert static analysis warning count, and run the app
+ shell: pwsh
+ run: .\build\test-aot-compatibility.ps1 ${{ matrix.version }}
+
diff --git a/.gitignore b/.gitignore
index af409279810..e06229e460f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -348,3 +348,6 @@ ASALocalRun/
# Tempo files
tempo-data/
+
+# Coyote Rewrite Files
+rewrite.coyote.json
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c3ed947ad40..7a9590b068a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -44,7 +44,7 @@ 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 7.0+
+* .NET 8.0
### Linux or MacOS
@@ -232,7 +232,7 @@ 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**
+> [!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.
@@ -248,8 +248,34 @@ 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**
+> [!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
+2.0](./LICENSE.TXT).
+
+### Copying files from other projects
+
+OpenTelemetry .NET uses some files from other projects, typically where a binary
+distribution does not exist or would be inconvenient.
+
+The following rules must be followed for PRs that include files from another
+project:
+
+* The license of the file is
+ [permissive](https://en.wikipedia.org/wiki/Permissive_free_software_licence).
+
+* The license of the file is left intact.
+
+* The contribution is correctly attributed in the [3rd party
+ notices](./THIRD-PARTY-NOTICES.TXT) file in the repository, as needed.
+
+See
+[EnvironmentVariablesExtensions.cs](./src/Shared/EnvironmentVariables/EnvironmentVariablesExtensions.cs)
+for an example of a file copied from another project and attributed in the [3rd
+party notices](./THIRD-PARTY-NOTICES.TXT) file.
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 626320dbe96..4c50a651adc 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,29 +1,47 @@
true
+ 1.7.0
-
+
-
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
@@ -49,29 +64,51 @@
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LICENSE b/LICENSE.TXT
similarity index 100%
rename from LICENSE
rename to LICENSE.TXT
diff --git a/NuGet.config b/NuGet.config
index c821ba89f4e..ca17f1b8088 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -1,12 +1,9 @@
-
+
-
-
+
@@ -16,8 +13,8 @@
-
-
+
+
diff --git a/OpenTelemetry.proj b/OpenTelemetry.proj
index 8ceedc47bf5..410e43df0a1 100644
--- a/OpenTelemetry.proj
+++ b/OpenTelemetry.proj
@@ -1,19 +1,32 @@
-
+
-
-
-
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln
index 7c75ed0c9b2..b3a52180514 100644
--- a/OpenTelemetry.sln
+++ b/OpenTelemetry.sln
@@ -11,16 +11,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.dockerignore = .dockerignore
.editorconfig = .editorconfig
+ .gitignore = .gitignore
+ .github\workflows\ci-concurrency.yml = .github\workflows\ci-concurrency.yml
CONTRIBUTING.md = CONTRIBUTING.md
- Directory.Packages.props = Directory.Packages.props
- test\Directory.Packages.props = test\Directory.Packages.props
- examples\Directory.Packages.props = examples\Directory.Packages.props
- docs\Directory.Packages.props = docs\Directory.Packages.props
global.json = global.json
- LICENSE = LICENSE
+ LICENSE.TXT = LICENSE.TXT
NuGet.config = NuGet.config
OpenTelemetry.proj = OpenTelemetry.proj
README.md = README.md
+ THIRD-PARTY-NOTICES.TXT = THIRD-PARTY-NOTICES.TXT
VERSIONING.md = VERSIONING.md
EndProjectSection
EndProject
@@ -30,19 +29,22 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{7CB2F02E
build\Common.prod.props = build\Common.prod.props
build\Common.props = build\Common.props
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\finalize-publicapi.ps1 = build\finalize-publicapi.ps1
build\GlobalAttrExclusions.txt = build\GlobalAttrExclusions.txt
build\opentelemetry-icon-color.png = build\opentelemetry-icon-color.png
build\OpenTelemetry.prod.loose.ruleset = build\OpenTelemetry.prod.loose.ruleset
build\OpenTelemetry.prod.ruleset = build\OpenTelemetry.prod.ruleset
build\OpenTelemetry.test.ruleset = build\OpenTelemetry.test.ruleset
- build\PreBuild.ps1 = build\PreBuild.ps1
build\process-codecoverage.ps1 = build\process-codecoverage.ps1
build\RELEASING.md = build\RELEASING.md
build\stylecop.json = build\stylecop.json
+ build\test-aot-compatibility.ps1 = build\test-aot-compatibility.ps1
+ build\test-threadSafety.ps1 = build\test-threadSafety.ps1
build\xunit.runner.json = build\xunit.runner.json
EndProjectSection
EndProject
@@ -58,10 +60,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testdata", "testdata", "{77
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{E359BB2B-9AEC-497D-B321-7DF2450C3B8E}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Jaeger", "src\OpenTelemetry.Exporter.Jaeger\OpenTelemetry.Exporter.Jaeger.csproj", "{8D47E3CF-9AE3-42FE-9084-FEB72D9AD769}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Jaeger.Tests", "test\OpenTelemetry.Exporter.Jaeger.Tests\OpenTelemetry.Exporter.Jaeger.Tests.csproj", "{21E69213-72D5-453F-BD00-75EF36AC4965}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Shims.OpenTracing", "src\OpenTelemetry.Shims.OpenTracing\OpenTelemetry.Shims.OpenTracing.csproj", "{AAC408FE-40EF-4479-97D9-697F2C1A0B28}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Shims.OpenTracing.Tests", "test\OpenTelemetry.Shims.OpenTracing.Tests\OpenTelemetry.Shims.OpenTracing.Tests.csproj", "{49A7853F-5B6F-4B65-A781-7D29A1C92164}"
@@ -80,6 +78,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Open
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{F1D0972B-38CF-49C2-9F4B-4C5DE02FB71D}"
ProjectSection(SolutionItems) = preProject
+ .github\codecov.yml = .github\codecov.yml
.github\CODEOWNERS = .github\CODEOWNERS
.github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md
EndProjectSection
@@ -93,20 +92,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEM
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{E69578EB-B456-4062-A645-877CD964528B}"
ProjectSection(SolutionItems) = preProject
- .github\workflows\apicompatibility.yml = .github\workflows\apicompatibility.yml
- .github\workflows\ci-md.yml = .github\workflows\ci-md.yml
.github\workflows\ci.yml = .github\workflows\ci.yml
- .github\workflows\code-coverage.yml = .github\workflows\code-coverage.yml
.github\workflows\codeql-analysis.yml = .github\workflows\codeql-analysis.yml
+ .github\workflows\Component.BuildTest.yml = .github\workflows\Component.BuildTest.yml
+ .github\workflows\concurrency-tests.yml = .github\workflows\concurrency-tests.yml
.github\workflows\docfx.yml = .github\workflows\docfx.yml
- .github\workflows\dotnet-format-md.yml = .github\workflows\dotnet-format-md.yml
.github\workflows\dotnet-format.yml = .github\workflows\dotnet-format.yml
- .github\workflows\integration-md.yml = .github\workflows\integration-md.yml
- .github\workflows\integration.yml = .github\workflows\integration.yml
.github\workflows\markdownlint.yml = .github\workflows\markdownlint.yml
+ .github\workflows\package-validation.yml = .github\workflows\package-validation.yml
.github\workflows\publish-packages-1.0.yml = .github\workflows\publish-packages-1.0.yml
.github\workflows\sanitycheck.yml = .github\workflows\sanitycheck.yml
.github\workflows\stale.yml = .github\workflows\stale.yml
+ .github\workflows\verifyaotcompat.yml = .github\workflows\verifyaotcompat.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C1542297-8763-4DF4-957C-489ED771C21D}"
@@ -119,6 +116,7 @@ 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}") = "OpenTelemetry.Instrumentation.Grpc.Tests", "test\OpenTelemetry.Instrumentation.Grpc.Tests\OpenTelemetry.Instrumentation.Grpc.Tests.csproj", "{305E9DFD-E73B-4A28-8769-795C25551020}"
@@ -144,6 +142,7 @@ 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
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "trace", "trace", "{5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}"
@@ -155,7 +154,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "metrics", "metrics", "{3277
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "logs", "logs", "{3862190B-E2C5-418E-AFDC-DB281FB5C705}"
ProjectSection(SolutionItems) = preProject
- docs\logs\getting-started\README.md = docs\logs\getting-started\README.md
+ docs\logs\README.md = docs\logs\README.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MicroserviceExample", "MicroserviceExample", "{4D492D62-5150-45F9-817F-C99562E364E2}"
@@ -174,6 +173,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{CB401DF1-FF5C-4055-886E-1183E832B2D6}"
ProjectSection(SolutionItems) = preProject
docs\Directory.Build.props = docs\Directory.Build.props
+ docs\Directory.Packages.props = docs\Directory.Packages.props
docs\docfx.json = docs\docfx.json
docs\toc.yml = docs\toc.yml
EndProjectSection
@@ -184,7 +184,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Instrumentati
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Examples.GrpcService", "examples\GrpcService\Examples.GrpcService.csproj", "{DB942F5A-D571-4DEA-B1A7-B6BE0E24E6ED}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started", "docs\logs\getting-started\getting-started.csproj", "{B3F03725-23A0-4582-9526-F6A7E38F35CC}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started-console", "docs\logs\getting-started-console\getting-started-console.csproj", "{B3F03725-23A0-4582-9526-F6A7E38F35CC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.InMemory", "src\OpenTelemetry.Exporter.InMemory\OpenTelemetry.Exporter.InMemory.csproj", "{9BCEA68B-50E2-4A3A-93E6-B51AF612BCC1}"
EndProject
@@ -208,8 +208,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "customizing-the-sdk", "docs
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Tests.Stress", "test\OpenTelemetry.Tests.Stress\OpenTelemetry.Tests.Stress.csproj", "{2770158A-D220-414B-ABC6-179371323579}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "source-generation", "docs\logs\source-generation\source-generation.csproj", "{1F6CC903-04C9-4E7C-B388-C215C467BFB9}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started-prometheus-grafana", "docs\metrics\getting-started-prometheus-grafana\getting-started-prometheus-grafana.csproj", "{41B784AA-3301-4126-AF9F-1D59BD04B0BF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.SemanticConventions", "src\OpenTelemetry.SemanticConventions\OpenTelemetry.SemanticConventions.csproj", "{D4519DF6-CC72-4AC4-A851-E21383098D11}"
@@ -236,9 +234,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Tests.Stress.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApp.AspNetCore", "test\TestApp.AspNetCore\TestApp.AspNetCore.csproj", "{5FDAF679-DE5A-4C73-A49B-8ABCF2399229}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "redaction", "docs\logs\redaction\redaction.csproj", "{A2DF46DE-50D7-4887-8C9D-4BD79CA19FAA}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "complex-objects", "docs\logs\complex-objects\complex-objects.csproj", "{9AAB00EC-ED6F-4462-82DE-7D864A9DB6C5}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.OpenTelemetryProtocol.Grpc", "src\OpenTelemetry.Exporter.OpenTelemetryProtocol.Grpc\OpenTelemetry.Exporter.OpenTelemetryProtocol.Grpc.csproj", "{7263001A-49F8-4C3C-AAA8-998F12DAAF64}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "redaction", "docs\logs\redaction\redaction.csproj", "{A2DF46DE-50D7-4887-8C9D-4BD79CA19FAA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Console.Tests", "test\OpenTelemetry.Exporter.Console.Tests\OpenTelemetry.Exporter.Console.Tests.csproj", "{011E70E1-152A-47BB-AF83-12DD12B125ED}"
EndProject
@@ -256,28 +254,94 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tail-based-sampling-example
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "stratified-sampling-example", "docs\trace\stratified-sampling-example\stratified-sampling-example.csproj", "{9C99621C-343E-479C-A943-332DB6129B71}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Api.Tests", "test\OpenTelemetry.Api.Tests\OpenTelemetry.Api.Tests.csproj", "{FD8433F4-EDCF-475C-9B4A-625D3DE11671}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.AotCompatibility.TestApp", "test\OpenTelemetry.AotCompatibility.TestApp\OpenTelemetry.AotCompatibility.TestApp.csproj", "{13A59BD9-9475-4991-B74D-7C20F1C63409}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.AotCompatibility.Tests", "test\OpenTelemetry.AotCompatibility.Tests\OpenTelemetry.AotCompatibility.Tests.csproj", "{D438EF9C-7959-47A0-B2A2-DEBFCDC2A8DC}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "links-sampler", "docs\trace\links-based-sampler\links-sampler.csproj", "{62AF4BD3-DCAE-4D44-AA5B-991C1071166B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}"
ProjectSection(SolutionItems) = preProject
+ src\Shared\ActivityHelperExtensions.cs = src\Shared\ActivityHelperExtensions.cs
src\Shared\ActivityInstrumentationHelper.cs = src\Shared\ActivityInstrumentationHelper.cs
+ src\Shared\DiagnosticDefinitions.cs = src\Shared\DiagnosticDefinitions.cs
+ 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\RequestMethodHelper.cs = src\Shared\RequestMethodHelper.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
+ src\Shared\SpanHelper.cs = src\Shared\SpanHelper.cs
+ src\Shared\StatusHelper.cs = src\Shared\StatusHelper.cs
+ src\Shared\TagAndValueTransformer.cs = src\Shared\TagAndValueTransformer.cs
+ src\Shared\TagTransformer.cs = src\Shared\TagTransformer.cs
+ src\Shared\TagTransformerJsonHelper.cs = src\Shared\TagTransformerJsonHelper.cs
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DiagnosticSourceInstrumentation", "DiagnosticSourceInstrumentation", "{28F3EC79-660C-4659-8B73-F90DC1173316}"
ProjectSection(SolutionItems) = preProject
src\Shared\DiagnosticSourceInstrumentation\DiagnosticSourceListener.cs = src\Shared\DiagnosticSourceInstrumentation\DiagnosticSourceListener.cs
src\Shared\DiagnosticSourceInstrumentation\DiagnosticSourceSubscriber.cs = src\Shared\DiagnosticSourceInstrumentation\DiagnosticSourceSubscriber.cs
- src\Shared\DiagnosticSourceInstrumentation\InstrumentationEventSource.cs = src\Shared\DiagnosticSourceInstrumentation\InstrumentationEventSource.cs
src\Shared\DiagnosticSourceInstrumentation\ListenerHandler.cs = src\Shared\DiagnosticSourceInstrumentation\ListenerHandler.cs
src\Shared\DiagnosticSourceInstrumentation\PropertyFetcher.cs = src\Shared\DiagnosticSourceInstrumentation\PropertyFetcher.cs
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EnvironmentVariables", "EnvironmentVariables", "{6D4B4FB2-0A8A-4044-948B-C063FD340439}"
+ ProjectSection(SolutionItems) = preProject
+ src\Shared\EnvironmentVariables\EnvironmentVariablesConfigurationProvider.cs = src\Shared\EnvironmentVariables\EnvironmentVariablesConfigurationProvider.cs
+ src\Shared\EnvironmentVariables\EnvironmentVariablesConfigurationSource.cs = src\Shared\EnvironmentVariables\EnvironmentVariablesConfigurationSource.cs
+ src\Shared\EnvironmentVariables\EnvironmentVariablesExtensions.cs = src\Shared\EnvironmentVariables\EnvironmentVariablesExtensions.cs
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Options", "Options", "{494902DD-C63F-48E0-BED3-B58EFB4051C8}"
+ ProjectSection(SolutionItems) = preProject
+ src\Shared\Options\ConfigurationExtensions.cs = src\Shared\Options\ConfigurationExtensions.cs
+ src\Shared\Options\DelegatingOptionsFactory.cs = src\Shared\Options\DelegatingOptionsFactory.cs
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shims", "Shims", "{A0CB9A10-F22D-4E66-A449-74B3D0361A9C}"
+ ProjectSection(SolutionItems) = preProject
+ src\Shared\Shims\IsExternalInit.cs = src\Shared\Shims\IsExternalInit.cs
+ src\Shared\Shims\NullableAttributes.cs = src\Shared\Shims\NullableAttributes.cs
+ src\Shared\Shims\UnconditionalSuppressMessageAttribute.cs = src\Shared\Shims\UnconditionalSuppressMessageAttribute.cs
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Api.Tests", "test\OpenTelemetry.Api.Tests\OpenTelemetry.Api.Tests.csproj", "{777C04B8-1BD5-43D7-B3CD-D2189DFABCF3}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Metrics", "Metrics", "{1C459B5B-C702-46FF-BF1A-EE795E420FFA}"
+ ProjectSection(SolutionItems) = preProject
+ src\Shared\Metrics\Base2ExponentialBucketHistogramHelper.cs = src\Shared\Metrics\Base2ExponentialBucketHistogramHelper.cs
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started-aspnetcore", "docs\logs\getting-started-aspnetcore\getting-started-aspnetcore.csproj", "{99B4D965-8782-4694-8DFA-B7A3630CEF60}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "links-creation", "docs\trace\links-creation-with-new-activities\links-creation.csproj", "{B4856711-6D4C-4246-A686-49458D4C1301}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "diagnostics", "diagnostics", "{52AF6D7D-9E66-4234-9A2C-5D16C6F22B40}"
+ ProjectSection(SolutionItems) = preProject
+ docs\diagnostics\README.md = docs\diagnostics\README.md
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "experimental-apis", "experimental-apis", "{17A22B0E-6EC3-4A39-B955-0A486AD06699}"
+ 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\OTEL1002.md = docs\diagnostics\experimental-apis\OTEL1002.md
+ docs\diagnostics\experimental-apis\OTEL1003.md = docs\diagnostics\experimental-apis\OTEL1003.md
+ docs\diagnostics\experimental-apis\README.md = docs\diagnostics\experimental-apis\README.md
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "resources", "resources", "{A115CE4C-71A8-4B95-96A5-C1DF46FD94C2}"
+ ProjectSection(SolutionItems) = preProject
+ docs\resources\README.md = docs\resources\README.md
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "extending-the-sdk", "docs\resources\extending-the-sdk\extending-the-sdk.csproj", "{7BE494FC-4B0D-4340-A62A-9C9F3E7389FE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dedicated-pipeline", "docs\logs\dedicated-pipeline\dedicated-pipeline.csproj", "{19545B37-8518-4BDD-AD49-00C031FB3C2A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -308,14 +372,6 @@ Global
{2A47F6A8-63E5-4237-8046-94CAF321E797}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A47F6A8-63E5-4237-8046-94CAF321E797}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A47F6A8-63E5-4237-8046-94CAF321E797}.Release|Any CPU.Build.0 = Release|Any CPU
- {8D47E3CF-9AE3-42FE-9084-FEB72D9AD769}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8D47E3CF-9AE3-42FE-9084-FEB72D9AD769}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8D47E3CF-9AE3-42FE-9084-FEB72D9AD769}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8D47E3CF-9AE3-42FE-9084-FEB72D9AD769}.Release|Any CPU.Build.0 = Release|Any CPU
- {21E69213-72D5-453F-BD00-75EF36AC4965}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {21E69213-72D5-453F-BD00-75EF36AC4965}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {21E69213-72D5-453F-BD00-75EF36AC4965}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {21E69213-72D5-453F-BD00-75EF36AC4965}.Release|Any CPU.Build.0 = Release|Any CPU
{AAC408FE-40EF-4479-97D9-697F2C1A0B28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AAC408FE-40EF-4479-97D9-697F2C1A0B28}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AAC408FE-40EF-4479-97D9-697F2C1A0B28}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -336,10 +392,6 @@ Global
{A38AC295-2745-4B85-8B6B-DCA864CEDD5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A38AC295-2745-4B85-8B6B-DCA864CEDD5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A38AC295-2745-4B85-8B6B-DCA864CEDD5B}.Release|Any CPU.Build.0 = Release|Any CPU
- {56A34828-621A-478B-A0B8-C065FE938383}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {56A34828-621A-478B-A0B8-C065FE938383}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {56A34828-621A-478B-A0B8-C065FE938383}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {56A34828-621A-478B-A0B8-C065FE938383}.Release|Any CPU.Build.0 = Release|Any CPU
{1AFFF251-3B0C-47CA-BE94-937083732C0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1AFFF251-3B0C-47CA-BE94-937083732C0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1AFFF251-3B0C-47CA-BE94-937083732C0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -356,10 +408,6 @@ Global
{305E9DFD-E73B-4A28-8769-795C25551020}.Debug|Any CPU.Build.0 = Debug|Any CPU
{305E9DFD-E73B-4A28-8769-795C25551020}.Release|Any CPU.ActiveCfg = Release|Any CPU
{305E9DFD-E73B-4A28-8769-795C25551020}.Release|Any CPU.Build.0 = Release|Any CPU
- {98F9556B-116F-49B5-9211-BB1D418446FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {98F9556B-116F-49B5-9211-BB1D418446FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {98F9556B-116F-49B5-9211-BB1D418446FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {98F9556B-116F-49B5-9211-BB1D418446FF}.Release|Any CPU.Build.0 = Release|Any CPU
{FF3E6E08-E8E4-4523-B526-847CD989279F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF3E6E08-E8E4-4523-B526-847CD989279F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF3E6E08-E8E4-4523-B526-847CD989279F}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -464,10 +512,6 @@ Global
{2770158A-D220-414B-ABC6-179371323579}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2770158A-D220-414B-ABC6-179371323579}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2770158A-D220-414B-ABC6-179371323579}.Release|Any CPU.Build.0 = Release|Any CPU
- {1F6CC903-04C9-4E7C-B388-C215C467BFB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1F6CC903-04C9-4E7C-B388-C215C467BFB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1F6CC903-04C9-4E7C-B388-C215C467BFB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1F6CC903-04C9-4E7C-B388-C215C467BFB9}.Release|Any CPU.Build.0 = Release|Any CPU
{41B784AA-3301-4126-AF9F-1D59BD04B0BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{41B784AA-3301-4126-AF9F-1D59BD04B0BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41B784AA-3301-4126-AF9F-1D59BD04B0BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -520,14 +564,14 @@ Global
{5FDAF679-DE5A-4C73-A49B-8ABCF2399229}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FDAF679-DE5A-4C73-A49B-8ABCF2399229}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FDAF679-DE5A-4C73-A49B-8ABCF2399229}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9AAB00EC-ED6F-4462-82DE-7D864A9DB6C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9AAB00EC-ED6F-4462-82DE-7D864A9DB6C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9AAB00EC-ED6F-4462-82DE-7D864A9DB6C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9AAB00EC-ED6F-4462-82DE-7D864A9DB6C5}.Release|Any CPU.Build.0 = Release|Any CPU
{A2DF46DE-50D7-4887-8C9D-4BD79CA19FAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A2DF46DE-50D7-4887-8C9D-4BD79CA19FAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A2DF46DE-50D7-4887-8C9D-4BD79CA19FAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A2DF46DE-50D7-4887-8C9D-4BD79CA19FAA}.Release|Any CPU.Build.0 = Release|Any CPU
- {7263001A-49F8-4C3C-AAA8-998F12DAAF64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7263001A-49F8-4C3C-AAA8-998F12DAAF64}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7263001A-49F8-4C3C-AAA8-998F12DAAF64}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7263001A-49F8-4C3C-AAA8-998F12DAAF64}.Release|Any CPU.Build.0 = Release|Any CPU
{011E70E1-152A-47BB-AF83-12DD12B125ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{011E70E1-152A-47BB-AF83-12DD12B125ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{011E70E1-152A-47BB-AF83-12DD12B125ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -560,22 +604,34 @@ Global
{9C99621C-343E-479C-A943-332DB6129B71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C99621C-343E-479C-A943-332DB6129B71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C99621C-343E-479C-A943-332DB6129B71}.Release|Any CPU.Build.0 = Release|Any CPU
- {FD8433F4-EDCF-475C-9B4A-625D3DE11671}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FD8433F4-EDCF-475C-9B4A-625D3DE11671}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FD8433F4-EDCF-475C-9B4A-625D3DE11671}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {FD8433F4-EDCF-475C-9B4A-625D3DE11671}.Release|Any CPU.Build.0 = Release|Any CPU
{13A59BD9-9475-4991-B74D-7C20F1C63409}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13A59BD9-9475-4991-B74D-7C20F1C63409}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13A59BD9-9475-4991-B74D-7C20F1C63409}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13A59BD9-9475-4991-B74D-7C20F1C63409}.Release|Any CPU.Build.0 = Release|Any CPU
- {D438EF9C-7959-47A0-B2A2-DEBFCDC2A8DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D438EF9C-7959-47A0-B2A2-DEBFCDC2A8DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D438EF9C-7959-47A0-B2A2-DEBFCDC2A8DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D438EF9C-7959-47A0-B2A2-DEBFCDC2A8DC}.Release|Any CPU.Build.0 = Release|Any CPU
{62AF4BD3-DCAE-4D44-AA5B-991C1071166B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{62AF4BD3-DCAE-4D44-AA5B-991C1071166B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{62AF4BD3-DCAE-4D44-AA5B-991C1071166B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{62AF4BD3-DCAE-4D44-AA5B-991C1071166B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {777C04B8-1BD5-43D7-B3CD-D2189DFABCF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {777C04B8-1BD5-43D7-B3CD-D2189DFABCF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {777C04B8-1BD5-43D7-B3CD-D2189DFABCF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {777C04B8-1BD5-43D7-B3CD-D2189DFABCF3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {99B4D965-8782-4694-8DFA-B7A3630CEF60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {99B4D965-8782-4694-8DFA-B7A3630CEF60}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {99B4D965-8782-4694-8DFA-B7A3630CEF60}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {99B4D965-8782-4694-8DFA-B7A3630CEF60}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B4856711-6D4C-4246-A686-49458D4C1301}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B4856711-6D4C-4246-A686-49458D4C1301}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B4856711-6D4C-4246-A686-49458D4C1301}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B4856711-6D4C-4246-A686-49458D4C1301}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7BE494FC-4B0D-4340-A62A-9C9F3E7389FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7BE494FC-4B0D-4340-A62A-9C9F3E7389FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7BE494FC-4B0D-4340-A62A-9C9F3E7389FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7BE494FC-4B0D-4340-A62A-9C9F3E7389FE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {19545B37-8518-4BDD-AD49-00C031FB3C2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {19545B37-8518-4BDD-AD49-00C031FB3C2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {19545B37-8518-4BDD-AD49-00C031FB3C2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {19545B37-8518-4BDD-AD49-00C031FB3C2A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -607,11 +663,11 @@ Global
{0C3E7D40-E0B3-4B77-8139-0E85C3600688} = {3277B1C0-BDFE-4460-9B0D-D9A661FB48DB}
{1F9D7748-D099-4E25-97F5-9C969D6FF969} = {3277B1C0-BDFE-4460-9B0D-D9A661FB48DB}
{81234AFA-B4E7-4D0D-AB97-FD559C78EDA2} = {3277B1C0-BDFE-4460-9B0D-D9A661FB48DB}
- {1F6CC903-04C9-4E7C-B388-C215C467BFB9} = {3862190B-E2C5-418E-AFDC-DB281FB5C705}
{41B784AA-3301-4126-AF9F-1D59BD04B0BF} = {3277B1C0-BDFE-4460-9B0D-D9A661FB48DB}
{6C7A1595-36D6-4229-BBB5-5A6B5791791D} = {3862190B-E2C5-418E-AFDC-DB281FB5C705}
{9A07D215-90AC-4BAF-BCDB-73D74FD3A5C5} = {3862190B-E2C5-418E-AFDC-DB281FB5C705}
{5FDAF679-DE5A-4C73-A49B-8ABCF2399229} = {77C7929A-2EED-4AA6-8705-B5C443C8AA0F}
+ {9AAB00EC-ED6F-4462-82DE-7D864A9DB6C5} = {3862190B-E2C5-418E-AFDC-DB281FB5C705}
{A2DF46DE-50D7-4887-8C9D-4BD79CA19FAA} = {3862190B-E2C5-418E-AFDC-DB281FB5C705}
{DEDE8442-03CA-48CF-99B9-EA224D89D148} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}
{EF4F6280-14D1-49D4-8095-1AC36E169AA8} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}
@@ -620,6 +676,17 @@ Global
{9C99621C-343E-479C-A943-332DB6129B71} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}
{62AF4BD3-DCAE-4D44-AA5B-991C1071166B} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}
{28F3EC79-660C-4659-8B73-F90DC1173316} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
+ {6D4B4FB2-0A8A-4044-948B-C063FD340439} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
+ {494902DD-C63F-48E0-BED3-B58EFB4051C8} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
+ {A0CB9A10-F22D-4E66-A449-74B3D0361A9C} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
+ {1C459B5B-C702-46FF-BF1A-EE795E420FFA} = {A49299FB-C5CD-4E0E-B7E1-B7867BBD67CC}
+ {99B4D965-8782-4694-8DFA-B7A3630CEF60} = {3862190B-E2C5-418E-AFDC-DB281FB5C705}
+ {B4856711-6D4C-4246-A686-49458D4C1301} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}
+ {52AF6D7D-9E66-4234-9A2C-5D16C6F22B40} = {7C87CAF9-79D7-4C26-9FFB-F3F1FB6911F1}
+ {17A22B0E-6EC3-4A39-B955-0A486AD06699} = {52AF6D7D-9E66-4234-9A2C-5D16C6F22B40}
+ {A115CE4C-71A8-4B95-96A5-C1DF46FD94C2} = {7C87CAF9-79D7-4C26-9FFB-F3F1FB6911F1}
+ {7BE494FC-4B0D-4340-A62A-9C9F3E7389FE} = {A115CE4C-71A8-4B95-96A5-C1DF46FD94C2}
+ {19545B37-8518-4BDD-AD49-00C031FB3C2A} = {3862190B-E2C5-418E-AFDC-DB281FB5C705}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521}
diff --git a/README.md b/README.md
index 308ba716c9a..d4cf02381b1 100644
--- a/README.md
+++ b/README.md
@@ -19,16 +19,7 @@ files.
## Project Status
-| Signal | Status |
-| ------- | ---------- |
-| Logs | Stable* |
-| Metrics | Stable |
-| Traces | Stable |
-
-*While the `OpenTelemetryLoggerProvider` (i.e integration with `ILogger`) is
- stable, the [OTLP Exporter for
- Logs](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry.Exporter.OpenTelemetryProtocol#enable-log-exporter)
- is still non-stable.
+**Stable** across all 3 signals i.e. `Logs`, `Metrics`, and `Traces`.
See [Spec Compliance
Matrix](https://github.com/open-telemetry/opentelemetry-specification/blob/main/spec-compliance-matrix.md)
@@ -39,10 +30,14 @@ repo.
If you are new here, please read the getting started docs:
-* [logs](./docs/logs/getting-started/README.md)
-* metrics: [ASP.NET Core](./docs/metrics/getting-started-aspnetcore/README.md) |
+* [Logs](./docs/logs/README.md): [ASP.NET
+ Core](./docs/logs/getting-started-aspnetcore/README.md) |
+ [Console](./docs/logs/getting-started-console/README.md)
+* [Metrics](./docs/metrics/README.md): [ASP.NET
+ Core](./docs/metrics/getting-started-aspnetcore/README.md) |
[Console](./docs/metrics/getting-started-console/README.md)
-* traces: [ASP.NET Core](./docs/trace/getting-started-aspnetcore/README.md) |
+* [Traces](./docs/trace/README.md): [ASP.NET
+ Core](./docs/trace/getting-started-aspnetcore/README.md) |
[Console](./docs/trace/getting-started-console/README.md)
This repository includes multiple installable components, available on
@@ -60,16 +55,18 @@ Here are the [instrumentation
libraries](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#instrumentation-library):
* [ASP.NET Core](./src/OpenTelemetry.Instrumentation.AspNetCore/README.md)
-* [Grpc.Net.Client](./src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md)
-* [HTTP clients](./src/OpenTelemetry.Instrumentation.Http/README.md)
-* [SQL client](./src/OpenTelemetry.Instrumentation.SqlClient/README.md)
+* gRPC client:
+ [Grpc.Net.Client](./src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md)
+* HTTP clients: [System.Net.Http.HttpClient and
+ System.Net.HttpWebRequest](./src/OpenTelemetry.Instrumentation.Http/README.md)
+* SQL clients: [Microsoft.Data.SqlClient and
+ System.Data.SqlClient](./src/OpenTelemetry.Instrumentation.SqlClient/README.md)
Here are the [exporter
libraries](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#exporter-library):
* [Console](./src/OpenTelemetry.Exporter.Console/README.md)
* [In-memory](./src/OpenTelemetry.Exporter.InMemory/README.md)
-* [Jaeger](./src/OpenTelemetry.Exporter.Jaeger/README.md)
* [OTLP](./src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md)
(OpenTelemetry Protocol)
* [Prometheus AspNetCore](./src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md)
@@ -108,7 +105,7 @@ extension scenarios:
See [CONTRIBUTING.md](CONTRIBUTING.md)
-We meet weekly on Tuesdays, and the time of the meeting alternates between 11AM
+We meet weekly on Tuesdays, and the time of the meeting alternates between 9AM
PT and 4PM PT. The meeting is subject to change depending on contributors'
availability. Check the [OpenTelemetry community
calendar](https://calendar.google.com/calendar/embed?src=google.com_b79e3e90j7bbsa2n2p5an5lf60%40group.calendar.google.com)
@@ -119,6 +116,11 @@ doc](https://docs.google.com/document/d/1yjjD6aBcLxlRazYrawukDgrhZMObwHARJbB9glW
If you have trouble accessing the doc, please get in touch on
[Slack](https://cloud-native.slack.com/archives/C01N3BC2W7Q).
+The meeting is open for all to join. We invite everyone to join our meeting,
+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)):
@@ -131,9 +133,13 @@ If you have trouble accessing the doc, please get in touch on
* [Cijo Thomas](https://github.com/cijothomas), Microsoft
* [Reiley Yang](https://github.com/reyang), Microsoft
-* [Robert Pająk](https://github.com/pellared), Splunk
* [Vishwesh Bankwar](https://github.com/vishweshbankwar), Microsoft
+[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)):
+
+* [Martin Thwaites](https://github.com/martinjt), Honeycomb
+
[Emeritus
Maintainer/Approver/Triager](https://github.com/open-telemetry/community/blob/main/community-membership.md#emeritus-maintainerapprovertriager):
@@ -142,6 +148,7 @@ Maintainer/Approver/Triager](https://github.com/open-telemetry/community/blob/ma
* [Liudmila Molkova](https://github.com/lmolkova)
* [Mike Goldsmith](https://github.com/MikeGoldsmith)
* [Paulo Janotti](https://github.com/pjanotti)
+* [Robert Pająk](https://github.com/pellared)
* [Sergey Kanzhelev](https://github.com/SergeyKanzhelev)
* [Victor Lu](https://github.com/victlu)
@@ -151,20 +158,21 @@ Maintainer/Approver/Triager](https://github.com/open-telemetry/community/blob/ma
## Release Schedule
-Only the [core components](./VERSIONING.md#core-components) of the repo have
-released a stable version. Components which are marked
-[pre-release](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/VERSIONING.md#pre-releases),
-are still work in progress and can undergo many breaking changes before stable
-release.
+See the [project
+milestones](https://github.com/open-telemetry/opentelemetry-dotnet/milestones)
+for details on upcoming releases. The dates and features described in issues and
+milestones are estimates, and subject to change.
See the [release
notes](https://github.com/open-telemetry/opentelemetry-dotnet/releases) for
existing releases.
-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.
+> [!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.
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).
diff --git a/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT
new file mode 100644
index 00000000000..b65f5723308
--- /dev/null
+++ b/THIRD-PARTY-NOTICES.TXT
@@ -0,0 +1,31 @@
+OpenTelemetry .NET uses third-party libraries or other resources that may be
+distributed under licenses different than the OpenTelemetry .NET software.
+
+The attached notices are provided for information only.
+
+License notice for .NET
+-------------------------------
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+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.
diff --git a/VERSIONING.md b/VERSIONING.md
index 507d877b460..cb70a80cd57 100644
--- a/VERSIONING.md
+++ b/VERSIONING.md
@@ -28,7 +28,7 @@ versions [1.1.0, 2.0.0).
Core components refer to the set of components which are required as per the
spec. This includes API, SDK, and exporters which are required by the
-specification. These exporters are OTLP, Jaeger, Zipkin, Console and InMemory.
+specification. These exporters are OTLP, Zipkin, Console and InMemory.
The core components are always versioned and released together. For example, if
Zipkin exporter has a bug fix and is released as 1.0.1, then all other core
diff --git a/build/Common.nonprod.props b/build/Common.nonprod.props
index cdcba2f64b6..7f617c45496 100644
--- a/build/Common.nonprod.props
+++ b/build/Common.nonprod.props
@@ -7,6 +7,10 @@
$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), 'OpenTelemetry.sln'))\build\OpenTelemetry.test.ruleset
+
+ net8.0
+
+
true
@@ -15,8 +19,6 @@
PreserveNewest
-
-
@@ -28,4 +30,18 @@
+
+
+
+
+ <_SkipTests>true
+ false
+
+
+
+
diff --git a/build/Common.prod.props b/build/Common.prod.props
index e6d3e2f9220..95c9f0c63ea 100644
--- a/build/Common.prod.props
+++ b/build/Common.prod.props
@@ -1,98 +1,98 @@
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
-
- All
-
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <_ReferencePathDirectories Include="@(ReferencePath -> '%(RootDir)%(Directory)')" />
-
-
- @(_ReferencePathDirectories->Distinct())
-
-
-
$(MSBuildThisFileDirectory)/OpenTelemetry.prod.ruleset
- $(NoWarn),1573,1712
- $(Build_ArtifactStagingDirectory)
- true
-
- $(RepoRoot)\build\GlobalAttrExclusions.txt
+ true
+ false
-
-
- $(MinVerMajor).$(MinVerMinor).$(MinVerPatch).$(BuildNumber)
-
-
-
-
+ githttps://github.com/open-telemetry/opentelemetry-dotnet
- Observability;OpenTelemetry;Monitoring;Telemetry;Tracing
+ Observability;OpenTelemetry;Monitoring;Telemetry;Tracing;Metrics;Loggingopentelemetry-icon-color.pnghttps://opentelemetry.io
- Apache-2.0OpenTelemetry Authors
+ Copyright The OpenTelemetry Authors
+ $(Build_ArtifactStagingDirectory)
+ true
+ snupkg
+ Apache-2.0true
+ $(RepoRoot)\LICENSE.TXT
+ $(RepoRoot)\THIRD-PARTY-NOTICES.TXT
-
-
-
-
-
+ truetrue
- true
- snupkg
+ true
-
-
+
+
+
+
-
- true
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ $(MinVerMajor).$(MinVerMinor).$(MinVerPatch).$(BuildNumber)
+ true
+ false
+
+
+
+
+
+
+
+
+
+ $(DefineConstants);EXPOSE_EXPERIMENTAL_FEATURES
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/Common.props b/build/Common.props
index c2538e31727..d54badad2c6 100644
--- a/build/Common.props
+++ b/build/Common.props
@@ -1,17 +1,45 @@
- 10.0
+ latesttrue$([System.IO.Directory]::GetParent($(MSBuildThisFileDirectory)).Parent.FullName)$(MSBuildThisFileDirectory)debug.snk$(DefineConstants);SIGNEDtrue
+ trueenableenable
+
+ $(NoWarn);OTEL1000;OTEL1001;OTEL1002;OTEL1003
+
+
+ net462
+ net481;net48;net472;net471;net47;net462
+
+
+ net8.0;net6.0;netstandard2.0;$(NetFrameworkMinimumSupportedVersion)
+ net8.0;net6.0;netstandard2.1;netstandard2.0;$(NetFrameworkMinimumSupportedVersion)
+ net8.0;net7.0;net6.0;netstandard2.0
+ net8.0;net6.0;netstandard2.1;netstandard2.0
+ net8.0;net6.0
+
+
+ net8.0;net7.0;net6.0
+ net8.0
+ net8.0;net7.0;net6.0
+
+ $(TargetFrameworksForDocs);$(NetFrameworkSupportedVersions)
+
+ net8.0;net7.0;net6.0
+
+ $(TargetFrameworksForTests);$(NetFrameworkMinimumSupportedVersion)
+
+
+
fulltrue
@@ -19,14 +47,7 @@
true
-
-
-
-
- 1.5.1
+ true
@@ -35,31 +56,24 @@
-
- All
-
-
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/build/InstrumentationLibraries.proj b/build/InstrumentationLibraries.proj
new file mode 100644
index 00000000000..4a2ee62aaa4
--- /dev/null
+++ b/build/InstrumentationLibraries.proj
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/PreBuild.ps1 b/build/PreBuild.ps1
deleted file mode 100644
index 988e5b9bbc6..00000000000
--- a/build/PreBuild.ps1
+++ /dev/null
@@ -1,46 +0,0 @@
-param(
- [string]$package,
- [string]$version,
- [string]$workDir = ".\LastMajorVersionBinaries"
-)
-
-if (-Not (Test-Path $workDir))
-{
- Write-Host "Working directory for compatibility check packages '$workDir' not found, creating..."
- New-Item -Path $workDir -ItemType "directory" | Out-Null
-}
-
-if (Test-Path -Path "$workDir\$package.$version.zip")
-{
- Write-Host "Previous package $package@$version already downloaded for compatibility check"
-}
-else
-{
- Write-Host "Retrieving package $package@$version for compatibility check"
- try
- {
- $Response = Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/$package/$version -Outfile "$workDir\$package.$version.zip"
- }
- catch
- {
- $StatusCode = $_.Exception.Response.StatusCode.value__
- throw "Error downloading the package $package@$version. Status code of the received response: $StatusCode"
- }
-}
-
-if (Test-Path -Path "$workDir\$package\$version\lib")
-{
- Write-Host "Previous package $package@$version already extracted to '$workDir\$package\$version\lib'"
-}
-else
-{
- Write-Host "Extracting package $package@$version from '$workDir\$package.$version.zip' to '$workDir\$package\$version' for compatibility check"
- try
- {
- Expand-Archive -LiteralPath "$workDir\$package.$version.zip" -DestinationPath "$workDir\$package\$version" -Force
- }
- catch
- {
- throw "Error extracting $package@$version.zip"
- }
-}
diff --git a/build/RELEASING.md b/build/RELEASING.md
index cbc5e825bbf..9d942f92dc7 100644
--- a/build/RELEASING.md
+++ b/build/RELEASING.md
@@ -84,7 +84,16 @@ Only for Maintainers.
git push origin 1.0.0-rc9.7
```
- If releasing both, push both tags above.
+ If releasing only a particular non-core component which has a dedicated
+ MinverTagPrefix such as AspNetCore instrumentation, only add and push the
+ tag with that particular prefix. For example:
+
+ ```sh
+ git tag -a Instrumentation.AspNetCore-1.6.0 -m "1.6.0 of AspNetCore instrumentation library"
+ git push origin Instrumentation.AspNetCore-1.6.0
+ ```
+
+ If releasing multiple kinds of components, push both tags for each of them.
7. Go to the [list of
tags](https://github.com/open-telemetry/opentelemetry-dotnet/tags)
@@ -128,4 +137,5 @@ Only for Maintainers.
by sending a Pull Request.
17. If a new stable version of the core packages were released, update
- `OTelPreviousStableVer` in Common.props to the just released stable version.
+ `OTelLatestStableVer` in Directory.Packages.props to the just released
+ stable version.
diff --git a/build/docker-compose.net6.0.yml b/build/docker-compose.net6.0.yml
index 0d592597539..099f1007277 100644
--- a/build/docker-compose.net6.0.yml
+++ b/build/docker-compose.net6.0.yml
@@ -5,5 +5,5 @@ services:
build:
args:
PUBLISH_FRAMEWORK: net6.0
- TEST_SDK_VERSION: 6.0
- BUILD_SDK_VERSION: 7.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
index d79fa366bb8..48a2589cda9 100644
--- a/build/docker-compose.net7.0.yml
+++ b/build/docker-compose.net7.0.yml
@@ -5,5 +5,5 @@ services:
build:
args:
PUBLISH_FRAMEWORK: net7.0
- TEST_SDK_VERSION: 7.0
- BUILD_SDK_VERSION: 7.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
new file mode 100644
index 00000000000..a5ac999e43e
--- /dev/null
+++ b/build/docker-compose.net8.0.yml
@@ -0,0 +1,9 @@
+version: '3.7'
+
+services:
+ tests:
+ build:
+ args:
+ PUBLISH_FRAMEWORK: net8.0
+ TEST_SDK_VERSION: "8.0"
+ BUILD_SDK_VERSION: "8.0"
diff --git a/build/process-codecoverage.ps1 b/build/process-codecoverage.ps1
deleted file mode 100644
index 6d14a4e973a..00000000000
--- a/build/process-codecoverage.ps1
+++ /dev/null
@@ -1,16 +0,0 @@
-$rootDirectory = Split-Path $PSScriptRoot -Parent
-[xml]$commonProps = Get-Content -Path $rootDirectory\Directory.Packages.props
-
-$packages = $commonProps.Project.ItemGroup.PackageVersion
-$microsoftCodeCoveragePkgVer = [string]($packages | Where-Object {$_.Include -eq "Microsoft.CodeCoverage"}).Version # This is collected in the format: "[17.4.1]"
-$microsoftCodeCoveragePkgVer = $microsoftCodeCoveragePkgVer.Trim();
-$microsoftCodeCoveragePkgVer = $microsoftCodeCoveragePkgVer.SubString(1, $microsoftCodeCoveragePkgVer.Length - 2) # Removing square brackets
-
-$files = Get-ChildItem "TestResults" -Filter "*.coverage" -Recurse
-Write-Host $env:USERPROFILE
-foreach ($file in $files)
-{
- $command = $env:USERPROFILE+ '\.nuget\packages\microsoft.codecoverage\' + $microsoftCodeCoveragePkgVer + '\build\netstandard2.0\CodeCoverage\CodeCoverage.exe analyze /output:' + $file.DirectoryName + '\' + $file.Name + '.xml '+ $file.FullName
- Write-Host $command
- Invoke-Expression $command
-}
diff --git a/build/stylecop.json b/build/stylecop.json
index 064a1ef5a76..6d32e9d35e1 100644
--- a/build/stylecop.json
+++ b/build/stylecop.json
@@ -2,8 +2,8 @@
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
"settings": {
"documentationRules": {
- "companyName": "OpenTelemetry Authors",
- "copyrightText": "Copyright The OpenTelemetry Authors\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License."
+ "copyrightText": "Copyright The OpenTelemetry Authors\nSPDX-License-Identifier: Apache-2.0",
+ "xmlHeader": false
},
"orderingRules": {
"usingDirectivesPlacement": "outsideNamespace"
diff --git a/build/test-aot-compatibility.ps1 b/build/test-aot-compatibility.ps1
new file mode 100644
index 00000000000..37483488f50
--- /dev/null
+++ b/build/test-aot-compatibility.ps1
@@ -0,0 +1,41 @@
+param([string]$targetNetFramework)
+
+$rootDirectory = Split-Path $PSScriptRoot -Parent
+$publishOutput = dotnet publish $rootDirectory/test/OpenTelemetry.AotCompatibility.TestApp/OpenTelemetry.AotCompatibility.TestApp.csproj -nodeReuse:false /p:UseSharedCompilation=false /p:ExposeExperimentalFeatures=true
+
+$actualWarningCount = 0
+
+foreach ($line in $($publishOutput -split "`r`n"))
+{
+ if ($line -like "*analysis warning IL*")
+ {
+ Write-Host $line
+
+ $actualWarningCount += 1
+ }
+}
+
+pushd $rootDirectory/test/OpenTelemetry.AotCompatibility.TestApp/bin/Release/$targetNetFramework/linux-x64
+
+Write-Host "Executing test App..."
+./OpenTelemetry.AotCompatibility.TestApp
+Write-Host "Finished executing test App"
+
+if ($LastExitCode -ne 0)
+{
+ Write-Host "There was an error while executing AotCompatibility Test App. LastExitCode is:", $LastExitCode
+}
+
+popd
+
+Write-Host "Actual warning count is:", $actualWarningCount
+$expectedWarningCount = 0
+
+$testPassed = 0
+if ($actualWarningCount -ne $expectedWarningCount)
+{
+ $testPassed = 1
+ Write-Host "Actual warning count:", actualWarningCount, "is not as expected. Expected warning count is:", $expectedWarningCount
+}
+
+Exit $testPassed
diff --git a/build/test-threadSafety.ps1 b/build/test-threadSafety.ps1
new file mode 100644
index 00000000000..6694870b6b4
--- /dev/null
+++ b/build/test-threadSafety.ps1
@@ -0,0 +1,34 @@
+param(
+ [Parameter()][string]$coyoteVersion="1.7.10",
+ [Parameter(Mandatory=$true)][string]$testProjectName,
+ [Parameter(Mandatory=$true)][string]$targetFramework,
+ [Parameter()][string]$categoryName="CoyoteConcurrencyTests",
+ [Parameter()][string]$configuration="Release"
+)
+
+$env:OTEL_RUN_COYOTE_TESTS = 'true'
+
+$rootDirectory = Split-Path $PSScriptRoot -Parent
+
+Write-Host "Install Coyote CLI."
+dotnet tool install --global Microsoft.Coyote.CLI
+
+Write-Host "Build $testProjectName project."
+dotnet build "$rootDirectory/test/$testProjectName/$testProjectName.csproj" --configuration $configuration
+
+$artifactsPath = Join-Path $rootDirectory "test/$testProjectName/bin/$configuration/$targetFramework"
+
+Write-Host "Generate Coyote rewriting options JSON file."
+$assemblies = Get-ChildItem $artifactsPath -Filter OpenTelemetry*.dll | ForEach-Object {$_.Name}
+
+$RewriteOptionsJson = @{}
+[void]$RewriteOptionsJson.Add("AssembliesPath", $artifactsPath)
+[void]$RewriteOptionsJson.Add("Assemblies", $assemblies)
+$RewriteOptionsJson | ConvertTo-Json -Compress | Set-Content -Path "$rootDirectory/test/$testProjectName/rewrite.coyote.json"
+
+Write-Host "Run Coyote rewrite."
+coyote rewrite "$rootDirectory/test/$testProjectName/rewrite.coyote.json"
+
+Write-Host "Execute re-written binary."
+dotnet test "$artifactsPath/$testProjectName.dll" --framework $targetFramework --filter CategoryName=$categoryName
+
diff --git a/docs/Directory.Build.props b/docs/Directory.Build.props
index 080d8d81dea..942eea5974c 100644
--- a/docs/Directory.Build.props
+++ b/docs/Directory.Build.props
@@ -3,10 +3,6 @@
Exe
-
-
- net7.0;net6.0
-
- $(TargetFrameworks);net462;net47;net471;net472;net48
+ $(TargetFrameworksForDocs)
diff --git a/docs/Directory.Packages.props b/docs/Directory.Packages.props
index 5c0fe4f3857..9dc0ffc0c6f 100644
--- a/docs/Directory.Packages.props
+++ b/docs/Directory.Packages.props
@@ -1,6 +1,3 @@
-
-
-
diff --git a/docs/diagnostics/README.md b/docs/diagnostics/README.md
new file mode 100644
index 00000000000..70758e8aa1f
--- /dev/null
+++ b/docs/diagnostics/README.md
@@ -0,0 +1,24 @@
+# OpenTelemetry Diagnostics
+
+This document describes the diagnostic categories used in OpenTelemetry .NET
+components. Diagnostics are used by the compiler to report information to users
+about experimental and/or obsolete code being invoked or to suggest improvements
+to specific code patterns identified through static analysis.
+
+## Experimental APIs
+
+Range: OTEL1000 - OTEL1999
+
+Experimental APIs exposed in OpenTelemetry .NET pre-relase builds. APIs are
+exposed experimentally when either the OpenTelemetry Specification has
+explicitly marked some feature as
+[experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/document-status.md)
+or when the SIG members are still working through the design for a feature and
+want to solicit feedback from the community.
+
+> [!NOTE]
+> Experimental APIs are exposed as `public` in pre-release builds and `internal`
+in stable builds.
+
+For defined diagnostics see: [OpenTelemetry .NET Experimental
+APIs](./experimental-apis/README.md)
diff --git a/docs/diagnostics/experimental-apis/OTEL1000.md b/docs/diagnostics/experimental-apis/OTEL1000.md
new file mode 100644
index 00000000000..1ea4be023a3
--- /dev/null
+++ b/docs/diagnostics/experimental-apis/OTEL1000.md
@@ -0,0 +1,42 @@
+# OpenTelemetry .NET Diagnostic: OTEL1000
+
+## Overview
+
+This is an Experimental API diagnostic covering the following APIs:
+
+* `LoggerProviderBuilder`
+* `LoggerProvider`
+* `IDeferredLoggerProviderBuilder`
+
+Experimental APIs may be changed or removed in the future.
+
+## Details
+
+The OpenTelemetry Specification defines a `LoggerProvider` as part of its
+[API](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/bridge-api.md)
+&
+[SDK](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/sdk.md)
+components.
+
+The SDK allows calling `Shutdown` and `ForceFlush` on the `LoggerProvider` and
+also allows processors to be added dynamically to a pipeline after its creation.
+
+Today the OpenTelemetry .NET log pipeline is built on top of the
+Microsoft.Extensions.Logging `ILogger` \ `ILoggerProvider` \ `ILoggerFactory`
+APIs which do not expose such features.
+
+We also have an issue with the `ILoggingBuilder.AddOpenTelemetry` API in that it
+interacts with the `OpenTelemetryLoggerOptions` class. Options classes are NOT
+available until the `IServiceProvider` is available and services can no longer
+be registered at that point. This prevents the current logging pipeline from
+exposing the same dependency injection surface we have for traces and metrics.
+
+We are exposing these APIs to solve these issues and gather feedback about their
+usefulness.
+
+## Logs Bridge API
+
+The OpenTelemetry Specification defines a Logs Bridge API which is rooted off of
+the `LoggerProvider` (`GetLogger`) and exposes a `Logger` API to submit log
+records. See [OTEL1001](./OTEL1001.md) for details about the Logs Bridge API
+implementation status.
diff --git a/docs/diagnostics/experimental-apis/OTEL1001.md b/docs/diagnostics/experimental-apis/OTEL1001.md
new file mode 100644
index 00000000000..5386726e644
--- /dev/null
+++ b/docs/diagnostics/experimental-apis/OTEL1001.md
@@ -0,0 +1,35 @@
+# OpenTelemetry .NET Diagnostic: OTEL1001
+
+## Overview
+
+This is an Experimental API diagnostic covering the following APIs:
+
+* `LoggerProvider.GetLogger`
+* `Logger`
+* `LogRecordAttributeList`
+* `LogRecordData`
+* `LogRecordSeverity`
+
+Experimental APIs may be changed or removed in the future.
+
+## Details
+
+The OpenTelemetry Specification defines a [Logs Bridge
+API](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/bridge-api.md).
+
+The Logs Bridge API is used by library authors to build log appenders which
+route messages from different log frameworks into OpenTelemetry.
+
+Today the OpenTelemetry .NET log pipeline is built on top of the
+Microsoft.Extensions.Logging `ILogger` \ `ILoggerProvider` \ `ILoggerFactory`
+APIs.
+
+We are exposing these APIs gather feedback about their usefulness. An
+alternative approach may be taken which would be to append into `ILogger`
+instead of OpenTelemetry directly.
+
+## LoggerProvider API
+
+The OpenTelemetry Specification defines a `LoggerProvider` API. See
+[OTEL1000](./OTEL1000.md) for details about the `LoggerProvider` implementation
+status.
diff --git a/docs/diagnostics/experimental-apis/OTEL1002.md b/docs/diagnostics/experimental-apis/OTEL1002.md
new file mode 100644
index 00000000000..8371f0d3bcd
--- /dev/null
+++ b/docs/diagnostics/experimental-apis/OTEL1002.md
@@ -0,0 +1,30 @@
+# OpenTelemetry .NET Diagnostic: OTEL1002
+
+## Overview
+
+This is an Experimental API diagnostic covering the following APIs:
+
+* `AlwaysOnExemplarFilter`
+* `AlwaysOffExemplarFilter`
+* `Exemplar`
+* `ExemplarFilter`
+* `MeterProviderBuilder.SetExemplarFilter` extension method
+* `TraceBasedExemplarFilter`
+
+Experimental APIs may be changed or removed in the future.
+
+## Details
+
+The OpenTelemetry Specification defines an [Exemplar
+API](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar)
+in the Metrics SDK.
+
+From the specification:
+
+> Exemplars are example data points for aggregated data. They provide specific
+> context to otherwise general aggregations. Exemplars allow correlation between
+> aggregated metric data and the original API calls where measurements are
+> recorded.
+
+We are exposing these APIs experimentally until the specification declares them
+stable.
diff --git a/docs/diagnostics/experimental-apis/OTEL1003.md b/docs/diagnostics/experimental-apis/OTEL1003.md
new file mode 100644
index 00000000000..5f62f03575f
--- /dev/null
+++ b/docs/diagnostics/experimental-apis/OTEL1003.md
@@ -0,0 +1,47 @@
+# 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
new file mode 100644
index 00000000000..a5d527de3ba
--- /dev/null
+++ b/docs/diagnostics/experimental-apis/README.md
@@ -0,0 +1,54 @@
+# OpenTelemetry .NET Experimental APIs
+
+This document describes experimental APIs exposed in OpenTelemetry .NET
+pre-relase builds. APIs are exposed experimentally when either the OpenTelemetry
+Specification has explicitly marked some feature as
+[experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/document-status.md)
+or when the SIG members are still working through the design for a feature and
+want to solicit feedback from the community.
+
+> [!NOTE]
+> Experimental APIs are exposed as `public` in pre-release builds and `internal`
+in stable builds.
+
+## Active
+
+Experimental APIs available in the pre-release builds:
+
+### OTEL1000
+
+Description: `LoggerProvider` and `LoggerProviderBuilder`
+
+Details: [OTEL1000](./OTEL1000.md)
+
+### OTEL1001
+
+Description: Logs Bridge API
+
+Details: [OTEL1001](./OTEL1001.md)
+
+### OTEL1002
+
+Description: Metrics Exemplar Support
+
+Details: [OTEL1002](./OTEL1002.md)
+
+### OTEL1003
+
+Description: MetricStreamConfiguration CardinalityLimit Support
+
+Details: [OTEL1003](./OTEL1003.md)
+
+## Inactive
+
+Experimental APIs which have been released stable or removed:
+
+
+
+None
diff --git a/docs/docfx.json b/docs/docfx.json
index 5fc4dfb889f..6fdd09cd28d 100644
--- a/docs/docfx.json
+++ b/docs/docfx.json
@@ -29,7 +29,10 @@
{
"files": [
".editorconfig",
- "**.cs"
+ "**.cs",
+ "Directory.Packages.props",
+ "LICENSE.TXT",
+ "THIRD-PARTY-NOTICES.TXT"
]
}
],
diff --git a/docs/logs/README.md b/docs/logs/README.md
new file mode 100644
index 00000000000..77a46c847e8
--- /dev/null
+++ b/docs/logs/README.md
@@ -0,0 +1,230 @@
+# OpenTelemetry .NET Logs
+
+
+
+Table of Contents
+
+* [Best Practices](#best-practices)
+* [Package Version](#package-version)
+* [Logging API](#logging-api)
+ * [ILogger](#ilogger)
+ * [LoggerFactory](#loggerfactory)
+* [Log Correlation](#log-correlation)
+* [Log Enrichment](#log-enrichment)
+* [Log Filtering](#log-filtering)
+* [Log Redaction](#log-redaction)
+
+
+
+
+## Best Practices
+
+The following tutorials have demonstrated the best practices for logging with
+OpenTelemetry .NET:
+
+* [Getting Started - ASP.NET Core
+ Application](./getting-started-aspnetcore/README.md)
+* [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;
+
+logger.LogInformation($"Hello from {food} {price}.");
+```
+
+Refer to the [logging performance
+benchmark](../../test/Benchmarks/Logs/LogBenchmarks.cs) for more details.
+
+## Package Version
+
+:heavy_check_mark: You should always use the
+[`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))
+from the latest stable version of
+[Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging/)
+package, regardless of the .NET runtime version being used:
+
+* If you are using the latest stable version of [OpenTelemetry .NET
+ SDK](../../src/OpenTelemetry/README.md), you do not have to worry about the
+ version of `Microsoft.Extensions.Logging` package because it is already taken
+ care of for you via [package dependency](../../Directory.Packages.props).
+* Starting from version `3.1.0`, the .NET runtime team is holding a high bar for
+ 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
+get a logger depends on two things:
+
+* The type of application you are building.
+* The place where you want to log.
+
+Here is the rule of thumb:
+
+* If you are building an application with [dependency injection
+ (DI)](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection)
+ (e.g. [ASP.NET Core](https://learn.microsoft.com/aspnet/core) and [.NET
+ Worker](https://learn.microsoft.com/dotnet/core/extensions/workers)), in most
+ cases you should use the logger provided by DI, there are special cases when
+ you want log before DI logging pipeline is available or after DI logging
+ pipeline is disposed. Refer to the [.NET official
+ document](https://learn.microsoft.com/dotnet/core/extensions/logging#integration-with-hosts-and-dependency-injection)
+ and [Getting Started with OpenTelemetry .NET Logs in 5 Minutes - ASP.NET Core
+ Application](./getting-started-aspnetcore/README.md) tutorial to learn more.
+* If you are building an application without DI, create a
+ [LoggerFactory](#loggerfactory) instance and configure OpenTelemetry to work
+ with it. Refer to the [Getting Started with OpenTelemetry .NET Logs in 5
+ Minutes - Console Application](./getting-started-console/README.md) tutorial
+ to learn more.
+
+:heavy_check_mark: You should use dot-separated
+[UpperCamelCase](https://en.wikipedia.org/wiki/Camel_case) as the log category
+name, which makes it convenient to [filter logs](#log-filtering). A common
+practice is to use fully qualified class name, and if further categorization is
+desired, append a subcategory name. Refer to the [.NET official
+document](https://learn.microsoft.com/dotnet/core/extensions/logging#log-category)
+to learn more.
+
+```csharp
+loggerFactory.CreateLogger(); // this is equivalent to CreateLogger("MyProduct.MyLibrary.MyClass")
+loggerFactory.CreateLogger("MyProduct.MyLibrary.MyClass"); // use the fully qualified class name
+loggerFactory.CreateLogger("MyProduct.MyLibrary.MyClass.DatabaseOperations"); // append a subcategory name
+loggerFactory.CreateLogger("MyProduct.MyLibrary.MyClass.FileOperations"); // append another subcategory name
+```
+
+:stop_sign: You should avoid creating loggers too frequently. Although loggers
+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
+
+:heavy_check_mark: You should use [compile-time logging source
+generation](https://docs.microsoft.com/dotnet/core/extensions/logger-message-generator)
+pattern to achieve the best performance.
+
+```csharp
+var food = "tomato";
+var price = 2.99;
+
+logger.SayHello(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);
+}
+```
+
+> [!NOTE]
+> There is no need to pass in an explicit
+ [EventId](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.eventid)
+ while using
+ [LoggerMessageAttribute](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.loggermessageattribute).
+ A durable `EventId` will be automatically assigned based on the hash of the
+ method name during code generation.
+
+:heavy_check_mark: You can use
+[LogPropertiesAttribute](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.logpropertiesattribute)
+from
+[Microsoft.Extensions.Telemetry.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Telemetry.Abstractions/)
+if you need to log complex objects. Check out the [Logging with Complex
+Objects](./complex-objects/README.md) tutorial for more details.
+
+:stop_sign: You should avoid the extension methods from
+[LoggerExtensions](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.loggerextensions),
+these methods are not optimized for performance.
+
+> [!WARNING]
+> The following code has bad performance due to
+ [boxing](https://learn.microsoft.com/dotnet/csharp/programming-guide/types/boxing-and-unboxing):
+
+```csharp
+var food = "tomato";
+var price = 2.99;
+
+logger.LogInformation("Hello from {food} {price}.", food, price);
+```
+
+Refer to the [logging performance
+benchmark](../../test/Benchmarks/Logs/LogBenchmarks.cs) for more details.
+
+## LoggerFactory
+
+In many cases, you can use [ILogger](#ilogger) without having to interact with
+[Microsoft.Extensions.Logging.LoggerFactory](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.loggerfactory)
+directly. This section is intended for users who need to create and manage
+`LoggerFactory` explicitly.
+
+:stop_sign: You should avoid creating `LoggerFactory` instances too frequently,
+`LoggerFactory` is fairly expensive and meant to be reused throughout the
+application. For most applications, one `LoggerFactory` instance per process
+would be sufficient.
+
+:heavy_check_mark: You should properly manage the lifecycle of
+[LoggerFactory](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.loggerfactory)
+instances if they are created by you.
+
+* If you forget to dispose the `LoggerFactory` instance before the application
+ ends, logs might get dropped due to the lack of proper flush.
+* If you dispose the `LoggerFactory` instance too early, any subsequent logging
+ API invocation associated with the logger factory could become no-op (i.e. no
+ logs will be emitted).
+
+## Log Correlation
+
+In OpenTelemetry, logs are automatically correlated to
+[traces](../trace/README.md). Check the [Log
+Correlation](./correlation/README.md) tutorial to learn more.
+
+## Log Enrichment
+
+TBD
+
+## Log Filtering
+
+The [Customizing OpenTelemetry .NET SDK for
+Logs](./customizing-the-sdk/README.md#log-filtering) document has provided
+instructions for basic filtering based on logger category name and severity
+level.
+
+For more advanced filtering and sampling, the .NET team has a plan to cover it
+in .NET 9 timeframe, please use this [runtime
+issue](https://github.com/dotnet/runtime/issues/82465) to track the progress or
+provide feedback and suggestions.
+
+## Log Redaction
+
+Logs might contain sensitive information such as passwords and credit card
+numbers, proper redaction is required to prevent privacy and security incidents.
+Check the [Log Redaction](./redaction/README.md) tutorial to learn more.
diff --git a/docs/logs/complex-objects/FoodRecallNotice.cs b/docs/logs/complex-objects/FoodRecallNotice.cs
new file mode 100644
index 00000000000..b04c01d7780
--- /dev/null
+++ b/docs/logs/complex-objects/FoodRecallNotice.cs
@@ -0,0 +1,15 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+public class FoodRecallNotice
+{
+ public string? BrandName { get; set; }
+
+ public string? ProductDescription { get; set; }
+
+ public string? ProductType { get; set; }
+
+ public string? RecallReasonDescription { get; set; }
+
+ public string? CompanyName { get; set; }
+}
diff --git a/docs/logs/complex-objects/Program.cs b/docs/logs/complex-objects/Program.cs
new file mode 100644
index 00000000000..ca6fa891955
--- /dev/null
+++ b/docs/logs/complex-objects/Program.cs
@@ -0,0 +1,38 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using Microsoft.Extensions.Logging;
+using OpenTelemetry.Logs;
+
+var loggerFactory = LoggerFactory.Create(builder =>
+{
+ builder.AddOpenTelemetry(logging =>
+ {
+ logging.AddConsoleExporter();
+ });
+});
+
+var logger = loggerFactory.CreateLogger();
+
+var foodRecallNotice = new FoodRecallNotice
+{
+ BrandName = "Contoso",
+ ProductDescription = "Salads",
+ ProductType = "Food & Beverages",
+ RecallReasonDescription = "due to a possible health risk from Listeria monocytogenes",
+ CompanyName = "Contoso Fresh Vegetables, Inc.",
+};
+
+logger.FoodRecallNotice(foodRecallNotice);
+
+// Dispose logger factory before the application ends.
+// This will flush the remaining logs and shutdown the logging pipeline.
+loggerFactory.Dispose();
+
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(LogLevel.Critical)]
+ public static partial void FoodRecallNotice(
+ this ILogger logger,
+ [LogProperties(OmitReferenceName = true)] FoodRecallNotice foodRecallNotice);
+}
diff --git a/docs/logs/complex-objects/README.md b/docs/logs/complex-objects/README.md
new file mode 100644
index 00000000000..7bcc666601a
--- /dev/null
+++ b/docs/logs/complex-objects/README.md
@@ -0,0 +1,109 @@
+# Logging with Complex Objects
+
+In the [Getting Started with OpenTelemetry .NET Logs in 5 Minutes - Console
+Application](../getting-started-console/README.md) tutorial, we've learned how
+to log primitive data types. In this tutorial, we'll learn how to log complex
+objects.
+
+Complex objects logging was introduced in .NET 8.0 via
+[LogPropertiesAttribute](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.logpropertiesattribute).
+This attribute and the corresponding code generation logic are provided by an
+extension package called
+[Microsoft.Extensions.Telemetry.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Telemetry.Abstractions/).
+
+> [!NOTE]
+> Although `Microsoft.Extensions.Telemetry.Abstractions` was introduced in .NET
+8.0, it supports previous versions of the target framework (e.g. .NET 6.0).
+Refer to the [compatible target
+frameworks](https://www.nuget.org/packages/Microsoft.Extensions.Telemetry.Abstractions/#supportedframeworks-body-tab)
+for more information.
+
+First, complete the [getting started](../getting-started-console/README.md)
+tutorial, then install the
+[Microsoft.Extensions.Telemetry.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Telemetry.Abstractions/)
+package:
+
+```sh
+dotnet add package Microsoft.Extensions.Telemetry.Abstractions
+```
+
+Define a new complex data type, as shown in [FoodRecallNotice.cs](./FoodRecallNotice.cs):
+
+```csharp
+public class FoodRecallNotice
+{
+ public string? BrandName { get; set; }
+
+ public string? ProductDescription { get; set; }
+
+ public string? ProductType { get; set; }
+
+ public string? RecallReasonDescription { get; set; }
+
+ public string? CompanyName { get; set; }
+}
+```
+
+Update the `Program.cs` file with the code from [Program.cs](./Program.cs). Note
+that the following code is added which uses the `LogPropertiesAttribute` to log
+the `FoodRecallNotice` object:
+
+```csharp
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(LogLevel.Critical)]
+ public static partial void FoodRecallNotice(
+ this ILogger logger,
+ [LogProperties(OmitReferenceName = true)] FoodRecallNotice foodRecallNotice);
+}
+```
+
+The following code is used to create a `FoodRecallNotice` object and log it:
+
+```csharp
+var foodRecallNotice = new FoodRecallNotice
+{
+ BrandName = "Contoso",
+ ProductDescription = "Salads",
+ ProductType = "Food & Beverages",
+ RecallReasonDescription = "due to a possible health risk from Listeria monocytogenes",
+ CompanyName = "Contoso Fresh Vegetables, Inc.",
+};
+
+logger.FoodRecallNotice(foodRecallNotice);
+```
+
+Run the application again (using `dotnet run`) and you should see the log output
+on the console.
+
+```text
+LogRecord.Timestamp: 2024-01-12T19:01:16.0604084Z
+LogRecord.CategoryName: Program
+LogRecord.Severity: Fatal
+LogRecord.SeverityText: Critical
+LogRecord.FormattedMessage:
+LogRecord.Body:
+LogRecord.Attributes (Key:Value):
+ CompanyName: Contoso Fresh Vegetables, Inc.
+ RecallReasonDescription: due to a possible health risk from Listeria monocytogenes
+ ProductType: Food & Beverages
+ ProductDescription: Salads
+ BrandName: Contoso
+LogRecord.EventId: 252550133
+LogRecord.EventName: FoodRecallNotice
+```
+
+> [!NOTE]
+> In this tutorial we've used
+[LogPropertiesAttribute.OmitReferenceName](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.logpropertiesattribute.omitreferencename)
+which changed the style of attribute names. There are more options available,
+check out the [learn more](#learn-more) section for more information.
+
+## Learn more
+
+* [Microsoft.Extensions.Logging.LogPropertiesAttribute](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.logpropertiesattribute)
+* [Microsoft.Extensions.Telemetry.Abstractions](https://github.com/dotnet/extensions/blob/main/src/Libraries/Microsoft.Extensions.Telemetry.Abstractions/README.md)
+* [Strong-type support feature
+ request](https://github.com/dotnet/runtime/issues/61947)
+* [LogPropertiesAttribute design
+ proposal](https://github.com/dotnet/runtime/issues/81730)
diff --git a/docs/logs/complex-objects/complex-objects.csproj b/docs/logs/complex-objects/complex-objects.csproj
new file mode 100644
index 00000000000..cb2c93fa1ff
--- /dev/null
+++ b/docs/logs/complex-objects/complex-objects.csproj
@@ -0,0 +1,9 @@
+
+
+ true
+
+
+
+
+
+
diff --git a/docs/logs/correlation/LoggerExtensions.cs b/docs/logs/correlation/LoggerExtensions.cs
new file mode 100644
index 00000000000..facd6d895c8
--- /dev/null
+++ b/docs/logs/correlation/LoggerExtensions.cs
@@ -0,0 +1,10 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using Microsoft.Extensions.Logging;
+
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(LogLevel.Information, "Food `{name}` price changed to `{price}`.")]
+ public static partial void FoodPriceChanged(this ILogger logger, string name, double price);
+}
diff --git a/docs/logs/correlation/Program.cs b/docs/logs/correlation/Program.cs
index 722e66347e6..b1a3284fbcc 100644
--- a/docs/logs/correlation/Program.cs
+++ b/docs/logs/correlation/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using Microsoft.Extensions.Logging;
@@ -20,40 +7,39 @@
using OpenTelemetry.Logs;
using OpenTelemetry.Trace;
-namespace Correlation;
-
public class Program
{
- private static readonly ActivitySource MyActivitySource = new(
- "MyCompany.MyProduct.MyLibrary");
+ private static readonly ActivitySource MyActivitySource = new("MyCompany.MyProduct.MyLibrary");
public static void Main()
{
- // Setup Logging
- using var loggerFactory = LoggerFactory.Create(builder =>
+ var tracerProvider = Sdk.CreateTracerProviderBuilder()
+ .AddSource("MyCompany.MyProduct.MyLibrary")
+ .AddConsoleExporter()
+ .Build();
+
+ var loggerFactory = LoggerFactory.Create(builder =>
{
- builder.AddOpenTelemetry(options =>
+ builder.AddOpenTelemetry(logging =>
{
- options.AddConsoleExporter();
+ logging.AddConsoleExporter();
});
});
var logger = loggerFactory.CreateLogger();
- // Setup Traces
- using var tracerProvider = Sdk.CreateTracerProviderBuilder()
- .AddSource("MyCompany.MyProduct.MyLibrary")
- .AddConsoleExporter()
- .Build();
-
- // Emit activity
using (var activity = MyActivitySource.StartActivity("SayHello"))
{
- activity?.SetTag("foo", 1);
-
- // emit logs within the context
- // of activity
- logger.LogInformation("Hello from {name} {price}.", "tomato", 2.99);
+ // Write a log within the context of an activity
+ logger.FoodPriceChanged("artichoke", 9.99);
}
+
+ // Dispose logger factory before the application ends.
+ // This will flush the remaining logs and shutdown the logging pipeline.
+ loggerFactory.Dispose();
+
+ // Dispose tracer provider before the application ends.
+ // This will flush the remaining spans and shutdown the tracing pipeline.
+ tracerProvider.Dispose();
}
}
diff --git a/docs/logs/correlation/README.md b/docs/logs/correlation/README.md
index 89878735d06..309cfea64d0 100644
--- a/docs/logs/correlation/README.md
+++ b/docs/logs/correlation/README.md
@@ -1,6 +1,6 @@
-# Logs correlation
+# Log Correlation
-The getting started docs for [logs](../getting-started/README.md) and
+The getting started docs for [logs](../getting-started-console/README.md) and
[traces](../../trace/getting-started-console/README.md) showed how to emit logs
and traces independently, and export them to console exporter.
@@ -27,35 +27,38 @@ of an active `Activity`. Running the application will show the following output
on the console:
```text
-LogRecord.Timestamp: 2022-05-18T18:51:16.4348626Z
-LogRecord.TraceId: d7aca5b2422ed8d15f56b6a93be4537d
-LogRecord.SpanId: c90ac2ad41ab4d46
+LogRecord.Timestamp: 2024-01-26T17:55:39.2273475Z
+LogRecord.TraceId: aed89c3b250fb9d8e16ccab1a4a9bbb5
+LogRecord.SpanId: bd44308753200c58
LogRecord.TraceFlags: Recorded
-LogRecord.CategoryName: Correlation.Program
-LogRecord.LogLevel: Information
-LogRecord.State: Hello from tomato 2.99.
+LogRecord.CategoryName: Program
+LogRecord.Severity: Info
+LogRecord.SeverityText: Information
+LogRecord.Body: Food `{name}` price changed to `{price}`.
+LogRecord.Attributes (Key:Value):
+ name: artichoke
+ price: 9.99
+ OriginalFormat (a.k.a Body): Food `{name}` price changed to `{price}`.
+LogRecord.EventId: 344095174
+LogRecord.EventName: FoodPriceChanged
-Resource associated with LogRecord:
-service.name: unknown_service:correlation
+...
-Activity.TraceId: d7aca5b2422ed8d15f56b6a93be4537d
-Activity.SpanId: c90ac2ad41ab4d46
-Activity.TraceFlags: Recorded
+Activity.TraceId: aed89c3b250fb9d8e16ccab1a4a9bbb5
+Activity.SpanId: bd44308753200c58
+Activity.TraceFlags: Recorded
Activity.ActivitySourceName: MyCompany.MyProduct.MyLibrary
-Activity.DisplayName: SayHello
-Activity.Kind: Internal
-Activity.StartTime: 2022-05-18T18:51:16.3427411Z
-Activity.Duration: 00:00:00.2248932
-Activity.Tags:
- foo: 1
-Resource associated with Activity:
- service.name: unknown_service:correlation
+Activity.DisplayName: SayHello
+Activity.Kind: Internal
+Activity.StartTime: 2024-01-26T17:55:39.2223849Z
+Activity.Duration: 00:00:00.0361682
+...
```
As you can see, the `LogRecord` automatically had the `TraceId`, `SpanId` fields
matching the ones from the `Activity`. In [the logs getting
-started](../getting-started/README.md) doc, the logging was done outside of an
-`Activity` context, hence these fields in `LogRecord` were not populated.
+started](../getting-started-console/README.md) doc, the logging was done outside
+of an `Activity` context, hence these fields in `LogRecord` were not populated.
## Learn more
diff --git a/docs/logs/correlation/correlation.csproj b/docs/logs/correlation/correlation.csproj
index 24f3305944a..19aa9791432 100644
--- a/docs/logs/correlation/correlation.csproj
+++ b/docs/logs/correlation/correlation.csproj
@@ -1,6 +1,5 @@
-
diff --git a/docs/logs/customizing-the-sdk/Program.cs b/docs/logs/customizing-the-sdk/Program.cs
index 549737954c9..1b22fdbfda9 100644
--- a/docs/logs/customizing-the-sdk/Program.cs
+++ b/docs/logs/customizing-the-sdk/Program.cs
@@ -1,54 +1,56 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;
using OpenTelemetry.Resources;
-namespace CustomizingTheSdk;
-
-public class Program
+var loggerFactory = LoggerFactory.Create(builder =>
{
- public static void Main()
+ builder.AddOpenTelemetry(logging =>
{
- using var loggerFactory = LoggerFactory.Create(builder =>
- {
- builder.AddOpenTelemetry(options =>
- {
- options.IncludeScopes = true;
- options.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(
- serviceName: "MyService",
- serviceVersion: "1.0.0"));
- options.AddConsoleExporter();
- });
- });
-
- var logger = loggerFactory.CreateLogger();
-
- logger.LogInformation("Hello from {name} {price}.", "tomato", 2.99);
- logger.LogWarning("Hello from {name} {price}.", "tomato", 2.99);
- logger.LogError("Hello from {name} {price}.", "tomato", 2.99);
-
- // log with scopes
- using (logger.BeginScope(new List>
- {
- new KeyValuePair("store", "Seattle"),
- }))
- {
- logger.LogInformation("Hello from {food} {price}.", "tomato", 2.99);
- }
- }
+ logging.IncludeScopes = true;
+ logging.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(
+ serviceName: "MyService",
+ serviceVersion: "1.0.0"));
+ logging.AddConsoleExporter();
+ });
+});
+
+var logger = loggerFactory.CreateLogger();
+
+logger.FoodPriceChanged("artichoke", 9.99);
+
+using (logger.BeginScope(new List>
+{
+ new KeyValuePair("store", "Seattle"),
+}))
+{
+ logger.FoodPriceChanged("truffle", 999.99);
+}
+
+logger.FoodRecallNotice(
+ brandName: "Contoso",
+ productDescription: "Salads",
+ productType: "Food & Beverages",
+ recallReasonDescription: "due to a possible health risk from Listeria monocytogenes",
+ companyName: "Contoso Fresh Vegetables, Inc.");
+
+// Dispose logger factory before the application ends.
+// This will flush the remaining logs and shutdown the logging pipeline.
+loggerFactory.Dispose();
+
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(LogLevel.Information, "Food `{name}` price changed to `{price}`.")]
+ public static partial void FoodPriceChanged(this ILogger logger, string name, double price);
+
+ [LoggerMessage(LogLevel.Critical, "A `{productType}` recall notice was published for `{brandName} {productDescription}` produced by `{companyName}` ({recallReasonDescription}).")]
+ public static partial void FoodRecallNotice(
+ this ILogger logger,
+ string brandName,
+ string productDescription,
+ string productType,
+ string recallReasonDescription,
+ string companyName);
}
diff --git a/docs/logs/customizing-the-sdk/README.md b/docs/logs/customizing-the-sdk/README.md
index a642d0621e2..cd48fd608ab 100644
--- a/docs/logs/customizing-the-sdk/README.md
+++ b/docs/logs/customizing-the-sdk/README.md
@@ -36,16 +36,16 @@ TODO
### AddProcessor
-[Processors](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/logging-library-sdk.md#logprocessor)
+[Processors](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/sdk.md#logrecordprocessor)
must be added using `OpenTelemetryLoggerOptions.AddProcessor()`.
It is not supported to add Processors after building the `LoggerFactory`.
```csharp
var loggerFactory = LoggerFactory.Create(builder =>
{
- builder.AddOpenTelemetry(options =>
+ builder.AddOpenTelemetry(logging =>
{
- options.AddProcessor(...)
+ logging.AddProcessor(...);
});
});
```
@@ -56,9 +56,12 @@ For more information on Processors, please review [Extending the SDK](../extendi
[Resource](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md)
is the immutable representation of the entity producing the telemetry.
-If no `Resource` is explicitly configured, the default is to use a resource
-indicating this [Telemetry
-SDK](https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/resource/semantic_conventions#telemetry-sdk).
+If no `Resource` is explicitly configured, the
+[default](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#semantic-attributes-with-sdk-provided-default-value)
+is to use a resource indicating this
+[Service](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#service)
+and [Telemetry
+SDK](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#telemetry-sdk).
The `SetResourceBuilder` method on `OpenTelemetryLoggerOptions` can be used to
set a single `ResourceBuilder`. If `SetResourceBuilder` is called multiple
times, only the last is kept. It is not possible to change the resource builder
@@ -69,9 +72,9 @@ The snippet below shows configuring a custom `ResourceBuilder` to the provider.
```csharp
var loggerFactory = LoggerFactory.Create(builder =>
{
- builder.AddOpenTelemetry(options =>
+ builder.AddOpenTelemetry(logging =>
{
- options.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(
+ logging.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(
serviceName: "MyService",
serviceVersion: "1.0.0"));
});
@@ -104,8 +107,8 @@ and also defines "Warning" as the minimum `LogLevel` for a user defined category
These rules as defined only apply to the `OpenTelemetryLoggerProvider`.
```csharp
-ILoggingBuilder.AddFilter("*", LogLevel.Error);
-ILoggingBuilder.AddFilter("category name", LogLevel.Warning);
+builder.AddFilter("*", LogLevel.Error);
+builder.AddFilter("MyProduct.MyLibrary.MyClass", LogLevel.Warning);
```
## Learn more
diff --git a/docs/logs/customizing-the-sdk/customizing-the-sdk.csproj b/docs/logs/customizing-the-sdk/customizing-the-sdk.csproj
index 24f3305944a..19aa9791432 100644
--- a/docs/logs/customizing-the-sdk/customizing-the-sdk.csproj
+++ b/docs/logs/customizing-the-sdk/customizing-the-sdk.csproj
@@ -1,6 +1,5 @@
-
diff --git a/docs/logs/dedicated-pipeline/DedicatedLogging/DedicatedLoggingServiceCollectionExtensions.cs b/docs/logs/dedicated-pipeline/DedicatedLogging/DedicatedLoggingServiceCollectionExtensions.cs
new file mode 100644
index 00000000000..538f23b5cb4
--- /dev/null
+++ b/docs/logs/dedicated-pipeline/DedicatedLogging/DedicatedLoggingServiceCollectionExtensions.cs
@@ -0,0 +1,73 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using OpenTelemetry.Logs;
+
+namespace DedicatedLogging;
+
+public static class DedicatedLoggingServiceCollectionExtensions
+{
+ public static IServiceCollection AddDedicatedLogging(
+ this IServiceCollection services,
+ IConfiguration configuration,
+ Action configureOpenTelemetry)
+ {
+ ArgumentNullException.ThrowIfNull(configureOpenTelemetry);
+
+ services.TryAddSingleton(sp =>
+ {
+ var loggerFactory = LoggerFactory.Create(builder =>
+ {
+ builder.AddConfiguration(configuration);
+
+ builder.AddOpenTelemetry(configureOpenTelemetry);
+ });
+
+ return new DedicatedLoggerFactory(loggerFactory);
+ });
+
+ services.TryAdd(ServiceDescriptor.Singleton(typeof(IDedicatedLogger<>), typeof(DedicatedLogger<>)));
+
+ return services;
+ }
+
+ private sealed class DedicatedLogger : IDedicatedLogger
+ {
+ private readonly ILogger innerLogger;
+
+ public DedicatedLogger(DedicatedLoggerFactory loggerFactory)
+ {
+ this.innerLogger = loggerFactory.CreateLogger(typeof(T).FullName!);
+ }
+
+ public IDisposable? BeginScope(TState state)
+ where TState : notnull
+ => this.innerLogger.BeginScope(state);
+
+ public bool IsEnabled(LogLevel logLevel)
+ => this.innerLogger.IsEnabled(logLevel);
+
+ public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter)
+ => this.innerLogger.Log(logLevel, eventId, state, exception, formatter);
+ }
+
+ private sealed class DedicatedLoggerFactory : ILoggerFactory
+ {
+ private readonly ILoggerFactory innerLoggerFactory;
+
+ public DedicatedLoggerFactory(ILoggerFactory loggerFactory)
+ {
+ this.innerLoggerFactory = loggerFactory;
+ }
+
+ public void AddProvider(ILoggerProvider provider)
+ => this.innerLoggerFactory.AddProvider(provider);
+
+ public ILogger CreateLogger(string categoryName)
+ => this.innerLoggerFactory.CreateLogger(categoryName);
+
+ public void Dispose()
+ => this.innerLoggerFactory.Dispose();
+ }
+}
diff --git a/docs/logs/dedicated-pipeline/DedicatedLogging/IDedicatedLogger.cs b/docs/logs/dedicated-pipeline/DedicatedLogging/IDedicatedLogger.cs
new file mode 100644
index 00000000000..ba09f27e271
--- /dev/null
+++ b/docs/logs/dedicated-pipeline/DedicatedLogging/IDedicatedLogger.cs
@@ -0,0 +1,12 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+namespace DedicatedLogging;
+
+public interface IDedicatedLogger : ILogger
+{
+}
+
+public interface IDedicatedLogger : IDedicatedLogger
+{
+}
diff --git a/docs/logs/dedicated-pipeline/Program.cs b/docs/logs/dedicated-pipeline/Program.cs
new file mode 100644
index 00000000000..ad671445cde
--- /dev/null
+++ b/docs/logs/dedicated-pipeline/Program.cs
@@ -0,0 +1,47 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using DedicatedLogging;
+using OpenTelemetry.Logs;
+
+var builder = WebApplication.CreateBuilder(args);
+
+builder.Logging.ClearProviders();
+
+builder.Logging.AddOpenTelemetry(options =>
+{
+ // Set up primary pipeline for common app logs
+ options.AddConsoleExporter();
+});
+
+builder.Services.AddDedicatedLogging(
+ builder.Configuration.GetSection("DedicatedLogging"), // Bind configuration for dedicated logging pipeline
+ options =>
+ {
+ // Set up secondary pipeline for dedicated logs
+ options.AddConsoleExporter();
+ });
+
+var app = builder.Build();
+
+app.MapGet("/", (HttpContext context, ILogger logger, IDedicatedLogger dedicatedLogger) =>
+{
+ // Standard log written
+ logger.FoodPriceChanged("artichoke", 9.99);
+
+ // Dedicated log written
+ dedicatedLogger.RequestInitiated(context.Connection.RemoteIpAddress?.ToString() ?? "unknown");
+
+ return "Hello from OpenTelemetry Logs!";
+});
+
+app.Run();
+
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(LogLevel.Information, "Food `{name}` price changed to `{price}`.")]
+ public static partial void FoodPriceChanged(this ILogger logger, string name, double price);
+
+ [LoggerMessage(LogLevel.Information, "Request initiated from `{ipAddress}`.")]
+ public static partial void RequestInitiated(this IDedicatedLogger logger, string ipAddress);
+}
diff --git a/docs/logs/dedicated-pipeline/README.md b/docs/logs/dedicated-pipeline/README.md
new file mode 100644
index 00000000000..9e620e193ad
--- /dev/null
+++ b/docs/logs/dedicated-pipeline/README.md
@@ -0,0 +1,4 @@
+# Dedicated pipeline
+
+This example shows how to create a dedicated logging pipeline for specific logs
+which will be sent to a different location than normal application logs.
diff --git a/docs/logs/dedicated-pipeline/appsettings.Development.json b/docs/logs/dedicated-pipeline/appsettings.Development.json
new file mode 100644
index 00000000000..770d3e93146
--- /dev/null
+++ b/docs/logs/dedicated-pipeline/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "DetailedErrors": true,
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/docs/logs/dedicated-pipeline/appsettings.json b/docs/logs/dedicated-pipeline/appsettings.json
new file mode 100644
index 00000000000..b16f05cea55
--- /dev/null
+++ b/docs/logs/dedicated-pipeline/appsettings.json
@@ -0,0 +1,14 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "DedicatedLogging": {
+ "LogLevel": {
+ "Default": "Information"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/docs/logs/dedicated-pipeline/dedicated-pipeline.csproj b/docs/logs/dedicated-pipeline/dedicated-pipeline.csproj
new file mode 100644
index 00000000000..cebc8460c42
--- /dev/null
+++ b/docs/logs/dedicated-pipeline/dedicated-pipeline.csproj
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/docs/logs/extending-the-sdk/LoggerExtensions.cs b/docs/logs/extending-the-sdk/LoggerExtensions.cs
index 5b9f87eb3a9..7476d833334 100644
--- a/docs/logs/extending-the-sdk/LoggerExtensions.cs
+++ b/docs/logs/extending-the-sdk/LoggerExtensions.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using OpenTelemetry;
using OpenTelemetry.Logs;
diff --git a/docs/logs/extending-the-sdk/MyExporter.cs b/docs/logs/extending-the-sdk/MyExporter.cs
index d2552616e62..6093f57394b 100644
--- a/docs/logs/extending-the-sdk/MyExporter.cs
+++ b/docs/logs/extending-the-sdk/MyExporter.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Text;
using OpenTelemetry;
diff --git a/docs/logs/extending-the-sdk/MyProcessor.cs b/docs/logs/extending-the-sdk/MyProcessor.cs
index 4c0c54ec173..5fcd34e1d8d 100644
--- a/docs/logs/extending-the-sdk/MyProcessor.cs
+++ b/docs/logs/extending-the-sdk/MyProcessor.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using OpenTelemetry;
using OpenTelemetry.Logs;
diff --git a/docs/logs/extending-the-sdk/Program.cs b/docs/logs/extending-the-sdk/Program.cs
index 5fea2ce69d4..cada6ec1f5d 100644
--- a/docs/logs/extending-the-sdk/Program.cs
+++ b/docs/logs/extending-the-sdk/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using Microsoft.Extensions.Logging;
using OpenTelemetry;
diff --git a/docs/logs/extending-the-sdk/README.md b/docs/logs/extending-the-sdk/README.md
index d18b88624f0..55ea13dfaf4 100644
--- a/docs/logs/extending-the-sdk/README.md
+++ b/docs/logs/extending-the-sdk/README.md
@@ -3,6 +3,7 @@
* [Building your own exporter](#exporter)
* [Building your own processor](#processor)
* [Building your own sampler](#sampler)
+* [Building your own resource detector](../../resources/README.md#resource-detector)
* [References](#references)
## Exporter
diff --git a/docs/logs/extending-the-sdk/extending-the-sdk.csproj b/docs/logs/extending-the-sdk/extending-the-sdk.csproj
index 92d3323112a..4d96c349671 100644
--- a/docs/logs/extending-the-sdk/extending-the-sdk.csproj
+++ b/docs/logs/extending-the-sdk/extending-the-sdk.csproj
@@ -1,6 +1,5 @@
-
diff --git a/docs/logs/getting-started-aspnetcore/Program.cs b/docs/logs/getting-started-aspnetcore/Program.cs
new file mode 100644
index 00000000000..179d9d2237a
--- /dev/null
+++ b/docs/logs/getting-started-aspnetcore/Program.cs
@@ -0,0 +1,49 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using OpenTelemetry.Logs;
+using OpenTelemetry.Resources;
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Remove default providers and add OpenTelemetry logging provider.
+// For instructional purposes only, disable the default .NET console logging provider to
+// use the verbose OpenTelemetry console exporter instead. For most development
+// and production scenarios the default console provider works well and there is no need to
+// clear these providers.
+builder.Logging.ClearProviders();
+
+builder.Logging.AddOpenTelemetry(logging =>
+{
+ var resourceBuilder = ResourceBuilder
+ .CreateDefault()
+ .AddService(builder.Environment.ApplicationName);
+
+ logging.SetResourceBuilder(resourceBuilder)
+
+ // ConsoleExporter is used for demo purpose only.
+ // In production environment, ConsoleExporter should be replaced with other exporters (e.g. OTLP Exporter).
+ .AddConsoleExporter();
+});
+
+var app = builder.Build();
+
+app.MapGet("/", (ILogger logger) =>
+{
+ logger.FoodPriceChanged("artichoke", 9.99);
+
+ return "Hello from OpenTelemetry Logs!";
+});
+
+app.Logger.StartingApp();
+
+app.Run();
+
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(LogLevel.Information, "Starting the app...")]
+ public static partial void StartingApp(this ILogger logger);
+
+ [LoggerMessage(LogLevel.Information, "Food `{name}` price changed to `{price}`.")]
+ public static partial void FoodPriceChanged(this ILogger logger, string name, double price);
+}
diff --git a/docs/logs/getting-started-aspnetcore/README.md b/docs/logs/getting-started-aspnetcore/README.md
new file mode 100644
index 00000000000..6c6bbe26dc2
--- /dev/null
+++ b/docs/logs/getting-started-aspnetcore/README.md
@@ -0,0 +1,142 @@
+# Getting Started with OpenTelemetry .NET Logs in 5 Minutes - ASP.NET Core Application
+
+First, download and install the [.NET
+SDK](https://dotnet.microsoft.com/download) on your computer.
+
+Create a new web application:
+
+```sh
+dotnet new web -o aspnetcoreapp
+cd aspnetcoreapp
+```
+
+Install the
+[OpenTelemetry.Exporter.Console](../../../src/OpenTelemetry.Exporter.Console/README.md)
+and
+[OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md)
+packages:
+
+```sh
+dotnet add package OpenTelemetry.Exporter.Console
+dotnet add package OpenTelemetry.Extensions.Hosting
+```
+
+Update the `Program.cs` file with the code from [Program.cs](./Program.cs).
+
+Run the application (using `dotnet run`) and then browse to the URL shown in the
+console for your application (e.g. `http://localhost:5000`). You should see the
+logs output from the console:
+
+```text
+LogRecord.Timestamp: 2023-09-06T22:59:17.9787564Z
+LogRecord.CategoryName: getting-started-aspnetcore
+LogRecord.Severity: Info
+LogRecord.SeverityText: Information
+LogRecord.Body: Starting the app...
+LogRecord.Attributes (Key:Value):
+ OriginalFormat (a.k.a Body): Starting the app...
+LogRecord.EventId: 225744744
+LogRecord.EventName: StartingApp
+
+...
+
+LogRecord.Timestamp: 2023-09-06T22:59:18.0644378Z
+LogRecord.CategoryName: Microsoft.Hosting.Lifetime
+LogRecord.Severity: Info
+LogRecord.SeverityText: Information
+LogRecord.Body: Now listening on: {address}
+LogRecord.Attributes (Key:Value):
+ address: http://localhost:5000
+ OriginalFormat (a.k.a Body): Now listening on: {address}
+LogRecord.EventId: 14
+LogRecord.EventName: ListeningOnAddress
+
+...
+
+LogRecord.Timestamp: 2023-09-06T23:00:46.1639248Z
+LogRecord.TraceId: 3507087d60ae4b1d2f10e68f4e40784a
+LogRecord.SpanId: c51be9f19c598b69
+LogRecord.TraceFlags: None
+LogRecord.CategoryName: Program
+LogRecord.Severity: Info
+LogRecord.SeverityText: Information
+LogRecord.Body: Food `{name}` price changed to `{price}`.
+LogRecord.Attributes (Key:Value):
+ name: artichoke
+ price: 9.99
+ OriginalFormat (a.k.a Body): Food `{name}` price changed to `{price}`.
+LogRecord.EventId: 344095174
+LogRecord.EventName: FoodPriceChanged
+
+...
+```
+
+Congratulations! You are now collecting logs using OpenTelemetry.
+
+What does the above program do?
+
+The program has cleared the default [logging
+providers](https://learn.microsoft.com/dotnet/core/extensions/logging-providers)
+then added OpenTelemetry as a logging provider to the ASP.NET Core logging
+pipeline. OpenTelemetry SDK is then configured with a
+[ConsoleExporter](../../../src/OpenTelemetry.Exporter.Console/README.md) to
+export the logs to the console for demonstration purpose (note: ConsoleExporter
+is not intended for production usage, other exporters such as [OTLP
+Exporter](../../../src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md)
+should be used instead). From the console output we can see logs from both our
+logger and the ASP.NET Core framework loggers, as indicated by the
+`LogRecord.CategoryName`.
+
+The example has demonstrated the best practice from ASP.NET Core by injecting
+generic `ILogger`:
+
+```csharp
+app.MapGet("/", (ILogger logger) =>
+{
+ logger.FoodPriceChanged("artichoke", 9.99);
+
+ return "Hello from OpenTelemetry Logs!";
+});
+```
+
+Following the .NET logging best practice, [compile-time logging source
+generation](https://docs.microsoft.com/dotnet/core/extensions/logger-message-generator)
+has been used across the example, which delivers high performance, structured
+logging, and type-checked parameters:
+
+```csharp
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(LogLevel.Information, "Starting the app...")]
+ public static partial void StartingApp(this ILogger logger);
+
+ [LoggerMessage(LogLevel.Information, "Food `{name}` price changed to `{price}`.")]
+ public static partial void FoodPriceChanged(this ILogger logger, string name, double price);
+}
+```
+
+For logs that occur between `builder.Build()` and `app.Run()` when injecting a
+generic `ILogger` is not an option, `app.Logger` is used instead:
+
+```csharp
+app.Logger.StartingApp();
+```
+
+> [!NOTE]
+> There are cases where logging is needed before the [dependency injection
+(DI)](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection)
+logging pipeline is available (e.g. before `builder.Build()`) or after the DI
+logging pipeline is disposed (e.g. after `app.Run()`). The common practice is to
+use a separate logging pipeline by creating a `LoggerFactory` instance.
+>
+> Refer to the [Getting Started with OpenTelemetry .NET Logs in 5 Minutes -
+Console Application](../getting-started-console/README.md) tutorial to learn
+more about how to create a `LoggerFactory` instance and configure OpenTelemetry
+to work with it.
+
+## Learn more
+
+* [Logging in C# and .NET](https://learn.microsoft.com/dotnet/core/extensions/logging)
+* [Logging with Complex Objects](../complex-objects/README.md)
+* [Customizing the OpenTelemetry .NET SDK](../customizing-the-sdk/README.md)
+* [Extending the OpenTelemetry .NET SDK](../extending-the-sdk/README.md)
diff --git a/docs/logs/getting-started-aspnetcore/appsettings.Development.json b/docs/logs/getting-started-aspnetcore/appsettings.Development.json
new file mode 100644
index 00000000000..770d3e93146
--- /dev/null
+++ b/docs/logs/getting-started-aspnetcore/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "DetailedErrors": true,
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/docs/logs/getting-started-aspnetcore/appsettings.json b/docs/logs/getting-started-aspnetcore/appsettings.json
new file mode 100644
index 00000000000..10f68b8c8b4
--- /dev/null
+++ b/docs/logs/getting-started-aspnetcore/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/docs/logs/getting-started-aspnetcore/getting-started-aspnetcore.csproj b/docs/logs/getting-started-aspnetcore/getting-started-aspnetcore.csproj
new file mode 100644
index 00000000000..cebc8460c42
--- /dev/null
+++ b/docs/logs/getting-started-aspnetcore/getting-started-aspnetcore.csproj
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/docs/logs/getting-started-console/Program.cs b/docs/logs/getting-started-console/Program.cs
new file mode 100644
index 00000000000..b907d169d20
--- /dev/null
+++ b/docs/logs/getting-started-console/Program.cs
@@ -0,0 +1,43 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using Microsoft.Extensions.Logging;
+using OpenTelemetry.Logs;
+
+var loggerFactory = LoggerFactory.Create(builder =>
+{
+ builder.AddOpenTelemetry(logging =>
+ {
+ logging.AddConsoleExporter();
+ });
+});
+
+var logger = loggerFactory.CreateLogger();
+
+logger.FoodPriceChanged("artichoke", 9.99);
+
+logger.FoodRecallNotice(
+ brandName: "Contoso",
+ productDescription: "Salads",
+ productType: "Food & Beverages",
+ recallReasonDescription: "due to a possible health risk from Listeria monocytogenes",
+ companyName: "Contoso Fresh Vegetables, Inc.");
+
+// Dispose logger factory before the application ends.
+// This will flush the remaining logs and shutdown the logging pipeline.
+loggerFactory.Dispose();
+
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(LogLevel.Information, "Food `{name}` price changed to `{price}`.")]
+ public static partial void FoodPriceChanged(this ILogger logger, string name, double price);
+
+ [LoggerMessage(LogLevel.Critical, "A `{productType}` recall notice was published for `{brandName} {productDescription}` produced by `{companyName}` ({recallReasonDescription}).")]
+ public static partial void FoodRecallNotice(
+ this ILogger logger,
+ string brandName,
+ string productDescription,
+ string productType,
+ string recallReasonDescription,
+ string companyName);
+}
diff --git a/docs/logs/getting-started-console/README.md b/docs/logs/getting-started-console/README.md
new file mode 100644
index 00000000000..aa251d09951
--- /dev/null
+++ b/docs/logs/getting-started-console/README.md
@@ -0,0 +1,119 @@
+# Getting Started with OpenTelemetry .NET Logs in 5 Minutes - Console Application
+
+First, download and install the [.NET
+SDK](https://dotnet.microsoft.com/download) on your computer.
+
+Create a new console application and run it:
+
+```sh
+dotnet new console --output getting-started
+cd getting-started
+dotnet run
+```
+
+You should see the following output:
+
+```text
+Hello World!
+```
+
+Install the
+[OpenTelemetry.Exporter.Console](../../../src/OpenTelemetry.Exporter.Console/README.md)
+package:
+
+```sh
+dotnet add package OpenTelemetry.Exporter.Console
+```
+
+Update the `Program.cs` file with the code from [Program.cs](./Program.cs).
+
+Run the application again (using `dotnet run`) and you should see the log output
+on the console.
+
+```text
+LogRecord.Timestamp: 2023-09-15T06:07:03.5502083Z
+LogRecord.CategoryName: Program
+LogRecord.Severity: Info
+LogRecord.SeverityText: Information
+LogRecord.Body: Food `{name}` price changed to `{price}`.
+LogRecord.Attributes (Key:Value):
+ name: artichoke
+ price: 9.99
+ OriginalFormat (a.k.a Body): Food `{name}` price changed to `{price}`.
+LogRecord.EventId: 344095174
+LogRecord.EventName: FoodPriceChanged
+
+...
+
+LogRecord.Timestamp: 2023-09-15T06:07:03.5683511Z
+LogRecord.CategoryName: Program
+LogRecord.Severity: Fatal
+LogRecord.SeverityText: Critical
+LogRecord.Body: A `{productType}` recall notice was published for `{brandName} {productDescription}` produced by `{companyName}` ({recallReasonDescription}).
+LogRecord.Attributes (Key:Value):
+ brandName: Contoso
+ productDescription: Salads
+ productType: Food & Beverages
+ recallReasonDescription: due to a possible health risk from Listeria monocytogenes
+ companyName: Contoso Fresh Vegetables, Inc.
+ OriginalFormat (a.k.a Body): A `{productType}` recall notice was published for `{brandName} {productDescription}` produced by `{companyName}` ({recallReasonDescription}).
+LogRecord.EventId: 1338249384
+LogRecord.EventName: FoodRecallNotice
+
+...
+```
+
+Congratulations! You are now collecting logs using OpenTelemetry.
+
+What does the above program do?
+
+The program has created a logging pipeline by instantiating a
+[`LoggerFactory`](https://docs.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory)
+instance, with OpenTelemetry added as a [logging
+provider](https://docs.microsoft.com/dotnet/core/extensions/logging-providers).
+OpenTelemetry SDK is then configured with a
+[ConsoleExporter](../../../src/OpenTelemetry.Exporter.Console/README.md) to
+export the logs to the console for demonstration purpose (note: ConsoleExporter
+is not intended for production usage, other exporters such as [OTLP
+Exporter](../../../src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md)
+should be used instead).
+
+The `LoggerFactory` instance is used to create an
+[`ILogger`](https://docs.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger)
+instance, which is used to do the actual logging.
+
+Following the .NET logging best practice, [compile-time logging source
+generation](https://docs.microsoft.com/dotnet/core/extensions/logger-message-generator)
+has been used across the example, which delivers high performance, structured
+logging, and type-checked parameters:
+
+```csharp
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(LogLevel.Information, "Food `{name}` price changed to `{price}`.")]
+ public static partial void FoodPriceChanged(this ILogger logger, string name, double price);
+
+ ...
+}
+```
+
+> [!NOTE]
+> For applications which use `ILogger` with [dependency injection
+(DI)](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection)
+(e.g. [ASP.NET Core](https://learn.microsoft.com/aspnet/core) and [.NET
+Worker](https://learn.microsoft.com/dotnet/core/extensions/workers)), the common
+practice is to add OpenTelemetry as a [logging
+provider](https://docs.microsoft.com/dotnet/core/extensions/logging-providers)
+to the DI logging pipeline, rather than set up a completely new logging pipeline
+by creating a new `LoggerFactory` instance.
+>
+> Refer to the [Getting Started with OpenTelemetry .NET Logs in 5 Minutes -
+ASP.NET Core Application](../getting-started-aspnetcore/README.md) tutorial to
+learn more.
+
+## Learn more
+
+* [Logging in C# and .NET](https://learn.microsoft.com/dotnet/core/extensions/logging)
+* [Logging with Complex Objects](../complex-objects/README.md)
+* [Customizing the OpenTelemetry .NET SDK](../customizing-the-sdk/README.md)
+* [Extending the OpenTelemetry .NET SDK](../extending-the-sdk/README.md)
diff --git a/docs/logs/getting-started/getting-started.csproj b/docs/logs/getting-started-console/getting-started-console.csproj
similarity index 75%
rename from docs/logs/getting-started/getting-started.csproj
rename to docs/logs/getting-started-console/getting-started-console.csproj
index 6e8adc423c3..f68cdb2a7fe 100644
--- a/docs/logs/getting-started/getting-started.csproj
+++ b/docs/logs/getting-started-console/getting-started-console.csproj
@@ -1,6 +1,5 @@
-
diff --git a/docs/logs/getting-started/Program.cs b/docs/logs/getting-started/Program.cs
deleted file mode 100644
index de8291df904..00000000000
--- a/docs/logs/getting-started/Program.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-using Microsoft.Extensions.Logging;
-using OpenTelemetry.Logs;
-
-namespace GettingStarted;
-
-public class Program
-{
- public static void Main()
- {
- using var loggerFactory = LoggerFactory.Create(builder =>
- {
- builder.AddOpenTelemetry(options =>
- {
- options.AddConsoleExporter();
- });
- });
-
- var logger = loggerFactory.CreateLogger();
-
- logger.LogInformation(eventId: 123, "Hello from {name} {price}.", "tomato", 2.99);
-
- if (logger.IsEnabled(LogLevel.Debug))
- {
- // If logger.IsEnabled returned false, the code doesn't have to spend time evaluating the arguments.
- // This can be especially helpful if the arguments are expensive to calculate.
- logger.LogDebug(eventId: 501, "System.Environment.Version: {version}.", System.Environment.Version);
- }
- }
-}
diff --git a/docs/logs/getting-started/README.md b/docs/logs/getting-started/README.md
deleted file mode 100644
index f37377bb7e8..00000000000
--- a/docs/logs/getting-started/README.md
+++ /dev/null
@@ -1,81 +0,0 @@
-# Getting Started with OpenTelemetry .NET Logs in 5 Minutes
-
-First, download and install the [.NET
-SDK](https://dotnet.microsoft.com/download) on your computer.
-
-Create a new console application and run it:
-
-```sh
-dotnet new console --output getting-started
-cd getting-started
-dotnet run
-```
-
-You should see the following output:
-
-```text
-Hello World!
-```
-
-Install the latest `Microsoft.Extensions.Logging` package:
-
- ```sh
- dotnet add package Microsoft.Extensions.Logging
- ```
-
-Install the
-[OpenTelemetry.Exporter.Console](../../../src/OpenTelemetry.Exporter.Console/README.md)
-package:
-
-```sh
-dotnet add package OpenTelemetry.Exporter.Console
-```
-
-Update the `Program.cs` file with the code from [Program.cs](./Program.cs):
-
-Run the application again (using `dotnet run`) and you should see the log output
-on the console.
-
-```text
-LogRecord.Timestamp: 2023-01-21T00:33:08.1467491Z
-LogRecord.CategoryName: GettingStarted.Program
-LogRecord.LogLevel: Information
-LogRecord.State (Key:Value):
- name: tomato
- price: 2.99
- OriginalFormat (a.k.a Body): Hello from {name} {price}.
-LogRecord.EventId: 123
-```
-
-Congratulations! You are now collecting logs using OpenTelemetry.
-
-What does the above program do?
-
-The program creates a
-[`LoggerFactory`](https://docs.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory)
-with OpenTelemetry added as a
-[LoggerProvider](https://docs.microsoft.com/dotnet/core/extensions/logging-providers).
-This `LoggerFactory` is used to create an
-[`ILogger`](https://docs.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger)
-instance, which is then used to do the logging. The log is sent to the
-`OpenTelemetryLoggerProvider`, which is configured to export logs to
-`ConsoleExporter`. `ConsoleExporter` simply displays it on the console.
-
-> **Note**
-> Certain types of applications (e.g. [ASP.NET
-Core](https://learn.microsoft.com/aspnet/core) and [.NET
-Worker](https://learn.microsoft.com/dotnet/core/extensions/workers)) have an
-`ILogger` based logging pipeline set up by default. In such apps, enabling
-OpenTelemetry should be done by adding OpenTelemetry as a provider to the
-*existing* logging pipeline, and users should not create a new `LoggerFactory`
-(which sets up a totally new logging pipeline). Also, obtaining `ILogger`
-instance could be done differently as well. See [Example ASP.NET Core
-application](../../../examples/AspNetCore/Program.cs) for an example which shows
-how to add OpenTelemetry to the logging pipeline already setup by the
-application.
-
-## Learn more
-
-* [Compile-time logging source generation](../source-generation/README.md)
-* [Customizing the OpenTelemetry .NET SDK](../customizing-the-sdk/README.md)
-* [Extending the OpenTelemetry .NET SDK](../extending-the-sdk/README.md)
diff --git a/docs/logs/redaction/MyClassWithRedactionEnumerator.cs b/docs/logs/redaction/MyClassWithRedactionEnumerator.cs
deleted file mode 100644
index e8030a01581..00000000000
--- a/docs/logs/redaction/MyClassWithRedactionEnumerator.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-//
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-using System.Collections;
-
-namespace Redaction
-{
- internal class MyClassWithRedactionEnumerator : IReadOnlyList>
- {
- private readonly IReadOnlyList> state;
-
- public MyClassWithRedactionEnumerator(IReadOnlyList> state)
- {
- this.state = state;
- }
-
- public int Count => this.state.Count;
-
- public KeyValuePair this[int index]
- {
- get
- {
- var item = this.state[index];
- var entryVal = item.Value;
- if (entryVal != null && entryVal.ToString() != null && entryVal.ToString().Contains(""))
- {
- return new KeyValuePair(item.Key, "newRedactedValueHere");
- }
-
- return item;
- }
- }
-
- public IEnumerator> GetEnumerator()
- {
- for (var i = 0; i < this.Count; i++)
- {
- yield return this[i];
- }
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return this.GetEnumerator();
- }
- }
-}
diff --git a/docs/logs/redaction/MyRedactionProcessor.cs b/docs/logs/redaction/MyRedactionProcessor.cs
index 14dc33033e8..7959faf3d60 100644
--- a/docs/logs/redaction/MyRedactionProcessor.cs
+++ b/docs/logs/redaction/MyRedactionProcessor.cs
@@ -1,25 +1,11 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
+using System.Collections;
using OpenTelemetry;
using OpenTelemetry.Logs;
-namespace Redaction;
-
-internal class MyRedactionProcessor : BaseProcessor
+internal sealed class MyRedactionProcessor : BaseProcessor
{
public override void OnEnd(LogRecord logRecord)
{
@@ -28,4 +14,44 @@ public override void OnEnd(LogRecord logRecord)
logRecord.Attributes = new MyClassWithRedactionEnumerator(logRecord.Attributes);
}
}
+
+ internal sealed class MyClassWithRedactionEnumerator : IReadOnlyList>
+ {
+ private readonly IReadOnlyList> state;
+
+ public MyClassWithRedactionEnumerator(IReadOnlyList> state)
+ {
+ this.state = state;
+ }
+
+ public int Count => this.state.Count;
+
+ public KeyValuePair this[int index]
+ {
+ get
+ {
+ var item = this.state[index];
+ var entryVal = item.Value?.ToString();
+ if (entryVal != null && entryVal.Contains(""))
+ {
+ return new KeyValuePair(item.Key, "newRedactedValueHere");
+ }
+
+ return item;
+ }
+ }
+
+ public IEnumerator> GetEnumerator()
+ {
+ for (var i = 0; i < this.Count; i++)
+ {
+ yield return this[i];
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return this.GetEnumerator();
+ }
+ }
}
diff --git a/docs/logs/redaction/Program.cs b/docs/logs/redaction/Program.cs
index f381856234e..fa33d884581 100644
--- a/docs/logs/redaction/Program.cs
+++ b/docs/logs/redaction/Program.cs
@@ -1,38 +1,29 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;
-namespace Redaction;
-
-public class Program
+var loggerFactory = LoggerFactory.Create(builder =>
{
- public static void Main()
+ builder.AddOpenTelemetry(logging =>
{
- using var loggerFactory = LoggerFactory.Create(builder =>
- builder.AddOpenTelemetry(options =>
- {
- options.AddProcessor(new MyRedactionProcessor());
- options.AddConsoleExporter();
- }));
+ logging.AddProcessor(new MyRedactionProcessor());
+ logging.AddConsoleExporter();
+ });
+});
+
+var logger = loggerFactory.CreateLogger();
- var logger = loggerFactory.CreateLogger();
+// Message will be redacted by MyRedactionProcessor
+logger.FoodPriceChanged("", 9.99);
- // message will be redacted by MyRedactionProcessor
- logger.LogInformation("OpenTelemetry {sensitiveString}.", "");
- }
+// Dispose logger factory before the application ends.
+// This will flush the remaining logs and shutdown the logging pipeline.
+loggerFactory.Dispose();
+
+internal static partial class LoggerExtensions
+{
+ [LoggerMessage(LogLevel.Information, "Food `{name}` price changed to `{price}`.")]
+ public static partial void FoodPriceChanged(this ILogger logger, string name, double price);
}
diff --git a/docs/logs/redaction/redaction.csproj b/docs/logs/redaction/redaction.csproj
index db220b16f4c..2dc5d8deb63 100644
--- a/docs/logs/redaction/redaction.csproj
+++ b/docs/logs/redaction/redaction.csproj
@@ -4,7 +4,6 @@
disable
-
diff --git a/docs/logs/source-generation/FoodSupplyLogs.cs b/docs/logs/source-generation/FoodSupplyLogs.cs
deleted file mode 100644
index c7c54610bfb..00000000000
--- a/docs/logs/source-generation/FoodSupplyLogs.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-using Microsoft.Extensions.Logging;
-
-namespace SourceGeneration;
-
-public static partial class FoodSupplyLogs
-{
- [LoggerMessage(
- EventId = 1,
- Level = LogLevel.Information,
- Message = "Food `{name}` price changed to `{price}`.")]
- public static partial void FoodPriceChanged(this ILogger logger, string name, double price);
-
- [LoggerMessage(
- EventId = 2,
- Message = "A `{productType}` recall notice was published for `{brandName} {productDescription}` produced by `{companyName}` ({recallReasonDescription}).")]
- public static partial void FoodRecallNotice(
- this ILogger logger,
- LogLevel logLevel,
- string brandName,
- string productDescription,
- string productType,
- string recallReasonDescription,
- string companyName);
-}
diff --git a/docs/logs/source-generation/Program.cs b/docs/logs/source-generation/Program.cs
deleted file mode 100644
index 42c0e41ec3a..00000000000
--- a/docs/logs/source-generation/Program.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-using Microsoft.Extensions.Logging;
-using OpenTelemetry.Logs;
-
-namespace SourceGeneration;
-
-public class Program
-{
- public static void Main()
- {
- using var loggerFactory = LoggerFactory.Create(builder =>
- {
- builder.AddOpenTelemetry(options =>
- {
- options.IncludeScopes = true;
- options.ParseStateValues = true;
- options.IncludeFormattedMessage = true;
- options.AddConsoleExporter();
- });
- });
-
- var logger = loggerFactory.CreateLogger();
-
- logger.FoodPriceChanged("artichoke", 9.99);
-
- logger.FoodRecallNotice(
- logLevel: LogLevel.Critical,
- brandName: "Contoso",
- productDescription: "Salads",
- productType: "Food & Beverages",
- recallReasonDescription: "due to a possible health risk from Listeria monocytogenes",
- companyName: "Contoso Fresh Vegetables, Inc.");
- }
-}
diff --git a/docs/logs/source-generation/README.md b/docs/logs/source-generation/README.md
deleted file mode 100644
index c24f9d45e37..00000000000
--- a/docs/logs/source-generation/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-# Compile-time logging source generation
-
-.NET 6 has introduced a more usable and performant logging solution with
-[`LoggerMessageAttribute`](https://docs.microsoft.com/dotnet/api/microsoft.extensions.logging.loggermessageattribute).
-
-## References
-
-* [Compile-time logging source generation](https://docs.microsoft.com/dotnet/core/extensions/logger-message-generator)
diff --git a/docs/metrics/README.md b/docs/metrics/README.md
index 390604e64a0..23df6fbf172 100644
--- a/docs/metrics/README.md
+++ b/docs/metrics/README.md
@@ -1,93 +1,499 @@
# OpenTelemetry .NET Metrics
+
+
+Table of Contents
+
+* [Best Practices](#best-practices)
+* [Package Version](#package-version)
+* [Metrics API](#metrics-api)
+ * [Meter](#meter)
+ * [Instruments](#instruments)
+* [MeterProvider Management](#meterprovider-management)
+* [Memory Management](#memory-management)
+ * [Pre-Aggregation](#pre-aggregation)
+ * [Cardinality Limits](#cardinality-limits)
+ * [Memory Preallocation](#memory-preallocation)
+* [Metrics Correlation](#metrics-correlation)
+* [Metrics Enrichment](#metrics-enrichment)
+
+
+
+
## Best Practices
-- Instruments SHOULD only be created once and reused throughout the application
- lifetime. This
- [example](../../docs/metrics/getting-started-console/Program.cs) shows how an
- instrument is created a `static` field and then used in the application. You
- could also look at this ASP.NET Core
- [example](../../examples/AspNetCore/Program.cs) which shows a more Dependency
- Injection friendly way of doing this by extracting the `Meter` and an
- instrument into a dedicated class called
- [Instrumentation](../../examples/AspNetCore/Instrumentation.cs) which is then
- added as a `Singleton` service.
-
-- When emitting metrics with tags, DO NOT change the order in which you provide
- tags. Changing the order of tag keys would increase the time taken by the SDK
- to record the measurement.
+The following tutorials have demonstrated the best practices for using metrics
+with OpenTelemetry .NET:
+
+* [Getting Started - ASP.NET Core
+ Application](./getting-started-aspnetcore/README.md)
+* [Getting Started - Console Application](./getting-started-console/README.md)
+
+## Package Version
+
+:heavy_check_mark: You should always use the
+[System.Diagnostics.Metrics](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics)
+APIs from the latest stable version of
+[System.Diagnostics.DiagnosticSource](https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource/)
+package, regardless of the .NET runtime version being used:
+
+* If you are using the latest stable version of [OpenTelemetry .NET
+ SDK](../../src/OpenTelemetry/README.md), you do not have to worry about the
+ version of `System.Diagnostics.DiagnosticSource` package because it is already
+ taken care of for you via [package
+ dependency](../../Directory.Packages.props).
+* The .NET runtime team is holding a high bar for backward compatibility on
+ `System.Diagnostics.DiagnosticSource` even during major version bumps, so
+ compatibility is not a concern here.
+
+## Metrics API
+
+### Meter
+
+:stop_sign: You should avoid creating
+[`System.Diagnostics.Metrics.Meter`](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.meter)
+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)).
+
+:heavy_check_mark: You should use dot-separated
+[UpperCamelCase](https://en.wikipedia.org/wiki/Camel_case) as the
+[`Meter.Name`](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.meter.name).
+In many cases, using the fully qualified class name might be a good option.
```csharp
-// If you emit the tag keys in this order: name -> color -> taste, stick to this order of tag keys for subsequent measurements.
-MyFruitCounter.Add(5, new("name", "apple"), new("color", "red"), new("taste", "sweet"));
-...
-...
-...
-// Same measurement with the order of tags changed: color -> name -> taste. This order of tags is different from the one that was first encountered by the SDK.
-MyFruitCounter.Add(7, new("color", "red"), new("name", "apple"), new("taste", "sweet")); // <--- DON'T DO THIS
+static readonly Meter MyMeter = new("MyCompany.MyProduct.MyLibrary", "1.0");
```
-- When emitting metrics with more than three tags, use `TagList` for better
- performance. Using
- [`TagList`](https://learn.microsoft.com/dotnet/api/system.diagnostics.taglist?view=net-7.0#remarks)
- avoids allocating any memory for up to eight tags, thereby, reducing the
- pressure on GC to free up memory.
+### Instruments
+
+:heavy_check_mark: You should understand and pick the right instrument type.
+
+ > [!NOTE]
+ > .NET runtime has provided several instrument types based on the [OpenTelemetry
+ Specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument).
+ Picking the right instrument type for your use case is crucial to ensure the
+ correct semantics and performance. Check the [Instrument
+ Selection](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/supplementary-guidelines.md#instrument-selection)
+ section from the supplementary guidelines for more information.
+
+ | OpenTelemetry Specification | .NET Instrument Type |
+ | --------------------------- | -------------------- |
+ | [Asynchronous Counter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#asynchronous-counter) | [`ObservableCounter`](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.observablecounter-1) |
+ | [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 |
+ | [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) |
+
+:stop_sign: You should avoid creating instruments (e.g. `Counter`) too
+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)).
+
+:stop_sign: You should avoid invalid instrument names.
+
+> [!NOTE]
+> OpenTelemetry will not collect metrics from instruments that are using invalid
+ names. Refer to the [OpenTelemetry
+ Specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-name-syntax)
+ for the valid syntax.
+
+:stop_sign: You should avoid changing the order of tags while reporting
+measurements.
+
+> [!WARNING]
+> The last line of code has bad performance since the tags are not following
+ the same order:
```csharp
-var tags = new TagList
-{
- { "DimName1", "DimValue1" },
- { "DimName2", "DimValue2" },
- { "DimName3", "DimValue3" },
- { "DimName4", "DimValue4" },
-};
+counter.Add(2, new("name", "apple"), new("color", "red"));
+counter.Add(3, new("name", "lime"), new("color", "green"));
+counter.Add(5, new("name", "lemon"), new("color", "yellow"));
+counter.Add(8, new("color", "yellow"), new("name", "lemon")); // bad perf
+```
+
+:heavy_check_mark: You should use TagList properly to achieve the best
+performance.
-// Uses a TagList as there are more than three tags
-counter.Add(100, tags); // <--- DO THIS
+There are two different ways of passing tags to an instrument API:
+* Pass the tags directly to the instrument API:
-// Avoid the below mentioned approaches when there are more than three tags
-var tag1 = new KeyValuePair("DimName1", "DimValue1");
-var tag2 = new KeyValuePair("DimName2", "DimValue2");
-var tag3 = new KeyValuePair("DimName3", "DimValue3");
-var tag4 = new KeyValuePair("DimName4", "DimValue4");
+ ```csharp
+ counter.Add(100, ("Key1", "Value1"), ("Key2", "Value2"));
+ ```
-counter.Add(100, tag1, tag2, tag3, tag4); // <--- DON'T DO THIS
+* Use
+ [`TagList`](https://learn.microsoft.com/dotnet/api/system.diagnostics.taglist):
-var readOnlySpanOfTags = new KeyValuePair[4] { tag1, tag2, tag3, tag4};
-counter.Add(100, readOnlySpanOfTags); // <--- DON'T DO THIS
+ ```csharp
+ var tags = new TagList
+ {
+ { "DimName1", "DimValue1" },
+ { "DimName2", "DimValue2" },
+ { "DimName3", "DimValue3" },
+ { "DimName4", "DimValue4" },
+ };
+
+ counter.Add(100, tags);
+ ```
+
+Here is the rule of thumb:
+
+* When reporting measurements with 3 tags or less, pass the tags directly to the
+ instrument API.
+* When reporting measurements with 4 to 8 tags (inclusive), use
+ [`TagList`](https://learn.microsoft.com/dotnet/api/system.diagnostics.taglist?#remarks)
+ to avoid heap allocation if avoiding GC pressure is a primary performance
+ goal. For high performance code which consider reducing CPU utilization more
+ important (e.g. to reduce latency, to save battery, etc.) than optimizing
+ memory allocations, use profiler and stress test to determine which approach
+ is better.
+ Here are some [metrics benchmark
+ results](../../test/Benchmarks/Metrics/MetricsBenchmarks.cs) for reference.
+* When reporting measurements with more than 8 tags, the two approaches share
+ very similar CPU performance and heap allocation. `TagList` is recommended due
+ to its better readability and maintainability.
+
+> [!NOTE]
+> When reporting measurements with more than 8 tags, the API allocates memory on
+ the hot code path. You SHOULD try to keep the number of tags less than or
+ equal to 8. If you are exceeding this, check if you can model some of the tags
+ as Resource, as [shown here](#metrics-enrichment).
+
+## MeterProvider Management
+
+:stop_sign: You should avoid creating `MeterProvider` instances too frequently,
+`MeterProvider` is fairly expensive and meant to be reused throughout the
+application. For most applications, one `MeterProvider` instance per process
+would be sufficient.
+
+```mermaid
+graph LR
+
+subgraph Meter A
+ InstrumentX
+end
+
+subgraph Meter B
+ InstrumentY
+ InstrumentZ
+end
+
+subgraph Meter Provider 2
+ MetricReader2
+ MetricExporter2
+ MetricReader3
+ MetricExporter3
+end
+
+subgraph Meter Provider 1
+ MetricReader1
+ MetricExporter1
+end
+
+InstrumentX --> | Measurements | MetricReader1
+InstrumentY --> | Measurements | MetricReader1 --> MetricExporter1
+InstrumentZ --> | Measurements | MetricReader2 --> MetricExporter2
+InstrumentZ --> | Measurements | MetricReader3 --> MetricExporter3
```
-- When emitting metrics with more than eight tags, the SDK allocates memory on
- the hot-path. You SHOULD try to keep the number of tags less than or equal to
- eight. Check if you can extract any shared tags such as `MachineName`,
- `Environment` etc. into `Resource` attributes. Refer to this
- [doc](../../docs/metrics/customizing-the-sdk/README.md#resource) for more
- information.
+:heavy_check_mark: You should properly manage the lifecycle of `MeterProvider`
+instances if they are created by you.
+
+Here is the rule of thumb when managing the lifecycle of `MeterProvider`:
+
+* If you are building an application with [dependency injection
+ (DI)](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection)
+ (e.g. [ASP.NET Core](https://learn.microsoft.com/aspnet/core) and [.NET
+ Worker](https://learn.microsoft.com/dotnet/core/extensions/workers)), in most
+ cases you should create the `MeterProvider` instance and let DI manage its
+ lifecycle. Refer to the [Getting Started with OpenTelemetry .NET Metrics in 5
+ Minutes - ASP.NET Core Application](./getting-started-aspnetcore/README.md)
+ tutorial to learn more.
+* If you are building an application without DI, create a `MeterProvider`
+ instance and manage the lifecycle explicitly. Refer to the [Getting Started
+ with OpenTelemetry .NET Metrics in 5 Minutes - Console
+ Application](./getting-started-console/README.md) tutorial to learn more.
+* If you forget to dispose the `MeterProvider` instance before the application
+ ends, metrics might get dropped due to the lack of proper flush.
+* If you dispose the `MeterProvider` instance too early, any subsequent
+ measurements will not be collected.
+
+## Memory Management
+
+In OpenTelemetry,
+[measurements](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#measurement)
+are reported via the metrics API. The SDK
+[aggregates](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#aggregation)
+metrics using certain algorithms and memory management strategies to achieve
+good performance and efficiency. Here are the rules which OpenTelemetry .NET
+follows while implementing the metrics aggregation logic:
+
+1. [**Pre-Aggregation**](#pre-aggregation): aggregation occurs within the SDK.
+2. [**Cardinality Limits**](#cardinality-limits): the aggregation logic respects
+ [cardinality
+ limits](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#cardinality-limits),
+ so the SDK does not use indefinite amount of memory when there is cardinality
+ explosion.
+3. [**Memory Preallocation**](#memory-preallocation): the memory used by
+ aggregation logic is allocated during the SDK initialization, so the SDK does
+ not have to allocate memory on-the-fly. This is to avoid garbage collection
+ being triggered on the hot code path.
+
+### Example
+
+Let us take the following example:
+
+* During the time range (T0, T1]:
+ * value = 1, name = `apple`, color = `red`
+ * value = 2, name = `lemon`, color = `yellow`
+* During the time range (T1, T2]:
+ * no fruit has been received
+* During the time range (T2, T3]:
+ * value = 5, name = `apple`, color = `red`
+ * value = 2, name = `apple`, color = `green`
+ * value = 4, name = `lemon`, color = `yellow`
+ * value = 2, name = `lemon`, color = `yellow`
+ * value = 1, name = `lemon`, color = `yellow`
+ * value = 3, name = `lemon`, color = `yellow`
+
+If we aggregate and export the metrics using [Cumulative Aggregation
+Temporality](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#temporality):
+
+* (T0, T1]
+ * attributes: {name = `apple`, color = `red`}, count: `1`
+ * attributes: {verb = `lemon`, color = `yellow`}, count: `2`
+* (T0, T2]
+ * attributes: {name = `apple`, color = `red`}, count: `1`
+ * attributes: {verb = `lemon`, color = `yellow`}, count: `2`
+* (T0, T3]
+ * attributes: {name = `apple`, color = `red`}, count: `6`
+ * attributes: {name = `apple`, color = `green`}, count: `2`
+ * attributes: {verb = `lemon`, color = `yellow`}, count: `12`
+
+If we aggregate and export the metrics using [Delta Aggregation
+Temporality](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#temporality):
+
+* (T0, T1]
+ * attributes: {name = `apple`, color = `red`}, count: `1`
+ * attributes: {verb = `lemon`, color = `yellow`}, count: `2`
+* (T1, T2]
+ * nothing since we do not have any measurement received
+* (T2, T3]
+ * attributes: {name = `apple`, color = `red`}, count: `5`
+ * attributes: {name = `apple`, color = `green`}, count: `2`
+ * attributes: {verb = `lemon`, color = `yellow`}, count: `10`
+
+### Pre-Aggregation
+
+Taking the [fruit example](#example), there are 6 measurements reported during
+`(T2, T3]`. Instead of exporting every individual measurement event, the SDK
+aggregates them and only exports the summarized results. This approach, as
+illustrated in the following diagram, is called pre-aggregation:
+
+```mermaid
+graph LR
+
+subgraph SDK
+ Instrument --> | Measurements | Pre-Aggregation[Pre-Aggregation]
+end
+
+subgraph Collector
+ Aggregation
+end
+
+Pre-Aggregation --> | Metrics | Aggregation
+```
+
+Pre-aggregation brings several benefits:
+
+1. Although the amount of calculation remains the same, the amount of data
+ transmitted can be significantly reduced using pre-aggregation, thus
+ improving the overall efficiency.
+2. Pre-aggregation makes it possible to apply [cardinality
+ limits](#cardinality-limits) during SDK initialization, combined with [memory
+ preallocation](#memory-preallocation), they make the metrics data collection
+ behavior more predictable (e.g. a server under denial-of-service attack would
+ still produce a constant volume of metrics data, rather than flooding the
+ observability system with large volume of measurement events).
+
+There are cases where users might want to export raw measurement events instead
+of using pre-aggregation, as illustrated in the following diagram. OpenTelemetry
+does not support this scenario at the moment, if you are interested, please join
+the discussion by replying to this [feature
+ask](https://github.com/open-telemetry/opentelemetry-specification/issues/617).
+
+```mermaid
+graph LR
+
+subgraph SDK
+ Instrument
+end
+
+subgraph Collector
+ Aggregation
+end
+
+Instrument --> | Measurements | Aggregation
+```
+
+### Cardinality Limits
+
+The number of unique combinations of attributes is called cardinality. Taking
+the [fruit example](#example), if we know that we can only have apple/lemon as
+the name, red/yellow/green as the color, then we can say the cardinality is 6.
+No matter how many apples and lemons we have, we can always use the following
+table to summarize the total number of fruits based on the name and color.
+
+| Name | Color | Count |
+| ----- | ------ | ----- |
+| apple | red | 6 |
+| apple | yellow | 0 |
+| apple | green | 2 |
+| lemon | red | 0 |
+| lemon | yellow | 12 |
+| lemon | green | 0 |
+
+In other words, we know how much storage and network are needed to collect and
+transmit these metrics, regardless of the traffic pattern.
+
+In real world applications, the cardinality can be extremely high. Imagine if we
+have a long running service and we collect metrics with 7 attributes and each
+attribute can have 30 different values. We might eventually end up having to
+remember the complete set of all 21,870,000,000 combinations! This cardinality
+explosion is a well-known challenge in the metrics space. For example, it can
+cause surprisingly high costs in the observability system, or even be leveraged
+by hackers to launch a denial-of-service attack.
+
+[Cardinality
+limit](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#cardinality-limits)
+is a throttling mechanism which allows the metrics collection system to have a
+predictable and reliable behavior when excessive cardinality happens, whether it
+was due to a malicious attack or developer making mistakes while writing code.
+
+OpenTelemetry has a default cardinality limit of `2000` per metric. This limit
+can be configured at the individual metric level using the [View
+API](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#view)
+and the `MetricStreamConfiguration.CardinalityLimit` setting. Refer to this
+[doc](../../docs/metrics/customizing-the-sdk/README.md#changing-the-cardinality-limit-for-a-metric)
+for more information.
+
+Given a metric, once the cardinality limit is reached, any new measurement which
+cannot be independently aggregated because of the limit will be dropped or
+aggregated using the [overflow
+attribute](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#overflow-attribute)
+(if enabled). When NOT using the overflow attribute feature a warning is written
+to the [self-diagnostic log](../../src/OpenTelemetry/README.md#self-diagnostics)
+the first time an overflow is detected for a given metric.
+
+> [!NOTE]
+> Overflow attribute was introduced in OpenTelemetry .NET
+ [1.6.0-rc.1](../../src/OpenTelemetry/CHANGELOG.md#160-rc1). It is currently an
+ experimental feature which can be turned on by setting the environment
+ variable `OTEL_DOTNET_EXPERIMENTAL_METRICS_EMIT_OVERFLOW_ATTRIBUTE=true`. Once
+ the [OpenTelemetry
+ Specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#overflow-attribute)
+ become stable, this feature will be turned on by default.
+
+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.
+
+> [!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.
+
+### Memory Preallocation
+
+OpenTelemetry .NET SDK aims to avoid memory allocation on the hot code path.
+When this is combined with [proper use of Metrics API](#metrics-api), heap
+allocation can be avoided on the hot code path. Refer to the [metrics benchmark
+results](../../test/Benchmarks/Metrics/MetricsBenchmarks.cs) to learn more.
+
+:heavy_check_mark: You should measure memory allocation on hot code path, and
+ideally avoid any heap allocation while using the metrics API and SDK,
+especially when you use metrics to measure the performance of your application
+(for example, you do not want to spend 2 seconds doing [garbage
+collection](https://learn.microsoft.com/dotnet/standard/garbage-collection/)
+while measuring an operation which normally takes 10 milliseconds).
+
+## Metrics Correlation
+
+In OpenTelemetry, metrics can be correlated to [traces](../trace/README.md) via
+[exemplars](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar).
+Check the [Exemplars](./exemplars/README.md) tutorial to learn more.
+
+## Metrics Enrichment
+
+When metrics are being collected, they normally get stored in a [time series
+database](https://en.wikipedia.org/wiki/Time_series_database). From storage and
+consumption perspective, metrics can be multi-dimensional. Taking the [fruit
+example](#example), there are two dimensions - "name" and "color". For basic
+scenarios, all the dimensions can be reported during the [Metrics
+API](#metrics-api) invocation, however, for less trivial scenarios, the
+dimensions can come from different sources:
+
+* [Measurements](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#measurement)
+ reported via the [Metrics API](#metrics-api).
+* Additional tags provided at instrument creation time. For example, the
+ [`Meter.CreateCounter(name, unit, description,
+ tags)`](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.meter.createcounter)
+ overload.
+* Additional tags provided at meter creation time. For example, the
+ [`Meter(name, version, tags,
+ scope)`](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.meter.-ctor)
+ overload.
+* [Resources](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md)
+ configured at the `MeterProvider` level. Refer to this
+ [doc](./customizing-the-sdk/README.md#resource) for details and examples.
+* Additional attributes provided by the exporter or collector. For example,
+ [jobs and instances](https://prometheus.io/docs/concepts/jobs_instances/) in
+ Prometheus.
+
+> [!NOTE]
+> Instrument level tags support is not yet implemented in OpenTelemetry .NET
+ since the [OpenTelemetry
+ Specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument)
+ does not support it.
+
+Here is the rule of thumb when modeling the dimensions:
+
+* If the dimension is static throughout the process lifetime (e.g. the name of
+ the machine, data center):
+ * If the dimension applies to all metrics, model it as Resource, or even
+ better, let the collector add these dimensions if feasible (e.g. a collector
+ running in the same data center should know the name of the data center,
+ rather than relying on / trusting each service instance to report the data
+ center name).
+ * If the dimension applies to a subset of metrics (e.g. the version of a
+ client library), model it as meter level tags.
+* If the dimension value is dynamic, report it via the [Metrics
+ API](#metrics-api).
+
+> [!NOTE]
+> There were discussions around adding a new concept called
+ `MeasurementProcessor`, which allows dimensions to be added to / removed from
+ measurements dynamically. This idea did not get traction due to the complexity
+ and performance implications, refer to this [pull
+ request](https://github.com/open-telemetry/opentelemetry-specification/pull/1938)
+ for more context.
## Common issues that lead to missing metrics
-- The `Meter` used to create the instruments is not added to the
+* The `Meter` used to create the instruments is not added to the
`MeterProvider`. Use `AddMeter` method to enable the processing for the
required metrics.
-- Instrument name is invalid. When naming instruments, ensure that the name you
- choose meets the criteria defined in the
- [spec](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-name-syntax).
- A few notable characters that are not allowed in the instrument name: `/`
- (forward slash), `\` (backward slash), any space character in the name.
-- MetricPoint limit is reached. By default, the SDK limits the number of maximum
- MetricPoints (unique combination of keys and values for a given Metric stream)
- to `2000`. This limit can be configured using
- `SetMaxMetricPointsPerMetricStream` method. Refer to this
- [doc](../../docs/metrics/customizing-the-sdk/README.md#changing-maximum-metricpoints-per-metricstream)
- for more information. The SDK would not process any newer unique key-value
- combination that it encounters, once this limit is reached.
-- MeterProvider is disposed. You need to ensure that the `MeterProvider`
- instance is kept active for metrics to be collected. In a typical application,
- a single MeterProvider is built at application startup, and is disposed of at
- application shutdown. For an ASP.NET Core application, use `AddOpenTelemetry`
- and `WithMetrics` methods from the `OpenTelemetry.Extensions.Hosting` package
- to correctly setup `MeterProvider`. Here's a [sample ASP.NET Core
- app](../../examples/AspNetCore/Program.cs) for reference. For simpler
- applications such as Console apps, refer to this
- [example](../../docs/metrics/getting-started-console/Program.cs).
diff --git a/docs/metrics/customizing-the-sdk/Program.cs b/docs/metrics/customizing-the-sdk/Program.cs
index c8b08c3cc5b..48c9a975311 100644
--- a/docs/metrics/customizing-the-sdk/Program.cs
+++ b/docs/metrics/customizing-the-sdk/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics.Metrics;
using OpenTelemetry;
@@ -29,7 +16,12 @@ public class Program
public static void Main()
{
using var meterProvider = Sdk.CreateMeterProviderBuilder()
- .ConfigureResource(res => res.AddService("example-service"))
+ .ConfigureResource(resource => resource.AddAttributes(new List>
+ {
+ new KeyValuePair("static-attribute1", "v1"),
+ new KeyValuePair("static-attribute2", "v2"),
+ }))
+ .ConfigureResource(resource => resource.AddService("MyServiceName"))
.AddMeter(Meter1.Name)
.AddMeter(Meter2.Name)
diff --git a/docs/metrics/customizing-the-sdk/README.md b/docs/metrics/customizing-the-sdk/README.md
index aaa7acb909c..4cb57f11693 100644
--- a/docs/metrics/customizing-the-sdk/README.md
+++ b/docs/metrics/customizing-the-sdk/README.md
@@ -102,7 +102,7 @@ using var meterProvider = Sdk.CreateMeterProviderBuilder()
See [Program.cs](./Program.cs) for complete example.
-> **Note**
+> [!NOTE]
> A common mistake while configuring `MeterProvider` is forgetting to
add the required `Meter`s to the provider. It is recommended to leverage the
wildcard subscription model where it makes sense. For example, if your
@@ -198,6 +198,7 @@ with the metric are of interest to you.
MyFruitCounter.Add(1, new("name", "apple"), new("color", "red"));
MyFruitCounter.Add(2, new("name", "lemon"), new("color", "yellow"));
MyFruitCounter.Add(2, new("name", "apple"), new("color", "green"));
+ // Because "color" is dropped the resulting metric values are - name:apple LongSum Value:3 and name:lemon LongSum Value:2
...
// If you provide an empty `string` array as `TagKeys` to the `MetricStreamConfiguration`
@@ -214,6 +215,7 @@ with the metric are of interest to you.
MyFruitCounter.Add(1, new("name", "apple"), new("color", "red"));
MyFruitCounter.Add(2, new("name", "lemon"), new("color", "yellow"));
MyFruitCounter.Add(2, new("name", "apple"), new("color", "green"));
+ // Because both "name" and "color" are dropped the resulting metric value is - LongSum Value:5
...
```
@@ -321,7 +323,7 @@ within the maximum number of buckets defined by `MaxSize`. The default
})
```
-> **Note**
+> [!NOTE]
> The SDK currently does not support any changes to `Aggregation` type
by using Views.
@@ -365,88 +367,28 @@ MyFruitCounter.Add(1, new("name", "apple"), new("color", "red"));
AnotherFruitCounter.Add(1, new("name", "apple"), new("color", "red"));
```
-### Changing maximum MetricPoints per MetricStream
-
-A Metric stream can contain as many Metric points as the number of unique
-combination of keys and values. To protect the SDK from unbounded memory usage,
-SDK limits the maximum number of metric points per metric stream, to a default
-of 2000. Once the limit is hit, any new key/value combination for that metric is
-ignored. The SDK chooses the key/value combinations in the order in which they
-are emitted. `SetMaxMetricPointsPerMetricStream` can be used to override the
-default.
-
-> **Note**
-> One `MetricPoint` is reserved for every `MetricStream` for the
-special case where there is no key/value pair associated with the metric. The
-maximum number of `MetricPoint`s has to accommodate for this special case.
-
-Consider the below example. Here we set the maximum number of `MetricPoint`s
-allowed to be `3`. This means that for every `MetricStream`, the SDK will export
-measurements for up to `3` distinct key/value combinations of the metric. There
-are two instruments published here: `MyFruitCounter` and `AnotherFruitCounter`.
-There are two total `MetricStream`s created one for each of these instruments.
-SDK will limit the maximum number of distinct key/value combinations for each of
-these `MetricStream`s to `3`.
+### Changing the cardinality limit for a Metric
-```csharp
-using System.Collections.Generic;
-using System.Diagnostics.Metrics;
-using OpenTelemetry;
-using OpenTelemetry.Metrics;
+To set the [cardinality limit](../README.md#cardinality-limits) for an
+individual metric, use `MetricStreamConfiguration.CardinalityLimit` setting on
+the View API:
-Counter MyFruitCounter = MyMeter.CreateCounter("MyFruitCounter");
-Counter AnotherFruitCounter = MyMeter.CreateCounter("AnotherFruitCounter");
+> [!NOTE]
+> `MetricStreamConfiguration.CardinalityLimit` is an experimental API only
+ available in pre-release builds. For details see:
+ [OTEL1003](../../diagnostics/experimental-apis/OTEL1003.md).
-using var meterProvider = Sdk.CreateMeterProviderBuilder()
- .AddMeter("*")
+```csharp
+var meterProvider = Sdk.CreateMeterProviderBuilder()
+ .AddMeter("MyCompany.MyProduct.MyLibrary")
+ // Set a custom CardinalityLimit (10) for "MyFruitCounter"
+ .AddView(
+ instrumentName: "MyFruitCounter",
+ new MetricStreamConfiguration { CardinalityLimit = 10 })
.AddConsoleExporter()
- .SetMaxMetricPointsPerMetricStream(3) // The default value is 2000
.Build();
-
-// There are four distinct key/value combinations emitted for `MyFruitCounter`:
-// 1. No key/value pair
-// 2. (name:apple, color:red)
-// 3. (name:lemon, color:yellow)
-// 4. (name:apple, color:green)
-
-// Since the maximum number of `MetricPoint`s allowed is `3`, the SDK will only export measurements for the following three combinations:
-// 1. No key/value pair
-// 2. (name:apple, color:red)
-// 3. (name:lemon, color:yellow)
-
-MyFruitCounter.Add(1); // Exported (No key/value pair)
-MyFruitCounter.Add(1, new("name", "apple"), new("color", "red")); // Exported
-MyFruitCounter.Add(2, new("name", "lemon"), new("color", "yellow")); // Exported
-MyFruitCounter.Add(1, new("name", "lemon"), new("color", "yellow")); // Exported
-MyFruitCounter.Add(2, new("name", "apple"), new("color", "green")); // Not exported
-MyFruitCounter.Add(5, new("name", "apple"), new("color", "red")); // Exported
-MyFruitCounter.Add(4, new("name", "lemon"), new("color", "yellow")); // Exported
-
-// There are four distinct key/value combinations emitted for `AnotherFruitCounter`:
-// 1. (name:kiwi)
-// 2. (name:banana, color:yellow)
-// 3. (name:mango, color:yellow)
-// 4. (name:banana, color:green)
-
-// Since the maximum number of `MetricPoint`s allowed is `3`, the SDK will only export measurements for the following three combinations:
-// 1. No key/value pair (This is a special case. The SDK reserves a `MetricPoint` for it even if it's not explicitly emitted.)
-// 2. (name:kiwi)
-// 3. (name:banana, color:yellow)
-
-AnotherFruitCounter.Add(4, new KeyValuePair("name", "kiwi")); // Exported
-AnotherFruitCounter.Add(1, new("name", "banana"), new("color", "yellow")); // Exported
-AnotherFruitCounter.Add(2, new("name", "mango"), new("color", "yellow")); // Not exported
-AnotherFruitCounter.Add(1, new("name", "mango"), new("color", "yellow")); // Not exported
-AnotherFruitCounter.Add(2, new("name", "banana"), new("color", "green")); // Not exported
-AnotherFruitCounter.Add(5, new("name", "banana"), new("color", "yellow")); // Exported
-AnotherFruitCounter.Add(4, new("name", "mango"), new("color", "yellow")); // Not exported
```
-> **Note**
-> The above limit is *per* metric stream, and applies to all the metric
-streams. There is no ability to apply different limits for each instrument at
-this moment.
-
### Exemplars
Exemplars are example data points for aggregated data. They provide access to
@@ -470,26 +412,23 @@ exemplars.
#### ExemplarFilter
-`ExemplarFilter` determines which measurements are eligible to become an
-Exemplar. i.e. `ExemplarFilter` determines which measurements are offered to
-`ExemplarReservoir`, which makes the final decision about whether the offered
-measurement gets stored as an exemplar. They can be used to control the noise
-and overhead associated with Exemplar collection.
+`ExemplarFilter` determines which measurements are offered to the configured
+`ExemplarReservoir`, which makes the final decision about whether or not the
+offered measurement gets recorded as an `Exemplar`. Generally `ExemplarFilter`
+is a mechanism to control the overhead associated with `Exemplar` offering.
-OpenTelemetry SDK comes with the following Filters:
+OpenTelemetry SDK comes with the following `ExemplarFilters` (defined on
+`ExemplarFilterType`):
-* `AlwaysOnExemplarFilter` - makes all measurements eligible for being an Exemplar.
-* `AlwaysOffExemplarFilter` - makes no measurements eligible for being an
- Exemplar. Using this is as good as turning off Exemplar feature, and is the current
+* `AlwaysOff`: Makes no measurements eligible for becoming an `Exemplar`. Using
+ this is as good as turning off the `Exemplar` feature and is the current
default.
-* `TraceBasedExemplarFilter` - makes those measurements eligible for being an
-Exemplar, which are recorded in the context of a sampled parent `Activity`
-(span).
-
-`SetExemplarFilter` method on `MeterProviderBuilder` can be used to set the
-desired `ExemplarFilter`.
+* `AlwaysOn`: Makes all measurements eligible for becoming an `Exemplar`.
+* `TraceBased`: Makes those measurements eligible for becoming an `Exemplar`
+ which are recorded in the context of a sampled `Activity` (span).
-The snippet below shows how to set `ExemplarFilter`.
+The `SetExemplarFilter` extension method on `MeterProviderBuilder` can be used
+to set the desired `ExemplarFilterType` and enable `Exemplar` collection:
```csharp
using OpenTelemetry;
@@ -497,31 +436,14 @@ using OpenTelemetry.Metrics;
using var meterProvider = Sdk.CreateMeterProviderBuilder()
// rest of config not shown
- .SetExemplarFilter(new TraceBasedExemplarFilter())
+ .SetExemplarFilter(ExemplarFilterType.TraceBased)
.Build();
```
-> **Note**
-> As of today, there is no separate toggle for enable/disable Exemplar feature.
-Exemplars can be disabled by setting filter as `AlwaysOffExemplarFilter`, which
-is also the default (i.e Exemplar feature is disabled by default). Users can
-enable the feature by setting filter to anything other than
-`AlwaysOffExemplarFilter`. For example: `.SetExemplarFilter(new TraceBasedExemplarFilter())`.
-
-If the built-in `ExemplarFilter`s are not meeting the needs, one may author
-custom `ExemplarFilter` as shown
-[here](../extending-the-sdk/README.md#exemplarfilter). A custom filter, which
-eliminates all un-interesting measurements from becoming Exemplar is a
-recommended way to control performance overhead associated with collecting
-Exemplars. See
-[benchmark](../../../test/Benchmarks/Metrics/ExemplarBenchmarks.cs) to see how
-much impact can `ExemplarFilter` have on performance.
-
#### ExemplarReservoir
-`ExemplarReservoir` receives the measurements sampled in by the `ExemplarFilter`
-and is responsible for storing Exemplars. `ExemplarReservoir` ultimately decides
-which measurements get stored as exemplars. The following are the default
+`ExemplarReservoir` receives the measurements sampled by the `ExemplarFilter`
+and is responsible for recording `Exemplar`s. The following are the default
reservoirs:
* `AlignedHistogramBucketExemplarReservoir` is the default reservoir used for
@@ -529,15 +451,15 @@ Histograms with buckets, and it stores at most one exemplar per histogram
bucket. The exemplar stored is the last measurement recorded - i.e. any new
measurement overwrites the previous one in that bucket.
-`SimpleExemplarReservoir` is the default reservoir used for all metrics except
-Histograms with buckets. It has a fixed reservoir pool, and implements the
-equivalent of [naive
+* `SimpleFixedSizeExemplarReservoir` is the default reservoir used for all
+metrics except Histograms with buckets. It has a fixed reservoir pool, and
+implements the equivalent of [naive
reservoir](https://en.wikipedia.org/wiki/Reservoir_sampling). The reservoir pool
-size (currently defaulting to 10) determines the maximum number of exemplars
+size (currently defaulting to 1) determines the maximum number of exemplars
stored.
-> **Note**
-> Currently there is no ability to change or configure Reservoir.
+> [!NOTE]
+> Currently there is no ability to change or configure `ExemplarReservoir`.
### Instrumentation
@@ -570,17 +492,32 @@ Refer to the individual exporter docs to learn how to use them:
[Resource](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md)
is the immutable representation of the entity producing the telemetry. If no
`Resource` is explicitly configured, the
-[default](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#semantic-attributes-with-sdk-provided-default-value)
+[default](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#semantic-attributes-with-sdk-provided-default-value)
is to use a resource indicating this
-[Service](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service).
-The `ConfigureResource` method on `MeterProviderBuilder` can be used to set a
-configure the resource on the provider. When the provider is built, it
-automatically builds the final `Resource` from the configured `ResourceBuilder`.
-There can only be a single `Resource` associated with a
-provider. It is not possible to change the resource builder *after* the provider
-is built, by calling the `Build()` method on the `MeterProviderBuilder`.
+[Service](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#service)
+and [Telemetry
+SDK](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#telemetry-sdk).
+The `ConfigureResource` method on `MeterProviderBuilder` can be used to
+configure the resource on the provider. `ConfigureResource` accepts an `Action`
+to configure the `ResourceBuilder`. Multiple calls to `ConfigureResource` can be
+made. When the provider is built, it builds the final `Resource` combining all
+the `ConfigureResource` calls. There can only be a single `Resource` associated
+with a provider. It is not possible to change the resource builder *after* the
+provider is built, by calling the `Build()` method on the
+`MeterProviderBuilder`.
+
`ResourceBuilder` offers various methods to construct resource comprising of
-multiple attributes from various sources.
+attributes from various sources. For example, `AddService()` adds
+[Service](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#service)
+resource. `AddAttributes` can be used to add any additional attributes to the
+`Resource`. It also allows adding `ResourceDetector`s.
+
+It is recommended to model attributes that are static throughout the lifetime of
+the process as Resources, instead of adding them as attributes(tags) on each
+measurement.
+
+Follow [this](../../resources/README.md#resource-detector) document
+to learn about writing custom resource detectors.
The snippet below shows configuring the `Resource` associated with the provider.
@@ -590,7 +527,12 @@ using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using var meterProvider = Sdk.CreateMeterProviderBuilder()
- .ConfigureResource(r => r.AddService("MyServiceName"))
+ .ConfigureResource(r => r.AddAttributes(new List>
+ {
+ new KeyValuePair("static-attribute1", "v1"),
+ new KeyValuePair("static-attribute2", "v2"),
+ }))
+ .ConfigureResource(resourceBuilder => resourceBuilder.AddService("service-name"))
.Build();
```
diff --git a/docs/metrics/exemplars/docker-compose.yaml b/docs/metrics/exemplars/docker-compose.yaml
index 87cd7a6c6d6..c8cc94fa4b1 100644
--- a/docs/metrics/exemplars/docker-compose.yaml
+++ b/docs/metrics/exemplars/docker-compose.yaml
@@ -48,4 +48,3 @@ services:
- GF_FEATURE_TOGGLES_ENABLE=traceqlEditor
ports:
- "3000:3000"
-
diff --git a/docs/metrics/extending-the-sdk/MyExporter.cs b/docs/metrics/extending-the-sdk/MyExporter.cs
index 36cb6cc4663..228d3e0c342 100644
--- a/docs/metrics/extending-the-sdk/MyExporter.cs
+++ b/docs/metrics/extending-the-sdk/MyExporter.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Text;
using OpenTelemetry;
diff --git a/docs/metrics/extending-the-sdk/MyExporterExtensions.cs b/docs/metrics/extending-the-sdk/MyExporterExtensions.cs
index bc1ea34eae0..bb5cb6deff6 100644
--- a/docs/metrics/extending-the-sdk/MyExporterExtensions.cs
+++ b/docs/metrics/extending-the-sdk/MyExporterExtensions.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using OpenTelemetry.Metrics;
diff --git a/docs/metrics/extending-the-sdk/Program.cs b/docs/metrics/extending-the-sdk/Program.cs
index 469a9aff087..a2952062261 100644
--- a/docs/metrics/extending-the-sdk/Program.cs
+++ b/docs/metrics/extending-the-sdk/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using System.Diagnostics.Metrics;
diff --git a/docs/metrics/extending-the-sdk/README.md b/docs/metrics/extending-the-sdk/README.md
index 4c409961d86..c7293ac418a 100644
--- a/docs/metrics/extending-the-sdk/README.md
+++ b/docs/metrics/extending-the-sdk/README.md
@@ -4,6 +4,7 @@
* [Building your own reader](#reader)
* [Building your own exemplar filter](#exemplarfilter)
* [Building your own exemplar reservoir](#exemplarreservoir)
+* [Building your own resource detector](../../resources/README.md#resource-detector)
* [References](#references)
## Exporter
@@ -73,44 +74,7 @@ Not supported.
## ExemplarFilter
-OpenTelemetry .NET SDK has provided the following built-in `ExemplarFilter`s:
-
-* [AlwaysOnExemplarFilter](../../../src/OpenTelemetry/Metrics/Exemplar/AlwaysOnExemplarFilter.cs)
-* [AlwaysOffExemplarFilter](../../../src/OpenTelemetry/Metrics/Exemplar/AlwaysOffExemplarFilter.cs)
-* [TraceBasedExemplarFilter](../../../src/OpenTelemetry/Metrics/Exemplar/TraceBasedExemplarFilter.cs)
-
-Custom exemplar filters can be implemented to achieve filtering based on other criterion:
-
-* `ExemplarFilter` should derive from `OpenTelemetry.ExemplarFilter` (which
- belongs to the [OpenTelemetry](../../../src/OpenTelemetry/README.md) package)
- and implement the `ShouldSample` method.
-
-One example is a filter, which filters all measurements of value lower
-than given threshold is given below. Such a filter prevents any measurements
-below the given threshold from ever becoming a `Exemplar`. Such filters could
-also incorporate the `TraceBasedExemplarFilter` condition as well, as storing
-exemplars for non-sampled traces may be undesired.
-
-```csharp
-public sealed class HighValueFilter : ExemplarFilter
-{
- private readonly double maxValue;
-
- public HighValueFilter(double maxValue)
- {
- this.maxValue = maxValue;
- }
- public override bool ShouldSample(long value, ReadOnlySpan> tags)
- {
- return Activity.Current?.Recorded && value > this.maxValue;
- }
-
- public override bool ShouldSample(double value, ReadOnlySpan> tags)
- {
- return Activity.Current?.Recorded && value > this.maxValue;
- }
-}
-```
+Not supported.
## ExemplarReservoir
diff --git a/docs/metrics/getting-started-aspnetcore/Program.cs b/docs/metrics/getting-started-aspnetcore/Program.cs
index 835703f0c81..3c38b73c16a 100644
--- a/docs/metrics/getting-started-aspnetcore/Program.cs
+++ b/docs/metrics/getting-started-aspnetcore/Program.cs
@@ -1,20 +1,6 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
-using System.Diagnostics;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
diff --git a/docs/metrics/getting-started-aspnetcore/README.md b/docs/metrics/getting-started-aspnetcore/README.md
index 5b76615e4ff..7f202931b90 100644
--- a/docs/metrics/getting-started-aspnetcore/README.md
+++ b/docs/metrics/getting-started-aspnetcore/README.md
@@ -20,15 +20,9 @@ packages:
```sh
dotnet add package OpenTelemetry.Exporter.Console
dotnet add package OpenTelemetry.Extensions.Hosting
-dotnet add package OpenTelemetry.Instrumentation.AspNetCore --prerelease
+dotnet add package OpenTelemetry.Instrumentation.AspNetCore
```
-> **Note** This quickstart guide uses prerelease packages. For a quickstart
-> which only relies on stable packages see: [Getting Started - Console
-> Application](../getting-started-console/README.md). For more information about
-> when instrumentation will be marked as stable see: [Instrumentation-1.0.0
-> milestone](https://github.com/open-telemetry/opentelemetry-dotnet/milestone/23).
-
Update the `Program.cs` file with the code from [Program.cs](./Program.cs).
Run the application again (using `dotnet run`) and then browse to the url shown
@@ -84,7 +78,7 @@ appBuilder.Services.AddOpenTelemetry()
);
```
-> **Note**
+> [!NOTE]
> The `AddOpenTelemetry` extension is part of the
[OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md)
package.
diff --git a/docs/metrics/getting-started-aspnetcore/getting-started-aspnetcore.csproj b/docs/metrics/getting-started-aspnetcore/getting-started-aspnetcore.csproj
index 1956f427004..375079fc34c 100644
--- a/docs/metrics/getting-started-aspnetcore/getting-started-aspnetcore.csproj
+++ b/docs/metrics/getting-started-aspnetcore/getting-started-aspnetcore.csproj
@@ -1,15 +1,7 @@
-
-
- net6.0;net7.0
- enable
- enable
-
-
-
diff --git a/docs/metrics/getting-started-console/Program.cs b/docs/metrics/getting-started-console/Program.cs
index 4911d3ce73c..89425c6d41c 100644
--- a/docs/metrics/getting-started-console/Program.cs
+++ b/docs/metrics/getting-started-console/Program.cs
@@ -1,25 +1,10 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics.Metrics;
using OpenTelemetry;
using OpenTelemetry.Metrics;
-namespace GettingStarted;
-
public class Program
{
private static readonly Meter MyMeter = new("MyCompany.MyProduct.MyLibrary", "1.0");
@@ -27,16 +12,23 @@ public class Program
public static void Main()
{
- using var meterProvider = Sdk.CreateMeterProviderBuilder()
+ var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter("MyCompany.MyProduct.MyLibrary")
.AddConsoleExporter()
.Build();
+ // In this example, we have low cardinality which is below the 2000
+ // default limit. If you have high cardinality, you need to set the
+ // cardinality limit properly.
MyFruitCounter.Add(1, new("name", "apple"), new("color", "red"));
MyFruitCounter.Add(2, new("name", "lemon"), new("color", "yellow"));
MyFruitCounter.Add(1, new("name", "lemon"), new("color", "yellow"));
MyFruitCounter.Add(2, new("name", "apple"), new("color", "green"));
MyFruitCounter.Add(5, new("name", "apple"), new("color", "red"));
MyFruitCounter.Add(4, new("name", "lemon"), new("color", "yellow"));
+
+ // Dispose meter provider before the application ends.
+ // This will flush the remaining metrics and shutdown the metrics pipeline.
+ meterProvider.Dispose();
}
}
diff --git a/docs/metrics/getting-started-console/README.md b/docs/metrics/getting-started-console/README.md
index c73961de86f..3f30652b313 100644
--- a/docs/metrics/getting-started-console/README.md
+++ b/docs/metrics/getting-started-console/README.md
@@ -69,19 +69,33 @@ MyFruitCounter.Add(2, new("name", "lemon"), new("color", "yellow"));
MyFruitCounter.Add(1, new("name", "lemon"), new("color", "yellow"));
```
-An OpenTelemetry
-[MeterProvider](#meterprovider)
-is configured to subscribe to instruments from the Meter
-`MyCompany.MyProduct.MyLibrary`, and aggregate the measurements in-memory. The
+An OpenTelemetry [MeterProvider](#meterprovider) is configured to subscribe to
+an instrument named "MyFruitCounter" from the Meter
+`MyCompany.MyProduct.MyLibrary`, and aggregate the measurements in-memory with a
+default [cardinality limit](../README.md#cardinality-limits) of `2000`. The
pre-aggregated metrics are exported to a `ConsoleExporter`.
```csharp
-using var meterProvider = Sdk.CreateMeterProviderBuilder()
+var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter("MyCompany.MyProduct.MyLibrary")
.AddConsoleExporter()
.Build();
```
+> [!NOTE]
+> If you need to collect metrics with cardinality higher than the default limit
+ `2000`, please follow the [cardinality
+ limits](../README.md#cardinality-limits) guidance. Here is a quick example of
+ how to change the cardinality limit to `10` for this particular metric:
+
+ ```csharp
+ var meterProvider = Sdk.CreateMeterProviderBuilder()
+ .AddMeter("MyCompany.MyProduct.MyLibrary")
+ .AddView(instrumentName: "MyFruitCounter", new MetricStreamConfiguration { CardinalityLimit = 10 })
+ .AddConsoleExporter()
+ .Build();
+ ```
+
```mermaid
graph LR
diff --git a/docs/metrics/getting-started-prometheus-grafana/Program.cs b/docs/metrics/getting-started-prometheus-grafana/Program.cs
index 1920698f308..0fd2437eefd 100644
--- a/docs/metrics/getting-started-prometheus-grafana/Program.cs
+++ b/docs/metrics/getting-started-prometheus-grafana/Program.cs
@@ -1,25 +1,11 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics.Metrics;
using OpenTelemetry;
+using OpenTelemetry.Exporter;
using OpenTelemetry.Metrics;
-namespace GettingStartedPrometheusGrafana;
-
public class Program
{
private static readonly Meter MyMeter = new("MyCompany.MyProduct.MyLibrary", "1.0");
@@ -27,21 +13,32 @@ public class Program
public static void Main()
{
- using var meterProvider = Sdk.CreateMeterProviderBuilder()
+ var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter("MyCompany.MyProduct.MyLibrary")
- .AddPrometheusHttpListener()
+ .AddOtlpExporter((exporterOptions, metricReaderOptions) =>
+ {
+ exporterOptions.Endpoint = new Uri("http://localhost:9090/api/v1/otlp/v1/metrics");
+ exporterOptions.Protocol = OtlpExportProtocol.HttpProtobuf;
+ metricReaderOptions.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds = 1000;
+ })
.Build();
Console.WriteLine("Press any key to exit");
+
while (!Console.KeyAvailable)
{
- Thread.Sleep(1000);
MyFruitCounter.Add(1, new("name", "apple"), new("color", "red"));
MyFruitCounter.Add(2, new("name", "lemon"), new("color", "yellow"));
MyFruitCounter.Add(1, new("name", "lemon"), new("color", "yellow"));
MyFruitCounter.Add(2, new("name", "apple"), new("color", "green"));
MyFruitCounter.Add(5, new("name", "apple"), new("color", "red"));
MyFruitCounter.Add(4, new("name", "lemon"), new("color", "yellow"));
+
+ Thread.Sleep(300);
}
+
+ // Dispose meter provider before the application ends.
+ // This will flush the remaining metrics and shutdown the metrics pipeline.
+ meterProvider.Dispose();
}
}
diff --git a/docs/metrics/getting-started-prometheus-grafana/README.md b/docs/metrics/getting-started-prometheus-grafana/README.md
index 69e87c9f793..7f39b121a72 100644
--- a/docs/metrics/getting-started-prometheus-grafana/README.md
+++ b/docs/metrics/getting-started-prometheus-grafana/README.md
@@ -1,10 +1,8 @@
# Getting Started with Prometheus and Grafana
- [Export metrics from the application](#export-metrics-from-the-application)
- - [Check results in the browser](#check-results-in-the-browser)
- [Collect metrics using Prometheus](#collect-metrics-using-prometheus)
- - [Configuration](#configuration)
- - [Start Prometheus](#start-prometheus)
+ - [Install and run Prometheus](#install-and-run-prometheus)
- [View results in Prometheus](#view-results-in-prometheus)
- [Explore metrics using Grafana](#explore-metrics-using-grafana)
- [Learn more](#learn-more)
@@ -18,43 +16,25 @@ this document.
Create a new console application and run it:
```sh
-dotnet new console --output getting-started-prometheus
-cd getting-started-prometheus
+dotnet new console --output getting-started-prometheus-grafana
+cd getting-started-prometheus-grafana
dotnet run
```
-Add a reference to [Prometheus
-Exporter Http Listener](../../../src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md):
+Add reference to [OTLP
+Exporter](../../../src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md):
```sh
-dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener --prerelease
+dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
```
-Now, we are going to make some small tweaks to the example in the
-getting-started metrics `Program.cs` to make the metrics available via
-OpenTelemetry Prometheus Exporter.
+Now copy the code from [Program.cs](./Program.cs) and run the application again.
-First, copy and paste everything from getting-started metrics
-[example](../getting-started-console/Program.cs) to the Program.cs file of the
-new console application (getting-started-prometheus) we've created.
-
-And replace the below line:
-
-```csharp
-.AddConsoleExporter()
-```
-
-with
-
-```csharp
-.AddPrometheusHttpListener()
-```
-
-`PrometheusHttpListener` is a wrapper that contains `PrometheusExporter`. With
-`AddPrometheusHttpListener()`, OpenTelemetry `PrometheusExporter` will export
-data via the endpoint defined by
-[PrometheusHttpListenerOptions.UriPrefixes](../../../src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md#uriprefixes),
-which is `http://localhost:9464/` by default.
+When we ran the application, the OTLP Exporter was attempting to export the
+metrics to `http://localhost:9090/api/v1/otlp/v1/metrics`. Since Prometheus
+server was not running, the metrics received by `OtlpExporter` were simply
+dropped on the floor. In the next step, we are going to learn about how to use
+Prometheus to collect and visualize the metrics.
```mermaid
graph LR
@@ -62,7 +42,7 @@ graph LR
subgraph SDK
MeterProvider
MetricReader[BaseExportingMetricReader]
- PrometheusHttpListener["PrometheusHttpListener (http://localhost:9464/)"]
+ OtlpExporter
end
subgraph API
@@ -71,7 +51,7 @@ end
Instrument --> | Measurements | MeterProvider
-MeterProvider --> | Metrics | MetricReader --> | Pull | PrometheusHttpListener
+MeterProvider --> | Metrics | MetricReader --> | Push | OtlpExporter --> | HTTP/protobuf | PrometheusServer[Prometheus server]
```
Also, for our learning purpose, use a while-loop to keep increasing the counter
@@ -79,86 +59,48 @@ value until any key is pressed.
```csharp
Console.WriteLine("Press any key to exit");
+
while (!Console.KeyAvailable)
{
- Thread.Sleep(1000);
MyFruitCounter.Add(1, new("name", "apple"), new("color", "red"));
MyFruitCounter.Add(2, new("name", "lemon"), new("color", "yellow"));
- MyFruitCounter.Add(1, new("name", "lemon"), new("color", "yellow"));
- ...
- ...
...
+
+ Thread.Sleep(300);
}
```
-After the above modifications, now our `Program.cs` should look like [this](./Program.cs).
-
-### Check results in the browser
-
-Start the application and keep it running. Now we should be able to see the
-metrics at [http://localhost:9464/metrics](http://localhost:9464/metrics) from a
-web browser:
-
-![Browser UI](https://user-images.githubusercontent.com/17327289/151633547-736c6d91-62d2-4e66-a53f-2e16c44bfabc.png)
-
-Now, we understand how we can configure `PrometheusHttpListener` to export metrics.
-Next, we are going to learn about how to use Prometheus to collect the metrics.
-
## Collect metrics using Prometheus
+### Install and run Prometheus
+
Follow the [first steps](https://prometheus.io/docs/introduction/first_steps/)
to download the [latest release](https://prometheus.io/download/) of Prometheus.
-### Configuration
-
After finished downloading, extract it to a local location that's easy to
-access. We will find the default Prometheus configuration YAML file in the
-folder, named `prometheus.yml`.
-
-Let's create a new file in the same location as where `prometheus.yml` locates,
-and named the new file as `otel.yml` for this exercise. Then, copy and paste the
-entire content below into the `otel.yml` file we have created just now.
-
-```yaml
-global:
- scrape_interval: 10s
- evaluation_interval: 10s
-scrape_configs:
- - job_name: "otel"
- static_configs:
- - targets: ["localhost:9464"]
-```
+access. Run the `prometheus(.exe)` server executable with feature flag
+[otlp-receiver](https://prometheus.io/docs/prometheus/latest/feature_flags/#otlp-receiver)
+enabled:
-### Start Prometheus
-
-Follow the instructions from
-[starting-prometheus](https://prometheus.io/docs/introduction/first_steps/#starting-prometheus)
-to start the Prometheus server and verify it has been started successfully.
-
-Please note that we will need pass in `otel.yml` file as the argument:
-
-```console
-./prometheus --config.file=otel.yml
+```sh
+./prometheus --enable-feature=otlp-write-receiver
```
### View results in Prometheus
To use the graphical interface for viewing our metrics with Prometheus, navigate
to [http://localhost:9090/graph](http://localhost:9090/graph), and type
-`MyFruitCounter` in the expression bar of the UI; finally, click the execute
-button.
+`MyFruitCounter_total` in the expression bar of the UI; finally, click the
+execute button.
We should be able to see the following chart from the browser:
![Prometheus UI](https://user-images.githubusercontent.com/17327289/151636225-6e4ce4c7-09f3-4996-8ca5-d404a88d9195.png)
-From the legend, we can see that the `instance` name and the `job` name are the
-values we have set in `otel.yml`.
-
Congratulations!
Now we know how to configure Prometheus server and deploy OpenTelemetry
-`PrometheusHttpListener` to export our metrics. Next, we are going to explore a tool
+`OtlpExporter` to export our metrics. Next, we are going to explore a tool
called Grafana, which has powerful visualizations for the metrics.
## Explore metrics using Grafana
@@ -191,28 +133,15 @@ Feel free to find some handy PromQL
[here](https://promlabs.com/promql-cheat-sheet/).
In the below example, the query targets to find out what is the per-second rate
-of increase of myFruitCounter over the past 5 minutes:
+of increase of `MyFruitCounter_total` over the past 5 minutes:
![Grafana
UI](https://user-images.githubusercontent.com/17327289/151636769-138ecb4f-b44f-477b-88eb-247fc4340252.png)
-```mermaid
-graph TD
-
-subgraph Prometheus
- PrometheusScraper
- PrometheusDatabase
-end
-
-PrometheusHttpListener["PrometheusHttpListener (listening at #quot;http://localhost:9464/#quot;)"] -->|HTTP GET| PrometheusScraper{{"Prometheus scraper (polling #quot;http://localhost:9464/metrics#quot; every 10 seconds)"}}
-PrometheusScraper --> PrometheusDatabase[("Prometheus TSDB (time series database)")]
-PrometheusDatabase -->|http://localhost:9090/graph| PrometheusUI["Browser (Prometheus Dashboard)"]
-PrometheusDatabase -->|http://localhost:9090/api/| Grafana[Grafana Server]
-Grafana -->|http://localhost:3000/dashboard| GrafanaUI["Browser (Grafana Dashboard)"]
-```
-
## Learn more
- [What is Prometheus?](https://prometheus.io/docs/introduction/overview/)
+- [Prometheus now supports OpenTelemetry
+ Metrics](https://horovits.medium.com/prometheus-now-supports-opentelemetry-metrics-83f85878e46a)
- [Grafana support for
Prometheus](https://prometheus.io/docs/visualization/grafana/#creating-a-prometheus-graph)
diff --git a/docs/metrics/getting-started-prometheus-grafana/getting-started-prometheus-grafana.csproj b/docs/metrics/getting-started-prometheus-grafana/getting-started-prometheus-grafana.csproj
index 8d59ff99ce3..cce12eec60d 100644
--- a/docs/metrics/getting-started-prometheus-grafana/getting-started-prometheus-grafana.csproj
+++ b/docs/metrics/getting-started-prometheus-grafana/getting-started-prometheus-grafana.csproj
@@ -1,5 +1,5 @@
-
+
diff --git a/docs/metrics/learning-more-instruments/Program.cs b/docs/metrics/learning-more-instruments/Program.cs
index 40b36c11500..c887e281461 100644
--- a/docs/metrics/learning-more-instruments/Program.cs
+++ b/docs/metrics/learning-more-instruments/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using System.Diagnostics.Metrics;
diff --git a/docs/resources/README.md b/docs/resources/README.md
new file mode 100644
index 00000000000..059acbc063d
--- /dev/null
+++ b/docs/resources/README.md
@@ -0,0 +1,109 @@
+# Resources
+
+## Resource Detector
+
+OpenTelemetry .NET SDK provides a resource detector for detecting resource
+information from the `OTEL_RESOURCE_ATTRIBUTES` and `OTEL_SERVICE_NAME`
+environment variables.
+
+Custom resource detectors can be implemented:
+
+* ResourceDetectors should inherit from
+ `OpenTelemetry.Resources.IResourceDetector`, (which belongs to the
+ [OpenTelemetry](../../src/OpenTelemetry/README.md) package), and implement
+ the `Detect` method.
+
+A demo `ResourceDetector` is shown [here](./extending-the-sdk/MyResourceDetector.cs):
+
+```csharp
+using OpenTelemetry.Resources;
+
+internal class MyResourceDetector : IResourceDetector
+{
+ public Resource Detect()
+ {
+ var attributes = new List>
+ {
+ new KeyValuePair("key", "val"),
+ };
+
+ return new Resource(attributes);
+ }
+}
+```
+
+There are two different ways to add the custom `ResourceDetector` to the
+OTEL signals, via the `Sdk.Create` approach:
+
+```csharp
+using System.Diagnostics;
+using System.Diagnostics.Metrics;
+using Microsoft.Extensions.Logging;
+using OpenTelemetry;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Resources;
+using OpenTelemetry.Trace;
+
+namespace ExtendingTheSdk;
+
+public class Program
+{
+ private static readonly ActivitySource DemoSource = new("OTel.Demo");
+ private static readonly Meter MeterDemoSource = new("OTel.Demo");
+
+ public static void Main()
+ {
+ using var tracerProvider = Sdk.CreateTracerProviderBuilder()
+ .AddSource("OTel.Demo")
+ .SetResourceBuilder(ResourceBuilder.CreateEmpty().AddDetector(
+ new MyResourceDetector()))
+ .Build();
+
+ using var meterProvider = Sdk.CreateMeterProviderBuilder()
+ .SetResourceBuilder(ResourceBuilder.CreateEmpty().AddDetector(
+ new MyResourceDetector()))
+ .Build();
+
+ using var loggerFactory = LoggerFactory.Create(builder =>
+ {
+ builder.AddOpenTelemetry(options =>
+ {
+ options.SetResourceBuilder(ResourceBuilder
+ .CreateDefault().AddDetector(
+ new MyResourceDetector()));
+ });
+ });
+
+ using (var foo = DemoSource.StartActivity("Foo"))
+ {
+ using (var bar = DemoSource.StartActivity("Bar"))
+ {
+ using (var baz = DemoSource.StartActivity("Baz"))
+ {
+ }
+ }
+ }
+
+ var counter = MeterDemoSource.CreateCounter("counter");
+ for (var i = 0; i < 20000; i++)
+ counter.Add(1, new("tag1", "value1"), new("tag2", "value2"));
+
+ var logger = loggerFactory.CreateLogger("OTel.Demo");
+ logger
+ .LogInformation("Hello from {name} {price}.", "tomato", 2.99);
+ }
+}
+```
+
+or via `OpenTelemetry.Extensions.Hosting` method:
+
+```csharp
+ services.AddSingleton();
+
+ services.AddOpenTelemetry()
+ .ConfigureResource(builder => builder
+ .AddDetector(sp =>
+ sp.GetRequiredService()))
+ .WithTracing(builder => builder.AddConsoleExporter())
+ .WithMetrics(builder => builder.AddConsoleExporter());
+```
diff --git a/docs/resources/extending-the-sdk/MyResourceDetector.cs b/docs/resources/extending-the-sdk/MyResourceDetector.cs
new file mode 100644
index 00000000000..df40d9b3302
--- /dev/null
+++ b/docs/resources/extending-the-sdk/MyResourceDetector.cs
@@ -0,0 +1,17 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using OpenTelemetry.Resources;
+
+internal class MyResourceDetector : IResourceDetector
+{
+ public Resource Detect()
+ {
+ var attributes = new List>
+ {
+ new KeyValuePair("key", "val"),
+ };
+
+ return new Resource(attributes);
+ }
+}
diff --git a/docs/resources/extending-the-sdk/Program.cs b/docs/resources/extending-the-sdk/Program.cs
new file mode 100644
index 00000000000..849bdcc182b
--- /dev/null
+++ b/docs/resources/extending-the-sdk/Program.cs
@@ -0,0 +1,61 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using System.Diagnostics;
+using System.Diagnostics.Metrics;
+using Microsoft.Extensions.Logging;
+using OpenTelemetry;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Resources;
+using OpenTelemetry.Trace;
+
+namespace ExtendingTheSdk;
+
+public class Program
+{
+ private static readonly ActivitySource DemoSource = new("OTel.Demo");
+ private static readonly Meter MeterDemoSource = new("OTel.Demo");
+
+ public static void Main()
+ {
+ using var tracerProvider = Sdk.CreateTracerProviderBuilder()
+ .AddSource("OTel.Demo")
+ .SetResourceBuilder(ResourceBuilder.CreateEmpty().AddDetector(
+ new MyResourceDetector()))
+ .Build();
+
+ using var meterProvider = Sdk.CreateMeterProviderBuilder()
+ .SetResourceBuilder(ResourceBuilder.CreateEmpty().AddDetector(
+ new MyResourceDetector()))
+ .Build();
+
+ using var loggerFactory = LoggerFactory.Create(builder =>
+ {
+ builder.AddOpenTelemetry(options =>
+ {
+ options.SetResourceBuilder(ResourceBuilder.CreateDefault().AddDetector(
+ new MyResourceDetector()));
+ });
+ });
+
+ using (var foo = DemoSource.StartActivity("Foo"))
+ {
+ using (var bar = DemoSource.StartActivity("Bar"))
+ {
+ using (var baz = DemoSource.StartActivity("Baz"))
+ {
+ }
+ }
+ }
+
+ var counter = MeterDemoSource.CreateCounter("counter");
+ for (var i = 0; i < 20000; i++)
+ {
+ counter.Add(1, new KeyValuePair("tag1", "value1"), new KeyValuePair("tag2", "value2"));
+ }
+
+ var logger = loggerFactory.CreateLogger("OTel.Demo");
+ logger
+ .LogInformation("Hello from {Name} {Price}", "tomato", 2.99);
+ }
+}
diff --git a/docs/resources/extending-the-sdk/extending-the-sdk.csproj b/docs/resources/extending-the-sdk/extending-the-sdk.csproj
new file mode 100644
index 00000000000..85aab7a7ed3
--- /dev/null
+++ b/docs/resources/extending-the-sdk/extending-the-sdk.csproj
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/docs/trace/README.md b/docs/trace/README.md
new file mode 100644
index 00000000000..c472800b3ba
--- /dev/null
+++ b/docs/trace/README.md
@@ -0,0 +1,172 @@
+# OpenTelemetry .NET Traces
+
+
+
+Table of Contents
+
+* [Best Practices](#best-practices)
+* [Package Version](#package-version)
+* [Tracing API](#tracing-api)
+ * [ActivitySource](#activitysource)
+ * [Activity](#activity)
+* [TracerProvider Management](#tracerprovider-management)
+* [Correlation](#correlation)
+
+
+
+
+## Best Practices
+
+The following tutorials have demonstrated the best practices for using traces
+with OpenTelemetry .NET:
+
+* [Getting Started - ASP.NET Core
+ Application](./getting-started-aspnetcore/README.md)
+* [Getting Started - Console Application](./getting-started-console/README.md)
+
+## Package Version
+
+:heavy_check_mark: You should always use the
+[System.Diagnostics.Activity](https://learn.microsoft.com/dotnet/api/system.diagnostics.activity)
+APIs from the latest stable version of
+[System.Diagnostics.DiagnosticSource](https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource/)
+package, regardless of the .NET runtime version being used:
+
+* If you are using the latest stable version of [OpenTelemetry .NET
+ SDK](../../src/OpenTelemetry/README.md), you do not have to worry about the
+ version of `System.Diagnostics.DiagnosticSource` package because it is already
+ taken care of for you via [package
+ dependency](../../Directory.Packages.props).
+* The .NET runtime team is holding a high bar for backward compatibility on
+ `System.Diagnostics.DiagnosticSource` even during major version bumps, so
+ compatibility is not a concern here.
+
+## Tracing API
+
+### ActivitySource
+
+:stop_sign: You should avoid creating
+[`System.Diagnostics.ActivitySource`](https://learn.microsoft.com/dotnet/api/system.diagnostics.activitysource)
+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)).
+
+:heavy_check_mark: You should use dot-separated
+[UpperCamelCase](https://en.wikipedia.org/wiki/Camel_case) as the
+[`ActivitySource.Name`](https://learn.microsoft.com/dotnet/api/system.diagnostics.activitysource.name).
+In many cases, using the fully qualified class name might be a good option.
+
+```csharp
+static readonly ActivitySource MyActivitySource = new("MyCompany.MyProduct.MyLibrary");
+```
+
+### Activity
+
+:heavy_check_mark: You should check
+[`Activity.IsAllDataRequested`](https://learn.microsoft.com/dotnet/api/system.diagnostics.activity.isalldatarequested)
+before [setting
+Tags](https://learn.microsoft.com/dotnet/api/system.diagnostics.activity.settag)
+for better performance.
+
+```csharp
+using (var activity = MyActivitySource.StartActivity("SayHello"))
+{
+ if (activity != null && activity.IsAllDataRequested == true)
+ {
+ activity.SetTag("http.url", "http://www.mywebsite.com");
+ }
+}
+```
+
+:heavy_check_mark: You should use
+[Activity.SetTag](https://learn.microsoft.com/dotnet/api/system.diagnostics.activity.settag)
+to [set
+attributes](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-attributes).
+
+:heavy_check_mark: You should finish/stop the activity properly. This can be
+done implicitly via a `using` statement, which is recommended. You can also
+explicitly call
+[Activity.Dispose](https://learn.microsoft.com/dotnet/api/system.diagnostics.activity.dispose)
+or
+[Activity.Stop](https://learn.microsoft.com/dotnet/api/system.diagnostics.activity.stop).
+
+> [!NOTE]
+> Activities which are not yet finished/stopped will not be exported.
+
+## TracerProvider Management
+
+:stop_sign: You should avoid creating `TracerProvider` instances too frequently,
+`TracerProvider` is fairly expensive and meant to be reused throughout the
+application. For most applications, one `TracerProvider` instance per process
+would be sufficient.
+
+:heavy_check_mark: You should properly manage the lifecycle of `TracerProvider`
+instances if they are created by you.
+
+Here is the rule of thumb when managing the lifecycle of `TracerProvider`:
+
+* If you are building an application with [dependency injection
+ (DI)](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection)
+ (e.g. [ASP.NET Core](https://learn.microsoft.com/aspnet/core) and [.NET
+ Worker](https://learn.microsoft.com/dotnet/core/extensions/workers)), in most
+ cases you should create the `TracerProvider` instance and let DI manage its
+ lifecycle. Refer to the [Getting Started with OpenTelemetry .NET Traces in 5
+ Minutes - ASP.NET Core Application](./getting-started-aspnetcore/README.md)
+ tutorial to learn more.
+* If you are building an application without DI, create a `TracerProvider`
+ instance and manage the lifecycle explicitly. Refer to the [Getting Started
+ with OpenTelemetry .NET Traces in 5 Minutes - Console
+ Application](./getting-started-console/README.md) tutorial to learn more.
+* If you forget to dispose the `TracerProvider` instance before the application
+ ends, activities might get dropped due to the lack of proper flush.
+* If you dispose the `TracerProvider` instance too early, any subsequent
+ activities will not be collected.
+
+## Correlation
+
+In OpenTelemetry, traces are automatically [correlated to
+logs](../logs/README.md#log-correlation) and can be [correlated to
+metrics](../metrics/README.md#metrics-correlation) via
+[exemplars](../metrics/exemplars/README.md).
+
+### Manually creating Activities
+
+As shown in the [getting started](getting-started-console/README.md) guide, it
+is very easy to manually create `Activity`. Due to this, it can be tempting to
+create too many activities (eg: for each method call). In addition to being
+expensive, excessive activities can also make trace visualization harder.
+Instead of manually creating `Activity`, check if you can leverage
+instrumentation libraries, such as [ASP.NET
+Core](../../src/OpenTelemetry.Instrumentation.AspNetCore/README.md),
+[HttpClient](../../src/OpenTelemetry.Instrumentation.Http/README.md) which will
+not only create and populate `Activity` with tags(attributes), but also take
+care of propagating/restoring the context across process boundaries. If the
+`Activity` produced by the instrumentation library is missing some information
+you need, it is generally recommended to enrich the existing Activity with that
+information, as opposed to creating a new one.
+
+### Modelling static tags as Resource
+
+Tags such as `MachineName`, `Environment` etc. which are static throughout the
+process lifetime should be modelled as `Resource`, instead of adding them to
+each `Activity`. Refer to this [doc](./customizing-the-sdk/README.md#resource)
+for details and examples.
+
+## Common issues that lead to missing traces
+
+* The `ActivitySource` used to create the `Activity` is not added to the
+ `TracerProvider`. Use `AddSource` method to enable the activity from a given
+ `ActivitySource`.
+* `TracerProvider` is disposed too early. You need to ensure that the
+ `TracerProvider` instance is kept active for traces to be collected. In a
+ typical application, a single TracerProvider is built at application startup,
+ and is disposed of at application shutdown. For an ASP.NET Core application,
+ use `AddOpenTelemetry` and `WithTraces` methods from the
+ `OpenTelemetry.Extensions.Hosting` package to correctly setup
+ `TracerProvider`. Here is a [sample ASP.NET Core
+ app](../../examples/AspNetCore/Program.cs) for reference. For simpler
+ applications such as Console apps, refer to this
+ [example](../../docs/trace/getting-started-console/Program.cs).
+* TODO: Sampling
diff --git a/docs/trace/customizing-the-sdk/Program.cs b/docs/trace/customizing-the-sdk/Program.cs
index 20f0f9df73e..fead3aa0be2 100644
--- a/docs/trace/customizing-the-sdk/Program.cs
+++ b/docs/trace/customizing-the-sdk/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry;
@@ -46,8 +33,12 @@ public static void Main()
// The following adds subscription to activities from all Activity Sources
// whose name starts with "AbcCompany.XyzProduct.".
.AddSource("AbcCompany.XyzProduct.*")
- .ConfigureResource(resourceBuilder => resourceBuilder.AddTelemetrySdk())
- .ConfigureResource(r => r.AddService("MyServiceName"))
+ .ConfigureResource(resource => resource.AddAttributes(new List>
+ {
+ new KeyValuePair("static-attribute1", "v1"),
+ new KeyValuePair("static-attribute2", "v2"),
+ }))
+ .ConfigureResource(resource => resource.AddService("MyServiceName"))
.AddConsoleExporter()
.Build();
diff --git a/docs/trace/customizing-the-sdk/README.md b/docs/trace/customizing-the-sdk/README.md
index e440446448c..4d4a0c772e4 100644
--- a/docs/trace/customizing-the-sdk/README.md
+++ b/docs/trace/customizing-the-sdk/README.md
@@ -37,7 +37,7 @@ appBuilder.Services.AddOpenTelemetry()
.WithTracing(builder => builder.AddConsoleExporter());
```
-> **Note**
+> [!NOTE]
> The
[AddOpenTelemetry](../../../src/OpenTelemetry.Extensions.Hosting/README.md#extension-method-reference)
extension automatically starts and stops the `TracerProvider` with the host.
@@ -51,7 +51,7 @@ required.
Call `Sdk.CreateTracerProviderBuilder()` to obtain a builder and then call
`Build()` once configuration is done to retrieve the `TracerProvider` instance.
-> **Note**
+> [!NOTE]
> Once built changes to `TracerProvider` configuration are not allowed,
with the exception of adding more processors.
@@ -128,7 +128,7 @@ var tracerProvider = Sdk.CreateTracerProviderBuilder()
See [Program.cs](./Program.cs) for complete example.
-> **Note**
+> [!NOTE]
> A common mistake while configuring `TracerProvider` is forgetting to
add all `ActivitySources` to the provider. It is recommended to leverage the
wild card subscription model where it makes sense. For example, if your
@@ -173,7 +173,7 @@ processor classes `SimpleExportProcessor` & `BatchExportProcessor` are provided
to support invoking exporters through the processor pipeline and implement the
standard behaviors prescribed by the OpenTelemetry specification.
-> **Note**
+> [!NOTE]
> The SDK only ever invokes processors and has no direct knowledge of
any registered exporters.
@@ -196,13 +196,13 @@ var tracerProvider = Sdk.CreateTracerProviderBuilder()
tracerProvider.AddProcessor(new MyProcessor3());
```
-> **Note**
+> [!NOTE]
> The order of processor registration is important. Each processor added
is invoked in order by the SDK. For example if a simple exporting processor is
added before an enrichment processor the exported data will not contain anything
added by the enrichment because it happens after the export.
-> **Note**
+> [!NOTE]
> A `TracerProvider` assumes ownership of **all** processors added to
it. This means that the provider will call the `Shutdown` method on all
registered processors when it is shutting down and call the `Dispose` method on
@@ -238,13 +238,13 @@ For exporting purposes, the SDK provides the following built-in processors:
: This is an exporting processor which passes telemetry to the configured
exporter immediately without any batching.
-> **Note**
+> [!NOTE]
> A special processor
[CompositeProcessor<T>](../../../src/OpenTelemetry/CompositeProcessor.cs)
is used by the SDK to chain multiple processors together and may be used as
needed by users to define sub-pipelines.
-> **Note**
+> [!NOTE]
> The processors shipped from this SDK are generic implementations and support
tracing and logging by implementing `Activity` and `LogRecord` respectively.
@@ -268,15 +268,15 @@ var tracerProvider = Sdk.CreateTracerProviderBuilder()
It is also common for exporters to provide their own extensions to simplify
registration. The snippet below shows how to add the
-[JaegerExporter](../../../src/OpenTelemetry.Exporter.Jaeger/README.md) to the
-provider before it is built.
+[OtlpExporter](../../../src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md)
+to the provider before it is built.
```csharp
using OpenTelemetry;
using OpenTelemetry.Trace;
var tracerProvider = Sdk.CreateTracerProviderBuilder()
- .AddJaegerExporter()
+ .AddOtlpExporter()
.Build();
```
@@ -288,9 +288,11 @@ writing custom exporters.
[Resource](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md)
is the immutable representation of the entity producing the telemetry. If no
`Resource` is explicitly configured, the
-[default](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#semantic-attributes-with-sdk-provided-default-value)
-resource is used to indicate the
-[Service](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service).
+[default](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#semantic-attributes-with-sdk-provided-default-value)
+is to use a resource indicating this
+[Service](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#service)
+and [Telemetry
+SDK](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#telemetry-sdk).
The `ConfigureResource` method on `TracerProviderBuilder` can be used to
configure the resource on the provider. `ConfigureResource` accepts an `Action`
to configure the `ResourceBuilder`. Multiple calls to `ConfigureResource` can be
@@ -301,14 +303,16 @@ provider is built, by calling the `Build()` method on the
`TracerProviderBuilder`.
`ResourceBuilder` offers various methods to construct resource comprising of
-multiple attributes from various sources. Examples include `AddTelemetrySdk()`
-which adds [Telemetry
-Sdk](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#telemetry-sdk)
-resource, and `AddService()` which adds
-[Service](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service)
-resource. It also allows adding `ResourceDetector`s.
-
-Follow [this](../extending-the-sdk/README.md#resource-detector) document
+attributes from various sources. For example, `AddService()` adds
+[Service](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#service)
+resource. `AddAttributes` can be used to add any additional attribute to the
+`Resource`. It also allows adding `ResourceDetector`s.
+
+It is recommended to model attributes that are static throughout the lifetime of
+the process as Resources, instead of adding them as attributes(tags) on each
+`Activity`.
+
+Follow [this](../../resources/README.md#resource-detector) document
to learn about writing custom resource detectors.
The snippet below shows configuring the `Resource` associated with the provider.
@@ -319,7 +323,11 @@ using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
var tracerProvider = Sdk.CreateTracerProviderBuilder()
- .ConfigureResource(resourceBuilder => resourceBuilder.AddTelemetrySdk())
+ .ConfigureResource(r => r.AddAttributes(new List>
+ {
+ new KeyValuePair("static-attribute1", "v1"),
+ new KeyValuePair("static-attribute2", "v2"),
+ }))
.ConfigureResource(resourceBuilder => resourceBuilder.AddService("service-name"))
.Build();
```
@@ -374,7 +382,7 @@ Sdk.SetDefaultTextMapPropagator(new MyCustomPropagator());
## Dependency injection support
-> **Note**
+> [!NOTE]
> This information applies to the OpenTelemetry SDK version 1.4.0 and
newer only.
@@ -419,14 +427,14 @@ When using the `Sdk.CreateTracerProviderBuilder` method the `TracerProvider`
owns its own `IServiceCollection`. It will only be able to see services
registered into that collection.
-> **Note**
+> [!NOTE]
> It is important to correctly manage the lifecycle of the
`TracerProvider`. See [Building a TracerProvider](#building-a-tracerprovider)
for details.
#### Using the OpenTelemetry.Extensions.Hosting package
-> **Note**
+> [!NOTE]
> If you are authoring an [ASP.NET Core
application](https://learn.microsoft.com/aspnet/core/fundamentals/host/web-host)
or using the [.NET Generic
@@ -455,7 +463,7 @@ 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.
-> **Note**
+> [!NOTE]
> Multiple calls to `WithTracing` will configure the same
`TracerProvider`. Only a single `TraceProvider` may exist in an
`IServiceCollection` \ `IServiceProvider`.
@@ -480,7 +488,7 @@ it is shutdown.
* `ConfigureServices`: Registers a callback function for configuring the
`IServiceCollection` used by the `TracerProviderBuilder`.
- > **Note**
+ > [!NOTE]
> `ConfigureServices` may only be called before the `IServiceProvider`
has been created after which point services can no longer be added.
@@ -491,7 +499,7 @@ it is shutdown.
implementationFactory)`: Adds a sampler into the `TracerProvider` using a
factory function to create the sampler instance.
-> **Note**
+> [!NOTE]
> The factory functions accepting `IServiceProvider` may always be used
regardless of how the SDK is initialized. When using an external service
collection (ex: `appBuilder.Services.AddOpenTelemetry()`), as is common in
@@ -502,7 +510,7 @@ build an `IServiceProvider` from it to make available to extensions.
## Configuration files and environment variables
-> **Note**
+> [!NOTE]
> This information applies to the OpenTelemetry SDK version 1.4.0 and
newer only.
@@ -558,7 +566,7 @@ var provider = Sdk.CreateTracerProviderBuilder()
The [OpenTelemetry
Specification](https://github.com/open-telemetry/opentelemetry-specification)
defines [specific environment
-variables](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md)
+variables](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md)
which may be used to configure SDK implementations.
The OpenTelemetry .NET SDK will look for the environment variables defined in
@@ -567,7 +575,7 @@ variables users may also manage these settings via the command-line,
configuration files, or any other source registered with the .NET configuration
engine. This provides greater flexibility than what the specification defines.
-> **Note**
+> [!NOTE]
> Not all of the environment variables defined in the specification are
supported. Consult the individual project README files for details on specific
environment variable support.
@@ -602,7 +610,7 @@ environment variables.
dotnet run --OTEL_SERVICE_NAME "MyService"
```
-> **Note**
+> [!NOTE]
> The [.NET
Configuration](https://learn.microsoft.com/dotnet/core/extensions/configuration)
pattern is hierarchical meaning the order of registered configuration sources
@@ -620,7 +628,7 @@ components.
Options classes can always be configured through code but users typically want to
control key settings through configuration.
-The following example shows how to configure `JaegerExporterOptions` by binding
+The following example shows how to configure `OtlpExporterOptions` by binding
to an `IConfiguration` section.
Json config file (usually appsettings.json):
@@ -628,13 +636,8 @@ Json config file (usually appsettings.json):
```json
{
"OpenTelemetry": {
- "Jaeger": {
- "Protocol": "UdpCompactThrift"
- "AgentHost": "localhost",
- "AgentPort": 6831,
- "BatchExportProcessorOptions": {
- "ScheduledDelayMilliseconds": 5000
- }
+ "Otlp": {
+ "Endpoint": "http://localhost:4317"
}
}
}
@@ -645,11 +648,11 @@ Code:
```csharp
var appBuilder = WebApplication.CreateBuilder(args);
-appBuilder.Services.Configure(
- appBuilder.Configuration.GetSection("OpenTelemetry:Jaeger"));
+appBuilder.Services.Configure(
+ appBuilder.Configuration.GetSection("OpenTelemetry:Otlp"));
appBuilder.Services.AddOpenTelemetry()
- .WithTracing(builder => builder.AddJaegerExporter());
+ .WithTracing(builder => builder.AddOtlpExporter());
```
The OpenTelemetry .NET SDK supports running multiple `TracerProvider`s inside
@@ -659,7 +662,7 @@ users to target configuration at specific components a "name" parameter is
typically supported on configuration extensions to control the options instance
used for the component being registered.
-The below example shows how to configure two `JaegerExporter` instances inside a
+The below example shows how to configure two `OtlpExporter` instances inside a
single `TracerProvider` sending to different ports.
Json config file (usually appsettings.json):
@@ -667,12 +670,12 @@ Json config file (usually appsettings.json):
```json
{
"OpenTelemetry": {
- "JaegerPrimary": {
- "AgentPort": 1818
+ "OtlpPrimary": {
+ "Endpoint": "http://localhost:4317"
+ },
+ "OtlpSecondary": {
+ "Endpoint": "http://localhost:4327"
},
- "JaegerSecondary": {
- "AgentPort": 8818
- }
}
}
```
@@ -682,16 +685,16 @@ Code:
```csharp
var appBuilder = WebApplication.CreateBuilder(args);
-appBuilder.Services.Configure(
- "JaegerPrimary",
- appBuilder.Configuration.GetSection("OpenTelemetry:JaegerPrimary"));
+appBuilder.Services.Configure(
+ "OtlpPrimary",
+ appBuilder.Configuration.GetSection("OpenTelemetry:OtlpPrimary"));
-appBuilder.Services.Configure(
- "JaegerSecondary",
- appBuilder.Configuration.GetSection("OpenTelemetry:JaegerSecondary"));
+appBuilder.Services.Configure(
+ "OtlpSecondary",
+ appBuilder.Configuration.GetSection("OpenTelemetry:OtlpSecondary"));
appBuilder.Services.AddOpenTelemetry()
.WithTracing(builder => builder
- .AddJaegerExporter(name: "JaegerPrimary", configure: null)
- .AddJaegerExporter(name: "JaegerSecondary", configure: null));
+ .AddOtlpExporter(name: "OtlpPrimary", configure: null)
+ .AddOtlpExporter(name: "OtlpSecondary", configure: null));
```
diff --git a/docs/trace/extending-the-sdk/MyEnrichingProcessor.cs b/docs/trace/extending-the-sdk/MyEnrichingProcessor.cs
index 4565852c1b1..a6107330485 100644
--- a/docs/trace/extending-the-sdk/MyEnrichingProcessor.cs
+++ b/docs/trace/extending-the-sdk/MyEnrichingProcessor.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry;
diff --git a/docs/trace/extending-the-sdk/MyExporter.cs b/docs/trace/extending-the-sdk/MyExporter.cs
index 3bdefc0d339..d37b9daac46 100644
--- a/docs/trace/extending-the-sdk/MyExporter.cs
+++ b/docs/trace/extending-the-sdk/MyExporter.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using System.Text;
diff --git a/docs/trace/extending-the-sdk/MyExporterExtensions.cs b/docs/trace/extending-the-sdk/MyExporterExtensions.cs
index d4d9c8072e2..b317591fc5f 100644
--- a/docs/trace/extending-the-sdk/MyExporterExtensions.cs
+++ b/docs/trace/extending-the-sdk/MyExporterExtensions.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using OpenTelemetry;
using OpenTelemetry.Trace;
diff --git a/docs/trace/extending-the-sdk/MyFilteringProcessor.cs b/docs/trace/extending-the-sdk/MyFilteringProcessor.cs
index 37571b3fd7a..04fdb77ad59 100644
--- a/docs/trace/extending-the-sdk/MyFilteringProcessor.cs
+++ b/docs/trace/extending-the-sdk/MyFilteringProcessor.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry;
diff --git a/docs/trace/extending-the-sdk/MyProcessor.cs b/docs/trace/extending-the-sdk/MyProcessor.cs
index 8b42d1f4016..4171821d49a 100644
--- a/docs/trace/extending-the-sdk/MyProcessor.cs
+++ b/docs/trace/extending-the-sdk/MyProcessor.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry;
diff --git a/docs/trace/extending-the-sdk/MyResourceDetector.cs b/docs/trace/extending-the-sdk/MyResourceDetector.cs
index 1d7d4ae7b9c..df40d9b3302 100644
--- a/docs/trace/extending-the-sdk/MyResourceDetector.cs
+++ b/docs/trace/extending-the-sdk/MyResourceDetector.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using OpenTelemetry.Resources;
diff --git a/docs/trace/extending-the-sdk/MySampler.cs b/docs/trace/extending-the-sdk/MySampler.cs
index a39f0e664b3..bbb4ae04793 100644
--- a/docs/trace/extending-the-sdk/MySampler.cs
+++ b/docs/trace/extending-the-sdk/MySampler.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using OpenTelemetry.Trace;
diff --git a/docs/trace/extending-the-sdk/Program.cs b/docs/trace/extending-the-sdk/Program.cs
index 382a5be6c85..ce001aee3e3 100644
--- a/docs/trace/extending-the-sdk/Program.cs
+++ b/docs/trace/extending-the-sdk/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry;
diff --git a/docs/trace/extending-the-sdk/README.md b/docs/trace/extending-the-sdk/README.md
index 7e8600eeb7f..3a7aa623da1 100644
--- a/docs/trace/extending-the-sdk/README.md
+++ b/docs/trace/extending-the-sdk/README.md
@@ -6,7 +6,7 @@ Quick links:
* [Building your own instrumentation library](#instrumentation-library)
* [Building your own processor](#processor)
* [Building your own sampler](#sampler)
-* [Building your own resource detector](#resource-detector)
+* [Building your own resource detector](../../resources/README.md#resource-detector)
* [Registration extension method guidance for library authors](#registration-extension-method-guidance-for-library-authors)
* [References](#references)
@@ -16,7 +16,6 @@ OpenTelemetry .NET SDK has provided the following built-in trace exporters:
* [Console](../../../src/OpenTelemetry.Exporter.Console/README.md)
* [InMemory](../../../src/OpenTelemetry.Exporter.InMemory/README.md)
-* [Jaeger](../../../src/OpenTelemetry.Exporter.Jaeger/README.md)
* [OpenTelemetryProtocol](../../../src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md)
* [Zipkin](../../../src/OpenTelemetry.Exporter.Zipkin/README.md)
@@ -124,7 +123,7 @@ guidelines.
This section describes the steps required to write a custom instrumentation
library.
-> **Note**
+> [!NOTE]
> If you are writing a new library or modifying an existing library the
recommendation is to use the [ActivitySource API/OpenTelemetry
API](../../../src/OpenTelemetry.Api/README.md#introduction-to-opentelemetry-net-tracing-api)
@@ -181,35 +180,36 @@ Writing an instrumentation library typically involves 3 steps.
* If the instrumentation library requires state management tied to that of
`TracerProvider` then it should:
- * Implement `IDisposable`.
+ * Implement `IDisposable`.
- * Provide an extension method which calls `AddSource` (to enable its
- `ActivitySource`) and `AddInstrumentation` (to enable state management)
- on the `TracerProviderBuilder` being configured.
+ * Provide an extension method which calls `AddSource` (to enable its
+ `ActivitySource`) and `AddInstrumentation` (to enable state management)
+ on the `TracerProviderBuilder` being configured.
- An example instrumentation using this approach is [SqlClient
- instrumentation](../../../src/OpenTelemetry.Instrumentation.SqlClient/TracerProviderBuilderExtensions.cs).
+ An example instrumentation using this approach is [SqlClient
+ instrumentation](../../../src/OpenTelemetry.Instrumentation.SqlClient/TracerProviderBuilderExtensions.cs).
- **CAUTION**: The instrumentation libraries requiring state management are
- usually hard to auto-instrument. Therefore, they take the risk of not
- being supported by [OpenTelemetry .NET Automatic
- Instrumentation](https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation).
+ > [!WARNING]
+ > The instrumentation libraries requiring state management are
+ usually hard to auto-instrument. Therefore, they take the risk of not
+ being supported by [OpenTelemetry .NET Automatic
+ Instrumentation](https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation).
* If the instrumentation library does not require any state management, then
providing an extension method is optional.
- * If an extension is provided it should call `AddSource` on the
- `TracerProviderBuilder` being configured to enable its
- `ActivitySource`.
+ * If an extension is provided it should call `AddSource` on the
+ `TracerProviderBuilder` being configured to enable its
+ `ActivitySource`.
- * If an extension is not provided, then the name of the `ActivitySource`
- used by the instrumented library must be documented so that end users
- can enable it by calling `AddSource` on the `TracerProviderBuilder`
- being configured.
+ * If an extension is not provided, then the name of the `ActivitySource`
+ used by the instrumented library must be documented so that end users
+ can enable it by calling `AddSource` on the `TracerProviderBuilder`
+ being configured.
- > **Note**
- > Changing the name of the source should be considered a
- breaking change.
+ > [!NOTE]
+ > Changing the name of the source should be considered a
+ breaking change.
### Special case : Instrumentation for libraries producing legacy Activity
@@ -341,24 +341,9 @@ class MySampler : Sampler
A demo sampler is shown [here](./MySampler.cs).
-## Resource Detector
-
-OpenTelemetry .NET SDK provides a resource detector for detecting resource
-information from the `OTEL_RESOURCE_ATTRIBUTES` and `OTEL_SERVICE_NAME`
-environment variables.
-
-Custom resource detectors can be implemented:
-
-* ResourceDetectors should inherit from
- `OpenTelemetry.Resources.IResourceDetector`, (which belongs to the
- [OpenTelemetry](../../../src/OpenTelemetry/README.md) package), and implement
- the `Detect` method.
-
-A demo ResourceDetector is shown [here](./MyResourceDetector.cs).
-
## Registration extension method guidance for library authors
-> **Note**
+> [!NOTE]
> This information applies to the OpenTelemetry SDK version 1.4.0 and
newer only.
@@ -367,7 +352,7 @@ register custom OpenTelemetry components into their `TracerProvider`s. These
extension methods can target either the `TracerProviderBuilder` or the
`IServiceCollection` classes. Both of these patterns are described below.
-> **Note**
+> [!NOTE]
> Libraries providing SDK plugins such as exporters, resource detectors,
and/or samplers should take a dependency on the [OpenTelemetry SDK
package](https://www.nuget.org/packages/opentelemetry). Library authors
@@ -403,7 +388,7 @@ When providing registration extensions:
from starting. The OpenTelemetry SDK is allowed to crash if it cannot be
started. It **MUST NOT** crash once running.
-> **Note**
+> [!NOTE]
> The SDK implementation of `TracerProviderBuilder` ensures that the
[.NET
Configuration](https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration)
@@ -632,7 +617,7 @@ single `AddMyLibrary` extension to configure the library itself and optionally
turn on OpenTelemetry integration for multiple signals (tracing & metrics in
this case).
-> **Note**
+> [!NOTE]
> `ConfigureOpenTelemetryTracerProvider` and
`ConfigureOpenTelemetryMeterProvider` do not automatically start OpenTelemetry.
The host is responsible for either calling `AddOpenTelemetry` in the
diff --git a/docs/trace/getting-started-aspnetcore/Program.cs b/docs/trace/getting-started-aspnetcore/Program.cs
index 178057b991a..5c2affb0c43 100644
--- a/docs/trace/getting-started-aspnetcore/Program.cs
+++ b/docs/trace/getting-started-aspnetcore/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry.Resources;
diff --git a/docs/trace/getting-started-aspnetcore/README.md b/docs/trace/getting-started-aspnetcore/README.md
index 5c9ea7ded58..982c6ff688a 100644
--- a/docs/trace/getting-started-aspnetcore/README.md
+++ b/docs/trace/getting-started-aspnetcore/README.md
@@ -20,15 +20,9 @@ packages:
```sh
dotnet add package OpenTelemetry.Exporter.Console
dotnet add package OpenTelemetry.Extensions.Hosting
-dotnet add package OpenTelemetry.Instrumentation.AspNetCore --prerelease
+dotnet add package OpenTelemetry.Instrumentation.AspNetCore
```
-> **Note** This quickstart guide uses prerelease packages. For a quickstart
-> which only relies on stable packages see: [Getting Started - Console
-> Application](../getting-started-console/README.md). For more information about
-> when instrumentation will be marked as stable see: [Instrumentation-1.0.0
-> milestone](https://github.com/open-telemetry/opentelemetry-dotnet/milestone/23).
-
Update the `Program.cs` file with the code from [Program.cs](./Program.cs).
Run the application again (using `dotnet run`) and then browse to the url shown
@@ -84,7 +78,7 @@ builder.Services.AddOpenTelemetry()
.AddConsoleExporter());
```
-> **Note**
+> [!NOTE]
> The `AddOpenTelemetry` extension is part of the
[OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md)
package.
diff --git a/docs/trace/getting-started-aspnetcore/getting-started-aspnetcore.csproj b/docs/trace/getting-started-aspnetcore/getting-started-aspnetcore.csproj
index 1956f427004..375079fc34c 100644
--- a/docs/trace/getting-started-aspnetcore/getting-started-aspnetcore.csproj
+++ b/docs/trace/getting-started-aspnetcore/getting-started-aspnetcore.csproj
@@ -1,15 +1,7 @@
-
-
- net6.0;net7.0
- enable
- enable
-
-
-
diff --git a/docs/trace/getting-started-console/Program.cs b/docs/trace/getting-started-console/Program.cs
index e7e061e185d..4acaf7b8a80 100644
--- a/docs/trace/getting-started-console/Program.cs
+++ b/docs/trace/getting-started-console/Program.cs
@@ -1,33 +1,17 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry;
using OpenTelemetry.Trace;
-namespace GettingStarted;
-
public class Program
{
- private static readonly ActivitySource MyActivitySource = new(
- "MyCompany.MyProduct.MyLibrary");
+ private static readonly ActivitySource MyActivitySource = new("MyCompany.MyProduct.MyLibrary");
public static void Main()
{
- using var tracerProvider = Sdk.CreateTracerProviderBuilder()
+ var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource("MyCompany.MyProduct.MyLibrary")
.AddConsoleExporter()
.Build();
@@ -39,5 +23,9 @@ public static void Main()
activity?.SetTag("baz", new int[] { 1, 2, 3 });
activity?.SetStatus(ActivityStatusCode.Ok);
}
+
+ // Dispose tracer provider before the application ends.
+ // This will flush the remaining spans and shutdown the tracing pipeline.
+ tracerProvider.Dispose();
}
}
diff --git a/docs/trace/getting-started-console/README.md b/docs/trace/getting-started-console/README.md
index 818f18ce1c7..6fbfeb3737b 100644
--- a/docs/trace/getting-started-console/README.md
+++ b/docs/trace/getting-started-console/README.md
@@ -85,7 +85,7 @@ is configured to subscribe to the activities from the source
`ConsoleExporter` simply displays it on the console.
```csharp
-using var tracerProvider = Sdk.CreateTracerProviderBuilder()
+var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource("MyCompany.MyProduct.MyLibrary")
.AddConsoleExporter()
.Build();
diff --git a/docs/trace/getting-started-jaeger/Program.cs b/docs/trace/getting-started-jaeger/Program.cs
index b57660f7470..d4603a71bd0 100644
--- a/docs/trace/getting-started-jaeger/Program.cs
+++ b/docs/trace/getting-started-jaeger/Program.cs
@@ -1,25 +1,11 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
-using System;
using System.Diagnostics;
+#if NETFRAMEWORK
using System.Net.Http;
-using System.Threading.Tasks;
+#endif
using OpenTelemetry;
-using OpenTelemetry.Exporter;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
diff --git a/docs/trace/getting-started-jaeger/README.md b/docs/trace/getting-started-jaeger/README.md
index bc0359142bf..07d529e738d 100644
--- a/docs/trace/getting-started-jaeger/README.md
+++ b/docs/trace/getting-started-jaeger/README.md
@@ -74,7 +74,7 @@ using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.Build();
```
-When we run the application, the `ConsoleExporter` was printing the traces on
+When we ran the application, the `ConsoleExporter` was printing the traces on
console, and the `OtlpExporter` was attempting to send the traces to Jaeger
Agent via the default endpoint `http://localhost:4317`.
@@ -142,7 +142,7 @@ Jaeger -->|http://localhost:16686/| JaegerUI["Browser (Jaeger UI)"]
## Final cleanup
-In the end, remove the Console Exporter so we only have Jaeger Exporter in the
+In the end, remove the Console Exporter so we only have OTLP Exporter in the
final application:
```csharp
diff --git a/docs/trace/getting-started-jaeger/getting-started-jaeger.csproj b/docs/trace/getting-started-jaeger/getting-started-jaeger.csproj
index 543e6766445..19bcfb68247 100644
--- a/docs/trace/getting-started-jaeger/getting-started-jaeger.csproj
+++ b/docs/trace/getting-started-jaeger/getting-started-jaeger.csproj
@@ -4,7 +4,8 @@
+
-
+
diff --git a/docs/trace/links-based-sampler/LinksAndParentBasedSampler.cs b/docs/trace/links-based-sampler/LinksAndParentBasedSampler.cs
index 2ea3ec78239..bca076a2734 100644
--- a/docs/trace/links-based-sampler/LinksAndParentBasedSampler.cs
+++ b/docs/trace/links-based-sampler/LinksAndParentBasedSampler.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using OpenTelemetry.Trace;
diff --git a/docs/trace/links-based-sampler/LinksBasedSampler.cs b/docs/trace/links-based-sampler/LinksBasedSampler.cs
index 7d6342c756a..b9306fab232 100644
--- a/docs/trace/links-based-sampler/LinksBasedSampler.cs
+++ b/docs/trace/links-based-sampler/LinksBasedSampler.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry.Trace;
diff --git a/docs/trace/links-based-sampler/Program.cs b/docs/trace/links-based-sampler/Program.cs
index 85ae36acac2..7ef89aa5fdb 100644
--- a/docs/trace/links-based-sampler/Program.cs
+++ b/docs/trace/links-based-sampler/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry;
diff --git a/docs/trace/links-creation-with-new-activities/Program.cs b/docs/trace/links-creation-with-new-activities/Program.cs
new file mode 100644
index 00000000000..c03af7bcc82
--- /dev/null
+++ b/docs/trace/links-creation-with-new-activities/Program.cs
@@ -0,0 +1,86 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using System.Diagnostics;
+using OpenTelemetry;
+using OpenTelemetry.Trace;
+
+namespace LinksCreationWithNewRootActivitiesDemo;
+
+internal class Program
+{
+ private static readonly ActivitySource MyActivitySource = new("LinksCreationWithNewRootActivities");
+
+ public static async Task Main(string[] args)
+ {
+ using var tracerProvider = Sdk.CreateTracerProviderBuilder()
+ .AddSource("LinksCreationWithNewRootActivities")
+ .AddConsoleExporter()
+ .Build();
+
+ using (var activity = MyActivitySource.StartActivity("OrchestratingActivity"))
+ {
+ activity?.SetTag("foo", 1);
+ await DoFanoutAsync();
+
+ using (var nestedActivity = MyActivitySource.StartActivity("WrapUp"))
+ {
+ nestedActivity?.SetTag("foo", 1);
+ }
+ }
+ }
+
+ public static async Task DoFanoutAsync()
+ {
+ var previous = Activity.Current;
+ const int NumConcurrentOperations = 10;
+
+ var activityContext = Activity.Current!.Context;
+ var links = new List
+ {
+ new ActivityLink(activityContext),
+ };
+
+ var tasks = new List();
+
+ // Fanning out to N concurrent operations.
+ // We create a new root activity for each operation and
+ // link it to an outer activity that happens to be the current
+ // activity.
+ for (int i = 0; i < NumConcurrentOperations; i++)
+ {
+ int operationIndex = i;
+
+ var task = Task.Run(() =>
+ {
+ // Reference: https://opentelemetry.io/docs/instrumentation/net/manual/#creating-new-root-activities
+ // Since we want to create a new root activity for each of the fanned out operations,
+ // this step helps us "de-parent" it from the current activity.
+ // Note: At least as of Oct 2023, this is the only mechanism to create a new root
+ // activity in the presence of an existing activity. This might change in the future
+ // if/when issue https://github.com/open-telemetry/opentelemetry-dotnet/issues/984
+ // is addressed.
+ Activity.Current = null;
+
+ // Reference: https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry.Api#activity-creation-options
+ // Reference: https://opentelemetry.io/docs/instrumentation/net/manual/#adding-links
+ // We create a new root activity for each of the fanned out operations and link it to the outer activity.
+ using var newRootActivityForFannedOutOperation = MyActivitySource.StartActivity(
+ ActivityKind.Internal, // Set this to the appropriate ActivityKind depending on your scenario
+ name: $"FannedOutActivity {operationIndex + 1}",
+ links: links);
+
+ // DO THE FANOUT WORK HERE...
+ });
+
+ tasks.Add(task);
+ }
+
+ // Wait for all tasks to complete
+ await Task.WhenAll(tasks);
+
+ // 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.
+ Activity.Current = previous;
+ }
+}
diff --git a/docs/trace/links-creation-with-new-activities/README.md b/docs/trace/links-creation-with-new-activities/README.md
new file mode 100644
index 00000000000..39552a7cbb6
--- /dev/null
+++ b/docs/trace/links-creation-with-new-activities/README.md
@@ -0,0 +1,158 @@
+# Creating new root activities that link to an existing activity: A Sample
+
+This sample shows how to create new root activities that
+[link](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#links-between-spans)
+to an existing activity. This can be useful in a fan-out or batched operation
+situation when you want to create a new trace with a new root activity
+BEFORE invoking each of the fanned out operations, and at the same time
+you want each of these new traces to be linked to the original activity.
+
+To give an example, let's say that:
+
+- Service A receives a request for a customer operation that impacts 1000s of
+resources. The term "resource" here means an entity that is managed by this
+service and should not be confused with the term "resource" in OpenTelemetry.
+- Service A orchestrates this overall operation by fanning out multiple
+calls to Service B, with one call for EACH of the impacted resources.
+- Let's say the number of spans generated for a single resource operation
+is in the order of several thousands of spans.
+
+In the above example, if you used the same trace for the entire flow, then
+you would end up with a huge trace with more than million spans. This will
+make visualizing and understanding the trace difficult.
+
+Further, it may make it difficult to do programmatic analytics at the
+*individual* resource operation level (for each of the 1000s of resource
+operations) as there would be no single trace that corresponds to each
+of the individual resource operations.
+
+Instead, by creating a new trace with a new root activity before the fanout
+call, you get a separate trace for each of the resource operations. In
+addition, by using the "span links" functionality in OpenTelemetry, we link
+each of these new root activities to the original activity.
+
+This enables more granular visualization and analytics.
+
+## How does this example work?
+
+To be able to create new root activities, we first set the Activity.Current
+to null so that we can "de-parent" the new activity from the current activity.
+
+For each of the fanned out operations, this creates a new root activity. As
+part of this activity creation, it links it to the previously current activity.
+
+Finally, we reset Activity.Current to the previous activity now after we are
+done with the fanout. This will ensure that the rest of the code executes
+in the context of the original activity.
+
+## When should you consider such an option? What are the tradeoffs?
+
+This is a good option to consider for operations that involve batched or
+fanout operations if using the same trace causes it to become huge.
+Using this approach, you can create a new trace for each of the fanned out
+operations and link them to the original activity.
+
+A tradeoff is that now we will have multiple traces instead of a single trace.
+However, many Observability tools have the ability to visualize linked traces
+together, and hence it is not necessarily a concern from that perspective.
+However, this model has the potential to add some complexity to any
+programmatic analysis since now it has to understand the concept of linked
+traces.
+
+## References
+
+- [Links between spans](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#links-between-spans)
+- [Creating new root activities](https://opentelemetry.io/docs/instrumentation/net/manual/#creating-new-root-activities)
+- [Activity Creation Options](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry.Api#activity-creation-options)
+- [A sample where links are used in a fan-in scenario](https://github.com/PacktPublishing/Modern-Distributed-Tracing-in-.NET/tree/main/chapter6/links)
+
+## Sample Output
+
+You should see output such as the below when you run this example. You can see
+that EACH of the "fanned out activities" have:
+
+- a new trace ID
+- an activity link to the original activity
+
+```text
+Activity.TraceId: 5ce4d8ad4926ecdd0084681f46fa38d9
+Activity.SpanId: 8f9e9441f0789f6e
+Activity.TraceFlags: Recorded
+Activity.ActivitySourceName: LinksCreationWithNewRootActivities
+Activity.DisplayName: FannedOutActivity 1
+Activity.Kind: Internal
+Activity.StartTime: 2023-10-17T01:24:40.4957326Z
+Activity.Duration: 00:00:00.0008656
+Activity.Links:
+ 2890476acefb53b93af64a0d91939051 16b83c1517629363
+Resource associated with Activity:
+ telemetry.sdk.name: opentelemetry
+ telemetry.sdk.language: dotnet
+ telemetry.sdk.version: 0.0.0-alpha.0.2600
+ service.name: unknown_service:links-creation
+
+Activity.TraceId: 16a8ad23d14a085f2a1f260a4b474d05
+Activity.SpanId: 0c3e835cfd60c604
+Activity.TraceFlags: Recorded
+Activity.ActivitySourceName: LinksCreationWithNewRootActivities
+Activity.DisplayName: FannedOutActivity 2
+Activity.Kind: Internal
+Activity.StartTime: 2023-10-17T01:24:40.5908290Z
+Activity.Duration: 00:00:00.0009197
+Activity.Links:
+ 2890476acefb53b93af64a0d91939051 16b83c1517629363
+Resource associated with Activity:
+ telemetry.sdk.name: opentelemetry
+ telemetry.sdk.language: dotnet
+ telemetry.sdk.version: 0.0.0-alpha.0.2600
+ service.name: unknown_service:links-creation
+
+Activity.TraceId: 46f0b5b68173b4acf4f50e1f5cdb3e55
+Activity.SpanId: 42e7f4439fc2b416
+Activity.TraceFlags: Recorded
+Activity.ActivitySourceName: LinksCreationWithNewRootActivities
+Activity.DisplayName: FannedOutActivity 3
+Activity.Kind: Internal
+Activity.StartTime: 2023-10-17T01:24:40.5930378Z
+Activity.Duration: 00:00:00.0008622
+Activity.Links:
+ 2890476acefb53b93af64a0d91939051 16b83c1517629363
+Resource associated with Activity:
+ telemetry.sdk.name: opentelemetry
+ telemetry.sdk.language: dotnet
+ telemetry.sdk.version: 0.0.0-alpha.0.2600
+ service.name: unknown_service:links-creation
+
+Activity.TraceId: 2890476acefb53b93af64a0d91939051
+Activity.SpanId: 6878c2a84d4d4996
+Activity.TraceFlags: Recorded
+Activity.ParentSpanId: 16b83c1517629363
+Activity.ActivitySourceName: LinksCreationWithNewRootActivities
+Activity.DisplayName: WrapUp
+Activity.Kind: Internal
+Activity.StartTime: 2023-10-17T01:24:40.5950683Z
+Activity.Duration: 00:00:00.0008843
+Activity.Tags:
+ foo: 1
+Resource associated with Activity:
+ telemetry.sdk.name: opentelemetry
+ telemetry.sdk.language: dotnet
+ telemetry.sdk.version: 0.0.0-alpha.0.2600
+ service.name: unknown_service:links-creation
+
+Activity.TraceId: 2890476acefb53b93af64a0d91939051
+Activity.SpanId: 16b83c1517629363
+Activity.TraceFlags: Recorded
+Activity.ActivitySourceName: LinksCreationWithNewRootActivities
+Activity.DisplayName: OrchestratingActivity
+Activity.Kind: Internal
+Activity.StartTime: 2023-10-17T01:24:40.4937024Z
+Activity.Duration: 00:00:00.1043390
+Activity.Tags:
+ foo: 1
+Resource associated with Activity:
+ telemetry.sdk.name: opentelemetry
+ telemetry.sdk.language: dotnet
+ telemetry.sdk.version: 0.0.0-alpha.0.2600
+ service.name: unknown_service:links-creation
+```
diff --git a/docs/logs/source-generation/source-generation.csproj b/docs/trace/links-creation-with-new-activities/links-creation.csproj
similarity index 61%
rename from docs/logs/source-generation/source-generation.csproj
rename to docs/trace/links-creation-with-new-activities/links-creation.csproj
index 6e8adc423c3..19aa9791432 100644
--- a/docs/logs/source-generation/source-generation.csproj
+++ b/docs/trace/links-creation-with-new-activities/links-creation.csproj
@@ -1,6 +1,5 @@
-
+
-
diff --git a/docs/trace/reporting-exceptions/Program.cs b/docs/trace/reporting-exceptions/Program.cs
index 4ffd8a4cfd9..62f2a11914e 100644
--- a/docs/trace/reporting-exceptions/Program.cs
+++ b/docs/trace/reporting-exceptions/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry;
diff --git a/docs/trace/reporting-exceptions/README.md b/docs/trace/reporting-exceptions/README.md
index 60ad6573e10..72e70683412 100644
--- a/docs/trace/reporting-exceptions/README.md
+++ b/docs/trace/reporting-exceptions/README.md
@@ -95,7 +95,7 @@ using (var activity = MyActivitySource.StartActivity("Foo"))
}
catch (SomeException ex)
{
- activity?.SetStatus(ActivityStatusCode.Error, ex.message);
+ activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
}
}
```
@@ -107,7 +107,7 @@ leveraging Activity status. Neither of the approach actually records the
Exception itself to do more richer debugging. `Activity.RecordException()`
allows the exception to be stored in the Activity as ActivityEvent as per
[OpenTelemetry
-convention](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/exceptions.md),
+convention](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/exceptions/exceptions-spans.md),
as shown below:
```csharp
@@ -119,7 +119,7 @@ using (var activity = MyActivitySource.StartActivity("Foo"))
}
catch (SomeException ex)
{
- activity?.SetStatus(ActivityStatusCode.Error, ex.message);
+ activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
activity?.RecordException(ex);
}
}
@@ -142,7 +142,7 @@ It might be useful to automatically capture the unhandled exceptions, travel
through the unfinished activities and export them for troubleshooting. Here goes
one possible way of doing this:
-> **Warning**
+> [!CAUTION]
> Use `AppDomain.UnhandledException` with caution. A throw in the
handler puts the process into an unrecoverable state.
diff --git a/docs/trace/stratified-sampling-example/Program.cs b/docs/trace/stratified-sampling-example/Program.cs
index e85179126e7..49d8e1b7e7b 100644
--- a/docs/trace/stratified-sampling-example/Program.cs
+++ b/docs/trace/stratified-sampling-example/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry;
diff --git a/docs/trace/stratified-sampling-example/StratifiedSampler.cs b/docs/trace/stratified-sampling-example/StratifiedSampler.cs
index 16ca4b437ce..cb01a23dee0 100644
--- a/docs/trace/stratified-sampling-example/StratifiedSampler.cs
+++ b/docs/trace/stratified-sampling-example/StratifiedSampler.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using OpenTelemetry.Trace;
diff --git a/docs/trace/stratified-sampling-example/stratified-sampling-example.csproj b/docs/trace/stratified-sampling-example/stratified-sampling-example.csproj
index e089b70bbcf..19aa9791432 100644
--- a/docs/trace/stratified-sampling-example/stratified-sampling-example.csproj
+++ b/docs/trace/stratified-sampling-example/stratified-sampling-example.csproj
@@ -1,14 +1,5 @@
-
-
- Exe
- enable
- enable
-
-
-
-
diff --git a/docs/trace/tail-based-sampling-span-level/ParentBasedElseAlwaysRecordSampler.cs b/docs/trace/tail-based-sampling-span-level/ParentBasedElseAlwaysRecordSampler.cs
index ae15a40d370..bce691b0c16 100644
--- a/docs/trace/tail-based-sampling-span-level/ParentBasedElseAlwaysRecordSampler.cs
+++ b/docs/trace/tail-based-sampling-span-level/ParentBasedElseAlwaysRecordSampler.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using OpenTelemetry.Trace;
diff --git a/docs/trace/tail-based-sampling-span-level/Program.cs b/docs/trace/tail-based-sampling-span-level/Program.cs
index 3dfc4cf4f08..de4f8ea9f17 100644
--- a/docs/trace/tail-based-sampling-span-level/Program.cs
+++ b/docs/trace/tail-based-sampling-span-level/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry;
diff --git a/docs/trace/tail-based-sampling-span-level/TailSamplingProcessor.cs b/docs/trace/tail-based-sampling-span-level/TailSamplingProcessor.cs
index 19352cfa898..5aa22092e75 100644
--- a/docs/trace/tail-based-sampling-span-level/TailSamplingProcessor.cs
+++ b/docs/trace/tail-based-sampling-span-level/TailSamplingProcessor.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using OpenTelemetry;
diff --git a/examples/AspNetCore/Controllers/WeatherForecastController.cs b/examples/AspNetCore/Controllers/WeatherForecastController.cs
index fab6acf5a73..3d09fe9ed61 100644
--- a/examples/AspNetCore/Controllers/WeatherForecastController.cs
+++ b/examples/AspNetCore/Controllers/WeatherForecastController.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
namespace Examples.AspNetCore.Controllers;
@@ -62,7 +49,7 @@ public IEnumerable Get()
// that calculating the forecast is an expensive operation and therefore
// something to be distinguished from the overall request.
// Note: Tags can be added to the current activity without the need for
- // a manual activity using Acitivty.Current?.SetTag()
+ // a manual activity using Activity.Current?.SetTag()
using var activity = this.activitySource.StartActivity("calculate forecast");
var rng = new Random();
diff --git a/examples/AspNetCore/Examples.AspNetCore.csproj b/examples/AspNetCore/Examples.AspNetCore.csproj
index fe6b61f8962..d07169358a7 100644
--- a/examples/AspNetCore/Examples.AspNetCore.csproj
+++ b/examples/AspNetCore/Examples.AspNetCore.csproj
@@ -1,7 +1,7 @@
- net6.0
+ $(DefaultTargetFrameworkForExampleApps)
@@ -15,7 +15,6 @@
-
diff --git a/examples/AspNetCore/Instrumentation.cs b/examples/AspNetCore/Instrumentation.cs
index e4583887e07..4b0ede1157f 100644
--- a/examples/AspNetCore/Instrumentation.cs
+++ b/examples/AspNetCore/Instrumentation.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
namespace Examples.AspNetCore;
@@ -35,7 +22,7 @@ public Instrumentation()
string? version = typeof(Instrumentation).Assembly.GetName().Version?.ToString();
this.ActivitySource = new ActivitySource(ActivitySourceName, version);
this.meter = new Meter(MeterName, version);
- this.FreezingDaysCounter = this.meter.CreateCounter("weather.days.freezing", "The number of days where the temperature is below freezing");
+ this.FreezingDaysCounter = this.meter.CreateCounter("weather.days.freezing", description: "The number of days where the temperature is below freezing");
}
public ActivitySource ActivitySource { get; }
diff --git a/examples/AspNetCore/Models/WeatherForecast.cs b/examples/AspNetCore/Models/WeatherForecast.cs
index d05d2d047ca..f86f30db78a 100644
--- a/examples/AspNetCore/Models/WeatherForecast.cs
+++ b/examples/AspNetCore/Models/WeatherForecast.cs
@@ -1,29 +1,15 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
-namespace Examples.AspNetCore
+namespace Examples.AspNetCore;
+
+public class WeatherForecast
{
- public class WeatherForecast
- {
- public DateTime Date { get; set; }
+ public DateTime Date { get; set; }
- public int TemperatureC { get; set; }
+ public int TemperatureC { get; set; }
- public int TemperatureF => 32 + (int)(this.TemperatureC / 0.5556);
+ public int TemperatureF => 32 + (int)(this.TemperatureC / 0.5556);
- public string? Summary { get; set; }
- }
+ public string? Summary { get; set; }
}
diff --git a/examples/AspNetCore/Program.cs b/examples/AspNetCore/Program.cs
index bc4e0602cda..18279940976 100644
--- a/examples/AspNetCore/Program.cs
+++ b/examples/AspNetCore/Program.cs
@@ -1,18 +1,5 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics.Metrics;
using Examples.AspNetCore;
@@ -25,21 +12,21 @@
var appBuilder = WebApplication.CreateBuilder(args);
-// Note: Switch between Zipkin/Jaeger/OTLP/Console by setting UseTracingExporter in appsettings.json.
-var tracingExporter = appBuilder.Configuration.GetValue("UseTracingExporter").ToLowerInvariant();
+// Note: Switch between Zipkin/OTLP/Console by setting UseTracingExporter in appsettings.json.
+var tracingExporter = appBuilder.Configuration.GetValue("UseTracingExporter", defaultValue: "console")!.ToLowerInvariant();
// Note: Switch between Prometheus/OTLP/Console by setting UseMetricsExporter in appsettings.json.
-var metricsExporter = appBuilder.Configuration.GetValue("UseMetricsExporter").ToLowerInvariant();
+var metricsExporter = appBuilder.Configuration.GetValue("UseMetricsExporter", defaultValue: "console")!.ToLowerInvariant();
// Note: Switch between Console/OTLP by setting UseLogExporter in appsettings.json.
-var logExporter = appBuilder.Configuration.GetValue("UseLogExporter").ToLowerInvariant();
+var logExporter = appBuilder.Configuration.GetValue("UseLogExporter", defaultValue: "console")!.ToLowerInvariant();
// Note: Switch between Explicit/Exponential by setting HistogramAggregation in appsettings.json
-var histogramAggregation = appBuilder.Configuration.GetValue("HistogramAggregation").ToLowerInvariant();
+var histogramAggregation = appBuilder.Configuration.GetValue("HistogramAggregation", defaultValue: "explicit")!.ToLowerInvariant();
// Build a resource configuration action to set service information.
Action configureResource = r => r.AddService(
- serviceName: appBuilder.Configuration.GetValue("ServiceName"),
+ serviceName: appBuilder.Configuration.GetValue("ServiceName", defaultValue: "otel-test")!,
serviceVersion: typeof(Program).Assembly.GetName().Version?.ToString() ?? "unknown",
serviceInstanceId: Environment.MachineName);
@@ -63,23 +50,10 @@
.AddAspNetCoreInstrumentation();
// Use IConfiguration binding for AspNetCore instrumentation options.
- appBuilder.Services.Configure(appBuilder.Configuration.GetSection("AspNetCoreInstrumentation"));
+ appBuilder.Services.Configure(appBuilder.Configuration.GetSection("AspNetCoreInstrumentation"));
switch (tracingExporter)
{
- case "jaeger":
- builder.AddJaegerExporter();
-
- builder.ConfigureServices(services =>
- {
- // Use IConfiguration binding for Jaeger exporter options.
- services.Configure(appBuilder.Configuration.GetSection("Jaeger"));
-
- // Customize the HttpClient that will be used when JaegerExporter is configured for HTTP transport.
- services.AddHttpClient("JaegerExporter", configureClient: (client) => client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value"));
- });
- break;
-
case "zipkin":
builder.AddZipkinExporter();
@@ -94,7 +68,7 @@
builder.AddOtlpExporter(otlpOptions =>
{
// Use IConfiguration directly for Otlp exporter endpoint option.
- otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue("Otlp:Endpoint"));
+ otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue("Otlp:Endpoint", defaultValue: "http://localhost:4317")!);
});
break;
@@ -110,7 +84,9 @@
// Ensure the MeterProvider subscribes to any custom Meters.
builder
.AddMeter(Instrumentation.MeterName)
- .SetExemplarFilter(new TraceBasedExemplarFilter())
+#if EXPOSE_EXPERIMENTAL_FEATURES
+ .SetExemplarFilter(ExemplarFilterType.TraceBased)
+#endif
.AddRuntimeInstrumentation()
.AddHttpClientInstrumentation()
.AddAspNetCoreInstrumentation();
@@ -140,7 +116,7 @@
builder.AddOtlpExporter(otlpOptions =>
{
// Use IConfiguration directly for Otlp exporter endpoint option.
- otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue("Otlp:Endpoint"));
+ otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue("Otlp:Endpoint", defaultValue: "http://localhost:4317")!);
});
break;
default:
@@ -167,7 +143,7 @@
options.AddOtlpExporter(otlpOptions =>
{
// Use IConfiguration directly for Otlp exporter endpoint option.
- otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue("Otlp:Endpoint"));
+ 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 c437a99b8bf..001d3cdea08 100644
--- a/examples/AspNetCore/README.md
+++ b/examples/AspNetCore/README.md
@@ -1,6 +1,6 @@
-# OpenTelemetry ASP.Net Core 6 Web API Example
+# OpenTelemetry ASP.NET Core 7 Web API Example
-This example uses the new WebApplication host that ships with .Net 6
+This example uses the new WebApplication host that ships with .NET 7
and shows how to setup
1. OpenTelemetry logging
diff --git a/examples/AspNetCore/appsettings.json b/examples/AspNetCore/appsettings.json
index 1f2d3368dc9..a6c4d31a2ac 100644
--- a/examples/AspNetCore/appsettings.json
+++ b/examples/AspNetCore/appsettings.json
@@ -15,12 +15,6 @@
"UseMetricsExporter": "console",
"UseLogExporter": "console",
"HistogramAggregation": "explicit",
- "Jaeger": {
- "AgentHost": "localhost",
- "AgentPort": 6831,
- "Endpoint": "http://localhost:14268",
- "Protocol": "UdpCompactThrift"
- },
"Zipkin": {
"Endpoint": "http://localhost:9411/api/v2/spans"
},
diff --git a/examples/Console/Examples.Console.csproj b/examples/Console/Examples.Console.csproj
index ee9d4d0c6ce..af250fb26f1 100644
--- a/examples/Console/Examples.Console.csproj
+++ b/examples/Console/Examples.Console.csproj
@@ -2,7 +2,7 @@
Exe
- net6.0
+ $(DefaultTargetFrameworkForExampleApps)$(NoWarn),CS0618
@@ -17,12 +17,11 @@
-
- all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
@@ -32,7 +31,6 @@
-
diff --git a/examples/Console/InstrumentationWithActivitySource.cs b/examples/Console/InstrumentationWithActivitySource.cs
index 439c5fb3efe..240f58289d8 100644
--- a/examples/Console/InstrumentationWithActivitySource.cs
+++ b/examples/Console/InstrumentationWithActivitySource.cs
@@ -1,176 +1,162 @@
-//
// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Text;
-namespace Examples.Console
+namespace Examples.Console;
+
+internal class InstrumentationWithActivitySource : IDisposable
{
- internal class InstrumentationWithActivitySource : IDisposable
+ private const string RequestPath = "/api/request";
+ private readonly SampleServer server = new();
+ private readonly SampleClient client = new();
+
+ public void Start(ushort port = 19999)
{
- private const string RequestPath = "/api/request";
- private readonly SampleServer server = new();
- private readonly SampleClient client = new();
+ var url = $"http://localhost:{port.ToString(CultureInfo.InvariantCulture)}{RequestPath}/";
+ this.server.Start(url);
+ this.client.Start(url);
+ }
- public void Start(ushort port = 19999)
- {
- var url = $"http://localhost:{port.ToString(CultureInfo.InvariantCulture)}{RequestPath}/";
- this.server.Start(url);
- this.client.Start(url);
- }
+ public void Dispose()
+ {
+ this.client.Dispose();
+ this.server.Dispose();
+ }
- public void Dispose()
- {
- this.client.Dispose();
- this.server.Dispose();
- }
+ private class SampleServer : IDisposable
+ {
+ private readonly HttpListener listener = new();
- private class SampleServer : IDisposable
+ public void Start(string url)
{
- private readonly HttpListener listener = new();
+ this.listener.Prefixes.Add(url);
+ this.listener.Start();
- public void Start(string url)
+ Task.Run(() =>
{
- this.listener.Prefixes.Add(url);
- this.listener.Start();
+ using var source = new ActivitySource("Samples.SampleServer");
- Task.Run(() =>
+ while (this.listener.IsListening)
{
- using var source = new ActivitySource("Samples.SampleServer");
-
- while (this.listener.IsListening)
+ try
{
- try
- {
- var context = this.listener.GetContext();
-
- using var activity = source.StartActivity(
- $"{context.Request.HttpMethod}:{context.Request.Url.AbsolutePath}",
- ActivityKind.Server);
+ var context = this.listener.GetContext();
- var headerKeys = context.Request.Headers.AllKeys;
- foreach (var headerKey in headerKeys)
- {
- string headerValue = context.Request.Headers[headerKey];
- activity?.SetTag($"http.header.{headerKey}", headerValue);
- }
-
- string requestContent;
- using (var childSpan = source.StartActivity("ReadStream", ActivityKind.Consumer))
- using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
- {
- requestContent = reader.ReadToEnd();
- childSpan.AddEvent(new ActivityEvent("StreamReader.ReadToEnd"));
- }
-
- activity?.SetTag("request.content", requestContent);
- activity?.SetTag("request.length", requestContent.Length.ToString());
+ using var activity = source.StartActivity(
+ $"{context.Request.HttpMethod}:{context.Request.Url.AbsolutePath}",
+ ActivityKind.Server);
- var echo = Encoding.UTF8.GetBytes("echo: " + requestContent);
- context.Response.ContentEncoding = Encoding.UTF8;
- context.Response.ContentLength64 = echo.Length;
- context.Response.OutputStream.Write(echo, 0, echo.Length);
- context.Response.Close();
+ var headerKeys = context.Request.Headers.AllKeys;
+ foreach (var headerKey in headerKeys)
+ {
+ string headerValue = context.Request.Headers[headerKey];
+ activity?.SetTag($"http.header.{headerKey}", headerValue);
}
- catch (Exception)
+
+ string requestContent;
+ using (var childSpan = source.StartActivity("ReadStream", ActivityKind.Consumer))
+ using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
{
- // expected when closing the listener.
+ requestContent = reader.ReadToEnd();
+ childSpan.AddEvent(new ActivityEvent("StreamReader.ReadToEnd"));
}
+
+ activity?.SetTag("request.content", requestContent);
+ activity?.SetTag("request.length", requestContent.Length.ToString());
+
+ var echo = Encoding.UTF8.GetBytes("echo: " + requestContent);
+ context.Response.ContentEncoding = Encoding.UTF8;
+ context.Response.ContentLength64 = echo.Length;
+ context.Response.OutputStream.Write(echo, 0, echo.Length);
+ context.Response.Close();
}
- });
- }
+ catch (Exception)
+ {
+ // expected when closing the listener.
+ }
+ }
+ });
+ }
- public void Dispose()
- {
- ((IDisposable)this.listener).Dispose();
- }
+ public void Dispose()
+ {
+ ((IDisposable)this.listener).Dispose();
}
+ }
+
+ private class SampleClient : IDisposable
+ {
+ private CancellationTokenSource cts;
+ private Task requestTask;
- private class SampleClient : IDisposable
+ public void Start(string url)
{
- private CancellationTokenSource cts;
- private Task requestTask;
+ this.cts = new CancellationTokenSource();
+ var cancellationToken = this.cts.Token;
- public void Start(string url)
- {
- this.cts = new CancellationTokenSource();
- var cancellationToken = this.cts.Token;
+ this.requestTask = Task.Run(
+ async () =>
+ {
+ using var source = new ActivitySource("Samples.SampleClient");
+ using var client = new HttpClient();
- this.requestTask = Task.Run(
- async () =>
+ var count = 1;
+ while (!cancellationToken.IsCancellationRequested)
{
- using var source = new ActivitySource("Samples.SampleClient");
- using var client = new HttpClient();
+ var content = new StringContent($"client message: {DateTime.Now}", Encoding.UTF8);
- var count = 1;
- while (!cancellationToken.IsCancellationRequested)
+ using (var activity = source.StartActivity("POST:" + RequestPath, ActivityKind.Client))
{
- var content = new StringContent($"client message: {DateTime.Now}", Encoding.UTF8);
-
- using (var activity = source.StartActivity("POST:" + RequestPath, ActivityKind.Client))
- {
- count++;
+ count++;
- activity?.AddEvent(new ActivityEvent("PostAsync:Started"));
- using var response = await client.PostAsync(url, content, cancellationToken).ConfigureAwait(false);
- activity?.AddEvent(new ActivityEvent("PostAsync:Ended"));
+ activity?.AddEvent(new ActivityEvent("PostAsync:Started"));
+ using var response = await client.PostAsync(url, content, cancellationToken).ConfigureAwait(false);
+ activity?.AddEvent(new ActivityEvent("PostAsync:Ended"));
- activity?.SetTag("http.status_code", (int)response.StatusCode);
+ activity?.SetTag("http.status_code", (int)response.StatusCode);
- var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
- activity?.SetTag("response.content", responseContent);
- activity?.SetTag("response.length", responseContent.Length.ToString(CultureInfo.InvariantCulture));
+ var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
+ activity?.SetTag("response.content", responseContent);
+ activity?.SetTag("response.length", responseContent.Length.ToString(CultureInfo.InvariantCulture));
- foreach (var header in response.Headers)
+ foreach (var header in response.Headers)
+ {
+ if (header.Value is IEnumerable