├── .editorconfig
├── .gitattributes
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request.md
│ └── question.md
├── PULL_REQUEST_TEMPLATE.md
├── dependabot.yml
└── workflows
│ ├── ci.yml
│ ├── dotnet-format.yml
│ ├── markdown-link-check.yml
│ ├── markdownlint.yml
│ ├── misspell.yml
│ └── oats.yml
├── .gitignore
├── .markdown_link_check_config.json
├── .markdownlint.yaml
├── .vscode
└── extensions.json
├── CHANGELOG.md
├── Directory.Build.props
├── GrafanaOpenTelemetry.sln
├── LICENSE
├── README.md
├── docker
└── docker-compose-aspnetcore
│ ├── .dockerignore
│ ├── docker-compose-aspnetcore.dcproj
│ ├── docker-compose.oats.yml
│ ├── docker-compose.override.yml
│ ├── docker-compose.self-contained.oats.yml
│ ├── docker-compose.yml
│ ├── launchSettings.json
│ ├── oats-template.yml
│ └── oats.yaml
├── docs
├── configuration.md
├── installation.md
├── migration.md
├── supported-instrumentations.md
└── supported-resource-detectors.md
├── examples
└── net8.0
│ └── aspnetcore
│ ├── Controllers
│ ├── HttpClientController.cs
│ ├── MsSqlController.cs
│ ├── RedisController.cs
│ └── WeatherForecastController.cs
│ ├── Dockerfile
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── TodoAppEndpoints.cs
│ ├── appsettings.json
│ └── aspnetcore.csproj
├── global.json
├── internal
├── RELEASING.md
└── img
│ └── Grafana_icon.png
├── launchSettings.json
├── package-readme.md
├── scripts
├── run-oats-tests.ps1
└── run-oats-tests.sh
├── src
├── Grafana.OpenTelemetry.Base
│ ├── ExporterSettings
│ │ ├── AgentOtlpExporter.cs
│ │ ├── CloudOtlpExporter.cs
│ │ ├── ExporterSettings.cs
│ │ ├── GrafanaCloudConfigurationHelper.cs
│ │ └── OtlpExporter.cs
│ ├── Grafana.OpenTelemetry.Base.csproj
│ ├── GrafanaOpenTelemetryEventSource.cs
│ ├── GrafanaOpenTelemetryResourceDetector.cs
│ ├── GrafanaOpenTelemetrySettings.cs
│ ├── Instrumentations
│ │ ├── AWSInitializer.cs
│ │ ├── AWSLambdaInitializer.cs
│ │ ├── AspNetCoreInitializer.cs
│ │ ├── AspNetInitializer.cs
│ │ ├── CassandraInitializer.cs
│ │ ├── ElasticsearchClientInitializer.cs
│ │ ├── EntityFrameworkCoreInitializer.cs
│ │ ├── GrpcNetClientInitializer.cs
│ │ ├── HangfireInitializer.cs
│ │ ├── HttpClientInitializer.cs
│ │ ├── Instrumentation.cs
│ │ ├── InstrumentationInitializer.cs
│ │ ├── MySqlDataInitializer.cs
│ │ ├── NetRuntimeMetricsInitializer.cs
│ │ ├── OwinInitializer.cs
│ │ ├── ProcessMetricsInitializer.cs
│ │ ├── QuartzInitializer.cs
│ │ ├── SqlClientInitializer.cs
│ │ ├── StackExchangeRedisInitializer.cs
│ │ └── WcfInitializer.cs
│ ├── MeterProviderBuilderExtensions.cs
│ ├── OpenTelemetryLoggerOptionsExtensions.cs
│ ├── ReflectionHelper.cs
│ ├── ResourceBuilderExtension.cs
│ ├── ResourceDetectors
│ │ ├── AWSEBSDetectorInitializer.cs
│ │ ├── AWSEC2DetectorInitializer.cs
│ │ ├── AWSECSDetectorInitializer.cs
│ │ ├── AWSEKSDetectorInitializer.cs
│ │ ├── AzureAppServiceDetectorInitializer.cs
│ │ ├── AzureContainerAppsDetectorInitializer.cs
│ │ ├── AzureVMDetectorInitializer.cs
│ │ ├── ContainerResource.cs
│ │ ├── HostDetectorInitializer.cs
│ │ ├── OperatingSystemResourceInitializer.cs
│ │ ├── ProcessResourceInitializer.cs
│ │ ├── ProcessRuntimeResource.cs
│ │ ├── ResourceDetector.cs
│ │ └── ResourceDetectorInitializer.cs
│ └── TracerProviderBuilderExtensions.cs
└── Grafana.OpenTelemetry
│ ├── Grafana.OpenTelemetry.csproj
│ ├── OpenTelemetryBuilderExtension.cs
│ └── rd.xml
└── tests
└── Grafana.OpenTelemetry.Tests
├── Grafana.OpenTelemetry.Tests.csproj
├── GrafanaCloudConfigurationHelperTest.cs
├── GrafanaOpenTelemetryResourceDetectorTest.cs
├── GrafanaOpenTelemetrySettingsTest.cs
├── InMemoryResourceExporter.cs
├── InstrumentationTest.cs
├── MeterProviderExtensionsTest.cs
├── OpenTelemetryLoggerOptionsExtensionsTest.cs
├── ReflectionHelperTest.cs
├── ResourceBuilderExtensionTest.cs
├── ResourceDetectorTest.cs
└── TracerProviderExtensionsTest.cs
/.editorconfig:
--------------------------------------------------------------------------------
1 | # To learn more about .editorconfig see https://aka.ms/editorconfigdocs
2 | ###############################
3 | # Core EditorConfig Options #
4 | ###############################
5 | # All files
6 | [*]
7 | charset = utf-8
8 | end_of_line = crlf
9 | indent_style = space
10 | indent_size = 2
11 | insert_final_newline = true
12 | trim_trailing_whitespace = true
13 |
14 | [*.{cs,cshtml,htm,html,md,py,sln,xml}]
15 | indent_size = 4
16 |
17 | ###############################
18 | # .NET Coding Conventions #
19 | ###############################
20 | # Directive order based on dotnet/runtime settings
21 | # https://github.com/dotnet/runtime/blob/main/.editorconfig
22 | [*.cs]
23 | # New line preferences
24 | csharp_new_line_before_open_brace = all
25 | csharp_new_line_before_else = true
26 | csharp_new_line_before_catch = true
27 | csharp_new_line_before_finally = true
28 | csharp_new_line_before_members_in_object_initializers = true
29 | csharp_new_line_before_members_in_anonymous_types = true
30 | csharp_new_line_between_query_expression_clauses = true
31 |
32 | # Indentation preferences
33 | csharp_indent_case_contents = true
34 | csharp_indent_switch_labels = true
35 | csharp_indent_labels = flush_left
36 |
37 | # Modifier preferences
38 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
39 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
40 |
41 | # this. preferences
42 | dotnet_style_qualification_for_field = true:suggestion
43 | dotnet_style_qualification_for_property = true:suggestion
44 | dotnet_style_qualification_for_method = true:suggestion
45 | dotnet_style_qualification_for_event = true:suggestion
46 |
47 | # var preferences, language keywords vs BCL types preferences
48 | csharp_style_var_for_built_in_types = true:silent
49 | csharp_style_var_when_type_is_apparent = true:silent
50 | csharp_style_var_elsewhere = true:silent
51 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent
52 | dotnet_style_predefined_type_for_member_access = true:silent
53 |
54 | # name all constant fields using PascalCase
55 | dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
56 | dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
57 | dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
58 | dotnet_naming_symbols.constant_fields.applicable_kinds = field
59 | dotnet_naming_symbols.constant_fields.required_modifiers = const
60 | dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
61 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case
62 |
63 | # Code style defaults
64 | dotnet_sort_system_directives_first = true
65 | csharp_prefer_braces = true:silent
66 | csharp_preserve_single_line_blocks = true
67 | csharp_preserve_single_line_statements = true
68 | csharp_prefer_simple_using_statement = true:suggestion
69 | dotnet_style_readonly_field = true:suggestion
70 | csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
71 | dotnet_style_prefer_simplified_interpolation = true:suggestion
72 | dotnet_style_object_initializer = true:suggestion
73 |
74 | # Expression-level preferences
75 | dotnet_style_object_initializer = true:suggestion
76 | dotnet_style_collection_initializer = true:suggestion
77 | dotnet_style_explicit_tuple_names = true:suggestion
78 | dotnet_style_coalesce_expression = true:suggestion
79 | dotnet_style_null_propagation = true:suggestion
80 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
81 | dotnet_style_prefer_inferred_tuple_names = true:suggestion
82 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
83 | dotnet_style_prefer_auto_properties = true:silent
84 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent
85 | dotnet_style_prefer_conditional_expression_over_return = true:silent
86 | csharp_prefer_simple_default_expression = true:suggestion
87 |
88 | # Expression-bodied members
89 | csharp_style_expression_bodied_methods = false:silent
90 | csharp_style_expression_bodied_constructors = false:silent
91 | csharp_style_expression_bodied_operators = false:silent
92 | csharp_style_expression_bodied_properties = true:silent
93 | csharp_style_expression_bodied_indexers = true:silent
94 | csharp_style_expression_bodied_accessors = true:silent
95 |
96 | # Pattern matching
97 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
98 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
99 | csharp_style_inlined_variable_declaration = true:suggestion
100 |
101 | # Null checking preferences
102 | csharp_style_throw_expression = true:suggestion
103 | csharp_style_conditional_delegate_call = true:suggestion
104 |
105 | # Other features
106 | csharp_style_prefer_index_operator = false:none
107 | csharp_style_prefer_range_operator = false:none
108 | csharp_style_pattern_local_over_anonymous_function = true:suggestion
109 | csharp_style_deconstructed_variable_declaration = true:suggestion
110 | csharp_style_namespace_declarations = file_scoped:suggestion
111 |
112 | # Space preferences
113 | csharp_space_after_cast = false
114 | csharp_space_after_colon_in_inheritance_clause = true
115 | csharp_space_after_keywords_in_control_flow_statements = true
116 | csharp_space_around_binary_operators = before_and_after
117 | csharp_space_before_colon_in_inheritance_clause = true
118 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
119 | csharp_space_between_method_call_name_and_opening_parenthesis = false
120 | csharp_space_between_method_call_parameter_list_parentheses = false
121 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
122 | csharp_space_between_method_declaration_parameter_list_parentheses = false
123 | csharp_space_between_parentheses = false
124 |
125 | # Parentheses preferences
126 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
127 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
128 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
129 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
130 |
131 | # Code analyzers
132 | # CA1031: Do not catch general exception types
133 | dotnet_diagnostic.CA1031.severity = none
134 |
135 | # CA1303: Do not pass literals as localized parameters
136 | dotnet_diagnostic.CA1303.severity = none
137 |
138 | # IDE0001: Simplify name
139 | dotnet_diagnostic.IDE0001.severity = warning
140 |
141 | # IDE0002: Simplify member access
142 | dotnet_diagnostic.IDE0002.severity = warning
143 |
144 | # IDE0005: Remove unnecessary import
145 | dotnet_diagnostic.IDE0005.severity = warning
146 |
147 | # RS0041: Public members should not use oblivious types
148 | dotnet_diagnostic.RS0041.severity = suggestion
149 |
150 | [obj/**.cs]
151 | generated_code = true
152 |
153 | [*.csproj]
154 | indent_size = 2
155 |
156 | [*.cshtml.cs]
157 | dotnet_diagnostic.SA1649.severity = none
158 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # https://help.github.com/articles/about-codeowners/
2 | # https://git-scm.com/docs/gitignore#_pattern_format
3 |
4 | * @grafana/otel-sdk
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug Report
3 | about: Create a report to help us improve
4 | labels: bug
5 | ---
6 |
7 | # Bug Report
8 |
9 | A list of [Grafana](https://www.nuget.org/profiles/Grafana) and
10 | [OpenTelemetry](https://www.nuget.org/profiles/OpenTelemetry) NuGet packages
11 | used, for example `Grafana.OpenTelemetry 0.6.0-beta.1`):
12 |
13 | *
14 |
15 | The .NET runtime version (e.g. `net462`, `net48`, `netcoreapp3.1`, `net8.0`
16 | etc.). You can find this information in your `*.csproj` file):
17 |
18 | *
19 |
20 | ## Symptom
21 |
22 | A clear and concise description of what the bug is.
23 |
24 | **What is the expected behavior?**
25 |
26 | What did you expect to see?
27 |
28 | **What is the actual behavior?**
29 |
30 | What did you see instead?
31 |
32 | ## Reproduce
33 |
34 | Create a self-contained project using the template of your choice, apply the
35 | minimum required code to result in the issue you're observing.
36 |
37 | ## Additional Context
38 |
39 | Add any other context about the problem here.
40 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature Request
3 | about: Suggest an idea for this project
4 | labels: enhancement
5 | ---
6 |
7 | # Feature Request
8 |
9 | Before opening a feature request against this project, consider whether the feature
10 | should/could be implemented in the [upstream OpenTelemetry .NET components](https://github.com/open-telemetry/opentelemetry-dotnet)
11 | If so, please [open an issue open-telemetry/opentelemetry-dotnet](https://github.com/open-telemetry/opentelemetry-dotnet/issues/new).
12 |
13 | If the feature is relevant for OpenTelemetry implementations of all languages,
14 | please [open an issue on
15 | opentelemetry-specification](https://github.com/open-telemetry/opentelemetry-specification/issues/new).
16 |
17 | **Is your feature request related to a problem?**
18 |
19 | If so, provide a concise description of the problem.
20 |
21 | **Describe the solution you'd like:**
22 |
23 | What do you want to happen instead? What is the expected behavior?
24 |
25 | **Describe alternatives you've considered.**
26 |
27 | Which alternative solutions or features have you considered?
28 |
29 | ## Additional Context
30 |
31 | Add any other context about the feature request here.
32 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Question
3 | about: Create a question to help us improve our knowledge base and documentation
4 | labels: question
5 | ---
6 |
7 | # Question
8 |
9 | Use [Github Discussions](https://github.com/grafana/grafana-opentelemetry-dotnet/discussions/new).
10 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Fixes #
2 |
3 | ## Changes
4 |
5 | Please provide a brief description of the changes here.
6 |
7 | ## Merge requirement checklist
8 |
9 | * [ ] Unit tests added/updated
10 | * [ ] [`CHANGELOG.md`](https://github.com/grafana/grafana-opentelemetry-dotnet) file updated for non-trivial changes
11 | * [ ] Changes in public API reviewed (if applicable)
12 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "daily"
7 | labels:
8 | - "infra"
9 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: ci
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | paths-ignore:
7 | - '**.md'
8 | pull_request:
9 | branches: [ main ]
10 | workflow_dispatch:
11 |
12 | env:
13 | DOTNET_CLI_TELEMETRY_OPTOUT: true
14 | DOTNET_NOLOGO: true
15 | DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION: 1
16 | NUGET_XMLDOC_MODE: skip
17 | TERM: xterm
18 |
19 | permissions: {}
20 |
21 | jobs:
22 | build-test:
23 | name: ${{ matrix.os-name }}
24 | runs-on: ${{ matrix.runner }}
25 |
26 | outputs:
27 | dotnet-sdk-version: ${{ steps.setup-dotnet.outputs.dotnet-version }}
28 |
29 | permissions:
30 | attestations: write
31 | contents: write
32 | id-token: write
33 |
34 | strategy:
35 | fail-fast: false
36 | matrix:
37 | include:
38 | - os-name: macos
39 | runner: macos-latest
40 | - os-name: linux
41 | runner: ubuntu-latest
42 | - os-name: windows
43 | runner: windows-latest
44 |
45 | steps:
46 |
47 | - name: Checkout code
48 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
49 | with:
50 | fetch-depth: 0
51 | filter: 'tree:0'
52 | show-progress: false
53 |
54 | - name: Setup .NET SDK
55 | uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
56 | id: setup-dotnet
57 |
58 | - name: Build
59 | run: dotnet build --configuration Release
60 |
61 | - name: Test
62 | run: dotnet test --configuration Release --logger:"GitHubActions;report-warnings=false"
63 |
64 | - name: Generate SBOM
65 | uses: anchore/sbom-action@e11c554f704a0b820cbf8c51673f6945e0731532 # v0.20.0
66 | with:
67 | artifact-name: build-${{ matrix.os-name }}.spdx.json
68 | output-file: ./artifacts/build.spdx.json
69 | path: ./artifacts/bin
70 | upload-release-assets: ${{ runner.os == 'Windows' }}
71 |
72 | - name: Attest artifacts
73 | uses: actions/attest-build-provenance@db473fddc028af60658334401dc6fa3ffd8669fd # v2.3.0
74 | if: |
75 | runner.os == 'Windows' &&
76 | github.event.repository.fork == false &&
77 | (github.ref_name == github.event.repository.default_branch || startsWith(github.ref, 'refs/tags/'))
78 | with:
79 | subject-path: |
80 | ./artifacts/bin/Grafana.OpenTelemetry*/release*/Grafana.OpenTelemetry*.dll
81 | ./artifacts/package/release/*
82 |
83 | - name: Publish NuGet packages
84 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
85 | with:
86 | name: packages-${{ matrix.os-name }}
87 | path: ./artifacts/package/release
88 | if-no-files-found: error
89 |
90 | validate-packages:
91 | needs: build-test
92 | runs-on: ubuntu-latest
93 | steps:
94 |
95 | - name: Download packages
96 | uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
97 | with:
98 | name: packages-windows
99 |
100 | - name: Setup .NET SDK
101 | uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
102 | with:
103 | dotnet-version: ${{ needs.build-test.outputs.dotnet-sdk-version }}
104 |
105 | - name: Validate NuGet packages
106 | shell: pwsh
107 | run: |
108 | dotnet tool install --global dotnet-validate --version 0.0.1-preview.304 --allow-roll-forward
109 | $packages = Get-ChildItem -Filter "*.nupkg" | ForEach-Object { $_.FullName }
110 | $invalidPackages = 0
111 | foreach ($package in $packages) {
112 | dotnet validate package local $package
113 | if ($LASTEXITCODE -ne 0) {
114 | $invalidPackages++
115 | }
116 | }
117 | if ($invalidPackages -gt 0) {
118 | Write-Output "::error::$invalidPackages NuGet package(s) failed validation."
119 | exit 1
120 | }
121 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet-format.yml:
--------------------------------------------------------------------------------
1 | name: dotnet format
2 |
3 | on:
4 | push:
5 | branches: [ 'main*' ]
6 | paths:
7 | - '**.cs'
8 | - '.editorconfig'
9 | pull_request:
10 | branches: [ 'main*' ]
11 | paths:
12 | - '**.cs'
13 | - '.editorconfig'
14 |
15 | jobs:
16 | check-format:
17 | runs-on: windows-latest
18 | permissions: {}
19 |
20 | steps:
21 | - name: check out code
22 | uses: actions/checkout@v4
23 | with:
24 | persist-credentials: false
25 |
26 | - name: dotnet format
27 | run: dotnet format --verify-no-changes
28 |
--------------------------------------------------------------------------------
/.github/workflows/markdown-link-check.yml:
--------------------------------------------------------------------------------
1 | name: markdown-link-check
2 |
3 | on:
4 | push:
5 | branches: [ 'main*' ]
6 | paths:
7 | - '**.md'
8 | pull_request:
9 | branches: [ 'main*' ]
10 | paths:
11 | - '**.md'
12 |
13 | jobs:
14 | build:
15 | runs-on: ubuntu-latest
16 | permissions: {}
17 |
18 | steps:
19 | - name: check out code
20 | uses: actions/checkout@v4
21 | with:
22 | persist-credentials: false
23 |
24 | - name: install markdown-link-check
25 | run: sudo npm install -g markdown-link-check
26 |
27 | - name: run markdown-link-check
28 | run: "find . -name '*.md' -print0 | xargs -0 -n1 markdown-link-check --config .markdown_link_check_config.json"
29 |
--------------------------------------------------------------------------------
/.github/workflows/markdownlint.yml:
--------------------------------------------------------------------------------
1 | name: markdownlint
2 |
3 | on:
4 | push:
5 | branches: [ 'main*' ]
6 | paths:
7 | - '**.md'
8 | pull_request:
9 | branches: [ 'main*' ]
10 | paths:
11 | - '**.md'
12 |
13 | jobs:
14 | build:
15 | runs-on: ubuntu-latest
16 | permissions: {}
17 |
18 | steps:
19 | - name: check out code
20 | uses: actions/checkout@v4
21 | with:
22 | persist-credentials: false
23 |
24 | - name: install markdownlint-cli
25 | run: sudo npm install -g markdownlint-cli
26 |
27 | - name: run markdownlint
28 | run: markdownlint .
29 |
--------------------------------------------------------------------------------
/.github/workflows/misspell.yml:
--------------------------------------------------------------------------------
1 | name: sanitycheck
2 |
3 | on:
4 | push:
5 | branches: [ 'main*' ]
6 | pull_request:
7 | branches: [ 'main*' ]
8 |
9 | jobs:
10 | misspell:
11 | runs-on: ubuntu-latest
12 | permissions: {}
13 |
14 | steps:
15 | - name: check out code
16 | uses: actions/checkout@v4
17 | with:
18 | persist-credentials: false
19 |
20 | - name: install misspell
21 | run: |
22 | curl -L -o ./install-misspell.sh https://git.io/misspell
23 | sh ./install-misspell.sh
24 |
25 | - name: run misspell
26 | run: ./bin/misspell -error .
27 |
--------------------------------------------------------------------------------
/.github/workflows/oats.yml:
--------------------------------------------------------------------------------
1 | name: OATS
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | paths-ignore:
7 | - '**/*.gitattributes'
8 | - '**/*.gitignore'
9 | - '**/*.md'
10 | pull_request:
11 | branches: [ main ]
12 | workflow_dispatch:
13 |
14 | permissions: {}
15 |
16 | jobs:
17 | acceptance-tests:
18 | runs-on: ubuntu-latest
19 | timeout-minutes: 20
20 |
21 | steps:
22 |
23 | - name: Checkout code
24 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
25 | with:
26 | filter: 'tree:0'
27 | persist-credentials: false
28 | show-progress: false
29 |
30 | - name: Set up Go
31 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
32 | with:
33 | go-version: '1.24'
34 |
35 | - name: Install OATS
36 | env:
37 | # renovate: datasource=github-releases depName=oats packageName=grafana/oats
38 | OATS_VERSION: v0.3.2
39 | run: go install "github.com/grafana/oats@${OATS_VERSION}"
40 |
41 | - name: Run acceptance tests
42 | run: oats --timeout=5m ./docker/docker-compose-aspnetcore
43 |
44 | - name: Upload log file
45 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
46 | if: failure()
47 | with:
48 | name: docker-compose.log
49 | path: oats/yaml/build/**/output.log
50 | if-no-files-found: ignore
51 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Aa]rtifacts/
21 | [Bb]uild/
22 | [Dd]ebug/
23 | [Dd]ebugPublic/
24 | [Rr]elease/
25 | [Rr]eleases/
26 | x64/
27 | x86/
28 | [Ww][Ii][Nn]32/
29 | [Aa][Rr][Mm]/
30 | [Aa][Rr][Mm]64/
31 | bld/
32 | [Bb]in/
33 | [Oo]bj/
34 | [Ll]og/
35 | [Ll]ogs/
36 |
37 | # Visual Studio 2015/2017 cache/options directory
38 | .vs/
39 | # Uncomment if you have tasks that create the project's static files in wwwroot
40 | #wwwroot/
41 |
42 | # Visual Studio 2017 auto generated files
43 | Generated\ Files/
44 |
45 | # MSTest test Results
46 | [Tt]est[Rr]esult*/
47 | [Bb]uild[Ll]og.*
48 |
49 | # NUnit
50 | *.VisualState.xml
51 | TestResult.xml
52 | nunit-*.xml
53 |
54 | # Build Results of an ATL Project
55 | [Dd]ebugPS/
56 | [Rr]eleasePS/
57 | dlldata.c
58 |
59 | # Benchmark Results
60 | BenchmarkDotNet.Artifacts/
61 |
62 | # .NET
63 | project.lock.json
64 | project.fragment.lock.json
65 | artifacts/
66 |
67 | # Tye
68 | .tye/
69 |
70 | # ASP.NET Scaffolding
71 | ScaffoldingReadMe.txt
72 |
73 | # StyleCop
74 | StyleCopReport.xml
75 |
76 | # Files built by Visual Studio
77 | *_i.c
78 | *_p.c
79 | *_h.h
80 | *.ilk
81 | *.meta
82 | *.obj
83 | *.iobj
84 | *.pch
85 | *.pdb
86 | *.ipdb
87 | *.pgc
88 | *.pgd
89 | *.rsp
90 | *.sbr
91 | *.tlb
92 | *.tli
93 | *.tlh
94 | *.tmp
95 | *.tmp_proj
96 | *_wpftmp.csproj
97 | *.log
98 | *.tlog
99 | *.vspscc
100 | *.vssscc
101 | .builds
102 | *.pidb
103 | *.svclog
104 | *.scc
105 |
106 | # Chutzpah Test files
107 | _Chutzpah*
108 |
109 | # Visual C++ cache files
110 | ipch/
111 | *.aps
112 | *.ncb
113 | *.opendb
114 | *.opensdf
115 | *.sdf
116 | *.cachefile
117 | *.VC.db
118 | *.VC.VC.opendb
119 |
120 | # Visual Studio profiler
121 | *.psess
122 | *.vsp
123 | *.vspx
124 | *.sap
125 |
126 | # Visual Studio Trace Files
127 | *.e2e
128 |
129 | # TFS 2012 Local Workspace
130 | $tf/
131 |
132 | # Guidance Automation Toolkit
133 | *.gpState
134 |
135 | # ReSharper is a .NET coding add-in
136 | _ReSharper*/
137 | *.[Rr]e[Ss]harper
138 | *.DotSettings.user
139 |
140 | # TeamCity is a build add-in
141 | _TeamCity*
142 |
143 | # DotCover is a Code Coverage Tool
144 | *.dotCover
145 |
146 | # AxoCover is a Code Coverage Tool
147 | .axoCover/*
148 | !.axoCover/settings.json
149 |
150 | # Coverlet is a free, cross platform Code Coverage Tool
151 | coverage*.json
152 | coverage*.xml
153 | coverage*.info
154 |
155 | # Visual Studio code coverage results
156 | *.coverage
157 | *.coveragexml
158 |
159 | # NCrunch
160 | _NCrunch_*
161 | .*crunch*.local.xml
162 | nCrunchTemp_*
163 |
164 | # MightyMoose
165 | *.mm.*
166 | AutoTest.Net/
167 |
168 | # Web workbench (sass)
169 | .sass-cache/
170 |
171 | # Installshield output folder
172 | [Ee]xpress/
173 |
174 | # DocProject is a documentation generator add-in
175 | DocProject/buildhelp/
176 | DocProject/Help/*.HxT
177 | DocProject/Help/*.HxC
178 | DocProject/Help/*.hhc
179 | DocProject/Help/*.hhk
180 | DocProject/Help/*.hhp
181 | DocProject/Help/Html2
182 | DocProject/Help/html
183 |
184 | # Click-Once directory
185 | publish/
186 |
187 | # Publish Web Output
188 | *.[Pp]ublish.xml
189 | *.azurePubxml
190 | # Note: Comment the next line if you want to checkin your web deploy settings,
191 | # but database connection strings (with potential passwords) will be unencrypted
192 | *.pubxml
193 | *.publishproj
194 |
195 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
196 | # checkin your Azure Web App publish settings, but sensitive information contained
197 | # in these scripts will be unencrypted
198 | PublishScripts/
199 |
200 | # NuGet Packages
201 | *.nupkg
202 | # NuGet Symbol Packages
203 | *.snupkg
204 | # The packages folder can be ignored because of Package Restore
205 | **/[Pp]ackages/*
206 | # except build/, which is used as an MSBuild target.
207 | !**/[Pp]ackages/build/
208 | # Uncomment if necessary however generally it will be regenerated when needed
209 | #!**/[Pp]ackages/repositories.config
210 | # NuGet v3's project.json files produces more ignorable files
211 | *.nuget.props
212 | *.nuget.targets
213 |
214 | # Microsoft Azure Build Output
215 | csx/
216 | *.build.csdef
217 |
218 | # Microsoft Azure Emulator
219 | ecf/
220 | rcf/
221 |
222 | # Windows Store app package directories and files
223 | AppPackages/
224 | BundleArtifacts/
225 | Package.StoreAssociation.xml
226 | _pkginfo.txt
227 | *.appx
228 | *.appxbundle
229 | *.appxupload
230 |
231 | # Visual Studio cache files
232 | # files ending in .cache can be ignored
233 | *.[Cc]ache
234 | # but keep track of directories ending in .cache
235 | !?*.[Cc]ache/
236 |
237 | # Others
238 | ClientBin/
239 | ~$*
240 | *~
241 | *.dbmdl
242 | *.dbproj.schemaview
243 | *.jfm
244 | *.pfx
245 | *.publishsettings
246 | orleans.codegen.cs
247 |
248 | # RIA/Silverlight projects
249 | Generated_Code/
250 |
251 | # Backup & report files from converting an old project file
252 | # to a newer Visual Studio version. Backup files are not needed,
253 | # because we have git ;-)
254 | _UpgradeReport_Files/
255 | Backup*/
256 | UpgradeLog*.XML
257 | UpgradeLog*.htm
258 | ServiceFabricBackup/
259 | *.rptproj.bak
260 |
261 | # SQL Server files
262 | *.mdf
263 | *.ldf
264 | *.ndf
265 |
266 | # SQLLite files
267 | *.db
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
298 | *.vbp
299 |
300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
301 | *.dsw
302 | *.dsp
303 |
304 | # Visual Studio 6 technical files
305 | *.ncb
306 | *.aps
307 |
308 | # Visual Studio LightSwitch build output
309 | **/*.HTMLClient/GeneratedArtifacts
310 | **/*.DesktopClient/GeneratedArtifacts
311 | **/*.DesktopClient/ModelManifest.xml
312 | **/*.Server/GeneratedArtifacts
313 | **/*.Server/ModelManifest.xml
314 | _Pvt_Extensions
315 |
316 | # Paket dependency manager
317 | .paket/paket.exe
318 | paket-files/
319 |
320 | # FAKE - F# Make
321 | .fake/
322 |
323 | # CodeRush personal settings
324 | .cr/personal
325 |
326 | # Python Tools for Visual Studio (PTVS)
327 | __pycache__/
328 | *.pyc
329 |
330 | # Cake - Uncomment if you are using it
331 | # tools/**
332 | # !tools/packages.config
333 |
334 | # Tabs Studio
335 | *.tss
336 |
337 | # Telerik's JustMock configuration file
338 | *.jmconfig
339 |
340 | # BizTalk build output
341 | *.btp.cs
342 | *.btm.cs
343 | *.odx.cs
344 | *.xsd.cs
345 |
346 | # OpenCover UI analysis results
347 | OpenCover/
348 |
349 | # Azure Stream Analytics local run output
350 | ASALocalRun/
351 |
352 | # MSBuild Binary and Structured Log
353 | *.binlog
354 |
355 | # NVidia Nsight GPU debugger configuration file
356 | *.nvuser
357 |
358 | # MFractors (Xamarin productivity tool) working folder
359 | .mfractor/
360 |
361 | # Local History for Visual Studio
362 | .localhistory/
363 |
364 | # Visual Studio History (VSHistory) files
365 | .vshistory/
366 |
367 | # BeatPulse healthcheck temp database
368 | healthchecksdb
369 |
370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
371 | MigrationBackup/
372 |
373 | # Ionide (cross platform F# VS Code tools) working folder
374 | .ionide/
375 |
376 | # Fody - auto-generated XML schema
377 | FodyWeavers.xsd
378 |
379 | # VS Code files for those working on multiple tools
380 | .vscode/*
381 | !.vscode/settings.json
382 | !.vscode/tasks.json
383 | !.vscode/launch.json
384 | !.vscode/extensions.json
385 | *.code-workspace
386 |
387 | # Local History for Visual Studio Code
388 | .history/
389 |
390 | # Windows Installer files from build outputs
391 | *.cab
392 | *.msi
393 | *.msix
394 | *.msm
395 | *.msp
396 |
397 | # JetBrains Rider
398 | *.sln.iml
399 |
400 | ##
401 | ## Visual studio for Mac
402 | ##
403 |
404 |
405 | # globs
406 | Makefile.in
407 | *.userprefs
408 | *.usertasks
409 | config.make
410 | config.status
411 | aclocal.m4
412 | install-sh
413 | autom4te.cache/
414 | *.tar.gz
415 | tarballs/
416 | test-results/
417 |
418 | # Mac bundle stuff
419 | *.dmg
420 | *.app
421 |
422 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
423 | # General
424 | .DS_Store
425 | .AppleDouble
426 | .LSOverride
427 |
428 | # Icon must end with two \r
429 | Icon
430 |
431 |
432 | # Thumbnails
433 | ._*
434 |
435 | # Files that might appear in the root of a volume
436 | .DocumentRevisions-V100
437 | .fseventsd
438 | .Spotlight-V100
439 | .TemporaryItems
440 | .Trashes
441 | .VolumeIcon.icns
442 | .com.apple.timemachine.donotpresent
443 |
444 | # Directories potentially created on remote AFP share
445 | .AppleDB
446 | .AppleDesktop
447 | Network Trash Folder
448 | Temporary Items
449 | .apdisk
450 |
451 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
452 | # Windows thumbnail cache files
453 | Thumbs.db
454 | ehthumbs.db
455 | ehthumbs_vista.db
456 |
457 | # Dump file
458 | *.stackdump
459 |
460 | # Folder config file
461 | [Dd]esktop.ini
462 |
463 | # Recycle Bin used on file shares
464 | $RECYCLE.BIN/
465 |
466 | # Windows Installer files
467 | *.cab
468 | *.msi
469 | *.msix
470 | *.msm
471 | *.msp
472 |
473 | # Windows shortcuts
474 | *.lnk
475 |
--------------------------------------------------------------------------------
/.markdown_link_check_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "retryOn429": true,
3 | "timeout": "30s",
4 | "aliveStatusCodes": [200, 403]
5 | }
6 |
--------------------------------------------------------------------------------
/.markdownlint.yaml:
--------------------------------------------------------------------------------
1 | # Default state for all rules
2 | default: true
3 |
4 | # allow long lines for tables and code blocks
5 | MD013:
6 | code_blocks: false
7 | tables: false
8 |
9 | # Allow same headers for non-siblings, e. g. in the CHANGELOG
10 | MD024:
11 | siblings_only: true
12 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "EditorConfig.EditorConfig",
4 | "github.vscode-github-actions",
5 | "ms-dotnettools.csharp"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
4 | Grafana Labs
5 | SHA256
6 | Grafana Labs
7 | true
8 | Copyright (c) Grafana Labs
9 | true
10 | true
11 | false
12 | en-US
13 |
14 | $(NoWarn);NU5104
15 | disable
16 | Grafana_icon.png
17 | Apache-2.0
18 | https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/
19 | package-readme.md
20 | https://github.com/grafana/grafana-opentelemetry-dotnet/blob/main/CHANGELOG.md
21 | false
22 | OpenTelemetry;Grafana;Metrics;Logs;Traces;Observability;Monitoring
23 | true
24 | git
25 | https://github.com/grafana/grafana-opentelemetry-dotnet
26 | snupkg
27 | true
28 | true
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/GrafanaOpenTelemetry.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31903.59
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F0687CB8-95E1-4372-9444-70676DE3A34A}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grafana.OpenTelemetry", "src\Grafana.OpenTelemetry\Grafana.OpenTelemetry.csproj", "{B4761520-2B6F-4605-BC3B-66710F7439EA}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grafana.OpenTelemetry.Base", "src\Grafana.OpenTelemetry.Base\Grafana.OpenTelemetry.Base.csproj", "{8CA452C6-61DA-49A9-8AA7-909D48E7ACF0}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{FB0399BE-6925-42B7-8431-C5A6E21DC8EC}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grafana.OpenTelemetry.Tests", "tests\Grafana.OpenTelemetry.Tests\Grafana.OpenTelemetry.Tests.csproj", "{30810D69-3237-4260-93C2-DC601C5AC80F}"
15 | EndProject
16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{2DC924CF-282A-446D-B94B-D2931E5C6130}"
17 | EndProject
18 | Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose-aspnetcore", "docker\docker-compose-aspnetcore\docker-compose-aspnetcore.dcproj", "{A4C41298-ED4F-4A4C-9B18-014986186C71}"
19 | EndProject
20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker", "docker", "{E63943FA-D9F6-4DC4-91EE-D0BD0BF8E324}"
21 | EndProject
22 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "net8.0", "net8.0", "{74BA358B-6EDB-463F-8AB2-313FAA4DE564}"
23 | EndProject
24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "aspnetcore", "examples\net8.0\aspnetcore\aspnetcore.csproj", "{BD1FB154-C711-4E37-947D-063F5DC4BF9E}"
25 | EndProject
26 | Global
27 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
28 | Debug|Any CPU = Debug|Any CPU
29 | Release|Any CPU = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
32 | {B4761520-2B6F-4605-BC3B-66710F7439EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {B4761520-2B6F-4605-BC3B-66710F7439EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {B4761520-2B6F-4605-BC3B-66710F7439EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {B4761520-2B6F-4605-BC3B-66710F7439EA}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {8CA452C6-61DA-49A9-8AA7-909D48E7ACF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {8CA452C6-61DA-49A9-8AA7-909D48E7ACF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {8CA452C6-61DA-49A9-8AA7-909D48E7ACF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {8CA452C6-61DA-49A9-8AA7-909D48E7ACF0}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {30810D69-3237-4260-93C2-DC601C5AC80F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {30810D69-3237-4260-93C2-DC601C5AC80F}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {30810D69-3237-4260-93C2-DC601C5AC80F}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {30810D69-3237-4260-93C2-DC601C5AC80F}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {A4C41298-ED4F-4A4C-9B18-014986186C71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {A4C41298-ED4F-4A4C-9B18-014986186C71}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {A4C41298-ED4F-4A4C-9B18-014986186C71}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {A4C41298-ED4F-4A4C-9B18-014986186C71}.Release|Any CPU.Build.0 = Release|Any CPU
48 | {BD1FB154-C711-4E37-947D-063F5DC4BF9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49 | {BD1FB154-C711-4E37-947D-063F5DC4BF9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
50 | {BD1FB154-C711-4E37-947D-063F5DC4BF9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 | {BD1FB154-C711-4E37-947D-063F5DC4BF9E}.Release|Any CPU.Build.0 = Release|Any CPU
52 | EndGlobalSection
53 | GlobalSection(SolutionProperties) = preSolution
54 | HideSolutionNode = FALSE
55 | EndGlobalSection
56 | GlobalSection(NestedProjects) = preSolution
57 | {B4761520-2B6F-4605-BC3B-66710F7439EA} = {F0687CB8-95E1-4372-9444-70676DE3A34A}
58 | {8CA452C6-61DA-49A9-8AA7-909D48E7ACF0} = {F0687CB8-95E1-4372-9444-70676DE3A34A}
59 | {30810D69-3237-4260-93C2-DC601C5AC80F} = {FB0399BE-6925-42B7-8431-C5A6E21DC8EC}
60 | {A4C41298-ED4F-4A4C-9B18-014986186C71} = {E63943FA-D9F6-4DC4-91EE-D0BD0BF8E324}
61 | {74BA358B-6EDB-463F-8AB2-313FAA4DE564} = {2DC924CF-282A-446D-B94B-D2931E5C6130}
62 | {BD1FB154-C711-4E37-947D-063F5DC4BF9E} = {74BA358B-6EDB-463F-8AB2-313FAA4DE564}
63 | EndGlobalSection
64 | EndGlobal
65 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Grafana OpenTelemetry distribution for .NET
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | [![Build][ci-badge]][ci-status]
12 | [![OATS][oats-badge]][oats-status]
13 | [![NuGet][package-badge-version]][package-download]
14 | [![SDK][otel-badge]][otel]
15 | [![Slack][slack-badge]][slack-channel]
16 |
17 |
18 | ## About
19 |
20 | This is a pre-configured and pre-packaged bundle of [OpenTelemetry .NET components][otel-contrib],
21 | optimized for [Grafana Cloud Application Observability][app-o11y].
22 |
23 | It requires only minimal setup and configuration and makes it very easy to emit
24 | OpenTelemetry metrics, logs, and traces from your .NET application.
25 |
26 | ## Getting Started
27 |
28 | ### Step 1: Install package
29 |
30 | For installing the distribution with the full set of dependencies, add a
31 | reference to the [`Grafana.OpenTelemetry`][package] package to your project.
32 |
33 | ```sh
34 | dotnet add package Grafana.OpenTelemetry
35 | ```
36 |
37 | ### Step 2: Enable the Grafana distribution at application startup
38 |
39 | The `UseGrafana` extension method on the `TracerProviderBuilder` or the
40 | `MetricProviderBuilder` can be used to set up the Grafana distribution. By
41 | default, telemetry data will be sent to Grafana Alloy or an OpenTelemetry collector
42 | that runs locally and listens to default OTLP ports.
43 |
44 | ```csharp
45 | using var tracerProvider = Sdk.CreateTracerProviderBuilder()
46 | .UseGrafana()
47 | .Build();
48 | ```
49 |
50 | Alternatively, you can send telemetry data directly to Grafana Cloud without
51 | involving an agent or collector. This can be configured via the environment
52 | variables `OTEL_EXPORTER_OTLP_PROTOCOL`, `OTEL_EXPORTER_OTLP_ENDPOINT`, and
53 | `OTEL_EXPORTER_OTLP_HEADERS`.
54 |
55 | For details on how to obtain those values, refer to
56 | [Send data to the Grafana Cloud OTLP endpoint: Quickstart architecture][push-oltp].
57 |
58 | ```sh
59 | export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
60 | export OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp-gateway-prod-eu-west-0.grafana.net/otlp"
61 | export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic a-secret-token"
62 | ```
63 |
64 | ## Documentation
65 |
66 | For detailed documentation and setup instructions, refer to the following
67 | documents:
68 |
69 | * [Installation](./docs/installation.md)
70 | * [Configuration](./docs/configuration.md)
71 | * [Supported instrumentations](./docs/supported-instrumentations.md)
72 | * [Supported resource detectors](./docs/supported-resource-detectors.md)
73 | * [Migrating to upstream](./docs/migration.md)
74 |
75 | ## Troubleshooting
76 |
77 | This project utilizes the [self-diagnostics feature of the .NET OpenTelemetry SDK][self-diagnostics].
78 |
79 | To enable self-diagnostics, go to the [current working directory][working-dir] of
80 | your process and create a configuration file named `OTEL_DIAGNOSTICS.json` with
81 | the following content:
82 |
83 | ```json
84 | {
85 | "LogDirectory": ".",
86 | "FileSize": 32768,
87 | "LogLevel": "Warning"
88 | }
89 | ```
90 |
91 | To disable self-diagnostics, delete the above file.
92 |
93 | ## Community
94 |
95 | To engage with the Grafana Application Observability community:
96 |
97 | * Chat with us on our community Slack channel. To invite yourself to the
98 | Grafana Slack, visit
99 | and join the [#application-observability][slack-channel] channel.
100 | * Ask questions on the [Discussions page][discussions].
101 | * [File an issue][issues] for bugs, issues, and feature suggestions.
102 |
103 | [app-o11y]: https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/
104 | [ci-badge]: https://github.com/grafana/grafana-opentelemetry-dotnet/actions/workflows/ci.yml/badge.svg?branch=main
105 | [ci-status]: https://github.com/grafana/grafana-opentelemetry-dotnet/actions/workflows/ci.yml
106 | [discussions]: https://github.com/grafana/grafana-opentelemetry-dotnet/discussions
107 | [issues]: https://github.com/grafana/grafana-opentelemetry-dotnet/issues/new
108 | [oats-badge]: https://github.com/grafana/grafana-opentelemetry-dotnet/actions/workflows/oats.yml/badge.svg?branch=main
109 | [oats-status]: https://github.com/grafana/grafana-opentelemetry-dotnet/actions/workflows/oats.yml
110 | [otel]: https://github.com/open-telemetry/opentelemetry-dotnet
111 | [otel-badge]: https://img.shields.io/badge/OTel--SDK-1.9.0-blue?style=flat&logo=opentelemetry
112 | [otel-contrib]: http://github.com/open-telemetry/opentelemetry-dotnet-contrib
113 | [package]: https://www.nuget.org/packages/Grafana.OpenTelemetry
114 | [package-badge-version]: https://img.shields.io/nuget/v/Grafana.OpenTelemetry?logo=nuget&label=NuGet&color=blue
115 | [package-download]: https://www.nuget.org/profiles/Grafana
116 | [push-oltp]: https://grafana.com/docs/grafana-cloud/send-data/otlp/send-data-otlp/#quickstart-architecture
117 | [self-diagnostics]: https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry/README.md#self-diagnostics
118 | [slack-badge]: https://img.shields.io/badge/%20Slack-%23app--o11y-brightgreen.svg?logo=slack
119 | [slack-channel]: https://grafana.slack.com/archives/C05E87XRK3J
120 | [working-dir]: https://en.wikipedia.org/wiki/Working_directory
121 |
--------------------------------------------------------------------------------
/docker/docker-compose-aspnetcore/.dockerignore:
--------------------------------------------------------------------------------
1 | **/.classpath
2 | **/.dockerignore
3 | **/.env
4 | **/.git
5 | **/.gitignore
6 | **/.project
7 | **/.settings
8 | **/.toolstarget
9 | **/.vs
10 | **/.vscode
11 | **/*.*proj.user
12 | **/*.dbmdl
13 | **/*.jfm
14 | **/azds.yaml
15 | **/bin
16 | **/charts
17 | **/docker-compose*
18 | **/Dockerfile*
19 | **/node_modules
20 | **/npm-debug.log
21 | **/obj
22 | **/secrets.dev.yaml
23 | **/values.dev.yaml
24 | LICENSE
25 | README.md
--------------------------------------------------------------------------------
/docker/docker-compose-aspnetcore/docker-compose-aspnetcore.dcproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 2.1
5 | Linux
6 | a4c41298-ed4f-4a4c-9b18-014986186c71
7 | LaunchBrowser
8 | {Scheme}://localhost:{ServicePort}/swagger
9 | aspnetcore
10 |
11 |
12 |
13 |
14 | docker-compose.yml
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/docker/docker-compose-aspnetcore/docker-compose.oats.yml:
--------------------------------------------------------------------------------
1 | services:
2 | aspnetcore:
3 | image: ${DOCKER_REGISTRY-}aspnetcore
4 | build:
5 | context: ../..
6 | dockerfile: examples/net8.0/aspnetcore/Dockerfile
7 | environment:
8 | - OTEL_EXPORTER_OTLP_ENDPOINT=http://lgtm:4317
9 | ports:
10 | - "5000:8080"
11 | - "8080:8080" # for OATs
12 | depends_on:
13 | - redis
14 | - mssql
15 | redis:
16 | image: redis:7.2
17 | ports:
18 | - "6379:6379"
19 | healthcheck:
20 | test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
21 | interval: 1s
22 | timeout: 3s
23 | retries: 5
24 | mssql:
25 | image: mcr.microsoft.com/mssql/server:2022-latest
26 | ports:
27 | - "1433:1433"
28 | environment:
29 | - ACCEPT_EULA=Y
30 | - MSSQL_SA_PASSWORD=Password12345%%
31 |
--------------------------------------------------------------------------------
/docker/docker-compose-aspnetcore/docker-compose.override.yml:
--------------------------------------------------------------------------------
1 | services:
2 | aspnetcore:
3 | environment:
4 | - ASPNETCORE_ENVIRONMENT=Development
5 | ports:
6 | - "8080"
7 |
--------------------------------------------------------------------------------
/docker/docker-compose-aspnetcore/docker-compose.self-contained.oats.yml:
--------------------------------------------------------------------------------
1 | services:
2 | aspnetcore:
3 | image: ${DOCKER_REGISTRY-}aspnetcore
4 | build:
5 | context: ../..
6 | dockerfile: examples/net8.0/aspnetcore/Dockerfile
7 | args:
8 | DOTNET_PUBLISH_ARGS: "--self-contained true /p:PublishSingleFile=true"
9 | entrypoint: ./aspnetcore
10 | environment:
11 | - OTEL_EXPORTER_OTLP_ENDPOINT=http://lgtm:4317
12 | ports:
13 | - "5000:8080"
14 | - "8080:8080" # for OATs
15 | depends_on:
16 | - redis
17 | - mssql
18 | redis:
19 | image: redis:7.2
20 | ports:
21 | - "6379:6379"
22 | healthcheck:
23 | test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
24 | interval: 1s
25 | timeout: 3s
26 | retries: 5
27 | mssql:
28 | image: mcr.microsoft.com/mssql/server:2022-latest
29 | ports:
30 | - "1433:1433"
31 | environment:
32 | - ACCEPT_EULA=Y
33 | - MSSQL_SA_PASSWORD=Password12345%%
34 |
--------------------------------------------------------------------------------
/docker/docker-compose-aspnetcore/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | aspnetcore:
3 | image: ${DOCKER_REGISTRY-}aspnetcore
4 | build:
5 | context: ../..
6 | dockerfile: examples/net8.0/aspnetcore/Dockerfile
7 | depends_on:
8 | - redis
9 | - mssql
10 | ports:
11 | - "8080:8080" # for OATs
12 | redis:
13 | image: redis:7.2
14 | ports:
15 | - "6379:6379"
16 | mssql:
17 | image: mcr.microsoft.com/mssql/server:2022-latest
18 | ports:
19 | - "1433:1433"
20 | environment:
21 | - ACCEPT_EULA=Y
22 | - MSSQL_SA_PASSWORD=Password12345%%
23 |
--------------------------------------------------------------------------------
/docker/docker-compose-aspnetcore/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Docker Compose": {
4 | "commandName": "DockerCompose",
5 | "commandVersion": "1.0",
6 | "serviceActions": {
7 | "aspnet": "StartDebugging",
8 | "aspnetcore": "StartDebugging"
9 | }
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/docker/docker-compose-aspnetcore/oats-template.yml:
--------------------------------------------------------------------------------
1 | matrix:
2 | - name: default
3 | docker-compose:
4 | generator: docker-lgtm
5 | files:
6 | - ./docker-compose.oats.yml
7 | - name: self-contained
8 | docker-compose:
9 | generator: docker-lgtm
10 | files:
11 | - ./docker-compose.self-contained.oats.yml
12 | interval: 500ms
13 |
--------------------------------------------------------------------------------
/docker/docker-compose-aspnetcore/oats.yaml:
--------------------------------------------------------------------------------
1 | include:
2 | - ./oats-template.yml
3 | input:
4 | - path: /api/HttpClient/Get
5 | - path: /api/HttpClient/GetError
6 | - path: /api/MsSql/ServerInfo
7 | - path: /api/MsSql/Tables
8 | - path: /api/Redis/LeftPush
9 | - path: /api/todo/items
10 | expected:
11 | logs:
12 | - logql: '{ service_name="aspnetcore" } |~ `Application started.`'
13 | contains:
14 | - 'Application started'
15 | metrics:
16 | - promql: http_client_request_duration_seconds_count{}
17 | value: '>= 0'
18 | - promql: http_client_request_duration_seconds_count{http_request_method="GET", http_response_status_code="200"}
19 | value: '>= 0'
20 | traces:
21 | - traceql: '{ resource.process.pid > 0 }'
22 | spans:
23 | - name: 'GET'
24 | - traceql: '{ span.http.route =~ "api/HttpClient/Get" }'
25 | spans:
26 | - name: 'GET api/HttpClient/Get'
27 | attributes:
28 | http.request.method: GET
29 | - name: 'GET api/HttpClient/Get'
30 | attributes:
31 | service.name: aspnetcore
32 | service.version: 1.0.0.0
33 | telemetry.distro.name: grafana-opentelemetry-dotnet
34 | telemetry.distro.version: regex:.+
35 | deployment.environment: production
36 | process.runtime.description: regex:.NET.+
37 | process.runtime.name: .NET
38 | process.runtime.version: regex:.+
39 | host.name: regex:.+
40 | telemetry.sdk.name: opentelemetry
41 | telemetry.sdk.language: dotnet
42 | telemetry.sdk.version: regex:.+
43 | - traceql: '{ span.http.route =~ "api/HttpClient/GetError" }'
44 | spans:
45 | - name: 'GET api/HttpClient/GetError'
46 | attributes:
47 | http.request.method: GET
48 | - name: 'GET'
49 | attributes:
50 | error.type: '500'
51 | http.request.method: GET
52 | http.response.status_code: '500'
53 | - traceql: '{ span.http.route =~ "api/MsSql/ServerInfo" }'
54 | spans:
55 | - name: 'master'
56 | attributes:
57 | db.system: mssql
58 | db.name: master
59 | db.statement: sp_server_info
60 | otel.library.name: OpenTelemetry.Instrumentation.SqlClient
61 | - traceql: '{ span.http.route =~ "api/MsSql/Tables" }'
62 | spans:
63 | - name: 'master'
64 | attributes:
65 | db.system: mssql
66 | db.name: master
67 | otel.library.name: OpenTelemetry.Instrumentation.SqlClient
68 | - traceql: '{ span.http.route =~ "api/Redis/LeftPush" }'
69 | spans:
70 | - name: 'LPUSH'
71 | attributes:
72 | db.statement: LPUSH
73 | db.system: redis
74 | net.peer.name: redis
75 | - traceql: '{ span.http.route =~ "/api/todo/items/" }'
76 | spans:
77 | - name: 'main'
78 | attributes:
79 | db.system: sqlite
80 | db.name: main
81 | peer.service: /app/App_Data/TodoApp.db
82 | otel.library.name: OpenTelemetry.Instrumentation.EntityFrameworkCore
83 |
--------------------------------------------------------------------------------
/docs/installation.md:
--------------------------------------------------------------------------------
1 | # Installing the Grafana OpenTelemetry distribution for .NET
2 |
3 | * [Supported .NET Versions](#supported-net-versions)
4 | * [Install the full package with all available instrumentations](#install-the-full-package-with-all-available-instrumentations)
5 | * [Install the base package](#install-the-base-package)
6 | * [Minimizing unneeded dependencies](#minimizing-unneeded-dependencies)
7 |
8 | ## Supported .NET Versions
9 |
10 | The packages shipped from this repository generally support all the officially
11 | supported versions of [.NET](https://dotnet.microsoft.com/download/dotnet) and
12 | [.NET Framework](https://dotnet.microsoft.com/download/dotnet-framework) (an
13 | older Windows-based .NET implementation), except `.NET Framework 3.5`.
14 |
15 | Some instrumentations and instrumentation libraries referenced by the
16 | distribution don't support both .NET and .NET Framework, but only one of them.
17 | For details, refer to the list of [supported instrumentations](./supported-instrumentations.md).
18 |
19 | ## Install the full package with all available instrumentations
20 |
21 | For installing the distribution with the full set of dependencies, add a
22 | reference to the [`Grafana.OpenTelemetry`](https://www.nuget.org/packages/Grafana.OpenTelemetry)
23 | package to your project.
24 |
25 | ```sh
26 | dotnet add package --prerelease Grafana.OpenTelemetry
27 | ```
28 |
29 | The list of [supported instrumentations](./supported-instrumentations.md)
30 | specifies what instrumentations are included in the full package.
31 |
32 | ## Install the base package
33 |
34 | For installing the distribution with a minimal set of dependencies, add a
35 | reference to the [`Grafana.OpenTelemetry.Base`](https://www.nuget.org/packages/Grafana.OpenTelemetry.Base)
36 | package to your project.
37 |
38 | ```sh
39 | dotnet add package --prerelease Grafana.OpenTelemetry.Base
40 | ```
41 |
42 | The list of [supported instrumentations](./supported-instrumentations.md) and
43 | [supported resource detectors](./supported-resource-detectors.md)
44 | specify which are included in the base package and enabled by default.
45 |
46 | ## Minimizing unneeded dependencies
47 |
48 | Users might utilize some instrumentation libraries the [full package](#install-the-full-package-with-all-available-instrumentations)
49 | contains, while other contained libraries will not be needed. However, the
50 | [full package](#install-the-full-package-with-all-available-instrumentations)
51 | still pulls in those unneeded instrumentations libraries with their
52 | dependencies.
53 |
54 | To mitigate this situation, [base package](#install-the-base-package)
55 | with a built-in lazy-loading mechanism can be used. This mechanism will
56 | initialize known available instrumentation library or resource detectors
57 | assembly, regardless of whether it's added as dependency of the [full package](#install-the-full-package-with-all-available-instrumentations)
58 | or as part of the instrumented project.
59 |
60 | For example, if it is desired to use the `AspNetCore` instrumentation without
61 | pulling in any other dependencies from the [full package](#install-the-full-package-with-all-available-instrumentations),
62 | it suffices to install the `AspNetCore` instrumentation library along with the
63 | base package.
64 |
65 | ```sh
66 | dotnet add package --prerelease Grafana.OpenTelemetry.Base
67 | dotnet add package --prerelease OpenTelemetry.Instrumentation.AspNetCore
68 | ```
69 |
70 | Then, the `AspNetCore` instrumentation will be lazy-loaded during the
71 | invocation of the `UseGrafana` extension method, no further code changes are
72 | necessary.
73 |
74 | ```csharp
75 | using var tracerProvider = Sdk.CreateTracerProviderBuilder()
76 | .UseGrafana()
77 | .Build();
78 | ```
79 |
80 | This way, any other [instrumentation library](./supported-instrumentations.md)
81 | or [resource detector](./supported-resource-detectors.md) supported by the
82 | distribution can be added via lazy loading.
83 |
--------------------------------------------------------------------------------
/docs/migration.md:
--------------------------------------------------------------------------------
1 | # Migrating to OpenTelemetry .NET
2 |
3 | All functionality provided by the distribution can also be utilized by manually
4 | installing and configuring upstream OpenTelemetry .NET packages. Follow these
5 | steps if you want to migrate from this distribution to the upstream
6 | OpenTelemetry .NET project.
7 |
8 | - Set appropriate environment variables or `web.config`/`app.config` values as
9 | explained here: [Send data to the Grafana Cloud OTLP endpoint][publish-otlp]
10 | - Install and activate the OpenTelemetry SDK,
11 | as covered in the upstream [Getting Started][getting-started] guide
12 | - Setup the OTLP exporter for metrics, logs, and traces - see the
13 | [exporter README][exporter-readme] for details. The exporter will respect the
14 | previously set environment variables:
15 | - `OTEL_EXPORTER_OTLP_PROTOCOL`
16 | - `OTEL_EXPORTER_OTLP_ENDPOINT`
17 | - `OTEL_EXPORTER_OTLP_HEADERS`
18 | - Install and configure any desired instrumentation packages
19 | [listed here](./supported-instrumentations.md)
20 | - [Add the OpenTelemetry resource attributes][resource-attributes]
21 | via the `OTEL_RESOURCE_ATTRIBUTES` environment variable
22 | - `service.name`
23 | - `service.namespace`
24 | - `service.instance.id`
25 | - `service.version`
26 | - `deployment.environment`
27 |
28 | ```shell
29 | export OTEL_RESOURCE_ATTRIBUTES=service.instance.id=,deployment.environment=...
30 | ```
31 |
32 | [exporter-readme]: https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md
33 | [getting-started]: https://github.com/open-telemetry/opentelemetry-dotnet#getting-started
34 | [publish-otlp]: https://grafana.com/docs/grafana-cloud/send-data/otlp/send-data-otlp/#quickstart-architecture
35 | [resource-attributes]: https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/instrument/resource-attributes/
36 |
--------------------------------------------------------------------------------
/docs/supported-instrumentations.md:
--------------------------------------------------------------------------------
1 | # Supported instrumentations
2 |
3 | At the moment, the following instrumentations are included in the distribution
4 | packages with [full](./installation.md#install-the-full-package-with-all-available-instrumentations)
5 | and [minimal](./installation.md#install-the-base-package) dependencies:
6 |
7 | | Identifier | Full | Base | Library name |
8 | | --------------------- | ------------------ | ------------------ | ------------ |
9 | | `AspNet` | :heavy_check_mark: | | [OpenTelemetry.Instrumentation.AspNet](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.AspNet) |
10 | | `AspNetCore` | :heavy_check_mark: | | [OpenTelemetry.Instrumentation.AspNetCore](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.AspNetCore) |
11 | | `AWS` | :heavy_check_mark: | | [OpenTelemetry.Instrumentation.AWS](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.AWS) |
12 | | `AWSLambda` | :heavy_check_mark: | | [OpenTelemetry.Instrumentation.AWSLambda](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.AWSLambda) |
13 | | `AWSResource` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Resources.AWS](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Resources.AWS) |
14 | | `AzureResource` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Resources.Azure](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Resources.Azure) |
15 | | `Cassandra` | :heavy_check_mark: | | [OpenTelemetry.Instrumentation.Cassandra](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Cassandra) |
16 | | `ContainerResource` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Resources.Container](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Resources.Container) |
17 | | `ElasticsearchClient` | :heavy_check_mark: | | [OpenTelemetry.Instrumentation.ElasticsearchClient](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.ElasticsearchClient) |
18 | | `EntityFrameworkCore` | :heavy_check_mark: | | [OpenTelemetry.Instrumentation.EntityFrameworkCore](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.EntityFrameworkCore) |
19 | | `GrpcNetClient` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Instrumentation.GrpcNetClient](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.GrpcNetClient) |
20 | | `Hangfire` | :heavy_check_mark: | | [OpenTelemetry.Instrumentation.Hangfire](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Hangfire) |
21 | | `HttpClient` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Instrumentation.Http](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Http) |
22 | | `HostResource` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Resources.Host](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Resources.Host) |
23 | | `MySqlData` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Instrumentation.MySqlData](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.MySqlData) |
24 | | | | | [MySql.Data.OpenTelemetry](https://www.nuget.org/packages/MySql.Data.OpenTelemetry) |
25 | | `NetRuntime` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Instrumentation.Runtime](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Runtime) |
26 | | `Owin` | :heavy_check_mark: | | [OpenTelemetry.Instrumentation.Owin](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Owin) |
27 | | `Process` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Instrumentation.Process](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Process) |
28 | | `ProcessResource` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Resources.Process](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Resources.Process) |
29 | | `ProcessRuntimeResource`| :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Resources.ProcessRuntime](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Resources.ProcessRuntime) |
30 | | `Quartz` | :heavy_check_mark: | | [OpenTelemetry.Instrumentation.Quartz](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Quartz) |
31 | | `SqlClient` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Instrumentation.SqlClient](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.SqlClient) |
32 | | `StackExchangeRedis` | :heavy_check_mark: | | [OpenTelemetry.Instrumentation.StackExchangeRedis](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.StackExchangeRedis) |
33 | | `Wcf` | :heavy_check_mark: | | [OpenTelemetry.Instrumentation.Wcf](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Wcf) |
34 |
35 | * The `AWSLambda` instrumentation is included but needs to be explicitly
36 | activated, as activating it in non-AWS scenarios causes errors.
37 | * The `ContainerResource` instrumentation is included but needs to be explicitly
38 | activated, as it currently adds container resource attributes for processes
39 | running not in containers.
40 | * The `MySqlData` instrumentation does not include the MySql.Data.OpenTelemetry
41 | package. Install separately if needed.
42 |
--------------------------------------------------------------------------------
/docs/supported-resource-detectors.md:
--------------------------------------------------------------------------------
1 | # Supported resource detectors
2 |
3 | The following resource detectors are recognized:
4 |
5 | | Identifier | Enabled by default | Pre-installed | Library name |
6 | | --------------------- | ------------------ | ------------------ | ------------ |
7 | | `AWSEBS` | | | [OpenTelemetry.Resources.AWS](https://www.nuget.org/packages/OpenTelemetry.Resources.AWS) |
8 | | `AWSEC2` | | | [OpenTelemetry.Resources.AWS](https://www.nuget.org/packages/OpenTelemetry.Resources.AWS) |
9 | | `AWSECS` | | | [OpenTelemetry.Resources.AWS](https://www.nuget.org/packages/OpenTelemetry.Resources.AWS) |
10 | | `AWSEKS` | | | [OpenTelemetry.Resources.AWS](https://www.nuget.org/packages/OpenTelemetry.Resources.AWS) |
11 | | `AzureAppService` | | | [OpenTelemetry.Resources.Azure](https://www.nuget.org/packages/OpenTelemetry.Resources.Azure) |
12 | | `AzureVM` | | | [OpenTelemetry.Resources.Azure](https://www.nuget.org/packages/OpenTelemetry.Resources.Azure) |
13 | | `AzureContainerApps` | | | [OpenTelemetry.Resources.Azure](https://www.nuget.org/packages/OpenTelemetry.Resources.Azure) |
14 | | `Container` | | :heavy_check_mark: | [OpenTelemetry.Resources.Container](https://www.nuget.org/packages/OpenTelemetry.Resources.Container) |
15 | | `Host` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Resources.Host](https://www.nuget.org/packages/OpenTelemetry.Resources.Host) |
16 | | `OperatingSystem` | | | [OpenTelemetry.Resources.OperatingSystem](https://www.nuget.org/packages/OpenTelemetry.Resources.OperatingSystem) |
17 | | `Process` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Resources.Process](https://www.nuget.org/packages/OpenTelemetry.Resources.Process) |
18 | | `ProcessRuntime` | :heavy_check_mark: | :heavy_check_mark: | [OpenTelemetry.Resources.ProcessRuntime](https://www.nuget.org/packages/OpenTelemetry.Resources.ProcessRuntime) |
19 |
20 | * The `Container` resource detector is included but needs to be explicitly
21 | activated, as activating it in non-container environments can causes erroneous
22 | attributes. A future release may activate it by default.
23 |
--------------------------------------------------------------------------------
/examples/net8.0/aspnetcore/Controllers/HttpClientController.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using Microsoft.AspNetCore.Mvc;
7 |
8 | namespace aspnetcore.Controllers;
9 |
10 | [Route("api/[controller]/[action]")]
11 | [ApiController]
12 | public class HttpClientController(HttpClient client) : ControllerBase
13 | {
14 | [HttpGet]
15 | public async Task>> Get()
16 | {
17 | var content = await client.GetStringAsync("https://postman-echo.com/get?hello=world");
18 | return Ok(content);
19 | }
20 |
21 | [HttpGet]
22 | public async Task>> GetError()
23 | {
24 | var response = await client.GetAsync("http://postman-echo.com/status/500");
25 | var content = await response.Content.ReadAsStringAsync();
26 | return Ok(content);
27 | }
28 |
29 | [HttpPost]
30 | public async Task> Post()
31 | {
32 | using var body = new StringContent("Hello World");
33 | using var response = await client.PostAsync("https://postman-echo.com/post", body);
34 |
35 | var content = await response.Content.ReadAsStringAsync();
36 |
37 | return Ok(content);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/examples/net8.0/aspnetcore/Controllers/MsSqlController.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System.Data;
7 | using Microsoft.AspNetCore.Mvc;
8 | using Microsoft.Data.SqlClient;
9 |
10 | namespace aspnetcore.Controllers;
11 |
12 | [Route("api/[controller]/[action]")]
13 | [ApiController]
14 | public class MsSqlController(SqlConnection db) : ControllerBase
15 | {
16 | [HttpGet]
17 | public async Task>> Tables()
18 | {
19 | await db.OpenAsync();
20 |
21 | await using var command = db.CreateCommand();
22 |
23 | command.CommandText = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES";
24 |
25 | var tables = new List();
26 |
27 | await using (var reader = await command.ExecuteReaderAsync())
28 | {
29 | while (await reader.ReadAsync())
30 | {
31 | tables.Add(reader.GetString(0));
32 | }
33 | }
34 |
35 | return Ok(tables);
36 | }
37 |
38 | [HttpGet]
39 | public async Task>> ServerInfo()
40 | {
41 | await db.OpenAsync();
42 |
43 | await using var command = db.CreateCommand();
44 |
45 | command.CommandText = "sp_server_info";
46 | command.CommandType = CommandType.StoredProcedure;
47 |
48 | var serverInfo = new List();
49 |
50 | await using (var reader = await command.ExecuteReaderAsync())
51 | {
52 | while (await reader.ReadAsync())
53 | {
54 | serverInfo.Add($"ID={reader.GetInt32(0)} , NAME={reader.GetString(1)} , VALUE={reader.GetString(2)}");
55 | }
56 | }
57 |
58 | return Ok(serverInfo);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/examples/net8.0/aspnetcore/Controllers/RedisController.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System.ComponentModel.DataAnnotations;
7 | using Microsoft.AspNetCore.Mvc;
8 | using StackExchange.Redis;
9 |
10 | namespace aspnetcore.Controllers;
11 |
12 | [Route("api/[controller]/[action]")]
13 | [ApiController]
14 | public class RedisController(IDatabase database, ILogger logger) : ControllerBase
15 | {
16 | const string LIST_KEY = "list";
17 |
18 | [HttpGet]
19 | public async Task> LeftPush()
20 | {
21 | if (!ModelState.IsValid)
22 | {
23 | return StatusCode(500);
24 | }
25 |
26 | var data = new LeftPushBody { Name = "test" };
27 | var length = await database.ListLeftPushAsync(LIST_KEY, data.Name);
28 |
29 | logger.LogInformation("LeftPush: {Name} - {Length}", data.Name, length);
30 |
31 | return Ok();
32 | }
33 |
34 | [HttpGet]
35 | public async Task> LeftPop()
36 | {
37 | var value = await database.ListLeftPopAsync(LIST_KEY);
38 |
39 | logger.LogInformation("LeftPop: {Value}", value);
40 |
41 | return Ok(value);
42 | }
43 |
44 | public class LeftPushBody
45 | {
46 | [Required]
47 | public string? Name { get; set; }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/examples/net8.0/aspnetcore/Controllers/WeatherForecastController.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using Microsoft.AspNetCore.Mvc;
7 |
8 | namespace aspnetcore.Controllers;
9 |
10 | [ApiController]
11 | [Route("[controller]")]
12 | public class WeatherForecastController : ControllerBase
13 | {
14 | private static readonly string[] Summaries =
15 | [
16 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
17 | ];
18 |
19 | [HttpGet(Name = "GetWeatherForecast")]
20 | public IEnumerable Get()
21 | {
22 | return [.. Enumerable.Range(1, 5).Select(index => new WeatherForecast
23 | {
24 | Date = DateTime.Now.AddDays(index),
25 | TemperatureC = Random.Shared.Next(-20, 55),
26 | Summary = Summaries[Random.Shared.Next(Summaries.Length)]
27 | })];
28 | }
29 |
30 | public class WeatherForecast
31 | {
32 | public DateTime Date { get; set; }
33 | public int TemperatureC { get; set; }
34 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
35 | public string? Summary { get; set; }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/examples/net8.0/aspnetcore/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
2 | ARG TARGETARCH
3 | ARG CONFIGURATION="Release"
4 | ARG DOTNET_PUBLISH_ARGS=""
5 |
6 | COPY . /source
7 | WORKDIR /source
8 |
9 | SHELL ["/bin/bash", "-o", "pipefail", "-c"]
10 |
11 | RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
12 | dotnet publish "examples/net8.0/aspnetcore/aspnetcore.csproj" --arch "${TARGETARCH}" --configuration "${CONFIGURATION}" --output /app ${DOTNET_PUBLISH_ARGS}
13 |
14 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS final
15 | WORKDIR /app
16 | EXPOSE 8080
17 |
18 | COPY --from=build /app .
19 | ENTRYPOINT ["dotnet", "aspnetcore.dll"]
20 |
--------------------------------------------------------------------------------
/examples/net8.0/aspnetcore/Program.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using aspnetcore;
7 | using Grafana.OpenTelemetry;
8 | using Microsoft.Data.SqlClient;
9 | using OpenTelemetry.Logs;
10 | using OpenTelemetry.Trace;
11 | using StackExchange.Redis;
12 |
13 | var builder = WebApplication.CreateBuilder(args);
14 |
15 | builder.Logging.AddOpenTelemetry(builder => builder.UseGrafana());
16 |
17 | builder.Services.AddOpenTelemetry()
18 | .WithMetrics(builder => builder.UseGrafana())
19 | .WithTracing(builder => builder.UseGrafana().AddConsoleExporter());
20 |
21 | // Redis
22 | builder.Services.AddSingleton(sp => ConnectionMultiplexer.Connect("redis:6379"));
23 | builder.Services.AddScoped(sp => sp.GetRequiredService().GetDatabase());
24 |
25 | // Microsoft SQL Server
26 | builder.Services.AddTransient(sp =>
27 | {
28 | var connectionString = "Server=mssql,1433;Database=master;User=sa;Password=Password12345%%;Encrypt=False;TrustServerCertificate=True";
29 | return new SqlConnection(connectionString);
30 | });
31 |
32 | builder.Services.AddHttpClient();
33 |
34 | builder.Services.AddControllers();
35 | builder.Services.AddTodoApp();
36 |
37 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
38 | builder.Services.AddEndpointsApiExplorer();
39 | builder.Services.AddSwaggerGen();
40 |
41 | var app = builder.Build();
42 |
43 | app.UseSwagger();
44 | app.UseSwaggerUI();
45 |
46 | app.UseAuthorization();
47 | app.MapControllers();
48 | app.MapTodoApp();
49 |
50 | app.MapGet("/", () => Results.Redirect("/swagger"));
51 |
52 | app.Run();
53 |
--------------------------------------------------------------------------------
/examples/net8.0/aspnetcore/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "aspnetcore": {
4 | "commandName": "Project",
5 | "launchBrowser": true,
6 | "launchUrl": "swagger",
7 | "environmentVariables": {
8 | "ASPNETCORE_ENVIRONMENT": "Development"
9 | },
10 | "dotnetRunMessages": true,
11 | "applicationUrl": "http://localhost:5125"
12 | },
13 | "IIS Express": {
14 | "commandName": "IISExpress",
15 | "launchBrowser": true,
16 | "launchUrl": "swagger",
17 | "environmentVariables": {
18 | "ASPNETCORE_ENVIRONMENT": "Development"
19 | }
20 | },
21 | "Docker": {
22 | "commandName": "Docker",
23 | "launchBrowser": true,
24 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
25 | "environmentVariables": {
26 | "ASPNETCORE_URLS": "http://+:80"
27 | },
28 | "publishAllPorts": true
29 | }
30 | },
31 | "$schema": "https://json.schemastore.org/launchsettings.json",
32 | "iisSettings": {
33 | "windowsAuthentication": false,
34 | "anonymousAuthentication": true,
35 | "iisExpress": {
36 | "applicationUrl": "http://localhost:11318",
37 | "sslPort": 0
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/examples/net8.0/aspnetcore/TodoAppEndpoints.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using Microsoft.EntityFrameworkCore;
7 |
8 | namespace aspnetcore;
9 |
10 | public static class TodoAppEndpoints
11 | {
12 | public static IServiceCollection AddTodoApp(this IServiceCollection services)
13 | {
14 | services.AddSingleton(TimeProvider.System);
15 | services.AddScoped();
16 |
17 | services.AddDbContext((serviceProvider, options) =>
18 | {
19 | var configuration = serviceProvider.GetRequiredService();
20 | var dataDirectory = configuration["DataDirectory"];
21 |
22 | if (string.IsNullOrEmpty(dataDirectory) || !Path.IsPathRooted(dataDirectory))
23 | {
24 | var environment = serviceProvider.GetRequiredService();
25 | dataDirectory = Path.Combine(environment.ContentRootPath, "App_Data");
26 | }
27 |
28 | if (!Directory.Exists(dataDirectory))
29 | {
30 | Directory.CreateDirectory(dataDirectory);
31 | }
32 |
33 | var databaseFile = Path.Combine(dataDirectory, "TodoApp.db");
34 |
35 | options.UseSqlite("Data Source=" + databaseFile);
36 | });
37 |
38 | return services;
39 | }
40 |
41 | public static IEndpointRouteBuilder MapTodoApp(this IEndpointRouteBuilder builder)
42 | {
43 | var todos = builder.MapGroup("/api/todo/items").WithTags("Todo");
44 | {
45 | todos.MapPost("/", async (CreateTodoItemModel model, TodoRepository repository) =>
46 | {
47 | var id = await repository.AddItemAsync(model.Text);
48 | return Results.Created($"/api/items/{id}", new { Id = id });
49 | });
50 |
51 | todos.MapGet("/", async (TodoRepository repository) => await repository.GetItemsAsync());
52 |
53 | todos.MapGet("/{id}", async (Guid id, TodoRepository repository) => await repository.GetItemAsync(id));
54 |
55 | todos.MapPost("/{id}/complete", async (Guid id, TodoRepository repository) =>
56 | {
57 | return await repository.CompleteItemAsync(id) switch
58 | {
59 | true => Results.NoContent(),
60 | false => Results.Problem(statusCode: StatusCodes.Status400BadRequest),
61 | _ => Results.Problem(statusCode: StatusCodes.Status404NotFound),
62 | };
63 | });
64 |
65 | todos.MapDelete("/{id}", async (Guid id, TodoRepository repository) =>
66 | {
67 | var deleted = await repository.DeleteItemAsync(id);
68 | return deleted switch
69 | {
70 | true => Results.NoContent(),
71 | false => Results.Problem(statusCode: StatusCodes.Status404NotFound),
72 | };
73 | });
74 | }
75 |
76 | return builder;
77 | }
78 |
79 | public class TodoContext(DbContextOptions options) : DbContext(options)
80 | {
81 | public DbSet Items { get; set; } = default!;
82 | }
83 |
84 | public class TodoRepository(TimeProvider timeProvider, TodoContext context)
85 | {
86 | public async Task AddItemAsync(string text)
87 | {
88 | await this.EnsureDatabaseAsync();
89 |
90 | var item = new TodoItem
91 | {
92 | CreatedAt = this.UtcNow(),
93 | Text = text
94 | };
95 |
96 | context.Add(item);
97 |
98 | await context.SaveChangesAsync();
99 |
100 | return item;
101 | }
102 |
103 | public async Task CompleteItemAsync(Guid itemId)
104 | {
105 | var item = await this.GetItemAsync(itemId);
106 |
107 | if (item is null)
108 | {
109 | return null;
110 | }
111 |
112 | if (item.CompletedAt.HasValue)
113 | {
114 | return false;
115 | }
116 |
117 | item.CompletedAt = this.UtcNow();
118 |
119 | context.Items.Update(item);
120 |
121 | await context.SaveChangesAsync();
122 |
123 | return true;
124 | }
125 |
126 | public async Task DeleteItemAsync(Guid itemId)
127 | {
128 | var item = await this.GetItemAsync(itemId);
129 |
130 | if (item is null)
131 | {
132 | return false;
133 | }
134 |
135 | context.Items.Remove(item);
136 |
137 | await context.SaveChangesAsync();
138 |
139 | return true;
140 | }
141 |
142 | public async Task GetItemAsync(Guid itemId)
143 | {
144 | await this.EnsureDatabaseAsync();
145 |
146 | return await context.Items.FindAsync([itemId]);
147 | }
148 |
149 | public async Task> GetItemsAsync()
150 | {
151 | await this.EnsureDatabaseAsync();
152 |
153 | return await context.Items
154 | .OrderBy(x => x.CompletedAt.HasValue)
155 | .ThenBy(x => x.CreatedAt)
156 | .ToListAsync();
157 | }
158 |
159 | private async Task EnsureDatabaseAsync() => await context.Database.EnsureCreatedAsync();
160 |
161 | private DateTime UtcNow() => timeProvider.GetUtcNow().UtcDateTime;
162 | }
163 |
164 | public class CreateTodoItemModel
165 | {
166 | public string Text { get; set; } = string.Empty;
167 | }
168 |
169 | public class TodoItem
170 | {
171 | public Guid Id { get; set; }
172 |
173 | public string Text { get; set; } = default!;
174 |
175 | public DateTime CreatedAt { get; set; }
176 |
177 | public DateTime? CompletedAt { get; set; }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/examples/net8.0/aspnetcore/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning",
6 | "System": "Warning"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/examples/net8.0/aspnetcore/aspnetcore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 | Linux
8 | ..\..\..
9 | ..\..\..\docker-compose-aspnetcore.dcproj
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "rollForward": "latestFeature",
4 | "version": "8.0.410",
5 | "allowPrerelease": false
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/internal/RELEASING.md:
--------------------------------------------------------------------------------
1 | # Release Process
2 |
3 | This project relies on manual steps to publish the libraries in this repo as
4 | NuGet packages. Package versioning is determined by git tags, and implemented
5 | using [the MinVer package](https://github.com/adamralph/minver). This package
6 | is also used by the OpenTelemetry .NET SDK.
7 |
8 | MinVer finds the latest tag in the repo commit history and uses the tag as
9 | the version when building the libaries and packages.
10 |
11 | NuGet treats any package version containing `-alpha`, `-beta`, or `-rc` as a
12 | *pre-release* package.
13 |
14 | To publish to the Grafana Labs NuGet organization, you must be added as a
15 | member by an existing organization administrator.
16 |
17 | ## Publication Steps
18 |
19 | 1. Determine the version to be released, set a tag on `main` via git:
20 | * `git checkout main`
21 | * `git tag VERSION` where `VERSION` is an appropriate SemVer version
22 | 2. Build both packages:
23 | * `dotnet build ./src/Grafana.OpenTelemetry.Base --configuration Release
24 | -p:Deterministic=true`
25 | * `dotnet build ./src/Grafana.OpenTelemetry --configuration Release
26 | -p:Deterministic=true`
27 | 3. [Open the NuGet package upload page](
28 | https://www.nuget.org/packages/manage/upload)
29 | 4. Upload the two packages, checking that fields are populated as expected.
30 | The packages will be located at:
31 | * `./src/Grafana.OpenTelemetry.Base/bin/Release/
32 | Grafana.OpenTelemetry.Base.VERSION.nupkg`
33 | * `./src/Grafana.OpenTelemetry/bin/Release/
34 | Grafana.OpenTelemetry.VERSION.nupkg`
35 |
--------------------------------------------------------------------------------
/internal/img/Grafana_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grafana/grafana-opentelemetry-dotnet/37b41e726f28fdddd8fb4feb403964cc609dc291/internal/img/Grafana_icon.png
--------------------------------------------------------------------------------
/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Docker Compose": {
4 | "commandName": "DockerCompose",
5 | "commandVersion": "1.0",
6 | "serviceActions": {
7 | "aspnetcore": "StartDebugging",
8 | "aspnet": "StartDebugging"
9 | }
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/package-readme.md:
--------------------------------------------------------------------------------
1 | # Grafana OpenTelemetry distribution for .NET
2 |
3 |
4 | [![NuGet][package-badge-version]][package-download]
5 | [![SDK][otel-badge]][otel]
6 | [![Slack][slack-badge]][slack-channel]
7 |
8 |
9 | ## About
10 |
11 | This is a pre-configured and pre-packaged bundle of [OpenTelemetry .NET components][otel-contrib],
12 | optimized for [Grafana Cloud Application Observability][app-o11y].
13 |
14 | It requires only minimal setup and configuration and makes it very easy to emit
15 | OpenTelemetry metrics, logs, and traces from your .NET application.
16 |
17 | ## Getting Started
18 |
19 | ### Step 1: Install package
20 |
21 | For installing the distribution with the full set of dependencies, add a
22 | reference to the [`Grafana.OpenTelemetry`][package] package to your project.
23 |
24 | ```sh
25 | dotnet add package Grafana.OpenTelemetry
26 | ```
27 |
28 | ### Step 2: Enable the Grafana distribution at application startup
29 |
30 | The `UseGrafana` extension method on the `TracerProviderBuilder` or the
31 | `MetricProviderBuilder` can be used to set up the Grafana distribution. By
32 | default, telemetry data will be sent to Grafana Alloy or an OpenTelemetry collector
33 | that runs locally and listens to default OTLP ports.
34 |
35 | ```csharp
36 | using var tracerProvider = Sdk.CreateTracerProviderBuilder()
37 | .UseGrafana()
38 | .Build();
39 | ```
40 |
41 | Alternatively, you can send telemetry data directly to Grafana Cloud without
42 | involving an agent or collector. This can be configured via the environment
43 | variables `OTEL_EXPORTER_OTLP_PROTOCOL`, `OTEL_EXPORTER_OTLP_ENDPOINT`, and
44 | `OTEL_EXPORTER_OTLP_HEADERS`.
45 |
46 | For details on how to obtain those values, refer to
47 | [Send data to the Grafana Cloud OTLP endpoint: Quickstart architecture][push-oltp].
48 |
49 | ## Documentation
50 |
51 | For detailed documentation and setup instructions, refer to [our documentation][docs].
52 |
53 | [app-o11y]: https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/
54 | [docs]: https://github.com/grafana/grafana-opentelemetry-dotnet/tree/main/docs
55 | [otel]: https://github.com/open-telemetry/opentelemetry-dotnet
56 | [otel-badge]: https://img.shields.io/badge/OTel--SDK-1.9.0-blue?style=flat&logo=opentelemetry
57 | [otel-contrib]: http://github.com/open-telemetry/opentelemetry-dotnet-contrib
58 | [package]: https://www.nuget.org/packages/Grafana.OpenTelemetry
59 | [package-badge-version]: https://img.shields.io/nuget/v/Grafana.OpenTelemetry?logo=nuget&label=NuGet&color=blue
60 | [package-download]: https://www.nuget.org/profiles/Grafana
61 | [push-oltp]: https://grafana.com/docs/grafana-cloud/send-data/otlp/send-data-otlp/#quickstart-architecture
62 | [slack-badge]: https://img.shields.io/badge/%20Slack-%23app--o11y-brightgreen.svg?logo=slack
63 | [slack-channel]: https://grafana.slack.com/archives/C05E87XRK3J
64 |
--------------------------------------------------------------------------------
/scripts/run-oats-tests.ps1:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env pwsh
2 |
3 | $ErrorActionPreference = "Stop"
4 | $InformationPreference = "Continue"
5 | $ProgressPreference = "SilentlyContinue"
6 |
7 | # renovate: datasource=github-releases depName=oats packageName=grafana/oats
8 | ${env:OATS_VERSION}="v0.3.2"
9 |
10 | go install "github.com/grafana/oats@${env:OATS_VERSION}"
11 | & "${env:GOPATH}/bin/oats" --timeout=5m ./docker/docker-compose-aspnetcore
12 |
--------------------------------------------------------------------------------
/scripts/run-oats-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -euo pipefail
4 |
5 | # renovate: datasource=github-releases depName=oats packageName=grafana/oats
6 | export OATS_VERSION=v0.3.2
7 |
8 | go install "github.com/grafana/oats@${OATS_VERSION}"
9 | ${GOPATH}/bin/oats --timeout=5m ./docker/docker-compose-aspnetcore
10 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ExporterSettings/AgentOtlpExporter.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using OpenTelemetry.Exporter;
8 | using OpenTelemetry.Logs;
9 | using OpenTelemetry.Metrics;
10 | using OpenTelemetry.Trace;
11 |
12 | namespace Grafana.OpenTelemetry
13 | {
14 | ///
15 | /// Settings for exporting telemetry to a Grafana Alloy or collector.
16 | ///
17 | public class AgentOtlpExporter : ExporterSettings
18 | {
19 | ///
20 | /// Gets or sets the address of the Grafana Alloy or collector. If not set, the OpenTelemetry
21 | /// default is used (`http://localhost:4817` for http/protobuf, and `http://localhost:4818`
22 | /// for grpc).
23 | ///
24 | public Uri Endpoint { get; set; }
25 |
26 | ///
27 | /// The OTLP protocol to be used for exporting telemetry data.
28 | ///
29 | public OtlpExportProtocol Protocol { get; set; }
30 |
31 | ///
32 | override internal void Apply(TracerProviderBuilder builder)
33 | {
34 | if (EnableTraces == false)
35 | {
36 | return;
37 | }
38 |
39 | builder.AddOtlpExporter(config => ApplyToConfig(config));
40 | }
41 |
42 | ///
43 | override internal void Apply(MeterProviderBuilder builder)
44 | {
45 | if (EnableMetrics == false)
46 | {
47 | return;
48 | }
49 |
50 | builder.AddOtlpExporter(config => ApplyToConfig(config));
51 | }
52 |
53 | ///
54 | override internal void Apply(OpenTelemetryLoggerOptions options)
55 | {
56 | if (EnableLogs == false)
57 | {
58 | return;
59 | }
60 |
61 | options.AddOtlpExporter(config => ApplyToConfig(config));
62 | }
63 |
64 | private void ApplyToConfig(OtlpExporterOptions options)
65 | {
66 | if (Endpoint != null)
67 | {
68 | options.Endpoint = Endpoint;
69 | }
70 |
71 | if (Protocol != default)
72 | {
73 | options.Protocol = (OtlpExportProtocol)Protocol;
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ExporterSettings/CloudOtlpExporter.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using Microsoft.Extensions.Configuration;
8 | using OpenTelemetry.Exporter;
9 | using OpenTelemetry.Logs;
10 | using OpenTelemetry.Metrics;
11 | using OpenTelemetry.Trace;
12 |
13 | namespace Grafana.OpenTelemetry
14 | {
15 | ///
16 | /// Settings for exporting telemetry directly to Grafana Alloy via OTLP.
17 | ///
18 | [Obsolete("This class is obsolete. Use OtlpExporter instead.")]
19 | public class CloudOtlpExporter : ExporterSettings
20 | {
21 | internal const string ZoneEnvVarName = "GRAFANA_CLOUD_ZONE";
22 | internal const string InstanceIdEnvVarName = "GRAFANA_CLOUD_INSTANCE_ID";
23 | internal const string ApiKeyEnvVarName = "GRAFANA_CLOUD_API_KEY";
24 |
25 | ///
26 | /// Gets or sets the zone of the Grafana Cloud stack.
27 | ///
28 | public string Zone { get; }
29 |
30 | ///
31 | /// Gets or sets the instance id of the Grafana Cloud stack.
32 | ///
33 | public string InstanceId { get; }
34 |
35 | ///
36 | /// Gets or sets the API key for sending data to the Grafana Cloud stack.
37 | ///
38 | public string ApiKey { get; }
39 |
40 | ///
41 | /// Initializes a new instance of .
42 | ///
43 | /// Parameters are set from environment variables.
44 | ///
45 | public CloudOtlpExporter()
46 | : this(new ConfigurationBuilder().AddEnvironmentVariables().Build())
47 | { }
48 |
49 | ///
50 | /// Initializes a new instance of with given
51 | /// parameters.
52 | ///
53 | /// The zone of the Grafana cloud stack
54 | /// The instance id of the Grafana cloud stack
55 | /// The API token for sending data to the Grafana cloud stack
56 | ///
57 | public CloudOtlpExporter(string zone, string instanceId, string apiKey)
58 | {
59 | this.Zone = zone ?? throw new ArgumentNullException(nameof(zone));
60 | this.InstanceId = instanceId ?? throw new ArgumentNullException(nameof(instanceId));
61 | this.ApiKey = apiKey ?? throw new ArgumentNullException(nameof(apiKey));
62 | }
63 |
64 | internal CloudOtlpExporter(IConfiguration configuration)
65 | : this(configuration[ZoneEnvVarName], configuration[InstanceIdEnvVarName], configuration[ApiKeyEnvVarName])
66 | { }
67 |
68 | ///
69 | override internal void Apply(TracerProviderBuilder builder)
70 | {
71 | if (EnableTraces == false)
72 | {
73 | return;
74 | }
75 |
76 | builder.AddOtlpExporter(config =>
77 | {
78 | var configurationHelper = new GrafanaCloudConfigurationHelper(Zone, InstanceId, ApiKey);
79 |
80 | config.Endpoint = configurationHelper.OtlpEndpointTraces;
81 | config.Headers = configurationHelper.OtlpAuthorizationHeader;
82 | config.Protocol = OtlpExportProtocol.HttpProtobuf;
83 | });
84 | }
85 |
86 | ///
87 | override internal void Apply(MeterProviderBuilder builder)
88 | {
89 | if (EnableMetrics == false)
90 | {
91 | return;
92 | }
93 |
94 | builder.AddOtlpExporter(config =>
95 | {
96 | var configurationHelper = new GrafanaCloudConfigurationHelper(Zone, InstanceId, ApiKey);
97 |
98 | config.Endpoint = configurationHelper.OtlpEndpointMetrics;
99 | config.Headers = configurationHelper.OtlpAuthorizationHeader;
100 | config.Protocol = OtlpExportProtocol.HttpProtobuf;
101 | });
102 | }
103 |
104 | ///
105 | override internal void Apply(OpenTelemetryLoggerOptions options)
106 | {
107 | if (EnableLogs == false)
108 | {
109 | return;
110 | }
111 |
112 | options.AddOtlpExporter(config =>
113 | {
114 | var configurationHelper = new GrafanaCloudConfigurationHelper(Zone, InstanceId, ApiKey);
115 |
116 | config.Endpoint = configurationHelper.OtlpEndpointLogs;
117 | config.Headers = configurationHelper.OtlpAuthorizationHeader;
118 | config.Protocol = OtlpExportProtocol.HttpProtobuf;
119 | });
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ExporterSettings/ExporterSettings.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Logs;
7 | using OpenTelemetry.Metrics;
8 | using OpenTelemetry.Trace;
9 |
10 | namespace Grafana.OpenTelemetry
11 | {
12 | ///
13 | /// All OpenTelemetry exporter settings supported by Grafana need to derive from this class.
14 | ///
15 | public abstract class ExporterSettings
16 | {
17 | ///
18 | /// Gets or sets whether traces should be sent to Grafana.
19 | ///
20 | public bool EnableTraces { get; set; } = true;
21 |
22 | ///
23 | /// Gets or sets whether metrics should be sent to Grafana.
24 | ///
25 | public bool EnableMetrics { get; set; } = true;
26 |
27 | ///
28 | /// Gets or sets whether logs should be sent to Grafana.
29 | ///
30 | public bool EnableLogs { get; set; } = true;
31 |
32 | ///
33 | /// Applies the exporter settings by initializing an exporter on the
34 | /// given .
35 | ///
36 | /// A
37 | internal abstract void Apply(TracerProviderBuilder builder);
38 |
39 | ///
40 | /// Applies the exporter settings by initializing an exporter on the
41 | /// given .
42 | ///
43 | /// A
44 | internal abstract void Apply(MeterProviderBuilder builder);
45 |
46 | ///
47 | /// Applies the exporter settings by initializing an exporter on the
48 | /// given .
49 | ///
50 | /// A instance.
51 | internal abstract void Apply(OpenTelemetryLoggerOptions options);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ExporterSettings/GrafanaCloudConfigurationHelper.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | ///
11 | /// Helper class for Grafana Cloud configuration.
12 | ///
13 | internal class GrafanaCloudConfigurationHelper
14 | {
15 | private const string PathExtensionTraces = "/v1/traces";
16 | private const string PathExtensionMetrics = "/v1/metrics";
17 | private const string PathExtensionLogs = "/v1/logs";
18 |
19 | private string _zone;
20 | private string _instanceId;
21 | private string _apiKey;
22 |
23 | public GrafanaCloudConfigurationHelper(string zone, string instanceId, string apiKey)
24 | {
25 | _zone = zone;
26 | _instanceId = instanceId;
27 | _apiKey = apiKey;
28 | }
29 |
30 | public Uri OtlpEndpointTraces
31 | {
32 | get => new Uri($"{GetOtlpEndpointBase()}{PathExtensionTraces}");
33 | }
34 |
35 | public Uri OtlpEndpointMetrics
36 | {
37 | get => new Uri($"{GetOtlpEndpointBase()}{PathExtensionMetrics}");
38 | }
39 |
40 | public Uri OtlpEndpointLogs
41 | {
42 | get => new Uri($"{GetOtlpEndpointBase()}{PathExtensionLogs}");
43 | }
44 |
45 | public string OtlpAuthorizationHeader
46 | {
47 | get
48 | {
49 | var authorizationValue = Convert.ToBase64String(
50 | System.Text.Encoding.UTF8.GetBytes($"{_instanceId}:{_apiKey}")
51 | );
52 |
53 | return $"Authorization=Basic {authorizationValue}";
54 | }
55 | }
56 |
57 | private string GetOtlpEndpointBase() => $"https://otlp-gateway-{_zone}.grafana.net/otlp";
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ExporterSettings/OtlpExporter.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using OpenTelemetry.Exporter;
8 | using OpenTelemetry.Logs;
9 | using OpenTelemetry.Metrics;
10 | using OpenTelemetry.Trace;
11 |
12 | namespace Grafana.OpenTelemetry
13 | {
14 | ///
15 | /// Settings for exporting telemetry via plain OTLP exporter settings.
16 | ///
17 | public class OtlpExporter : ExporterSettings
18 | {
19 | ///
20 | /// Gets or sets the target to which the exporter is going to send telemetry.
21 | /// Must be a valid Uri with scheme (http or https) and host, and
22 | /// may contain a port and path.
23 | ///
24 | public Uri Endpoint { get; set; }
25 |
26 | ///
27 | /// Gets or sets optional headers for the connection. Refer to the specification for information on the expected format for Headers.
28 | ///
29 | public string Headers { get; set; }
30 |
31 | ///
32 | /// Gets or sets the the OTLP transport protocol. Supported values: Grpc and HttpProtobuf
33 | ///
34 | public OtlpExportProtocol Protocol { get; set; }
35 |
36 | ///
37 | override internal void Apply(TracerProviderBuilder builder)
38 | {
39 | if (EnableTraces == false)
40 | {
41 | return;
42 | }
43 |
44 | builder.AddOtlpExporter(config =>
45 | {
46 | config.Endpoint = new Uri($"{Endpoint}/v1/traces");
47 | config.Headers = Headers;
48 | config.Protocol = Protocol;
49 | });
50 | }
51 |
52 | ///
53 | override internal void Apply(MeterProviderBuilder builder)
54 | {
55 | if (EnableMetrics == false)
56 | {
57 | return;
58 | }
59 |
60 | builder.AddOtlpExporter(config =>
61 | {
62 | config.Endpoint = new Uri($"{Endpoint}/v1/metrics");
63 | config.Headers = Headers;
64 | config.Protocol = Protocol;
65 | });
66 | }
67 |
68 | ///
69 | override internal void Apply(OpenTelemetryLoggerOptions options)
70 | {
71 | if (EnableLogs == false)
72 | {
73 | return;
74 | }
75 |
76 | options.AddOtlpExporter(config =>
77 | {
78 | config.Endpoint = new Uri($"{Endpoint}/v1/logs");
79 | config.Headers = Headers;
80 | config.Protocol = Protocol;
81 | });
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Grafana.OpenTelemetry.Base.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Minimal Grafana distribution of OpenTelemetry .NET
5 | true
6 | net8.0;netstandard2.0;net462
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | all
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | <_Parameter1>Grafana.OpenTelemetry.Tests
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/GrafanaOpenTelemetryEventSource.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using System.Diagnostics.Tracing;
8 | using System.Text.Json;
9 |
10 | namespace Grafana.OpenTelemetry
11 | {
12 | [EventSource(Name = "OpenTelemetry-Grafana-Distribution")]
13 | internal sealed class GrafanaOpenTelemetryEventSource : EventSource
14 | {
15 | public static GrafanaOpenTelemetryEventSource Log = new GrafanaOpenTelemetryEventSource();
16 |
17 | [NonEvent]
18 | public void EnabledMetricsInstrumentation(string instrumentationLibrary)
19 | {
20 | if (Log.IsEnabled(EventLevel.Informational, EventKeywords.All))
21 | {
22 | this.EnabledInstrumentation("metrics", instrumentationLibrary);
23 | }
24 | }
25 |
26 | [NonEvent]
27 | public void EnabledTracingInstrumentation(string instrumentationLibrary)
28 | {
29 | if (Log.IsEnabled(EventLevel.Informational, EventKeywords.All))
30 | {
31 | this.EnabledInstrumentation("tracing", instrumentationLibrary);
32 | }
33 | }
34 |
35 | [NonEvent]
36 | public void FailureEnablingMetricsInstrumentation(string instrumentationLibrary, Exception ex)
37 | {
38 | if (Log.IsEnabled(EventLevel.Warning, EventKeywords.All))
39 | {
40 | this.FailureEnablingInstrumentation("metrics", instrumentationLibrary, ex.ToString());
41 | }
42 | }
43 |
44 | [NonEvent]
45 | public void FailureEnablingTracingInstrumentation(string instrumentationLibrary, Exception ex)
46 | {
47 | if (Log.IsEnabled(EventLevel.Warning, EventKeywords.All))
48 | {
49 | this.FailureEnablingInstrumentation("tracing", instrumentationLibrary, ex.ToString());
50 | }
51 | }
52 |
53 | [NonEvent]
54 | public void InitializeDistribution(GrafanaOpenTelemetrySettings settings)
55 | {
56 | var settingsJson = JsonSerializer.Serialize(settings);
57 |
58 | InitializeDistribution(settingsJson);
59 | }
60 |
61 | [Event(1, Message = "Grafana distribution initializing with settings: {0}'", Level = EventLevel.Informational)]
62 | public void InitializeDistribution(string settings)
63 | {
64 | this.WriteEvent(1, settings);
65 | }
66 |
67 | [Event(2, Message = "Grafana distribution enabling {0} instrumentation '{1}'", Level = EventLevel.Informational)]
68 | public void EnabledInstrumentation(string signal, string instrumentationLibrary)
69 | {
70 | this.WriteEvent(2, signal, instrumentationLibrary);
71 | }
72 |
73 | [Event(3, Message = "Grafana distribution cannot enable {0} instrumentation '{1}'. Exception: {2}", Level = EventLevel.Warning)]
74 | public void FailureEnablingInstrumentation(string signal, string instrumentationLibrary, string ex)
75 | {
76 | this.WriteEvent(3, signal, instrumentationLibrary, ex);
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/GrafanaOpenTelemetryResourceDetector.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System.Collections.Generic;
7 | using System.Reflection;
8 | using OpenTelemetry.Resources;
9 |
10 | namespace Grafana.OpenTelemetry
11 | {
12 | internal class GrafanaOpenTelemetryResourceDetector : IResourceDetector
13 | {
14 | internal const string ResourceKey_DistroName = "telemetry.distro.name";
15 | internal const string ResourceKey_DistroVersion = "telemetry.distro.version";
16 | internal const string ResourceKey_DeploymentEnvironment = "deployment.environment";
17 | internal const string ResourceValue_DistroName = "grafana-opentelemetry-dotnet";
18 |
19 | private GrafanaOpenTelemetrySettings _settings;
20 |
21 | public GrafanaOpenTelemetryResourceDetector(GrafanaOpenTelemetrySettings settings)
22 | {
23 | _settings = settings;
24 | }
25 |
26 | public Resource Detect()
27 | {
28 | var attributes = new List>(new KeyValuePair[]
29 | {
30 | new KeyValuePair(ResourceKey_DistroName, ResourceValue_DistroName),
31 | new KeyValuePair(ResourceKey_DistroVersion, GetDistroVersion()),
32 | new KeyValuePair(ResourceKey_DeploymentEnvironment, _settings.DeploymentEnvironment)
33 | });
34 |
35 | attributes.AddRange(_settings.ResourceAttributes);
36 |
37 | return new Resource(attributes);
38 | }
39 |
40 | static internal string GetDistroVersion()
41 | {
42 | var informationalVersion = typeof(GrafanaOpenTelemetryResourceDetector)
43 | .Assembly
44 | .GetCustomAttribute()?
45 | .InformationalVersion;
46 |
47 | if (string.IsNullOrWhiteSpace(informationalVersion))
48 | {
49 | informationalVersion = "0.0.0";
50 | }
51 |
52 | // A Git hash is appended to the informational version after a "+" character. That's of limited use and
53 | // therefore removed here.
54 | return informationalVersion.Split('+')[0];
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/GrafanaOpenTelemetrySettings.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Reflection;
9 | using Microsoft.Extensions.Configuration;
10 |
11 | namespace Grafana.OpenTelemetry
12 | {
13 | ///
14 | /// Settings for configuring the OpenTelemetry .NET distribution for Grafana.
15 | ///
16 | public class GrafanaOpenTelemetrySettings
17 | {
18 | internal const string DisableInstrumentationsEnvVarName = "GRAFANA_DOTNET_DISABLE_INSTRUMENTATIONS";
19 | internal const string DisableResourceDetectorsEnvVarName = "GRAFANA_DOTNET_DISABLE_RESOURCE_DETECTORS";
20 | internal const string ResourceDetectorsEnvVarName = "GRAFANA_DOTNET_RESOURCE_DETECTORS";
21 | internal const string ServiceNameEnvVarName = "OTEL_SERVICE_NAME";
22 |
23 | ///
24 | /// Gets or sets the exporter settings for sending telemetry data to Grafana.
25 | ///
26 | /// By default, this is set to:
27 | /// 1. j initialized by environment variables, or if
28 | /// the environment variables aren't present, it is set to
29 | /// 2. a with the default OTLP endpoint.
30 | ///
31 | /// If set to `null`, no exporter will be initialized by the OpenTelemetry .NET
32 | /// distribution for Grafana.
33 | ///
34 | public ExporterSettings ExporterSettings { get; set; }
35 |
36 | ///
37 | /// Gets the list of instrumentations to be activated.
38 | ///
39 | /// By default, all available instrumentations are activated.
40 | ///
41 | public HashSet Instrumentations { get; } = new HashSet((Instrumentation[])Enum.GetValues(typeof(Instrumentation)));
42 |
43 | ///
44 | /// Gets the list of resource detectors to be activated.
45 | ///
46 | /// By default, all only resource detectors that do not impact application startup are activated.
47 | ///
48 | public HashSet ResourceDetectors { get; } = new HashSet(new ResourceDetector[]
49 | {
50 | // Activating the container resource detector by default always populates a `container.id` attribute,
51 | // even when running in a non-container Linux setting.
52 | // ResourceDetector.Container,
53 | ResourceDetector.Host,
54 | ResourceDetector.Process,
55 | ResourceDetector.ProcessRuntime,
56 | });
57 |
58 | ///
59 | /// Gets or sets the logical name of the service to be instrumented.
60 | ///
61 | /// This corresponds to the `service.name` resource attribute.
62 | ///
63 | public string ServiceName { get; set; } = Assembly.GetEntryAssembly()?.GetName().Name ?? System.Diagnostics.Process.GetCurrentProcess().ProcessName;
64 |
65 | ///
66 | /// Gets or sets the version of the service to be instrumented.
67 | ///
68 | /// This corresponds to the `service.version` resource attribute.
69 | ///
70 | public string ServiceVersion { get; set; } = Assembly.GetEntryAssembly()?.GetName().Version.ToString() ?? "unknown";
71 |
72 | ///
73 | /// Gets or sets the string id of the service instance.
74 | ///
75 | /// This corresponds to the `service.instance.id` resource attribute.
76 | ///
77 | public string ServiceInstanceId { get; set; }
78 |
79 | ///
80 | /// Gets or sets the name of the deployment environment ("staging" or "production").
81 | ///
82 | public string DeploymentEnvironment { get; set; } = "production";
83 |
84 | ///
85 | /// Gets a dictionary of custom resource attributes.
86 | ///
87 | public IDictionary ResourceAttributes { get; } = new Dictionary();
88 |
89 | ///
90 | /// Initializes an instance of .
91 | ///
92 | public GrafanaOpenTelemetrySettings()
93 | : this(new ConfigurationBuilder().AddEnvironmentVariables().Build())
94 | { }
95 |
96 | internal GrafanaOpenTelemetrySettings(IConfiguration configuration)
97 | {
98 | try
99 | {
100 | #pragma warning disable CS0618
101 | ExporterSettings = new CloudOtlpExporter();
102 | #pragma warning restore CS0618
103 | }
104 | catch (Exception)
105 | {
106 | ExporterSettings = new AgentOtlpExporter();
107 | }
108 |
109 |
110 | // Activating AWSLambda instrumentation by default causes the provider builder to bail in case certain
111 | // Lambda-specific environment variables are missing.
112 | //
113 | // De-activate it until the related issue is resolved: https://github.com/grafana/app-o11y/issues/378
114 | Instrumentations.Remove(Instrumentation.AWSLambda);
115 |
116 | var disableInstrumentations = configuration[DisableInstrumentationsEnvVarName];
117 |
118 | if (!string.IsNullOrEmpty(disableInstrumentations))
119 | {
120 | foreach (var instrumentationStr in disableInstrumentations.Split(new char[] { ',', ':' }))
121 | {
122 | if (Enum.TryParse(instrumentationStr, out var instrumentation))
123 | {
124 | Instrumentations.Remove(instrumentation);
125 | }
126 | }
127 | }
128 |
129 | var resourceDetectors = configuration[ResourceDetectorsEnvVarName];
130 |
131 | if (!string.IsNullOrEmpty(resourceDetectors))
132 | {
133 | ResourceDetectors.Clear();
134 |
135 | foreach (var resourceDetectorStr in resourceDetectors.Split(new char[] { ',', ':' }))
136 | {
137 | if (Enum.TryParse(resourceDetectorStr, out var resourceDetector))
138 | {
139 | ResourceDetectors.Add(resourceDetector);
140 | }
141 | }
142 | }
143 |
144 | var disableResourceDetectors = configuration[DisableResourceDetectorsEnvVarName];
145 |
146 | if (!string.IsNullOrEmpty(disableResourceDetectors))
147 | {
148 | foreach (var resourceDetectorStr in disableResourceDetectors.Split(new char[] { ',', ':' }))
149 | {
150 | if (Enum.TryParse(resourceDetectorStr, out var resourceDetector))
151 | {
152 | ResourceDetectors.Remove(resourceDetector);
153 | }
154 | }
155 | }
156 |
157 | var serviceName = configuration[ServiceNameEnvVarName];
158 |
159 | if (!string.IsNullOrEmpty(serviceName))
160 | {
161 | ServiceName = serviceName;
162 | }
163 |
164 | // Set deployment environment from known environment variables.
165 | foreach (var envVarName in new string[] { "DOTNET_ENVIRONMENT", "ASPNETCORE_ENVIRONMENT" })
166 | {
167 | var deploymentEnvironment = Environment.GetEnvironmentVariable(envVarName);
168 |
169 | if (deploymentEnvironment != null)
170 | {
171 | DeploymentEnvironment = deploymentEnvironment.ToLower();
172 | }
173 | }
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/AWSInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Trace;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class AWSInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.AWS;
13 |
14 | protected override void InitializeTracing(TracerProviderBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Instrumentation.AWS",
18 | "OpenTelemetry.Trace.TracerProviderBuilderExtensions",
19 | "AddAWSInstrumentation",
20 | new object[] { builder });
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/AWSLambdaInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Trace;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class AWSLambdaInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.AWSLambda;
13 |
14 | protected override void InitializeTracing(TracerProviderBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Instrumentation.AWSLambda",
18 | "OpenTelemetry.Instrumentation.AWSLambda.TracerProviderBuilderExtensions",
19 | "AddAWSLambdaConfigurations",
20 | new object[] { builder });
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/AspNetCoreInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Metrics;
7 | using OpenTelemetry.Trace;
8 |
9 | namespace Grafana.OpenTelemetry
10 | {
11 | internal class AspNetCoreInitializer : InstrumentationInitializer
12 | {
13 | public override Instrumentation Id { get; } = Instrumentation.AspNetCore;
14 |
15 | protected override void InitializeTracing(TracerProviderBuilder builder)
16 | {
17 | ReflectionHelper.CallStaticMethod(
18 | "OpenTelemetry.Instrumentation.AspNetCore",
19 | "OpenTelemetry.Trace.AspNetCoreInstrumentationTracerProviderBuilderExtensions",
20 | "AddAspNetCoreInstrumentation",
21 | new object[] { builder });
22 | }
23 |
24 | protected override void InitializeMetrics(MeterProviderBuilder builder)
25 | {
26 | ReflectionHelper.CallStaticMethod(
27 | "OpenTelemetry.Instrumentation.AspNetCore",
28 | "OpenTelemetry.Metrics.AspNetCoreInstrumentationMeterProviderBuilderExtensions",
29 | "AddAspNetCoreInstrumentation",
30 | new object[] { builder });
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/AspNetInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Metrics;
7 | using OpenTelemetry.Trace;
8 |
9 | namespace Grafana.OpenTelemetry
10 | {
11 | internal class AspNetInitializer : InstrumentationInitializer
12 | {
13 | public override Instrumentation Id { get; } = Instrumentation.AspNet;
14 |
15 | protected override void InitializeTracing(TracerProviderBuilder builder)
16 | {
17 | ReflectionHelper.CallStaticMethod(
18 | "OpenTelemetry.Instrumentation.AspNet",
19 | "OpenTelemetry.Trace.TracerProviderBuilderExtensions",
20 | "AddAspNetInstrumentation",
21 | new object[] { builder });
22 | }
23 |
24 | protected override void InitializeMetrics(MeterProviderBuilder builder)
25 | {
26 | ReflectionHelper.CallStaticMethod(
27 | "OpenTelemetry.Instrumentation.AspNet",
28 | "OpenTelemetry.Metrics.MeterProviderBuilderExtensions",
29 | "AddAspNetInstrumentation",
30 | new object[] { builder });
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/CassandraInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Metrics;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class CassandraInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.Cassandra;
13 |
14 | protected override void InitializeMetrics(MeterProviderBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Instrumentation.Cassandra",
18 | "OpenTelemetry.Metrics.MeterProviderBuilderExtensions",
19 | "AddCassandraInstrumentation",
20 | new object[] { builder });
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/ElasticsearchClientInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Trace;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class ElasticsearchClientInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.ElasticsearchClient;
13 |
14 | protected override void InitializeTracing(TracerProviderBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Instrumentation.ElasticsearchClient",
18 | "OpenTelemetry.Trace.TracerProviderBuilderExtensions",
19 | "AddElasticsearchClientInstrumentation",
20 | new object[] { builder });
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/EntityFrameworkCoreInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Trace;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class EntityFrameworkCoreInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.EntityFrameworkCore;
13 |
14 | protected override void InitializeTracing(TracerProviderBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Instrumentation.EntityFrameworkCore",
18 | "OpenTelemetry.Trace.TracerProviderBuilderExtensions",
19 | "AddEntityFrameworkCoreInstrumentation",
20 | new object[] { builder });
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/GrpcNetClientInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Trace;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class GrpcNetClientInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.GrpcNetClient;
13 |
14 | protected override void InitializeTracing(TracerProviderBuilder builder)
15 | {
16 | builder.AddGrpcClientInstrumentation();
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/HangfireInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Trace;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class HangfireInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.Hangfire;
13 |
14 | protected override void InitializeTracing(TracerProviderBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Instrumentation.Hangfire",
18 | "OpenTelemetry.Trace.TracerProviderBuilderExtensions",
19 | "AddHangfireInstrumentation",
20 | new object[] { builder });
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/HttpClientInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Metrics;
7 | using OpenTelemetry.Trace;
8 |
9 | namespace Grafana.OpenTelemetry
10 | {
11 | internal class HttpClientInitializer : InstrumentationInitializer
12 | {
13 | public override Instrumentation Id { get; } = Instrumentation.HttpClient;
14 |
15 | protected override void InitializeTracing(TracerProviderBuilder builder)
16 | {
17 | builder.AddHttpClientInstrumentation();
18 | }
19 |
20 | protected override void InitializeMetrics(MeterProviderBuilder builder)
21 | {
22 | builder.AddHttpClientInstrumentation();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/Instrumentation.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | namespace Grafana.OpenTelemetry
7 | {
8 | ///
9 | /// An enum representing different instrumentation libraries.
10 | ///
11 | public enum Instrumentation
12 | {
13 | ///
14 | /// .NET runtime metrics (OpenTelemetry.Instrumentation.Runtime)
15 | ///
16 | NetRuntime,
17 |
18 | ///
19 | /// .NET process metrics (OpenTelemetry.Instrumentation.Process)
20 | ///
21 | Process,
22 |
23 | ///
24 | /// HttpClient metrics and traces (OpenTelemetry.Instrumentation.Http)
25 | ///
26 | HttpClient,
27 |
28 | ///
29 | /// ASP.NET Core metrics and traces (OpenTelemetry.Instrumentation.AspNetCore)
30 | ///
31 | AspNetCore,
32 |
33 | ///
34 | /// gRPC client traces (OpenTelemetry.Instrumentation.GrpcNetClient)
35 | ///
36 | GrpcNetClient,
37 |
38 | ///
39 | /// SQL client traces (OpenTelemetry.Instrumentation.SqlClient)
40 | ///
41 | SqlClient,
42 |
43 | ///
44 | /// AWS traces (OpenTelemetry.Instrumentation.AWS)
45 | ///
46 | AWS,
47 |
48 | ///
49 | /// AWS Lambda traces (OpenTelemetry.Instrumentation.AWSLambda)
50 | ///
51 | AWSLambda,
52 |
53 | ///
54 | /// ASP.NET metrics and traces (OpenTelemetry.Instrumentation.AspNetCore)
55 | ///
56 | AspNet,
57 |
58 | ///
59 | /// Cassandra metrics (OpenTelemetry.Instrumentation.Cassandra)
60 | ///
61 | Cassandra,
62 |
63 | ///
64 | /// Elasticsearch client traces (OpenTelemetry.Instrumentation.ElasticsearchClient)
65 | ///
66 | ElasticsearchClient,
67 |
68 | ///
69 | /// EntityFrameworkCore traces (OpenTelemetry.Instrumentation.EntityFrameworkCore)
70 | ///
71 | EntityFrameworkCore,
72 |
73 | ///
74 | /// Hangfire traces (OpenTelemetry.Instrumentation.Hangfire)
75 | ///
76 | Hangfire,
77 |
78 | ///
79 | /// MySqlData traces (OpenTelemetry.Instrumentation.MySqlData)
80 | ///
81 | MySqlData,
82 |
83 | ///
84 | /// Owin metrics and traces (OpenTelemetry.Instrumentation.Owin)
85 | ///
86 | Owin,
87 |
88 | ///
89 | /// Quarty traces (OpenTelemetry.Instrumentation.Quartz)
90 | ///
91 | Quartz,
92 |
93 | ///
94 | /// StackExchange.Redis traces (OpenTelemetry.Instrumentation.StackExchangeRedis)
95 | ///
96 | StackExchangeRedis,
97 |
98 | ///
99 | /// WCF traces (OpenTelemetry.Instrumentation.Wcf)
100 | ///
101 | Wcf
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/InstrumentationInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using OpenTelemetry.Metrics;
8 | using OpenTelemetry.Trace;
9 |
10 | namespace Grafana.OpenTelemetry
11 | {
12 | internal abstract class InstrumentationInitializer
13 | {
14 | public static InstrumentationInitializer[] Initializers = new InstrumentationInitializer[]
15 | {
16 | #if NETFRAMEWORK
17 | new AspNetInitializer(),
18 | new OwinInitializer(),
19 | #endif
20 | new AspNetCoreInitializer(),
21 | new AWSInitializer(),
22 | new AWSLambdaInitializer(),
23 | new CassandraInitializer(),
24 | new ElasticsearchClientInitializer(),
25 | new EntityFrameworkCoreInitializer(),
26 | new GrpcNetClientInitializer(),
27 | new HangfireInitializer(),
28 | new HttpClientInitializer(),
29 | new MySqlDataInitializer(),
30 | new NetRuntimeMetricsInitializer(),
31 | new ProcessMetricsInitializer(),
32 | new QuartzInitializer(),
33 | new SqlClientInitializer(),
34 | new StackExchangeRedisInitializer(),
35 | new WcfInitializer(),
36 | };
37 |
38 | abstract public Instrumentation Id { get; }
39 |
40 | public void Initialize(TracerProviderBuilder builder)
41 | {
42 | try
43 | {
44 | InitializeTracing(builder);
45 |
46 | GrafanaOpenTelemetryEventSource.Log.EnabledTracingInstrumentation(Id.ToString());
47 | }
48 | catch (Exception ex)
49 | {
50 | GrafanaOpenTelemetryEventSource.Log.FailureEnablingTracingInstrumentation(Id.ToString(), ex);
51 | }
52 | }
53 |
54 | public void Initialize(MeterProviderBuilder builder)
55 | {
56 | try
57 | {
58 | InitializeMetrics(builder);
59 |
60 | GrafanaOpenTelemetryEventSource.Log.EnabledMetricsInstrumentation(Id.ToString());
61 | }
62 | catch (Exception ex)
63 | {
64 | GrafanaOpenTelemetryEventSource.Log.FailureEnablingMetricsInstrumentation(Id.ToString(), ex);
65 | }
66 | }
67 |
68 | protected virtual void InitializeTracing(TracerProviderBuilder builder)
69 | { }
70 |
71 | protected virtual void InitializeMetrics(MeterProviderBuilder builder)
72 | { }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/MySqlDataInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Trace;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class MySqlDataInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.MySqlData;
13 |
14 | protected override void InitializeTracing(TracerProviderBuilder builder)
15 | {
16 | // MySQL.Data.OpenTelemetry
17 | ReflectionHelper.CallStaticMethod(
18 | "MySQL.Data.OpenTelemetry",
19 | "OpenTelemetry.Trace.TracerProviderBuilderExtensions",
20 | "AddConnectorNet",
21 | new object[] { builder });
22 |
23 | // OpenTelemetry.Instrumentation.MySqlData
24 | ReflectionHelper.CallStaticMethod(
25 | "OpenTelemetry.Instrumentation.MySqlData",
26 | "OpenTelemetry.Trace.TracerProviderBuilderExtensions",
27 | "AddMySqlDataInstrumentation",
28 | new object[] { builder });
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/NetRuntimeMetricsInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Metrics;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class NetRuntimeMetricsInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.NetRuntime;
13 |
14 | protected override void InitializeMetrics(MeterProviderBuilder builder)
15 | {
16 | builder.AddRuntimeInstrumentation();
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/OwinInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Trace;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class OwinInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.Owin;
13 |
14 | protected override void InitializeTracing(TracerProviderBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Instrumentation.Owin",
18 | "OpenTelemetry.Trace.TracerProviderBuilderExtensions",
19 | "AddOwinInstrumentation",
20 | new object[] { builder, null });
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/ProcessMetricsInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Metrics;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class ProcessMetricsInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.Process;
13 |
14 | protected override void InitializeMetrics(MeterProviderBuilder builder)
15 | {
16 | builder.AddProcessInstrumentation();
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/QuartzInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Trace;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class QuartzInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.Quartz;
13 |
14 | protected override void InitializeTracing(TracerProviderBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Instrumentation.Quartz",
18 | "OpenTelemetry.Trace.TraceProviderBuilderExtensions",
19 | "AddQuartzInstrumentation",
20 | new object[] { builder });
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/SqlClientInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Trace;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class SqlClientInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.SqlClient;
13 |
14 | protected override void InitializeTracing(TracerProviderBuilder builder)
15 | {
16 | builder.AddSqlClientInstrumentation();
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/StackExchangeRedisInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Trace;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class StackExchangeRedisInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.StackExchangeRedis;
13 |
14 | protected override void InitializeTracing(TracerProviderBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Instrumentation.StackExchangeRedis",
18 | "OpenTelemetry.Trace.TracerProviderBuilderExtensions",
19 | "AddRedisInstrumentation",
20 | new object[] { builder });
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/Instrumentations/WcfInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Trace;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class WcfInitializer : InstrumentationInitializer
11 | {
12 | public override Instrumentation Id { get; } = Instrumentation.Wcf;
13 |
14 | protected override void InitializeTracing(TracerProviderBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Instrumentation.Wcf",
18 | "OpenTelemetry.Trace.TracerProviderBuilderExtensions",
19 | "AddWcfInstrumentation",
20 | new object[] { builder });
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/MeterProviderBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using OpenTelemetry.Metrics;
9 |
10 | namespace Grafana.OpenTelemetry
11 | {
12 | ///
13 | /// Metrics-related extension provided by the OpenTelemetry .NET distribution for Grafana.
14 | ///
15 | public static class MeterProviderBuilderExtensions
16 | {
17 | ///
18 | /// Sets up metrics with the OpenTelemetry .NET distribution for Grafana.
19 | ///
20 | /// A
21 | /// A callback for customizing default Grafana OpenTelemetry settings
22 | /// A modified
23 | public static MeterProviderBuilder UseGrafana(this MeterProviderBuilder builder, Action configure = default)
24 | {
25 | GrafanaOpenTelemetrySettings settings = new GrafanaOpenTelemetrySettings();
26 |
27 | if (configure != null)
28 | {
29 | configure?.Invoke(settings);
30 | }
31 |
32 | GrafanaOpenTelemetryEventSource.Log.InitializeDistribution(settings);
33 |
34 | // Default to using experimental gRPC instrumentation
35 | if (Environment.GetEnvironmentVariable("OTEL_DOTNET_EXPERIMENTAL_ASPNETCORE_ENABLE_GRPC_INSTRUMENTATION") == null)
36 | {
37 | Environment.SetEnvironmentVariable("OTEL_DOTNET_EXPERIMENTAL_ASPNETCORE_ENABLE_GRPC_INSTRUMENTATION", "true");
38 | }
39 |
40 | return builder
41 | .AddGrafanaExporter(settings?.ExporterSettings)
42 | .AddInstrumentations(settings?.Instrumentations)
43 | .AddResourceDetectors(settings?.ResourceDetectors)
44 | .ConfigureResource(resourceBuilder => resourceBuilder.AddGrafanaResource(settings));
45 | }
46 |
47 | internal static MeterProviderBuilder AddGrafanaExporter(this MeterProviderBuilder builder, ExporterSettings settings)
48 | {
49 | settings?.Apply(builder);
50 |
51 | return builder;
52 | }
53 |
54 | internal static MeterProviderBuilder AddInstrumentations(this MeterProviderBuilder builder, HashSet instrumentations)
55 | {
56 | if (instrumentations == null)
57 | {
58 | return builder;
59 | }
60 |
61 | foreach (var initializer in InstrumentationInitializer.Initializers)
62 | {
63 | if (instrumentations.Contains(initializer.Id))
64 | {
65 | initializer.Initialize(builder);
66 | }
67 | }
68 |
69 | return builder;
70 | }
71 |
72 | internal static MeterProviderBuilder AddResourceDetectors(this MeterProviderBuilder builder, HashSet resourceDetectors)
73 | {
74 | if (resourceDetectors == null)
75 | {
76 | return builder;
77 | }
78 |
79 | foreach (var initializer in ResourceDetectorInitializer.Initializers)
80 | {
81 | if (resourceDetectors.Contains(initializer.Id))
82 | {
83 | initializer.Initialize(builder);
84 | }
85 | }
86 |
87 | return builder;
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/OpenTelemetryLoggerOptionsExtensions.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using Microsoft.Extensions.Logging;
8 | using OpenTelemetry.Logs;
9 | using OpenTelemetry.Resources;
10 |
11 | namespace Grafana.OpenTelemetry
12 | {
13 | ///
14 | /// Logging-related extension provided by the OpenTelemetry .NET distribution for Grafana.
15 | ///
16 | public static class OpenTelemetryLoggerOptionsExtensions
17 | {
18 | ///
19 | /// Sets up an with the OpenTelemetry .NET distribution for Grafana.
20 | ///
21 | ///
22 | /// A callback for customizing default Grafana OpenTelemetry settings
23 | /// A modified object
24 | public static OpenTelemetryLoggerOptions UseGrafana(this OpenTelemetryLoggerOptions options, Action configure = default)
25 | {
26 | GrafanaOpenTelemetrySettings settings = new GrafanaOpenTelemetrySettings();
27 |
28 | if (configure != null)
29 | {
30 | configure?.Invoke(settings);
31 | }
32 |
33 | GrafanaOpenTelemetryEventSource.Log.InitializeDistribution(settings);
34 |
35 | // Default to using stable HTTP semantic conventions
36 | if (Environment.GetEnvironmentVariable("OTEL_SEMCONV_STABILITY_OPT_IN") == null)
37 | {
38 | Environment.SetEnvironmentVariable("OTEL_SEMCONV_STABILITY_OPT_IN", "http");
39 | }
40 |
41 | var resourceBuilder = ResourceBuilder
42 | .CreateDefault()
43 | .AddGrafanaResource(settings);
44 |
45 | return options
46 | .AddGrafanaExporter(settings?.ExporterSettings)
47 | .SetResourceBuilder(resourceBuilder);
48 | }
49 |
50 | internal static OpenTelemetryLoggerOptions AddGrafanaExporter(this OpenTelemetryLoggerOptions options, ExporterSettings settings)
51 | {
52 | settings?.Apply(options);
53 |
54 | return options;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ReflectionHelper.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System.Linq;
7 | using System.Reflection;
8 |
9 | namespace Grafana.OpenTelemetry
10 | {
11 | internal static class ReflectionHelper
12 | {
13 | internal static void CallStaticMethod(string assemblyName, string typeName, string methodName, object[] arguments)
14 | {
15 | var assembly = Assembly.Load(assemblyName);
16 | var type = assembly.GetType(typeName);
17 | var method = type.GetMethod(methodName, arguments.Select(obj => obj is null ? null : obj.GetType()).ToArray());
18 | method.Invoke(null, arguments);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceBuilderExtension.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Resources;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal static class ResourceBuilderExtension
11 | {
12 | public static ResourceBuilder AddGrafanaResource(this ResourceBuilder resourceBuilder, GrafanaOpenTelemetrySettings settings)
13 | {
14 | var serviceInstanceIdProvided = !string.IsNullOrEmpty(settings.ServiceInstanceId);
15 |
16 | return resourceBuilder
17 | .AddDetector(new GrafanaOpenTelemetryResourceDetector(settings))
18 | .AddService(
19 | serviceName: settings.ServiceName,
20 | serviceVersion: settings.ServiceVersion,
21 | serviceInstanceId: serviceInstanceIdProvided ? settings.ServiceInstanceId : null,
22 | autoGenerateServiceInstanceId: serviceInstanceIdProvided == false);
23 |
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/AWSEBSDetectorInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | #if !NETSTANDARD
7 | using OpenTelemetry.Resources;
8 |
9 | namespace Grafana.OpenTelemetry
10 | {
11 | internal class AWSEBSDetectorInitializer : ResourceDetectorInitializer
12 | {
13 | public override ResourceDetector Id { get; } = ResourceDetector.AWSEBS;
14 |
15 | protected override ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
16 | {
17 | ReflectionHelper.CallStaticMethod(
18 | "OpenTelemetry.Resources.AWS",
19 | "OpenTelemetry.Resources.AWSResourceBuilderExtensions",
20 | "AddAWSEBSDetector",
21 | new object[] { builder });
22 | return builder;
23 | }
24 | }
25 | }
26 | #endif
27 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/AWSEC2DetectorInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | #if !NETSTANDARD
7 | using OpenTelemetry.Resources;
8 |
9 | namespace Grafana.OpenTelemetry
10 | {
11 | internal class AWSEC2DetectorInitializer : ResourceDetectorInitializer
12 | {
13 | public override ResourceDetector Id { get; } = ResourceDetector.AWSEC2;
14 |
15 | protected override ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
16 | {
17 | ReflectionHelper.CallStaticMethod(
18 | "OpenTelemetry.Resources.AWS",
19 | "OpenTelemetry.Resources.AWSResourceBuilderExtensions",
20 | "AddAWSEC2Detector",
21 | new object[] { builder });
22 | return builder;
23 | }
24 | }
25 | }
26 | #endif
27 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/AWSECSDetectorInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | #if !NETSTANDARD && !NETFRAMEWORK
7 | using OpenTelemetry.Resources;
8 |
9 | namespace Grafana.OpenTelemetry
10 | {
11 | internal class AWSECSDetectorInitializer : ResourceDetectorInitializer
12 | {
13 | public override ResourceDetector Id { get; } = ResourceDetector.AWSECS;
14 |
15 | protected override ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
16 | {
17 | ReflectionHelper.CallStaticMethod(
18 | "OpenTelemetry.Resources.AWS",
19 | "OpenTelemetry.Resources.AWSResourceBuilderExtensions",
20 | "AddAWSECSDetector",
21 | new object[] { builder });
22 | return builder;
23 | }
24 | }
25 | }
26 | #endif
27 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/AWSEKSDetectorInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | #if !NETSTANDARD && !NETFRAMEWORK
7 | using OpenTelemetry.Resources;
8 |
9 | namespace Grafana.OpenTelemetry
10 | {
11 | internal class AWSEKSDetectorInitializer : ResourceDetectorInitializer
12 | {
13 | public override ResourceDetector Id { get; } = ResourceDetector.AWSEKS;
14 |
15 | protected override ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
16 | {
17 | ReflectionHelper.CallStaticMethod(
18 | "OpenTelemetry.Resources.AWS",
19 | "OpenTelemetry.Resources.AWSResourceBuilderExtensions",
20 | "AddAWSEKSDetector",
21 | new object[] { builder });
22 | return builder;
23 | }
24 | }
25 | }
26 | #endif
27 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/AzureAppServiceDetectorInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Resources;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class AzureAppServiceDetectorInitializer : ResourceDetectorInitializer
11 | {
12 | public override ResourceDetector Id { get; } = ResourceDetector.AzureAppService;
13 |
14 | protected override ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Resources.Azure",
18 | "OpenTelemetry.Resources.AzureResourceBuilderExtensions",
19 | "AddAzureAppServiceDetector",
20 | new object[] { builder });
21 | return builder;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/AzureContainerAppsDetectorInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Resources;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class AzureContainerAppsDetectorInitializer : ResourceDetectorInitializer
11 | {
12 | public override ResourceDetector Id { get; } = ResourceDetector.AzureContainerApps;
13 |
14 | protected override ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Resources.Azure",
18 | "OpenTelemetry.Resources.AzureResourceBuilderExtensions",
19 | "AddAzureContainerAppsDetector",
20 | new object[] { builder });
21 | return builder;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/AzureVMDetectorInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry.Resources;
7 |
8 | namespace Grafana.OpenTelemetry
9 | {
10 | internal class AzureVMDetectorInitializer : ResourceDetectorInitializer
11 | {
12 | public override ResourceDetector Id { get; } = ResourceDetector.AzureVM;
13 |
14 | protected override ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
15 | {
16 | ReflectionHelper.CallStaticMethod(
17 | "OpenTelemetry.Resources.Azure",
18 | "OpenTelemetry.Resources.AzureResourceBuilderExtensions",
19 | "AddAzureVMDetector",
20 | new object[] { builder });
21 | return builder;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/ContainerResource.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | #if NET8_0_OR_GREATER
7 |
8 | using OpenTelemetry.Resources;
9 |
10 | namespace Grafana.OpenTelemetry
11 | {
12 | internal class ContainerResourceInitializer : ResourceDetectorInitializer
13 | {
14 | public override ResourceDetector Id { get; } = ResourceDetector.Container;
15 |
16 | protected override ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
17 | {
18 | return builder.AddContainerDetector();
19 | }
20 | }
21 | }
22 |
23 | #endif
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/HostDetectorInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | #if !NETSTANDARD
7 |
8 | using OpenTelemetry.Resources;
9 |
10 | namespace Grafana.OpenTelemetry
11 | {
12 | internal class HostResourceInitializer : ResourceDetectorInitializer
13 | {
14 | public override ResourceDetector Id { get; } = ResourceDetector.Host;
15 |
16 | protected override ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
17 | {
18 | return builder.AddHostDetector();
19 | }
20 | }
21 | }
22 |
23 | #endif
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/OperatingSystemResourceInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | #if !NETSTANDARD
7 |
8 | using OpenTelemetry.Resources;
9 |
10 | namespace Grafana.OpenTelemetry
11 | {
12 | internal class OperatingSystemResourceInitializer : ResourceDetectorInitializer
13 | {
14 | public override ResourceDetector Id { get; } = ResourceDetector.OperatingSystem;
15 |
16 | protected override ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
17 | {
18 | return builder.AddOperatingSystemDetector();
19 | }
20 | }
21 | }
22 |
23 | #endif
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/ProcessResourceInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | #if !NETSTANDARD
7 |
8 | using OpenTelemetry.Resources;
9 |
10 | namespace Grafana.OpenTelemetry
11 | {
12 | internal class ProcessResourceInitializer : ResourceDetectorInitializer
13 | {
14 | public override ResourceDetector Id { get; } = ResourceDetector.Process;
15 |
16 | protected override ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
17 | {
18 | return builder.AddProcessDetector();
19 | }
20 | }
21 | }
22 |
23 | #endif
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/ProcessRuntimeResource.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | #if !NETSTANDARD
7 |
8 | using OpenTelemetry.Resources;
9 |
10 | namespace Grafana.OpenTelemetry
11 | {
12 | internal class ProcessRuntimeResourceInitializer : ResourceDetectorInitializer
13 | {
14 | public override ResourceDetector Id { get; } = ResourceDetector.ProcessRuntime;
15 |
16 | protected override ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
17 | {
18 | return builder.AddProcessRuntimeDetector();
19 | }
20 | }
21 | }
22 |
23 | #endif
24 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/ResourceDetector.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | namespace Grafana.OpenTelemetry
7 | {
8 | ///
9 | /// An enum representing different resource detectors.
10 | ///
11 | public enum ResourceDetector
12 | {
13 | ///
14 | /// AWS EBS Resource Detector (OpenTelemetry.Resources.AWS)
15 | ///
16 | AWSEBS,
17 | ///
18 | /// AWS EC2 Resource Detector (OpenTelemetry.Resources.AWS)
19 | ///
20 | AWSEC2,
21 | ///
22 | /// AWS ECS Resource Detector (OpenTelemetry.Resources.AWS)
23 | ///
24 | AWSECS,
25 | ///
26 | /// AWS EKS Resource Detector (OpenTelemetry.Resources.AWS)
27 | ///
28 | AWSEKS,
29 |
30 | ///
31 | /// Azure App Service Resource Detector (OpenTelemetry.Resources.Azure)
32 | ///
33 | AzureAppService,
34 | ///
35 | /// Azure Virtual Machine Resource Detector (OpenTelemetry.Resources.Azure)
36 | ///
37 | AzureVM,
38 | ///
39 | /// Azure Container Apps Resource Detector (OpenTelemetry.Resources.Azure)
40 | ///
41 | AzureContainerApps,
42 |
43 | ///
44 | /// Container Resource Detector (OpenTelemetry.Resources.Container)
45 | ///
46 | Container,
47 |
48 | ///
49 | /// Host Resource Detector (OpenTelemetry.Resources.Host)
50 | ///
51 | Host,
52 |
53 | ///
54 | /// Operating System Resource Detector (OpenTelemetry.Resources.OperatingSystem)
55 | ///
56 | OperatingSystem,
57 |
58 | ///
59 | /// Process Resource Detector (OpenTelemetry.Resources.Process)
60 | ///
61 | Process,
62 |
63 | ///
64 | /// Process Runtime Resource Detector (OpenTelemetry.Resources.ProcessRuntime)
65 | ///
66 | ProcessRuntime
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/ResourceDetectors/ResourceDetectorInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using OpenTelemetry.Metrics;
8 | using OpenTelemetry.Resources;
9 | using OpenTelemetry.Trace;
10 |
11 | namespace Grafana.OpenTelemetry
12 | {
13 | internal abstract class ResourceDetectorInitializer
14 | {
15 | public static ResourceDetectorInitializer[] Initializers = new ResourceDetectorInitializer[]
16 | {
17 | #if !NETSTANDARD
18 | new AWSEBSDetectorInitializer(),
19 | new AWSEC2DetectorInitializer(),
20 | #endif
21 | #if !NETSTANDARD && !NETFRAMEWORK
22 | new AWSECSDetectorInitializer(),
23 | new AWSEKSDetectorInitializer(),
24 | #endif
25 | new AzureAppServiceDetectorInitializer(),
26 | new AzureVMDetectorInitializer(),
27 | new AzureContainerAppsDetectorInitializer(),
28 | #if NET8_0_OR_GREATER
29 | new ContainerResourceInitializer(),
30 | #endif
31 | #if !NETSTANDARD
32 | new HostResourceInitializer(),
33 | new OperatingSystemResourceInitializer(),
34 | new ProcessResourceInitializer(),
35 | new ProcessRuntimeResourceInitializer()
36 | #endif
37 | };
38 |
39 | abstract public ResourceDetector Id { get; }
40 |
41 | public void Initialize(TracerProviderBuilder builder)
42 | {
43 | try
44 | {
45 | builder.ConfigureResource(resourceBuilder => InitializeResourceDetector(resourceBuilder));
46 |
47 | GrafanaOpenTelemetryEventSource.Log.EnabledTracingInstrumentation(Id.ToString());
48 | }
49 | catch (Exception ex)
50 | {
51 | GrafanaOpenTelemetryEventSource.Log.FailureEnablingTracingInstrumentation(Id.ToString(), ex);
52 | }
53 | }
54 |
55 | public void Initialize(MeterProviderBuilder builder)
56 | {
57 | try
58 | {
59 | builder.ConfigureResource(resourceBuilder => InitializeResourceDetector(resourceBuilder));
60 |
61 | GrafanaOpenTelemetryEventSource.Log.EnabledMetricsInstrumentation(Id.ToString());
62 | }
63 | catch (Exception ex)
64 | {
65 | GrafanaOpenTelemetryEventSource.Log.FailureEnablingMetricsInstrumentation(Id.ToString(), ex);
66 | }
67 | }
68 |
69 | protected virtual ResourceBuilder InitializeResourceDetector(ResourceBuilder builder)
70 | {
71 | return builder;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry.Base/TracerProviderBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using OpenTelemetry.Trace;
9 |
10 | namespace Grafana.OpenTelemetry
11 | {
12 | ///
13 | /// Tracing-related extension provided by the OpenTelemetry .NET distribution for Grafana.
14 | ///
15 | public static class TracerProviderBuilderExtensions
16 | {
17 | ///
18 | /// Sets up tracing with the OpenTelemetry .NET distribution for Grafana.
19 | ///
20 | /// A
21 | /// A callback for customizing default Grafana OpenTelemetry settings
22 | /// A modified
23 | public static TracerProviderBuilder UseGrafana(this TracerProviderBuilder builder, Action configure = default)
24 | {
25 | GrafanaOpenTelemetrySettings settings = new GrafanaOpenTelemetrySettings();
26 |
27 | if (configure != null)
28 | {
29 | configure?.Invoke(settings);
30 | }
31 |
32 | GrafanaOpenTelemetryEventSource.Log.InitializeDistribution(settings);
33 |
34 | // Default to using experimental gRPC instrumentation
35 | if (Environment.GetEnvironmentVariable("OTEL_DOTNET_EXPERIMENTAL_ASPNETCORE_ENABLE_GRPC_INSTRUMENTATION") == null)
36 | {
37 | Environment.SetEnvironmentVariable("OTEL_DOTNET_EXPERIMENTAL_ASPNETCORE_ENABLE_GRPC_INSTRUMENTATION", "true");
38 | }
39 |
40 | return builder
41 | .AddGrafanaExporter(settings?.ExporterSettings)
42 | .AddInstrumentations(settings?.Instrumentations)
43 | .AddResourceDetectors(settings?.ResourceDetectors)
44 | .ConfigureResource(resourceBuilder => resourceBuilder.AddGrafanaResource(settings));
45 | }
46 |
47 | internal static TracerProviderBuilder AddGrafanaExporter(this TracerProviderBuilder builder, ExporterSettings settings)
48 | {
49 | settings?.Apply(builder);
50 |
51 | return builder;
52 | }
53 |
54 | internal static TracerProviderBuilder AddInstrumentations(this TracerProviderBuilder builder, HashSet instrumentations)
55 | {
56 | if (instrumentations == null)
57 | {
58 | return builder;
59 | }
60 |
61 | foreach (var initializer in InstrumentationInitializer.Initializers)
62 | {
63 | if (instrumentations.Contains(initializer.Id))
64 | {
65 | initializer.Initialize(builder);
66 | }
67 | }
68 |
69 | return builder;
70 | }
71 |
72 | internal static TracerProviderBuilder AddResourceDetectors(this TracerProviderBuilder builder, HashSet resourceDetectors)
73 | {
74 | if (resourceDetectors == null)
75 | {
76 | return builder;
77 | }
78 |
79 | foreach (var initializer in ResourceDetectorInitializer.Initializers)
80 | {
81 | if (resourceDetectors.Contains(initializer.Id))
82 | {
83 | initializer.Initialize(builder);
84 | }
85 | }
86 |
87 | return builder;
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry/Grafana.OpenTelemetry.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Full Grafana distribution of OpenTelemetry .NET
5 | true
6 | net8.0;netstandard2.0;net462
7 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | all
21 | runtime; build; native; contentfiles; analyzers; buildtransitive
22 |
23 |
24 |
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | <_Parameter1>Grafana.OpenTelemetry.Tests
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry/OpenTelemetryBuilderExtension.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | #if !NETFRAMEWORK
7 |
8 | using System;
9 | using OpenTelemetry;
10 |
11 | namespace Grafana.OpenTelemetry
12 | {
13 | ///
14 | /// Extension for the provided by the OpenTelemetry .NET distribution
15 | /// for Grafana.
16 | ///
17 | /// This is used for easier configuration for ASP.NET Core projects.
18 | ///
19 | public static class OpenTelemetryBuilderExtension
20 | {
21 | ///
22 | /// Sets up tracing and metrics with the OpenTelemetry .NET distribution for Grafana.
23 | ///
24 | /// A
25 | /// A callback for customizing default Grafana OpenTelemetry settings
26 | /// A modified
27 | public static IOpenTelemetryBuilder UseGrafana(this IOpenTelemetryBuilder builder, Action configure = default)
28 | {
29 | return builder
30 | .WithTracing(tracerProviderBuilder => tracerProviderBuilder.UseGrafana(configure))
31 | .WithMetrics(metricProviderBuilder => metricProviderBuilder.UseGrafana(configure));
32 | }
33 | }
34 | }
35 | #endif
36 |
--------------------------------------------------------------------------------
/src/Grafana.OpenTelemetry/rd.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/tests/Grafana.OpenTelemetry.Tests/Grafana.OpenTelemetry.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | $(TargetFrameworks);net481
6 | false
7 | true
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/Grafana.OpenTelemetry.Tests/GrafanaCloudConfigurationHelperTest.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using Xunit;
8 |
9 | namespace Grafana.OpenTelemetry.Tests
10 | {
11 | public class GrafanaCloudConfigurationHelperTest
12 | {
13 | [Fact]
14 | public void OtlpEndpoint()
15 | {
16 | var helper = new GrafanaCloudConfigurationHelper("prod-us-east-0", "", "");
17 |
18 | Assert.Equal(
19 | new Uri($"https://otlp-gateway-prod-us-east-0.grafana.net/otlp/v1/traces"),
20 | helper.OtlpEndpointTraces);
21 |
22 | Assert.Equal(
23 | new Uri($"https://otlp-gateway-prod-us-east-0.grafana.net/otlp/v1/metrics"),
24 | helper.OtlpEndpointMetrics);
25 |
26 | Assert.Equal(
27 | new Uri($"https://otlp-gateway-prod-us-east-0.grafana.net/otlp/v1/logs"),
28 | helper.OtlpEndpointLogs);
29 | }
30 |
31 | [Fact]
32 | public void OtlpAuthorizationHeader()
33 | {
34 | var helper = new GrafanaCloudConfigurationHelper("", "701628", "a_secret");
35 |
36 | Assert.Equal(
37 | "Authorization=Basic NzAxNjI4OmFfc2VjcmV0",
38 | helper.OtlpAuthorizationHeader);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tests/Grafana.OpenTelemetry.Tests/GrafanaOpenTelemetryResourceDetectorTest.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using Xunit;
9 |
10 | namespace Grafana.OpenTelemetry.Tests
11 | {
12 | public class GrafanaOpenTelemetryResourceDetectorTest
13 | {
14 | [Fact]
15 | public void DefaultDeploymentEnvironment()
16 | {
17 | var settings = new GrafanaOpenTelemetrySettings();
18 | var resource = new GrafanaOpenTelemetryResourceDetector(settings).Detect();
19 | var resourceAttributes = new Dictionary();
20 |
21 | foreach (var attribute in resource.Attributes)
22 | {
23 | resourceAttributes[attribute.Key] = attribute.Value;
24 | }
25 |
26 | Assert.Equal("production", resourceAttributes["deployment.environment"]);
27 | }
28 |
29 | [Fact]
30 | public void CustomDeploymentEnvironment()
31 | {
32 | var settings = new GrafanaOpenTelemetrySettings();
33 | settings.DeploymentEnvironment = "custom";
34 |
35 | var resource = new GrafanaOpenTelemetryResourceDetector(settings).Detect();
36 | var resourceAttributes = new Dictionary();
37 |
38 | foreach (var attribute in resource.Attributes)
39 | {
40 | resourceAttributes[attribute.Key] = attribute.Value;
41 | }
42 |
43 | Assert.Equal("custom", resourceAttributes["deployment.environment"]);
44 | }
45 |
46 | [Fact]
47 | public void DeploymentEnvironmentFromEnv()
48 | {
49 | Environment.SetEnvironmentVariable("DOTNET_ENVIRONMENT", "CustomEnv");
50 |
51 | var settings = new GrafanaOpenTelemetrySettings();
52 | var resource = new GrafanaOpenTelemetryResourceDetector(settings).Detect();
53 | var resourceAttributes = new Dictionary();
54 |
55 | foreach (var attribute in resource.Attributes)
56 | {
57 | resourceAttributes[attribute.Key] = attribute.Value;
58 | }
59 |
60 | Assert.Equal("customenv", resourceAttributes["deployment.environment"]);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/tests/Grafana.OpenTelemetry.Tests/GrafanaOpenTelemetrySettingsTest.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Reflection;
9 | using Xunit;
10 |
11 | namespace Grafana.OpenTelemetry.Tests
12 | {
13 | public class GrafanaOpenTelemetrySettingsTest
14 | {
15 | public GrafanaOpenTelemetrySettingsTest()
16 | {
17 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.DisableInstrumentationsEnvVarName, null);
18 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.ServiceNameEnvVarName, null);
19 | }
20 |
21 | [Fact(Skip = "provider builders crashes on enabling AWSLambda instrumentation by default")]
22 | public void DefaultInstrumentations()
23 | {
24 | var settings = new GrafanaOpenTelemetrySettings();
25 |
26 | Assert.Equal(new HashSet((Instrumentation[])Enum.GetValues(typeof(Instrumentation))), settings.Instrumentations);
27 | }
28 |
29 | [Fact]
30 | public void DefaultInstrumentationsWithout()
31 | {
32 | var settings = new GrafanaOpenTelemetrySettings();
33 |
34 | // De-activate AWSLambda instrumenation until this issue is resolved: https://github.com/grafana/app-o11y/issues/378
35 | //
36 | // Once it's resolved, this test can be removed and the `DefaultInstrumentation` test can be re-activated.
37 | var expectedSettings = new HashSet((Instrumentation[])Enum.GetValues(typeof(Instrumentation)));
38 | expectedSettings.Remove(Instrumentation.AWSLambda);
39 |
40 | Assert.Equal(expectedSettings, settings.Instrumentations);
41 | }
42 |
43 | [Fact]
44 | public void DisableInstrumentations()
45 | {
46 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.DisableInstrumentationsEnvVarName, "Process,NetRuntime");
47 |
48 | var settings = new GrafanaOpenTelemetrySettings();
49 |
50 | Assert.DoesNotContain(Instrumentation.Process, settings.Instrumentations);
51 | Assert.DoesNotContain(Instrumentation.NetRuntime, settings.Instrumentations);
52 |
53 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.DisableInstrumentationsEnvVarName, null);
54 | }
55 |
56 | [Fact]
57 | public void DisableInstrumentationsColon()
58 | {
59 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.DisableInstrumentationsEnvVarName, "Process:NetRuntime");
60 |
61 | var settings = new GrafanaOpenTelemetrySettings();
62 |
63 | Assert.DoesNotContain(Instrumentation.Process, settings.Instrumentations);
64 | Assert.DoesNotContain(Instrumentation.NetRuntime, settings.Instrumentations);
65 |
66 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.DisableInstrumentationsEnvVarName, null);
67 | }
68 |
69 | [Fact]
70 | public void DisableResourceDetectors()
71 | {
72 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.DisableResourceDetectorsEnvVarName, "Host,Process");
73 |
74 | var settings = new GrafanaOpenTelemetrySettings();
75 |
76 | Assert.DoesNotContain(ResourceDetector.Host, settings.ResourceDetectors);
77 | Assert.DoesNotContain(ResourceDetector.Process, settings.ResourceDetectors);
78 |
79 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.DisableResourceDetectorsEnvVarName, null);
80 | }
81 |
82 | [Fact]
83 | public void DisableResourceDetectorsColon()
84 | {
85 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.DisableResourceDetectorsEnvVarName, "Host:Process");
86 |
87 | var settings = new GrafanaOpenTelemetrySettings();
88 |
89 | Assert.DoesNotContain(ResourceDetector.Host, settings.ResourceDetectors);
90 | Assert.DoesNotContain(ResourceDetector.Process, settings.ResourceDetectors);
91 |
92 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.DisableResourceDetectorsEnvVarName, null);
93 | }
94 |
95 | [Fact]
96 | public void SetSingleResourceDetector()
97 | {
98 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.ResourceDetectorsEnvVarName, "Container");
99 |
100 | var settings = new GrafanaOpenTelemetrySettings();
101 |
102 | Assert.Single(settings.ResourceDetectors);
103 | Assert.Contains(ResourceDetector.Container, settings.ResourceDetectors);
104 |
105 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.ResourceDetectorsEnvVarName, null);
106 | }
107 |
108 | [Fact]
109 | public void SetResourceDetectors()
110 | {
111 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.ResourceDetectorsEnvVarName, "Container,Process");
112 |
113 | var settings = new GrafanaOpenTelemetrySettings();
114 |
115 | Assert.Equal(2, settings.ResourceDetectors.Count);
116 | Assert.Contains(ResourceDetector.Container, settings.ResourceDetectors);
117 | Assert.Contains(ResourceDetector.Process, settings.ResourceDetectors);
118 |
119 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.ResourceDetectorsEnvVarName, null);
120 | }
121 |
122 | [Fact]
123 | public void SetResourceDetectorsColon()
124 | {
125 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.ResourceDetectorsEnvVarName, "Container:Process");
126 |
127 | var settings = new GrafanaOpenTelemetrySettings();
128 |
129 | Assert.Equal(2, settings.ResourceDetectors.Count);
130 | Assert.Contains(ResourceDetector.Container, settings.ResourceDetectors);
131 | Assert.Contains(ResourceDetector.Process, settings.ResourceDetectors);
132 |
133 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.ResourceDetectorsEnvVarName, null);
134 | }
135 |
136 | [Fact]
137 | public void SetAndDisableResourceDetectors()
138 | {
139 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.ResourceDetectorsEnvVarName, "Host,Container");
140 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.DisableResourceDetectorsEnvVarName, "Container");
141 |
142 | var settings = new GrafanaOpenTelemetrySettings();
143 |
144 | Assert.Single(settings.ResourceDetectors);
145 | Assert.Contains(ResourceDetector.Host, settings.ResourceDetectors);
146 |
147 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.ResourceDetectorsEnvVarName, null);
148 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.DisableResourceDetectorsEnvVarName, null);
149 | }
150 |
151 | [Fact]
152 | public void DefaultServiceName()
153 | {
154 | var settings = new GrafanaOpenTelemetrySettings();
155 |
156 | Assert.Equal(Assembly.GetEntryAssembly()?.GetName().Name ?? System.Diagnostics.Process.GetCurrentProcess().ProcessName, settings.ServiceName);
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/tests/Grafana.OpenTelemetry.Tests/InMemoryResourceExporter.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using OpenTelemetry;
9 | using OpenTelemetry.Resources;
10 |
11 | namespace Grafana.OpenTelemetry.Tests
12 | {
13 | ///
14 | /// The upstream `InMemoryExporter` doesn't capture resources.
15 | ///
16 | /// This implementation adds support for capturing the resource.
17 | ///
18 | public class InMemoryResourceExporter : BaseExporter
19 | where T : class
20 | {
21 | private readonly ICollection<(T, Resource)> exportedItems;
22 | private readonly ExportFunc onExport;
23 | private bool disposed;
24 | private string disposedStackTrace;
25 |
26 | public InMemoryResourceExporter(ICollection<(T, Resource)> exportedItems)
27 | {
28 | this.exportedItems = exportedItems;
29 | this.onExport = this.DefaultExport;
30 | }
31 |
32 | private InMemoryResourceExporter(ExportFunc exportFunc)
33 | {
34 | this.onExport = exportFunc;
35 | }
36 |
37 | internal delegate ExportResult ExportFunc(in Batch batch);
38 |
39 | public override ExportResult Export(in Batch batch)
40 | {
41 | if (this.disposed)
42 | {
43 | // Note: In-memory exporter is designed for testing purposes so this error is strategic to surface lifecycle management bugs during development.
44 | throw new ObjectDisposedException(
45 | this.GetType().Name,
46 | $"The in-memory exporter is still being invoked after it has been disposed. This could be the result of invalid lifecycle management of the OpenTelemetry .NET SDK. Dispose was called on the following stack trace:{Environment.NewLine}{this.disposedStackTrace}");
47 | }
48 |
49 | return this.onExport(batch);
50 | }
51 |
52 | ///
53 | protected override void Dispose(bool disposing)
54 | {
55 | if (!this.disposed)
56 | {
57 | this.disposedStackTrace = Environment.StackTrace;
58 | this.disposed = true;
59 | }
60 |
61 | base.Dispose(disposing);
62 | }
63 |
64 | private ExportResult DefaultExport(in Batch batch)
65 | {
66 | if (this.exportedItems == null)
67 | {
68 | return ExportResult.Failure;
69 | }
70 |
71 | foreach (var data in batch)
72 | {
73 | this.exportedItems.Add((data, this.ParentProvider.GetResource()));
74 | }
75 |
76 | return ExportResult.Success;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/tests/Grafana.OpenTelemetry.Tests/InstrumentationTest.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using Xunit;
10 |
11 | namespace Grafana.OpenTelemetry.Tests
12 | {
13 | public class InstrumentationTest
14 | {
15 | [Fact]
16 | public void EnumMatchesInitializers()
17 | {
18 | var expected = new HashSet((Instrumentation[])Enum.GetValues(typeof(Instrumentation)));
19 | #if !NETFRAMEWORK
20 | expected.Remove(Instrumentation.AspNet);
21 | expected.Remove(Instrumentation.Owin);
22 | #endif
23 | var actual = new HashSet(InstrumentationInitializer.Initializers.Select(x => x.Id));
24 | Assert.Equivalent(expected, actual, strict: true);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Grafana.OpenTelemetry.Tests/MeterProviderExtensionsTest.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using OpenTelemetry;
7 | using OpenTelemetry.Metrics;
8 | using Xunit;
9 |
10 | namespace Grafana.OpenTelemetry.Tests
11 | {
12 | public class MeterProviderExtensionsTest
13 | {
14 | [Fact]
15 | public void EnableDefaultInstrumentations()
16 | {
17 | Sdk
18 | .CreateMeterProviderBuilder()
19 | .UseGrafana()
20 | .Build();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tests/Grafana.OpenTelemetry.Tests/OpenTelemetryLoggerOptionsExtensionsTest.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using Microsoft.Extensions.Logging;
7 | using Xunit;
8 |
9 | namespace Grafana.OpenTelemetry.Tests
10 | {
11 | public class OpenTelemetryLoggerOptionsExtensionsTest
12 | {
13 | [Fact]
14 | public void BuildDefault()
15 | {
16 | var loggerFactory = LoggerFactory.Create(builder =>
17 | {
18 | builder.AddOpenTelemetry(logging =>
19 | {
20 | logging.UseGrafana();
21 | });
22 | });
23 |
24 | var logger = loggerFactory.CreateLogger();
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Grafana.OpenTelemetry.Tests/ReflectionHelperTest.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using Xunit;
8 |
9 | namespace Grafana.OpenTelemetry.Tests
10 | {
11 | public class ReflectionHelperTest
12 | {
13 | internal static int Counter = 0;
14 |
15 | #pragma warning disable xUnit1013 // Allow public method that's not a [Theory]
16 | public static void Increment(int increment)
17 | {
18 | Counter += increment;
19 | }
20 | #pragma warning restore xUnit1013 // Allow public method that's not a [Theory]
21 |
22 | [Fact]
23 | public void CallStaticMethod()
24 | {
25 | ReflectionHelper.CallStaticMethod(
26 | typeof(ReflectionHelperTest).Assembly.GetName().Name,
27 | "Grafana.OpenTelemetry.Tests.ReflectionHelperTest",
28 | "Increment",
29 | new object[] { 4 });
30 |
31 | Assert.Equal(4, Counter);
32 | }
33 |
34 | [Fact]
35 | public void CallStaticMethodThrow()
36 | {
37 | Assert.Throws(() =>
38 | {
39 | ReflectionHelper.CallStaticMethod(
40 | typeof(ReflectionHelperTest).Assembly.GetName().Name,
41 | "Not-exist",
42 | "Not-exist",
43 | new object[] { 4 });
44 | });
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/Grafana.OpenTelemetry.Tests/ResourceBuilderExtensionTest.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System.Linq;
7 | using OpenTelemetry.Resources;
8 | using Xunit;
9 |
10 | namespace Grafana.OpenTelemetry.Tests
11 | {
12 | public class ResourceBuilderExtensionTest
13 | {
14 | [Fact]
15 | public void StableServiceInstanceId()
16 | {
17 | var resource1 = ResourceBuilder
18 | .CreateEmpty()
19 | .AddGrafanaResource(new GrafanaOpenTelemetrySettings())
20 | .Build()
21 | .Attributes
22 | .ToDictionary(x => x.Key, x => x.Value);
23 | var resource2 = ResourceBuilder
24 | .CreateEmpty()
25 | .AddGrafanaResource(new GrafanaOpenTelemetrySettings())
26 | .Build()
27 | .Attributes
28 | .ToDictionary(x => x.Key, x => x.Value);
29 |
30 | Assert.NotNull(resource1["service.instance.id"]);
31 | Assert.NotNull(resource2["service.instance.id"]);
32 | Assert.Equal(resource1["service.instance.id"], resource2["service.instance.id"]);
33 | }
34 |
35 | [Fact]
36 | public void OverrideServiceInstanceId()
37 | {
38 | var settings = new GrafanaOpenTelemetrySettings
39 | {
40 | ServiceInstanceId = "test-id"
41 | };
42 | var resource1 = ResourceBuilder
43 | .CreateEmpty()
44 | .AddGrafanaResource(settings)
45 | .Build()
46 | .Attributes
47 | .ToDictionary(x => x.Key, x => x.Value);
48 |
49 | Assert.NotNull(resource1["service.instance.id"]);
50 | Assert.Equal(resource1["service.instance.id"], "test-id");
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/tests/Grafana.OpenTelemetry.Tests/ResourceDetectorTest.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using Xunit;
10 |
11 | namespace Grafana.OpenTelemetry.Tests
12 | {
13 | public class ResourceDetectorTest
14 | {
15 | [Fact]
16 | public void EnumMatchesInitializers()
17 | {
18 | var expected = new HashSet((ResourceDetector[])Enum.GetValues(typeof(ResourceDetector)));
19 | #if NETSTANDARD
20 | expected.Remove(ResourceDetector.AWSEBS);
21 | expected.Remove(ResourceDetector.AWSEC2);
22 | #endif
23 | #if NETSTANDARD || NETFRAMEWORK
24 | expected.Remove(ResourceDetector.AWSECS);
25 | expected.Remove(ResourceDetector.AWSEKS);
26 | #endif
27 | #if !NET8_0_OR_GREATER
28 | expected.Remove(ResourceDetector.Container);
29 | #endif
30 | #if NETSTANDARD
31 | expected.Remove(ResourceDetector.Host);
32 | expected.Remove(ResourceDetector.OperatingSystem);
33 | expected.Remove(ResourceDetector.Process);
34 | expected.Remove(ResourceDetector.ProcessRuntime);
35 | #endif
36 | var actual = new HashSet(ResourceDetectorInitializer.Initializers.Select(x => x.Id));
37 | Assert.Equivalent(expected, actual, strict: true);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/Grafana.OpenTelemetry.Tests/TracerProviderExtensionsTest.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright Grafana Labs
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Diagnostics;
9 | using OpenTelemetry;
10 | using OpenTelemetry.Resources;
11 | using OpenTelemetry.Trace;
12 | using Xunit;
13 |
14 | namespace Grafana.OpenTelemetry.Tests
15 | {
16 | public class TracerProviderExtensionsTest
17 | {
18 | private static ActivitySource activitySource = new ActivitySource(typeof(TracerProviderExtensionsTest).Name);
19 |
20 | [Fact]
21 | public void EnableDefaultInstrumentations()
22 | {
23 | Sdk
24 | .CreateTracerProviderBuilder()
25 | .UseGrafana()
26 | .Build();
27 | }
28 |
29 | [Fact]
30 | public void StandardResourceAttributes()
31 | {
32 | var spans = new List<(Activity, Resource)>();
33 |
34 | Sdk
35 | .CreateTracerProviderBuilder()
36 | .UseGrafana()
37 | .AddProcessor(new SimpleActivityExportProcessor(new InMemoryResourceExporter(spans)))
38 | .AddSource(activitySource.Name)
39 | .Build();
40 |
41 | var span = activitySource.StartActivity("root");
42 | span.Stop();
43 | span.Dispose();
44 |
45 | var activity = Assert.Single(spans);
46 |
47 | var resourceTags = new Dictionary();
48 |
49 | foreach (var tag in activity.Item2.Attributes)
50 | {
51 | resourceTags.Add(tag.Key, tag.Value);
52 | }
53 |
54 | Assert.Equal("grafana-opentelemetry-dotnet", (string)resourceTags["telemetry.distro.name"]);
55 | Assert.NotNull(resourceTags["telemetry.distro.version"]);
56 |
57 | Assert.NotNull(resourceTags["service.name"]);
58 | Assert.NotNull(resourceTags["service.instance.id"]);
59 | Assert.NotNull(resourceTags["service.version"]);
60 |
61 | Assert.NotNull(resourceTags["deployment.environment"]);
62 |
63 | Assert.NotNull(resourceTags["process.runtime.name"]);
64 | Assert.NotNull(resourceTags["process.runtime.description"]);
65 | Assert.NotNull(resourceTags["process.runtime.version"]);
66 |
67 | Assert.NotNull(resourceTags["process.pid"]);
68 |
69 | Assert.NotNull(resourceTags["host.name"]);
70 |
71 | Assert.NotNull(resourceTags["telemetry.sdk.name"]);
72 | Assert.NotNull(resourceTags["telemetry.sdk.language"]);
73 | Assert.NotNull(resourceTags["telemetry.sdk.version"]);
74 | }
75 |
76 | [Fact]
77 | public void CustomResourceAttributes()
78 | {
79 | var spans = new List<(Activity, Resource)>();
80 |
81 | Sdk
82 | .CreateTracerProviderBuilder()
83 | .UseGrafana(settings =>
84 | {
85 | settings.ServiceName = "service-name";
86 | settings.ResourceAttributes["custom.attribute"] = "custom_value";
87 | })
88 | .AddProcessor(new SimpleActivityExportProcessor(new InMemoryResourceExporter(spans)))
89 | .AddSource(activitySource.Name)
90 | .Build();
91 |
92 | var span = activitySource.StartActivity("root");
93 | span.Stop();
94 | span.Dispose();
95 |
96 | var activity = Assert.Single(spans);
97 |
98 | var resourceTags = new Dictionary();
99 |
100 | foreach (var tag in activity.Item2.Attributes)
101 | {
102 | if (tag.Value is string val)
103 | {
104 | resourceTags.Add(tag.Key, val);
105 | }
106 | }
107 |
108 | Assert.Equal("custom_value", resourceTags["custom.attribute"]);
109 | Assert.Equal("service-name", resourceTags["service.name"]);
110 | }
111 |
112 | [Fact]
113 | public void OverrideResourceAttributes()
114 | {
115 | var spans = new List<(Activity, Resource)>();
116 |
117 | Sdk
118 | .CreateTracerProviderBuilder()
119 | .UseGrafana()
120 | .ConfigureResource(resourceBuilder =>
121 | {
122 | resourceBuilder
123 | .AddService(
124 | serviceName: "a",
125 | serviceVersion: "0",
126 | serviceInstanceId: "b");
127 | })
128 | .AddProcessor(new SimpleActivityExportProcessor(new InMemoryResourceExporter(spans)))
129 | .AddSource(activitySource.Name)
130 | .Build();
131 |
132 | var span = activitySource.StartActivity("root");
133 | span.Stop();
134 | span.Dispose();
135 |
136 | var activity = Assert.Single(spans);
137 |
138 | var resourceTags = new Dictionary();
139 |
140 | foreach (var tag in activity.Item2.Attributes)
141 | {
142 | if (tag.Value is string val)
143 | {
144 | resourceTags.Add(tag.Key, val);
145 | }
146 | }
147 |
148 | Assert.Equal("a", resourceTags["service.name"]);
149 | Assert.Equal("b", resourceTags["service.instance.id"]);
150 | Assert.Equal("0", resourceTags["service.version"]);
151 | }
152 |
153 | [Fact]
154 | public void OverrideResourceAttributesEnvironment()
155 | {
156 | Environment.SetEnvironmentVariable(GrafanaOpenTelemetrySettings.ServiceNameEnvVarName, "service-name");
157 |
158 | var spans = new List<(Activity, Resource)>();
159 |
160 | Sdk
161 | .CreateTracerProviderBuilder()
162 | .UseGrafana()
163 | .AddProcessor(new SimpleActivityExportProcessor(new InMemoryResourceExporter(spans)))
164 | .AddSource(activitySource.Name)
165 | .Build();
166 |
167 | var span = activitySource.StartActivity("root");
168 | span.Stop();
169 | span.Dispose();
170 |
171 | var activity = Assert.Single(spans);
172 |
173 | var resourceTags = new Dictionary();
174 |
175 | foreach (var tag in activity.Item2.Attributes)
176 | {
177 | if (tag.Value is string val)
178 | {
179 | resourceTags.Add(tag.Key, val);
180 | }
181 | }
182 |
183 | Assert.Equal("service-name", resourceTags["service.name"]);
184 | }
185 | }
186 | }
187 |
--------------------------------------------------------------------------------