├── OSSMETADATA ├── smoke-tests ├── collector │ ├── data-results │ │ └── .gitkeep │ └── otel-collector-config.yaml ├── docker-compose.yml ├── smoke-sdk-grpc.bats ├── smoke-sdk-http.bats └── test_helpers │ └── utilities.bash ├── .github ├── CODEOWNERS ├── workflows │ ├── apply-labels.yml │ ├── add-to-project-v2.yml │ ├── stale.yml │ └── validate-pr-title.yml ├── ISSUE_TEMPLATE │ ├── question-discussion.md │ ├── feature_request.md │ ├── security-vulnerability-report.md │ └── bug_report.md ├── release.yml ├── PULL_REQUEST_TEMPLATE.md └── dependabot.yml ├── examples ├── aspnetcore │ ├── .dockerignore │ ├── my-web-app.png │ ├── appsettings.Development.json │ ├── Dockerfile │ ├── WeatherForecast.cs │ ├── appsettings.json │ ├── aspnetcore.csproj │ ├── Properties │ │ └── launchSettings.json │ ├── README.md │ ├── Program.cs │ └── Controllers │ │ └── WeatherForecastController.cs ├── aspnetcore-fsharp │ ├── my-web-app.png │ ├── appsettings.json │ ├── aspnetcore-fsharp.fsproj │ ├── README.md │ ├── Program.fs │ └── Routing.fs ├── console │ ├── appsettings.json │ ├── console.csproj │ ├── Program.cs │ └── README.md └── aspnetcore-redis │ ├── my-web-app-with-redis.png │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── WeatherForecast.cs │ ├── aspnetcoreredis.csproj │ ├── Properties │ └── launchSettings.json │ ├── Program.cs │ ├── README.md │ └── Controllers │ └── WeatherForecastController.cs ├── honeycomb.png ├── Honeycomb.OpenTelemetry.snk.gpg ├── CONTRIBUTING.md ├── SUPPORT.md ├── CODE_OF_CONDUCT.md ├── DEVELOPMENT.md ├── Directory.build.props ├── NOTICE ├── src ├── Honeycomb.OpenTelemetry │ ├── BaggageSpanProcessor.cs │ ├── WebApplicationBuilderExtensions.cs │ ├── DeterministicSampler.cs │ ├── Honeycomb.OpenTelemetry.csproj │ ├── MeterProviderBuilderExtensions.cs │ ├── EnvironmentOptions.cs │ ├── ConsoleTraceLinkExporter.cs │ ├── ResourceBuilderExtensions.cs │ ├── TracerProviderBuilderExtensions.cs │ └── HoneycombOptions.cs ├── Honeycomb.OpenTelemetry.Instrumentation.AspNetCore │ ├── Honeycomb.OpenTelemetry.Instrumentation.AspNetCore.csproj │ └── TracerProviderBuilderExtensions.cs └── Honeycomb.OpenTelemetry.CommonInstrumentations │ ├── TracerProviderBuilderExtensions.cs │ └── Honeycomb.OpenTelemetry.CommonInstrumentations.csproj ├── test └── Honeycomb.OpenTelemetry.Tests │ ├── appsettings.test.json │ ├── Honeycomb.OpenTelemetry.Tests.csproj │ ├── HoneycombOptionsExtensionsTests.cs │ ├── EnvironmentOptionsTests.cs │ ├── DeterministicSamplerTests.cs │ └── HoneycombOptionsTests.cs ├── .vscode ├── launch.json └── tasks.json ├── RELEASING.md ├── SECURITY.md ├── Makefile ├── README.md ├── .circleci └── config.yml ├── .editorconfig ├── .gitignore ├── honeycomb-opentelemetry.sln ├── LICENSE └── CHANGELOG.md /OSSMETADATA: -------------------------------------------------------------------------------- 1 | osslifecycle=archived 2 | -------------------------------------------------------------------------------- /smoke-tests/collector/data-results/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @honeycombio/pipeline-team 2 | -------------------------------------------------------------------------------- /examples/aspnetcore/.dockerignore: -------------------------------------------------------------------------------- 1 | **/bin/ 2 | **/obj/ -------------------------------------------------------------------------------- /honeycomb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycombio/honeycomb-opentelemetry-dotnet/HEAD/honeycomb.png -------------------------------------------------------------------------------- /Honeycomb.OpenTelemetry.snk.gpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycombio/honeycomb-opentelemetry-dotnet/HEAD/Honeycomb.OpenTelemetry.snk.gpg -------------------------------------------------------------------------------- /examples/aspnetcore/my-web-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycombio/honeycomb-opentelemetry-dotnet/HEAD/examples/aspnetcore/my-web-app.png -------------------------------------------------------------------------------- /examples/aspnetcore-fsharp/my-web-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycombio/honeycomb-opentelemetry-dotnet/HEAD/examples/aspnetcore-fsharp/my-web-app.png -------------------------------------------------------------------------------- /examples/console/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Honeycomb": { 3 | "ServiceName": "my-console-app", 4 | "ApiKey": "", 5 | "Dataset": "" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/aspnetcore-redis/my-web-app-with-redis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycombio/honeycomb-opentelemetry-dotnet/HEAD/examples/aspnetcore-redis/my-web-app-with-redis.png -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guide 2 | 3 | Please see our [general guide for OSS lifecycle and practices.](https://github.com/honeycombio/home/blob/main/honeycomb-oss-lifecycle-and-practices.md) 4 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # How to Get Help 2 | 3 | This project uses GitHub issues to track bugs, feature requests, and questions about using the project. Please search for existing issues before filing a new one. 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This project has adopted the Honeycomb User Community Code of Conduct to clarify expected behavior in our community. 4 | 5 | https://www.honeycomb.io/honeycomb-user-community-code-of-conduct/ -------------------------------------------------------------------------------- /examples/aspnetcore/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/aspnetcore-redis/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.github/workflows/apply-labels.yml: -------------------------------------------------------------------------------- 1 | name: Apply project labels 2 | on: [issues, pull_request_target, label] 3 | jobs: 4 | apply-labels: 5 | runs-on: ubuntu-latest 6 | name: Apply common project labels 7 | steps: 8 | - uses: honeycombio/oss-management-actions/labels@v1 9 | with: 10 | github-token: ${{ secrets.GITHUB_TOKEN }} 11 | -------------------------------------------------------------------------------- /examples/aspnetcore/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build 2 | WORKDIR /app 3 | COPY . ./ 4 | RUN dotnet publish -c release -f net6.0 -o /out 5 | 6 | # final stage/image 7 | FROM mcr.microsoft.com/dotnet/sdk:6.0 8 | WORKDIR /app 9 | COPY --from=build /out ./ 10 | 11 | ENV ASPNETCORE_URLS=http://+:5001 12 | EXPOSE 5001 13 | ENTRYPOINT ["dotnet", "aspnetcore.dll"] -------------------------------------------------------------------------------- /examples/aspnetcore/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace aspnetcore 4 | { 5 | public class WeatherForecast 6 | { 7 | public DateTime Date { get; set; } 8 | 9 | public int TemperatureC { get; set; } 10 | 11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 12 | 13 | public string Summary { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/aspnetcore-redis/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | "Honeycomb": { 11 | "ServiceName": "aspnetcore-redis-example", 12 | "ApiKey": "{apikey}", 13 | "Debug": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/aspnetcore-redis/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace aspnetcoreredis 4 | { 5 | public class WeatherForecast 6 | { 7 | public DateTime Date { get; set; } 8 | 9 | public int TemperatureC { get; set; } 10 | 11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 12 | 13 | public string Summary { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/aspnetcore/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | "Honeycomb": { 11 | "ServiceName": "aspnetcore-example", 12 | "ApiKey": "{apikey}", 13 | "MetricsDataset": "aspnetcore-example-metrics", 14 | "Debug": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question-discussion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question/Discussion 3 | about: General question about how things work or a discussion 4 | title: '' 5 | labels: 'type: discussion' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 15 | -------------------------------------------------------------------------------- /examples/aspnetcore-fsharp/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | "Honeycomb": { 11 | "ServiceName": "aspnetcore-fsharp-example", 12 | "ApiKey": "{apikey}", 13 | "MetricsDataset": "aspnetcore-fsharp-example-metrics", 14 | "Debug": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.github/workflows/add-to-project-v2.yml: -------------------------------------------------------------------------------- 1 | name: Add to project 2 | on: 3 | issues: 4 | types: [opened] 5 | pull_request_target: 6 | types: [opened] 7 | jobs: 8 | add-to-project: 9 | runs-on: ubuntu-latest 10 | name: Add issues and PRs to project 11 | steps: 12 | - uses: actions/add-to-project@main 13 | with: 14 | project-url: https://github.com/orgs/honeycombio/projects/27 15 | github-token: ${{ secrets.GHPROJECTS_TOKEN }} 16 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | ## Building & Testing 2 | 3 | ### Using local packages with other projects 4 | 5 | To share this project with another local project you will need to build and store the distributable nuget package in a local nuget source directory. The following makefile target creates a local nuget source, builds and publishes the packages. 6 | 7 | `make publish_local` 8 | 9 | After the command has run, you can add the package to another project using the normal add package command: 10 | 11 | `dotnet add package Honeycomb.OpenTelemetry` 12 | -------------------------------------------------------------------------------- /Directory.build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | true 5 | true 6 | 7 | 8 | 9 | true 10 | $(MSBuildThisFileDirectory)Honeycomb.OpenTelemetry.snk 11 | 12 | -------------------------------------------------------------------------------- /examples/console/console.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | # .github/release.yml 2 | 3 | changelog: 4 | exclude: 5 | labels: 6 | - no-changelog 7 | categories: 8 | - title: 💥 Breaking Changes 💥 9 | labels: 10 | - "version: bump major" 11 | - breaking-change 12 | - title: 💡 Enhancements 13 | labels: 14 | - "type: enhancement" 15 | - title: 🐛 Fixes 16 | labels: 17 | - "type: bug" 18 | - title: 🛠 Maintenance 19 | labels: 20 | - "type: maintenance" 21 | - "type: dependencies" 22 | - "type: documentation" 23 | - title: 🤷 Other Changes 24 | labels: 25 | - "*" 26 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-Present Honeycomb, Hound Technology, Inc. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: 'type: enhancement' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 15 | 16 | **Is your feature request related to a problem? Please describe.** 17 | 18 | 19 | **Describe the solution you'd like** 20 | 21 | 22 | **Describe alternatives you've considered** 23 | 24 | 25 | **Additional context** 26 | -------------------------------------------------------------------------------- /smoke-tests/collector/otel-collector-config.yaml: -------------------------------------------------------------------------------- 1 | receivers: 2 | otlp: 3 | protocols: 4 | grpc: 5 | http: 6 | 7 | processors: 8 | batch: 9 | 10 | exporters: 11 | file: 12 | path: /var/lib/data.json 13 | logging: 14 | loglevel: debug 15 | 16 | service: 17 | pipelines: 18 | traces: 19 | receivers: [otlp] 20 | processors: [batch] 21 | exporters: [file, logging] 22 | metrics: 23 | receivers: [otlp] 24 | processors: [batch] 25 | exporters: [file, logging] 26 | logs: 27 | receivers: [otlp] 28 | processors: [batch] 29 | # exporters: [file, logging] 30 | exporters: [logging] 31 | -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry/BaggageSpanProcessor.cs: -------------------------------------------------------------------------------- 1 | using OpenTelemetry; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | 5 | namespace Honeycomb.OpenTelemetry 6 | { 7 | /// 8 | /// Span processor that adds fields to every new span 9 | /// 10 | public class BaggageSpanProcessor : BaseProcessor 11 | { 12 | /// 13 | public override void OnStart(Activity activity) 14 | { 15 | foreach (var entry in Baggage.Current) 16 | { 17 | activity.SetTag(entry.Key, entry.Value); 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/security-vulnerability-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Security vulnerability report 3 | about: Let us know if you discover a security vulnerability 4 | title: '' 5 | labels: 'type: security' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 15 | **Versions** 16 | 17 | - .NET runtime & version (eg .NET Core, .NET Framework): 18 | - Honeycomb OpenTelemetry Distribution: 19 | 20 | **Description** 21 | 22 | (Please include any relevant CVE advisory links) 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 12 | 13 | ## Which problem is this PR solving? 14 | 15 | - 16 | 17 | ## Short description of the changes 18 | 19 | - 20 | 21 | -------------------------------------------------------------------------------- /test/Honeycomb.OpenTelemetry.Tests/appsettings.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "Honeycomb": { 3 | "ApiKey": "my-apikey", 4 | "TracesApiKey": "my-traces-apikey", 5 | "MetricsApiKey": "my-metrics-apikey", 6 | "Dataset": "my-dataset", 7 | "TracesDataset": "my-traces-dataset", 8 | "MetricsDataset": "my-metrics-dataset", 9 | "SampleRate": 5, 10 | "Endpoint": "my-endpoint", 11 | "TracesEndpoint": "my-traces-endpoint", 12 | "MetricsEndpoint": "my-metrics-endpoint", 13 | "MeterNames": [ 14 | "meter1", 15 | "meter2" 16 | ], 17 | "ServiceName": "my-service", 18 | "ServiceVersion": "my-version", 19 | "EnableLocalVisualizations": true, 20 | "Debug": true 21 | } 22 | } -------------------------------------------------------------------------------- /examples/aspnetcore/aspnetcore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | false 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/aspnetcore-redis/aspnetcoreredis.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | false 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Let us know if something is not working as expected 4 | title: '' 5 | labels: 'type: bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 17 | 18 | **Versions** 19 | 20 | - .NET runtime & version (eg .NET Core, .NET Framework): 21 | - Honeycomb OpenTelemetry Distribution: 22 | 23 | **Steps to reproduce** 24 | 25 | 1. 26 | 27 | **Additional context** 28 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "nuget" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | labels: 13 | - "type: dependencies" 14 | reviewers: 15 | - "honeycombio/pipeline-team" 16 | commit-message: 17 | prefix: "maint" 18 | include: "scope" 19 | ignore: 20 | # We don't target .NET 7 yet and this breaks LTS EFCore 21 | - dependency-name: "Npgsql.OpenTelemetry" 22 | update-types: ["version-update:semver-major"] 23 | -------------------------------------------------------------------------------- /examples/aspnetcore-fsharp/aspnetcore-fsharp.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | net6.0 6 | aspnetcore_fsharp 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/aspnetcore/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:33487", 8 | "sslPort": 44351 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "swagger", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "aspnetcore": { 21 | "commandName": "Project", 22 | "dotnetRunMessages": "true", 23 | "launchBrowser": true, 24 | "launchUrl": "swagger", 25 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/aspnetcore-redis/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:33487", 8 | "sslPort": 44351 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "swagger", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "aspnetcoreredis": { 21 | "commandName": "Project", 22 | "dotnetRunMessages": "true", 23 | "launchBrowser": true, 24 | "launchUrl": "swagger", 25 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/aspnetcore-redis/Program.cs: -------------------------------------------------------------------------------- 1 | using OpenTelemetry.Trace; 2 | using StackExchange.Redis; 3 | 4 | var builder = WebApplication.CreateBuilder(args); 5 | builder.Services.AddControllers(); 6 | 7 | var redis = ConnectionMultiplexer.Connect( 8 | new ConfigurationOptions 9 | { 10 | EndPoints = { "localhost:6379" }, 11 | AbortOnConnectFail = false, // allow for reconnects if redis is not available 12 | } 13 | ); 14 | builder.Services.AddSingleton(redis); 15 | 16 | var honeycombOptions = builder.Configuration.GetHoneycombOptions(); 17 | 18 | builder.Services.AddOpenTelemetry().WithTracing(otelBuilder => 19 | otelBuilder 20 | .AddHoneycomb(honeycombOptions) 21 | .AddAspNetCoreInstrumentationWithBaggage() 22 | .AddRedisInstrumentation(redis) 23 | ); 24 | 25 | builder.Services.AddSingleton(TracerProvider.Default.GetTracer(honeycombOptions.ServiceName)); 26 | 27 | var app = builder.Build(); 28 | app.MapControllers(); 29 | await app.RunAsync(); -------------------------------------------------------------------------------- /examples/aspnetcore/README.md: -------------------------------------------------------------------------------- 1 | # Honeycomb.OpenTelemetry ASP.NET Core web example 2 | 3 | This example shows how to use the Honeycomb OpenTelemetry distro with a .NET Core web application. 4 | 5 | ## Using the Example 6 | 7 | - First, set your Honeycomb API key and a service name in the [appsettings.json](appsettings.json) configuration file. 8 | - If you are using Honeycomb Classic, add `TracesDataset`. 9 | - If you are sending Metrics, add `MetricsDataset`. 10 | 11 | Run `dotnet run` to start the app. 12 | 13 | To generate telemetry, navigate to `localhost:5001/weatherforecast`. 14 | 15 | ![my-web-app](./my-web-app.png) 16 | 17 | As part of the configuration process, an instance of the Tracer is registed in the services Dependency Injection map that can be be injected into controllers and used to add additional context and create additional spans. 18 | 19 | See [Startup.cs](Startup.cs) for an example of how the `AddHoneycomb` method is called. 20 | 21 | See [WeatherForecastController](Controllers/WeatherForecastController.cs) for an example app being instrumented. 22 | -------------------------------------------------------------------------------- /examples/aspnetcore/Program.cs: -------------------------------------------------------------------------------- 1 | using OpenTelemetry.Metrics; 2 | using OpenTelemetry.Trace; 3 | 4 | using System.Diagnostics.Metrics; 5 | 6 | var builder = WebApplication.CreateBuilder(args); 7 | builder.Services.AddControllers(); 8 | 9 | var honeycombOptions = builder.Configuration.GetHoneycombOptions(); 10 | 11 | // Setup OpenTelemetry Tracing 12 | builder.Services.AddOpenTelemetry().WithTracing(otelBuilder => 13 | otelBuilder 14 | .AddHoneycomb(honeycombOptions) 15 | .AddAspNetCoreInstrumentationWithBaggage() 16 | ); 17 | 18 | // Register Tracer so it can be injected into other components (eg Controllers) 19 | builder.Services.AddSingleton(TracerProvider.Default.GetTracer(honeycombOptions.ServiceName)); 20 | 21 | // Setup OpenTelemetry Metrics 22 | builder.Services.AddOpenTelemetry().WithMetrics(otelBuilder => 23 | otelBuilder.AddHoneycomb(honeycombOptions) 24 | ); 25 | 26 | // Register Meter so it can be injected into other components (eg controllers) 27 | builder.Services.AddSingleton(new Meter(honeycombOptions.MetricsDataset)); 28 | 29 | var app = builder.Build(); 30 | 31 | app.MapControllers(); 32 | await app.RunAsync(); -------------------------------------------------------------------------------- /examples/aspnetcore-redis/README.md: -------------------------------------------------------------------------------- 1 | # Honeycomb.OpenTelemetry ASP.NET Core with Redis web example 2 | 3 | This example shows how to use the Honeycomb OpenTelemetry distro with a .NET Core web application. 4 | This example also includes automatic instrumentation of Redis. 5 | 6 | ## Using the Example 7 | 8 | - Install Redis and start the service, for example `brew services start redis` 9 | - Set your Honeycomb API key and a service name in the [appsettings.json](appsettings.json) configuration file. 10 | - If you are using Honeycomb Classic, add `TracesDataset`. 11 | 12 | Run `dotnet run` to start the app. 13 | 14 | To generate telemetry, navigate to `localhost:5001/weatherforecast`. 15 | 16 | ![my-web-app-with-redis](./my-web-app-with-redis.png) 17 | 18 | As part of the configuration process, an instance of the Tracer is registed in the services Dependency Injection map that can be be injected into controllers and used to add additional context and create additional spans. 19 | 20 | See [Startup.cs](Startup.cs) for an example of how the `AddHoneycomb` method is called. 21 | 22 | See [WeatherForecastController](Controllers/WeatherForecastController.cs) for an example app being instrumented. 23 | -------------------------------------------------------------------------------- /examples/aspnetcore-fsharp/README.md: -------------------------------------------------------------------------------- 1 | # Honeycomb.OpenTelemetry ASP.NET Core web example 2 | 3 | This example shows how to use the Honeycomb OpenTelemetry distro with a .NET Core web application. 4 | 5 | ## Using the Example 6 | 7 | - First, set your Honeycomb API key and a service name in the [appsettings.json](appsettings.json) configuration file. 8 | - If you are using Honeycomb Classic, add `TracesDataset`. 9 | - If you are sending Metrics, add `MetricsDataset`. 10 | 11 | Run `dotnet run` to start the app. 12 | 13 | To generate telemetry, navigate to `localhost:5001/weatherforecast`. 14 | 15 | ![my-web-app](./my-web-app.png) 16 | 17 | As part of the configuration process, an instance of the Tracer is registed in the services Dependency Injection map that can be be injected into controllers and used to add additional context and create additional spans. 18 | 19 | See [Program.fs](https://github.com/honeycombio/honeycomb-opentelemetry-dotnet/blob/main/examples/aspnetcore-fsharp/Program.fs#L22) for an example of how the `AddHoneycomb` method is called. 20 | 21 | See [Routing.fs](https://github.com/honeycombio/honeycomb-opentelemetry-dotnet/blob/main/examples/aspnetcore-fsharp/Routing.fs#L38) for an example app being instrumented. 22 | -------------------------------------------------------------------------------- /smoke-tests/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.0' 2 | 3 | x-env-base: &env_base 4 | HONEYCOMB_API_KEY: bogus_key 5 | HONEYCOMB_DATASET: bogus_dataset 6 | HONEYCOMB_METRICS_DATASET: bogus_dataset 7 | OTEL_SERVICE_NAME: "aspnetcore-example" 8 | DEBUG: "true" 9 | 10 | x-app-base: &app_base 11 | build: 12 | context: ../ 13 | dockerfile: ./examples/aspnetcore/Dockerfile 14 | image: honeycomb/aspnetcore 15 | depends_on: 16 | - collector 17 | 18 | services: 19 | collector: 20 | image: otel/opentelemetry-collector:0.52.0 21 | command: ["--config=/etc/otel-collector-config.yaml"] 22 | volumes: 23 | - "./collector/otel-collector-config.yaml:/etc/otel-collector-config.yaml" 24 | - "./collector:/var/lib" 25 | 26 | app-sdk-http: 27 | <<: *app_base 28 | environment: 29 | <<: *env_base 30 | HONEYCOMB_API_ENDPOINT: http://collector:4318 31 | OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf 32 | ports: 33 | - "127.0.0.1:5001:5001" 34 | 35 | app-sdk-grpc: 36 | <<: *app_base 37 | environment: 38 | <<: *env_base 39 | HONEYCOMB_API_ENDPOINT: http://collector:4317 40 | OTEL_EXPORTER_OTLP_PROTOCOL: grpc 41 | ports: 42 | - "127.0.0.1:5001:5001" -------------------------------------------------------------------------------- /smoke-tests/smoke-sdk-grpc.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helpers/utilities 4 | 5 | CONTAINER_NAME="app-sdk-grpc" 6 | OTEL_SERVICE_NAME="aspnetcore-example" 7 | METRICS_DATASET="bogus_dataset" 8 | 9 | setup_file() { 10 | echo "# 🚧" >&3 11 | docker-compose up --build --detach collector ${CONTAINER_NAME} 12 | wait_for_ready_app ${CONTAINER_NAME} 13 | curl --silent "http://localhost:5001/weatherforecast" 14 | wait_for_traces 15 | wait_for_metrics 15 16 | } 17 | 18 | teardown_file() { 19 | cp collector/data.json collector/data-results/data-${CONTAINER_NAME}.json 20 | docker-compose stop ${CONTAINER_NAME} 21 | docker-compose restart collector 22 | wait_for_flush 23 | } 24 | 25 | # TESTS 26 | 27 | @test "Manual instrumentation produces span with name of span" { 28 | result=$(span_names_for ${OTEL_SERVICE_NAME}) 29 | assert_equal "$result" '"sleep"' 30 | } 31 | 32 | @test "Manual instrumentation adds custom attribute" { 33 | result=$(span_attributes_for ${OTEL_SERVICE_NAME} | jq "select(.key == \"delay_ms\").value.intValue") 34 | assert_equal "$result" '"100"' 35 | } 36 | 37 | @test "Manual instrumentation produces metrics" { 38 | result=$(metric_names_for ${METRICS_DATASET}) 39 | assert_equal "$result" '"sheep"' 40 | } -------------------------------------------------------------------------------- /smoke-tests/smoke-sdk-http.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helpers/utilities 4 | 5 | CONTAINER_NAME="app-sdk-http" 6 | OTEL_SERVICE_NAME="aspnetcore-example" 7 | METRICS_DATASET="bogus_dataset" 8 | 9 | setup_file() { 10 | echo "# 🚧" >&3 11 | docker-compose up --build --detach collector ${CONTAINER_NAME} 12 | wait_for_ready_app ${CONTAINER_NAME} 13 | curl --silent "http://localhost:5001/weatherforecast" 14 | wait_for_traces 15 | wait_for_metrics 15 16 | } 17 | 18 | teardown_file() { 19 | cp collector/data.json collector/data-results/data-${CONTAINER_NAME}.json 20 | docker-compose stop ${CONTAINER_NAME} 21 | docker-compose restart collector 22 | wait_for_flush 23 | } 24 | 25 | # TESTS 26 | 27 | @test "Manual instrumentation produces span with name of span" { 28 | result=$(span_names_for ${OTEL_SERVICE_NAME}) 29 | assert_equal "$result" '"sleep"' 30 | } 31 | 32 | @test "Manual instrumentation adds custom attribute" { 33 | result=$(span_attributes_for ${OTEL_SERVICE_NAME} | jq "select(.key == \"delay_ms\").value.intValue") 34 | assert_equal "$result" '"100"' 35 | } 36 | 37 | @test "Manual instrumentation produces metrics" { 38 | result=$(metric_names_for ${METRICS_DATASET}) 39 | assert_equal "$result" '"sheep"' 40 | } 41 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | // Use IntelliSense to find out which attributes exist for C# debugging 6 | // Use hover for the description of the existing attributes 7 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 8 | "name": ".NET Core Launch (console)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/test/Honeycomb.OpenTelemetry.Tests/bin/Debug/netcoreapp3.1/Honeycomb.OpenTelemetry.Tests.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}/test/Honeycomb.OpenTelemetry.Tests", 16 | // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console 17 | "console": "internalConsole", 18 | "stopAtEntry": false 19 | }, 20 | { 21 | "name": ".NET Core Attach", 22 | "type": "coreclr", 23 | "request": "attach" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /test/Honeycomb.OpenTelemetry.Tests/Honeycomb.OpenTelemetry.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | all 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | # Releasing Process 2 | 3 | - Update `CHANGELOG.md` with the changes since the last release. Consider automating with a command such as these two: 4 | - `git log $(git describe --tags --abbrev=0)..HEAD --no-merges --oneline > new-in-this-release.log` 5 | - `git log --pretty='%C(green)%d%Creset- %s | [%an](https://github.com/)'` 6 | - Update VersionPrefix (and VersionSuffix if necessary) in the `*.csproj` files 7 | - If updating the OTel SDK, update the OTLP version in `HoneycombOptions.cs` 8 | - If updating the OTel SDK, update the OTel version in `README.md` 9 | - Commit changes, push, and open a release preparation pull request for review. 10 | - Once the pull request is merged, fetch the updated `main` branch. 11 | - Apply a tag for the new version on the merged commit (e.g. `git tag -a v1.3.0 -m "v1.3.0"`) 12 | - Note: We only tag the main package (even if changes were made to the instr packages) so the pipeline doesn't double-run 13 | - Push the tag upstream (this will kick off the release pipeline in CI) e.g. `git push origin v1.3.0` 14 | - Ensure that there is a draft GitHub release created as part of CI publish steps (this will also publish to Nuget). 15 | - Click "generate release notes" in Github for full changelog notes and any new contributors 16 | - Publish the Github draft release - if it is a prerelease (e.g. beta) click the prerelease checkbox. 17 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | on: 3 | schedule: 4 | - cron: '30 1 * * *' 5 | 6 | jobs: 7 | stale: 8 | name: 'Close stale issues and PRs' 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | 14 | steps: 15 | - uses: actions/stale@v4 16 | with: 17 | start-date: '2021-09-01T00:00:00Z' 18 | stale-issue-message: 'Marking this issue as stale because it has been open 14 days with no activity. Please add a comment if this is still an ongoing issue; otherwise this issue will be automatically closed in 7 days.' 19 | stale-pr-message: 'Marking this PR as stale because it has been open 30 days with no activity. Please add a comment if this PR is still relevant; otherwise this PR will be automatically closed in 7 days.' 20 | close-issue-message: 'Closing this issue due to inactivity. Please see our [Honeycomb OSS Lifecyle and Practices](https://github.com/honeycombio/home/blob/main/honeycomb-oss-lifecycle-and-practices.md).' 21 | close-pr-message: 'Closing this PR due to inactivity. Please see our [Honeycomb OSS Lifecyle and Practices](https://github.com/honeycombio/home/blob/main/honeycomb-oss-lifecycle-and-practices.md).' 22 | days-before-issue-stale: 14 23 | days-before-pr-stale: 30 24 | days-before-issue-close: 7 25 | days-before-pr-close: 7 26 | any-of-labels: 'status: info needed,status: revision needed' 27 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | This security policy applies to public projects under the [honeycombio organization][gh-organization] on GitHub. 4 | For security reports involving the services provided at `(ui|ui-eu|api|api-eu).honeycomb.io`, refer to the [Honeycomb Bug Bounty Program][bugbounty] for scope, expectations, and reporting procedures. 5 | 6 | ## Security/Bugfix Versions 7 | 8 | Security and bug fixes are generally provided only for the last minor version. 9 | Fixes are released either as part of the next minor version or as an on-demand patch version. 10 | 11 | Security fixes are given priority and might be enough to cause a new version to be released. 12 | 13 | ## Reporting a Vulnerability 14 | 15 | We encourage responsible disclosure of security vulnerabilities. 16 | If you find something suspicious, we encourage and appreciate your report! 17 | 18 | ### Ways to report 19 | 20 | In order for the vulnerability reports to reach maintainers as soon as possible, the preferred way is to use the "Report a vulnerability" button under the "Security" tab of the associated GitHub project. 21 | This creates a private communication channel between the reporter and the maintainers. 22 | 23 | If you are absolutely unable to or have strong reasons not to use GitHub's vulnerability reporting workflow, please reach out to the Honeycomb security team at [security@honeycomb.io](mailto:security@honeycomb.io). 24 | 25 | [gh-organization]: https://github.com/honeycombio 26 | [bugbounty]: https://www.honeycomb.io/bugbountyprogram 27 | -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry/WebApplicationBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Honeycomb.OpenTelemetry; 2 | 3 | namespace Microsoft.Extensions.Configuration 4 | { 5 | /// 6 | /// Extension methods for to help configure Honeycomb with OpenTelemetry. 7 | /// 8 | public static class ConfigurationManagerExtensions 9 | { 10 | /// 11 | /// Attempts to retrieve an instance of used to configure the OpenTelemetry SDK. 12 | /// 13 | public static HoneycombOptions GetHoneycombOptions(this ConfigurationManager builder) 14 | { 15 | return builder 16 | .GetSection(HoneycombOptions.ConfigSectionName) 17 | .Get(); 18 | } 19 | } 20 | 21 | /// 22 | /// Extension methods for to help configure Honeycomb with OpenTelemetry. 23 | /// 24 | public static class ConfigurationInterfaceExtensions 25 | { 26 | /// 27 | /// Attempts to retrieve an instance of used to configure the OpenTelemetry SDK. 28 | /// 29 | public static HoneycombOptions GetHoneycombOptions(this IConfiguration configuration) 30 | { 31 | return configuration 32 | .GetSection(HoneycombOptions.ConfigSectionName) 33 | .Get(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/test/Honeycomb.OpenTelemetry.Tests/Honeycomb.OpenTelemetry.Tests.csproj", 11 | "/property:GenerateFullPaths=true", 12 | "/consoleloggerparameters:NoSummary" 13 | ], 14 | "problemMatcher": "$msCompile" 15 | }, 16 | { 17 | "label": "publish", 18 | "command": "dotnet", 19 | "type": "process", 20 | "args": [ 21 | "publish", 22 | "${workspaceFolder}/test/Honeycomb.OpenTelemetry.Tests/Honeycomb.OpenTelemetry.Tests.csproj", 23 | "/property:GenerateFullPaths=true", 24 | "/consoleloggerparameters:NoSummary" 25 | ], 26 | "problemMatcher": "$msCompile" 27 | }, 28 | { 29 | "label": "watch", 30 | "command": "dotnet", 31 | "type": "process", 32 | "args": [ 33 | "watch", 34 | "run", 35 | "${workspaceFolder}/test/Honeycomb.OpenTelemetry.Tests/Honeycomb.OpenTelemetry.Tests.csproj", 36 | "/property:GenerateFullPaths=true", 37 | "/consoleloggerparameters:NoSummary" 38 | ], 39 | "problemMatcher": "$msCompile" 40 | } 41 | ] 42 | } -------------------------------------------------------------------------------- /examples/aspnetcore-fsharp/Program.fs: -------------------------------------------------------------------------------- 1 | open System 2 | open System.Diagnostics.Metrics 3 | 4 | open Microsoft.AspNetCore 5 | open Microsoft.AspNetCore.Builder 6 | open Microsoft.Extensions.DependencyInjection 7 | open Microsoft.Extensions.Hosting 8 | open Microsoft.Extensions.Configuration 9 | 10 | open Giraffe 11 | open Giraffe.EndpointRouting 12 | 13 | open OpenTelemetry 14 | open OpenTelemetry.Trace 15 | open OpenTelemetry.Metrics 16 | open Honeycomb.OpenTelemetry 17 | 18 | let configureServices (services: IServiceCollection) (honeycombOptions: HoneycombOptions) = 19 | services 20 | .AddRouting() 21 | .AddGiraffe() 22 | .AddOpenTelemetry() 23 | .WithTracing(fun otelBuilder -> 24 | otelBuilder 25 | .AddHoneycomb(honeycombOptions) 26 | .AddAspNetCoreInstrumentationWithBaggage() 27 | |> ignore) 28 | .WithMetrics(fun otelBuilder -> 29 | otelBuilder.AddHoneycomb(honeycombOptions) 30 | |> ignore) 31 | |> ignore 32 | 33 | let configureApp (appBuilder: IApplicationBuilder) (honeycombOptions: HoneycombOptions) = 34 | let tracer = TracerProvider.Default.GetTracer(honeycombOptions.ServiceName) 35 | let meter = new Meter(honeycombOptions.MetricsDataset) 36 | appBuilder 37 | .UseRouting() 38 | .UseGiraffe(Routing.endpoints tracer meter) 39 | |> ignore 40 | 41 | let args = Environment.GetCommandLineArgs() 42 | let builder = WebApplication.CreateBuilder(args) 43 | let honeycombOptions = builder.Configuration.GetHoneycombOptions(); 44 | 45 | configureServices builder.Services honeycombOptions 46 | 47 | let app = builder.Build() 48 | configureApp app honeycombOptions 49 | 50 | app.Run() -------------------------------------------------------------------------------- /examples/aspnetcore-fsharp/Routing.fs: -------------------------------------------------------------------------------- 1 | module Routing 2 | 3 | open System 4 | open System.Diagnostics.Metrics 5 | 6 | open Microsoft.AspNetCore.Http 7 | 8 | open Giraffe 9 | open Giraffe.EndpointRouting 10 | open OpenTelemetry.Trace 11 | 12 | type WeatherForecast = 13 | { Date: DateTime 14 | TemperatureC: int 15 | Summary: string } 16 | 17 | let private createForecast index (rng: Random) (weatherSummaries: string[]) = 18 | { Date = DateTime.Now.AddDays(index) 19 | TemperatureC = rng.Next(-20,55) 20 | Summary = weatherSummaries[rng.Next(weatherSummaries.Length)] } 21 | 22 | let weatherSummaries = 23 | [| 24 | "Freezing" 25 | "Bracing" 26 | "Chilly" 27 | "Cool" 28 | "Mild" 29 | "Warm" 30 | "Balmy" 31 | "Hot" 32 | "Sweltering" 33 | "Scorching" 34 | |] 35 | 36 | let private weatherForecastHandler (tracer: Tracer) (sheepCounter: Counter) = 37 | fun (next : HttpFunc) (ctx : HttpContext) -> 38 | use forecastSpan = tracer.StartActiveSpan("app.weatherForecast") 39 | 40 | let rng = Random() 41 | let forecast = 42 | [| 43 | for index in 0..4 -> 44 | createForecast index rng weatherSummaries 45 | |] 46 | 47 | forecastSpan.SetAttribute("app.weatherForecast.days", forecast.Length) |> ignore 48 | 49 | sheepCounter.Add(1) 50 | 51 | json forecast next ctx 52 | 53 | let endpoints (tracer: Tracer) (meter: Meter) = 54 | let sheepCounter = meter.CreateCounter("app.sheep") 55 | [ 56 | GET [ 57 | route "/" (text "Hello World") 58 | route "/weatherforecast" (weatherForecastHandler tracer sheepCounter) 59 | ] 60 | ] -------------------------------------------------------------------------------- /examples/aspnetcore/Controllers/WeatherForecastController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using OpenTelemetry.Trace; 3 | using System.Diagnostics.Metrics; 4 | 5 | namespace aspnetcore.Controllers 6 | { 7 | [ApiController] 8 | [Route("[controller]")] 9 | public class WeatherForecastController : ControllerBase 10 | { 11 | private static readonly string[] Summaries = new[] 12 | { 13 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 14 | }; 15 | 16 | private readonly ILogger _logger; 17 | private readonly Tracer _tracer; 18 | private readonly Counter _counter; 19 | 20 | public WeatherForecastController(ILogger logger, Tracer tracer, Meter meter) 21 | { 22 | _logger = logger; 23 | _tracer = tracer; 24 | _counter = meter.CreateCounter("sheep"); 25 | } 26 | 27 | [HttpGet] 28 | public async Task> Get() 29 | { 30 | using (var span = _tracer.StartActiveSpan("sleep")) 31 | { 32 | span.SetAttribute("delay_ms", 100); 33 | await Task.Delay(TimeSpan.FromMilliseconds(100)); 34 | } 35 | 36 | _counter.Add(1); 37 | 38 | var rng = new Random(); 39 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 40 | { 41 | Date = DateTime.Now.AddDays(index), 42 | TemperatureC = rng.Next(-20, 55), 43 | Summary = Summaries[rng.Next(Summaries.Length)] 44 | }) 45 | .ToArray(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry.Instrumentation.AspNetCore/Honeycomb.OpenTelemetry.Instrumentation.AspNetCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | 7 | 8 | true 9 | true 10 | true 11 | snupkg 12 | 13 | 14 | 0.29.0 15 | beta 16 | Honeycomb.OpenTelemetry.Instrumentation.AspNetCore 17 | Honeycomb 18 | OpenTelemetry AspNetCore instrumentation extensions 19 | https://docs.honeycomb.io/getting-data-in/dotnet/ 20 | Apache-2.0 21 | https://github.com/honeycombio/honeycomb-opentelemetry-dotnet/blob/main/CHANGELOG.md 22 | Copyright (c) Honeycomb 23 | opentelemetry honeycomb observability tracing 24 | honeycomb.png 25 | https://github.com/honeycombio/honeycomb-opentelemetry-dotnet 26 | git 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /examples/aspnetcore-redis/Controllers/WeatherForecastController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.Extensions.Logging; 7 | using OpenTelemetry.Trace; 8 | using StackExchange.Redis; 9 | 10 | namespace aspnetcoreredis.Controllers 11 | { 12 | [ApiController] 13 | [Route("[controller]")] 14 | public class WeatherForecastController : ControllerBase 15 | { 16 | private static readonly string[] Summaries = new[] 17 | { 18 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 19 | }; 20 | 21 | private readonly ILogger _logger; 22 | private readonly Tracer _tracer; 23 | 24 | private readonly IConnectionMultiplexer _redisConnection; 25 | 26 | public WeatherForecastController(ILogger logger, Tracer tracer, IConnectionMultiplexer redisConnection) 27 | { 28 | _logger = logger; 29 | _tracer = tracer; 30 | _redisConnection = redisConnection; 31 | } 32 | 33 | [HttpGet] 34 | public async Task> Get() 35 | { 36 | using (var span = _tracer.StartActiveSpan("sleep")) 37 | { 38 | span.SetAttribute("delay_ms", 100); 39 | var db = _redisConnection.GetDatabase(); 40 | var pong = await db.PingAsync(); 41 | await Task.Delay(TimeSpan.FromMilliseconds(100)); 42 | } 43 | 44 | var rng = new Random(); 45 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 46 | { 47 | Date = DateTime.Now.AddDays(index), 48 | TemperatureC = rng.Next(-20, 55), 49 | Summary = Summaries[rng.Next(Summaries.Length)] 50 | }) 51 | .ToArray(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # default location for local nuget package source 2 | NUGET_PACKAGES_LOCAL ?= ${HOME}/.nuget/local 3 | 4 | build: 5 | dotnet build 6 | 7 | test: build 8 | dotnet test --no-build 9 | 10 | clean-smoke-tests: 11 | rm -rf ./smoke-tests/collector/data.json 12 | rm -rf ./smoke-tests/collector/data-results/*.json 13 | rm -rf ./smoke-tests/report.* 14 | 15 | clean: clean-smoke-tests 16 | rm -rf ./examples/aspnetcore/bin/* 17 | rm -rf ./examples/aspnetcore/obj/* 18 | rm -rf ./test/Honeycomb.OpenTelemetry.Tests/bin/* 19 | rm -rf ./test/Honeycomb.OpenTelemetry.Tests/obj/* 20 | rm -rf ./src/Honeycomb.OpenTelemetry/bin/* 21 | rm -rf ./src/Honeycomb.OpenTelemetry/obj/* 22 | dotnet clean 23 | 24 | 25 | smoke-tests/collector/data.json: 26 | @echo "" 27 | @echo "+++ Zhuzhing smoke test's Collector data.json" 28 | @touch $@ && chmod o+w $@ 29 | 30 | smoke-sdk-grpc: smoke-tests/collector/data.json 31 | @echo "" 32 | @echo "+++ Running gRPC smoke tests." 33 | @echo "" 34 | cd smoke-tests && bats ./smoke-sdk-grpc.bats --report-formatter junit --output ./ 35 | 36 | smoke-sdk-http: smoke-tests/collector/data.json 37 | @echo "" 38 | @echo "+++ Running HTTP smoke tests." 39 | @echo "" 40 | cd smoke-tests && bats ./smoke-sdk-http.bats --report-formatter junit --output ./ 41 | 42 | smoke-sdk: smoke-sdk-grpc smoke-sdk-http 43 | 44 | smoke: smoke-sdk 45 | 46 | unsmoke: 47 | @echo "" 48 | @echo "+++ Spinning down the smokers." 49 | @echo "" 50 | cd smoke-tests && docker-compose down --volumes 51 | 52 | ## use this for local testing 53 | resmoke: unsmoke smoke 54 | 55 | ${NUGET_PACKAGES_LOCAL}: 56 | @mkdir -p ${NUGET_PACKAGES_LOCAL} 57 | 58 | local_nuget_source_registered: ${NUGET_PACKAGES_LOCAL} 59 | @dotnet nuget list source | grep -q '${NUGET_PACKAGES_LOCAL}' || dotnet nuget add source -n local ${NUGET_PACKAGES_LOCAL} 60 | 61 | publish_local: local_nuget_source_registered 62 | @echo "Publishing nuget package(s) to: ${NUGET_PACKAGES_LOCAL}\n" 63 | @dotnet pack -c release -o ${NUGET_PACKAGES_LOCAL} -p:signed=false 64 | 65 | .PHONY: build test clean smoke unsmoke resmoke local_nuget_source_registered publish_local smoke-sdk-grpc smoke-sdk-http smoke-sdk clean-smoke-tests 66 | -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry.CommonInstrumentations/TracerProviderBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Npgsql; 2 | using StackExchange.Redis; 3 | 4 | namespace OpenTelemetry.Trace 5 | { 6 | /// 7 | /// Extension methods to add instrumentation support for many common instrumentation packages. 8 | /// 9 | public static class TracerProviderBuilderExtensions 10 | { 11 | /// 12 | /// Adds support for common instrumentation packages. Refer to documentation for a complete list of included instrumentations. 13 | /// 14 | /// being configured. 15 | /// The instance of to chain the calls. 16 | public static TracerProviderBuilder AddCommonInstrumentations(this TracerProviderBuilder builder) 17 | { 18 | // Only add Redis instrumentation if we can find a Redis connection in DI 19 | if (builder is IDeferredTracerProviderBuilder deferredBuilder) 20 | { 21 | deferredBuilder.Configure((sp, b) => 22 | { 23 | var connection = sp.GetService(typeof(IConnectionMultiplexer)) as IConnectionMultiplexer; 24 | if (connection != null) 25 | { 26 | b.AddRedisInstrumentation(connection); 27 | } 28 | }); 29 | } 30 | 31 | return 32 | builder 33 | #if NET6_0_OR_GREATER 34 | .AddAspNetCoreInstrumentationWithBaggage() 35 | .AddGrpcClientInstrumentation() 36 | #elif NET462_OR_GREATER 37 | .AddAspNetInstrumentation() 38 | #endif 39 | #if NETSTANDARD2_0_OR_GREATER 40 | .AddQuartzInstrumentation() 41 | #endif 42 | .AddHttpClientInstrumentation() 43 | .AddSqlClientInstrumentation() 44 | .AddEntityFrameworkCoreInstrumentation() 45 | .AddMySqlDataInstrumentation() 46 | .AddWcfInstrumentation() 47 | .AddNpgsql(); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry.Instrumentation.AspNetCore/TracerProviderBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using OpenTelemetry.Instrumentation.AspNetCore; 2 | 3 | namespace OpenTelemetry.Trace 4 | { 5 | /// 6 | /// Extension methods to simplify registering of ASP.NET Core request instrumentation. 7 | /// 8 | public static class TracerProviderBuilderExtensions 9 | { 10 | /// 11 | /// Enables the incoming requests automatic data collection for ASP.NET Core and adds current trace context baggage as 12 | /// attributes to created spans. 13 | /// 14 | /// being configured. 15 | /// The instance of to chain the calls. 16 | public static TracerProviderBuilder AddAspNetCoreInstrumentationWithBaggage(this TracerProviderBuilder builder) 17 | { 18 | return builder.AddAspNetCoreInstrumentation(options => 19 | { 20 | options.RecordException = true; 21 | options.EnrichWithBaggage(); 22 | } 23 | ); 24 | } 25 | 26 | /// 27 | /// Configures the AspNetCore instrumentation to adds current trace context baggage as attributes to created spans. 28 | /// 29 | /// being configured. 30 | public static void EnrichWithBaggage(this AspNetCoreInstrumentationOptions options) 31 | { 32 | options.EnrichWithHttpRequest = (activity, request) => 33 | { 34 | foreach (var entry in Baggage.Current) 35 | { 36 | activity.SetTag(entry.Key, entry.Value); 37 | } 38 | }; 39 | options.EnrichWithHttpResponse = (activity, response) => 40 | { 41 | foreach (var entry in Baggage.Current) 42 | { 43 | activity.SetTag(entry.Key, entry.Value); 44 | } 45 | }; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/Honeycomb.OpenTelemetry.Tests/HoneycombOptionsExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace Honeycomb.OpenTelemetry { 4 | public class HoneycombOptionsExtensionsTests 5 | { 6 | private const string ModernApiKey = "6936628e60f4c6157fde46"; 7 | private const string ClassicApiKey = "a142c03cf06936628e60f4c6157fde46"; 8 | 9 | [Theory] 10 | [InlineData("", "", "x-otlp-version=0.19.0,x-honeycomb-team=")] 11 | [InlineData(ModernApiKey, "", "x-otlp-version=0.19.0,x-honeycomb-team=6936628e60f4c6157fde46")] 12 | [InlineData(ModernApiKey, "dataset", "x-otlp-version=0.19.0,x-honeycomb-team=6936628e60f4c6157fde46")] 13 | [InlineData(ClassicApiKey, "", "x-otlp-version=0.19.0,x-honeycomb-team=a142c03cf06936628e60f4c6157fde46")] 14 | [InlineData(ClassicApiKey, "dataset", "x-otlp-version=0.19.0,x-honeycomb-team=a142c03cf06936628e60f4c6157fde46,x-honeycomb-dataset=dataset")] 15 | public void TracesHeaders(string apikey, string dataset, string expectedHeader) { 16 | var options = new HoneycombOptions 17 | { 18 | TracesApiKey = apikey, 19 | TracesDataset = dataset 20 | }; 21 | Assert.Equal(expectedHeader, options.GetTraceHeaders()); 22 | } 23 | 24 | [Theory] 25 | [InlineData("", "", "x-otlp-version=0.19.0,x-honeycomb-team=,x-honeycomb-dataset=")] 26 | [InlineData(ModernApiKey, "", "x-otlp-version=0.19.0,x-honeycomb-team=6936628e60f4c6157fde46,x-honeycomb-dataset=")] 27 | [InlineData(ModernApiKey, "dataset", "x-otlp-version=0.19.0,x-honeycomb-team=6936628e60f4c6157fde46,x-honeycomb-dataset=dataset")] 28 | [InlineData(ClassicApiKey, "", "x-otlp-version=0.19.0,x-honeycomb-team=a142c03cf06936628e60f4c6157fde46,x-honeycomb-dataset=")] 29 | [InlineData(ClassicApiKey, "dataset", "x-otlp-version=0.19.0,x-honeycomb-team=a142c03cf06936628e60f4c6157fde46,x-honeycomb-dataset=dataset")] 30 | public void MetricsHeaders(string apikey, string dataset, string expectedHeader) { 31 | var options = new HoneycombOptions 32 | { 33 | MetricsApiKey = apikey, 34 | MetricsDataset = dataset 35 | }; 36 | Assert.Equal(expectedHeader, options.GetMetricsHeaders()); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /.github/workflows/validate-pr-title.yml: -------------------------------------------------------------------------------- 1 | name: "Validate PR Title" 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | main: 12 | name: Validate PR title 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: amannn/action-semantic-pull-request@v5 16 | id: lint_pr_title 17 | name: "🤖 Check PR title follows conventional commit spec" 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | with: 21 | # Have to specify all types because `maint` and `rel` aren't defaults 22 | types: | 23 | maint 24 | rel 25 | fix 26 | feat 27 | chore 28 | ci 29 | docs 30 | style 31 | refactor 32 | perf 33 | test 34 | ignoreLabels: | 35 | "type: dependencies" 36 | # When the previous steps fails, the workflow would stop. By adding this 37 | # condition you can continue the execution with the populated error message. 38 | - if: always() && (steps.lint_pr_title.outputs.error_message != null) 39 | name: "📝 Add PR comment about using conventional commit spec" 40 | uses: marocchino/sticky-pull-request-comment@v2 41 | with: 42 | header: pr-title-lint-error 43 | message: | 44 | Thank you for contributing to the project! 🎉 45 | 46 | We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted. 47 | 48 | Make sure to prepend with `feat:`, `fix:`, or another option in the list below. 49 | 50 | Once you update the title, this workflow will re-run automatically and validate the updated title. 51 | 52 | Details: 53 | 54 | ``` 55 | ${{ steps.lint_pr_title.outputs.error_message }} 56 | ``` 57 | 58 | # Delete a previous comment when the issue has been resolved 59 | - if: ${{ steps.lint_pr_title.outputs.error_message == null }} 60 | name: "❌ Delete PR comment after title has been updated" 61 | uses: marocchino/sticky-pull-request-comment@v2 62 | with: 63 | header: pr-title-lint-error 64 | delete: true 65 | -------------------------------------------------------------------------------- /examples/console/Program.cs: -------------------------------------------------------------------------------- 1 | using OpenTelemetry.Trace; 2 | using Honeycomb.OpenTelemetry; 3 | using OpenTelemetry.Metrics; 4 | using System.Diagnostics.Metrics; 5 | using OpenTelemetry.Resources; 6 | using System.Collections.Generic; 7 | 8 | namespace console 9 | { 10 | class Program 11 | { 12 | static void Main(string[] args) 13 | { 14 | // configure HoneycombOptions 15 | var options = new HoneycombOptions 16 | { 17 | ServiceName = "my-app", 18 | ApiKey = "{apikey}", 19 | TracesDataset = "{traces-dataset}", 20 | MetricsDataset = "{metrics-dataset}", // optional 21 | ResourceBuilder = ResourceBuilder.CreateDefault().AddAttributes( 22 | new Dictionary 23 | { 24 | {"my-attribute", "some-value"} 25 | }) 26 | }; 27 | 28 | // ------------ TRACES ------------ 29 | 30 | // configure OpenTelemetry SDK to send trace data to Honeycomb 31 | // NOTE: the tracer provider should be a long-lived resource, and disposed 32 | // at the end of your app lifecycle to ensure all telemetry is exported 33 | using var tracerProvider = OpenTelemetry.Sdk.CreateTracerProviderBuilder() 34 | .AddHoneycomb(options) 35 | .Build(); 36 | 37 | // get an instance of a tracer that can be used to create spans 38 | var tracer = tracerProvider.GetTracer(options.ServiceName); 39 | 40 | // create span to describe some application logic 41 | using var span = tracer.StartActiveSpan("doSomething"); 42 | span.SetAttribute("user_id", 123); 43 | 44 | // ------------ METRICS (optional) ------------ 45 | 46 | // configure OpenTelemetry SDK to send metric data to Honeycomb 47 | using var meterProvider = OpenTelemetry.Sdk.CreateMeterProviderBuilder() 48 | .AddHoneycomb(options) 49 | .Build(); 50 | 51 | // meter name used here must be configured in the OpenTelemetry SDK 52 | // service name is configured by default 53 | // you may configure additional meter names using the Honeycomb options 54 | using var meter = new Meter(options.ServiceName); 55 | Counter counter = meter.CreateCounter("sheep"); 56 | counter.Add(1); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /examples/console/README.md: -------------------------------------------------------------------------------- 1 | # Honeycomb.OpenTelemetry Console example 2 | 3 | This example shows how to use the Honeycomb.OpenTelemetry distro with a .NET console application. 4 | 5 | To run the example, you need to create an instance of HoneycombOptions and pass it into the `AddHoneycomb` function of the OpenTelemetry TraceProviderBuilder. There are a variety of ways to create the options, as shown below. 6 | 7 | ### Manually 8 | 9 | ```csharp 10 | var options = new HoneycombOptions 11 | { 12 | ServiceName = "my-app", 13 | ApiKey = "{apikey}", 14 | Dataset = "{dataset}" 15 | }; 16 | ``` 17 | 18 | ### Command line arguments 19 | 20 | Create options using command line arguments: 21 | 22 | ```csharp 23 | var options = HoneycombOptionsHelper.GetHoneycombOptions(args); 24 | ``` 25 | 26 | Run app with command line arguments: 27 | 28 | `dotnet run --service-name=my-app --honeycomb-apikey={apikey} --honeycomb-dataset={dataset}` 29 | 30 | ### Configuration files 31 | 32 | If you application uses JSON or XML configuration files, you crate an instance of HoneycombOptions to pass to the `AddHoneycomb` function. 33 | 34 | ```json 35 | { 36 | "Honeycomb": { 37 | "ServiceName": "my-app", 38 | "ApiKey": "{apikey}", 39 | "Dataset": "{dataset}" 40 | } 41 | } 42 | ``` 43 | 44 | ```xml 45 | 46 | my-app 47 | {apikey} 48 | {dataset} 49 | 50 | ``` 51 | 52 | ```csharp 53 | var config = new ConfigurationBuilder().AddJsonFile("{setting-file-name}").Build(); 54 | var options = HoneycombOptionsHelper.GetHoneycombOptions(configuration); 55 | var tracerProvider = new TracerProviderBuilder() 56 | .AddHoneycomb(options) 57 | .Build() 58 | ``` 59 | 60 | ### Setting Resource Attributes 61 | 62 | You can set additional resource attributes by either using an environment variable or programmatically using HoneycomnOptions when configuring the SDK. 63 | 64 | #### Environment Variable 65 | 66 | You can use `OTEL_RESOURCE_ATTRIBUTES` to set extra resoruce attributes. The value is key value pairs and multiple entries are separated using a comma (`,`). 67 | 68 | For example: 69 | 70 | `export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=dev"` 71 | 72 | #### Programatically using HoneycombOptions 73 | 74 | You can set resource attributes proramatically by creating your own ResourceBuilder and passing adding it to HoneycombOptions. 75 | 76 | ```csharp 77 | var resourceBuilder = ResourceBuilder.CreateDefault().AddAttributes( 78 | new Dictionary 79 | { 80 | {"deployment.environment", "dev"} 81 | }); 82 | var tracerProvider = OpenTelemetry.Sdk.CreateTracerProviderBuilder() 83 | .AddHoneycomb(options => options.ResourceBuilder = resourceBuilder) 84 | .Build(); 85 | ``` 86 | 87 | ### Example 88 | 89 | See [Program.cs](Program.cs) for a complete example. 90 | -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry/DeterministicSampler.cs: -------------------------------------------------------------------------------- 1 | using OpenTelemetry.Trace; 2 | using System.Collections.Generic; 3 | 4 | namespace Honeycomb.OpenTelemetry 5 | { 6 | /// 7 | /// This Sampler implementation allows for distributed sampling based on a trace ID. 8 | /// It accepts a sample rate N and will deterministically sample 1/N events based 9 | /// on the target field. Hence, two or more processes can decide whether or not to 10 | /// sample related events without communication. 11 | /// 12 | /// - A sample rate of 0 means the Sampler will never sample. 13 | /// 14 | /// - A sampler rate of 1 means the Sampler will always sample. 15 | /// 16 | /// This implementation is based on the implementations (and necessarily needs to 17 | /// be in line with) other Honeycomb SDK implementations. 18 | /// 19 | public class DeterministicSampler : Sampler 20 | { 21 | internal const uint NeverSample = 0; 22 | internal const uint AlwaysSample = 1; 23 | internal const string SampleRateField = "SampleRate"; 24 | private const double AlwaysSampleRatio = 1.0; 25 | private const double NeverSameRatio = 0.0; 26 | 27 | private Sampler _innerSampler; 28 | private readonly List> _sampleResultAttributes; 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | /// The desired sample rate, expressed as 1/{sampleRate}. 34 | /// 35 | public DeterministicSampler(uint sampleRate) 36 | { 37 | double ratio; 38 | switch(sampleRate) 39 | { 40 | case NeverSample: 41 | ratio = NeverSameRatio; 42 | break; 43 | case AlwaysSample: 44 | ratio = AlwaysSampleRatio; 45 | break; 46 | default: 47 | ratio = AlwaysSampleRatio / sampleRate; 48 | break; 49 | } 50 | _innerSampler = new TraceIdRatioBasedSampler(ratio); 51 | _sampleResultAttributes = new List> 52 | { 53 | new KeyValuePair(SampleRateField, sampleRate) 54 | }; 55 | } 56 | 57 | /// 58 | public override SamplingResult ShouldSample(in SamplingParameters samplingParameters) 59 | { 60 | var result = _innerSampler.ShouldSample(samplingParameters); 61 | return new SamplingResult( 62 | result.Decision, 63 | _sampleResultAttributes 64 | ); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry/Honeycomb.OpenTelemetry.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0;netstandard2.1;netstandard2.0;net462 5 | true 6 | 7 | 8 | true 9 | true 10 | true 11 | snupkg 12 | 13 | 14 | 1.5.0 15 | Honeycomb.OpenTelemetry 16 | Honeycomb 17 | Honeycomb's OpenTelemetry SDK 18 | https://docs.honeycomb.io/getting-data-in/dotnet/ 19 | Apache-2.0 20 | https://github.com/honeycombio/honeycomb-opentelemetry-dotnet/blob/main/CHANGELOG.md 21 | Copyright (c) Honeycomb 22 | opentelemetry honeycomb observability tracing 23 | honeycomb.png 24 | https://github.com/honeycombio/honeycomb-opentelemetry-dotnet 25 | git 26 | 27 | 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 | -------------------------------------------------------------------------------- /test/Honeycomb.OpenTelemetry.Tests/EnvironmentOptionsTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Xunit; 3 | 4 | namespace Honeycomb.OpenTelemetry 5 | { 6 | public class EnvironmentOptionsTests 7 | { 8 | [Fact] 9 | public void Can_get_options_from_env_vars() 10 | { 11 | var values = new Dictionary 12 | { 13 | {"HONEYCOMB_API_KEY", "my-api-key"}, 14 | {"HONEYCOMB_TRACES_API_KEY", "my-traces-api-key"}, 15 | {"HONEYCOMB_METRICS_API_KEY", "my-metrics-api-key"}, 16 | {"HONEYCOMB_DATASET", "my-dataset"}, 17 | {"HONEYCOMB_TRACES_DATASET", "my-traces-dataset"}, 18 | {"HONEYCOMB_METRICS_DATASET", "my-metrics-dataset"}, 19 | {"HONEYCOMB_API_ENDPOINT", "my-endpoint"}, 20 | {"HONEYCOMB_TRACES_ENDPOINT", "my-traces-endpoint"}, 21 | {"HONEYCOMB_METRICS_ENDPOINT", "my-metrics-endpoint"}, 22 | {"HONEYCOMB_SAMPLE_RATE", "10"}, 23 | {"OTEL_SERVICE_NAME", "my-service-name"}, 24 | {"SERVICE_VERSION", "my-service-version"}, 25 | {"HONEYCOMB_ENABLE_LOCAL_VISUALIZATIONS", "true" }, 26 | {"DEBUG", "true"}, 27 | {"OTEL_EXPORTER_OTLP_PROTOCOL", "grpc"}, 28 | }; 29 | var options = new EnvironmentOptions(values); 30 | Assert.Equal("my-api-key", options.ApiKey); 31 | Assert.Equal("my-traces-api-key", options.TracesApiKey); 32 | Assert.Equal("my-metrics-api-key", options.MetricsApiKey); 33 | Assert.Equal("my-dataset", options.Dataset); 34 | Assert.Equal("my-traces-dataset", options.TracesDataset); 35 | Assert.Equal("my-metrics-dataset", options.MetricsDataset); 36 | Assert.Equal("my-endpoint", options.ApiEndpoint); 37 | Assert.Equal("my-traces-endpoint", options.TracesEndpoint); 38 | Assert.Equal("my-metrics-endpoint", options.MetricsEndpoint); 39 | Assert.Equal((uint)10, options.SampleRate); 40 | Assert.Equal("my-service-name", options.ServiceName); 41 | Assert.Equal("my-service-version", options.ServiceVersion); 42 | Assert.True(options.EnableLocalVisualizations); 43 | Assert.True(options.Debug); 44 | Assert.Equal("grpc", options.OtelExporterOtlpProtocol); 45 | } 46 | 47 | [Fact] 48 | public void Optional_args_fall_back_to_defaults() 49 | { 50 | var options = new EnvironmentOptions(new Dictionary()); 51 | Assert.Equal((uint)1, options.SampleRate); 52 | Assert.False(options.EnableLocalVisualizations); 53 | } 54 | 55 | [Fact] 56 | public void Sample_rate_returns_default_for_invalid_value() 57 | { 58 | var values = new Dictionary 59 | { 60 | {"HONEYCOMB_SAMPLE_RATE", "invalid"} 61 | }; 62 | var options = new EnvironmentOptions(values); 63 | Assert.Equal((uint)1, options.SampleRate); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Honeycomb OpenTelemetry Distro for .NET 2 | 3 | [![OSS Lifecycle](https://img.shields.io/osslifecycle/honeycombio/honeycomb-opentelemetry-dotnet)](https://github.com/honeycombio/home/blob/main/honeycomb-oss-lifecycle-and-practices.md) 4 | [![CircleCI](https://circleci.com/gh/honeycombio/honeycomb-opentelemetry-dotnet.svg?style=shield)](https://circleci.com/gh/honeycombio/honeycomb-opentelemetry-dotnet) 5 | [![Dependencies](https://img.shields.io/librariesio/release/nuget/Honeycomb.Opentelemetry.svg)](https://github.com/honeycombio/honeycomb-opentelemetry-dotnet/blob/main/src/Honeycomb.OpenTelemetry/Honeycomb.OpenTelemetry.csproj) 6 | [![Nuget](https://img.shields.io/nuget/v/Honeycomb.OpenTelemetry.svg)](https://www.nuget.org/packages/Honeycomb.OpenTelemetry) 7 | 8 | **STATUS**: This project is now archived. See [this issue](https://github.com/honeycombio/honeycomb-opentelemetry-dotnet/issues/378) for more details. 9 | 10 | This is Honeycomb's distribution of OpenTelemetry for .NET. 11 | 12 | Latest release built with: 13 | 14 | - [OpenTelemetry Version 1.6.0](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/core-1.6.0) 15 | 16 | ***NOTE*** 17 | 18 | OpenTelemetry .NET SDK versions after 1.6.0 use updated HTTP semantic conventions that result in different telemetry attribute keys and can contribute to unexpected query results in Honeycomb. For this reason, we have decided the Honeycomb OpenTelemetry distro will not take further updates yet. 19 | 20 | Please see our [Migration guide for HTTP semantic conventions](https://docs.honeycomb.io/troubleshoot/product-lifecycle/recommended-migrations/#migrate-to-stabilized-opentelemetry-semantic-conventions) for more details. 21 | 22 | ## Getting Started 23 | 24 | Honeycomb's OpenTelemetry .NET SDK gives you the ability to add manual instrumentation to your applications. 25 | 26 | - [Documentation](https://docs.honeycomb.io/getting-data-in/dotnet/opentelemetry-distro/) 27 | - [Examples](/examples/) 28 | 29 | ## Why would I want to use this? 30 | 31 | - Streamlined configuration for sending data to Honeycomb! 32 | - Easy interop with existing instrumentation with OpenTelemetry! 33 | - Deterministic sampling! 34 | - Multi-span attributes! 35 | 36 | ### Overriding OpenTelemetry SDK Builder options 37 | 38 | The OpenTelemetry SDK uses a builder pattern to set options and currently does not provide a way to know if a particular option has already been set. 39 | This can lead to the same option being set multiple times with the last one wins behaviour. 40 | 41 | For example, the `AddHoneycomb(options)` function configures a Sampler so another call to `SetSampler(sampler)` will override the first sampler. 42 | 43 | 44 | ### HTTP Semantic Conventions 45 | 46 | The semantic conventions for attribute names used in HTTP instrumentation libraries is being updated and could cause distruption for existing users who rely on the existing names. 47 | For this reason, we have locked HTTP instrumentation packages to [1.6.0-beta.3](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/1.6.0-beta.3) which includes the `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable that allows users to opt-in to the new behaviour when they are ready to. 48 | 49 | See this [Migration Guide](https://docs.honeycomb.io/getting-data-in/semconv/migration) for details on how to switch between the old and new attribute keys when using Honeycomb. 50 | 51 | ## License 52 | 53 | [Apache 2.0 License](./LICENSE). 54 | -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry.CommonInstrumentations/Honeycomb.OpenTelemetry.CommonInstrumentations.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0;netstandard2.1;netstandard2.0;net462 5 | true 6 | 7 | 8 | true 9 | true 10 | true 11 | snupkg 12 | 13 | 14 | 0.29.0 15 | beta 16 | Honeycomb.OpenTelemetry.CommonInstrumentations 17 | Honeycomb 18 | Honeycomb's OpenTelemetry common instrumentations package. Adds support for many common instrumentation libraries for you. 19 | https://docs.honeycomb.io/getting-data-in/dotnet/ 20 | Apache-2.0 21 | https://github.com/honeycombio/honeycomb-opentelemetry-dotnet/blob/main/CHANGELOG.md 22 | Copyright (c) Honeycomb 23 | opentelemetry honeycomb observability tracing 24 | honeycomb.png 25 | https://github.com/honeycombio/honeycomb-opentelemetry-dotnet 26 | git 27 | 28 | 29 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /test/Honeycomb.OpenTelemetry.Tests/DeterministicSamplerTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using OpenTelemetry.Trace; 4 | using Xunit; 5 | 6 | namespace Honeycomb.OpenTelemetry.Tests 7 | { 8 | public class DeterministicSamplerTests 9 | { 10 | [Fact] 11 | public void NeverSampleRateAlwaysReturnsDropResult() 12 | { 13 | var sampler = new DeterministicSampler(DeterministicSampler.NeverSample); 14 | for (int i = 0; i < 100; i++) 15 | { 16 | var traceID = ActivityTraceId.CreateRandom(); 17 | var parameters = new SamplingParameters( 18 | parentContext: default, 19 | traceId: traceID, 20 | name: "Span", 21 | kind: ActivityKind.Client 22 | ); 23 | 24 | var result = sampler.ShouldSample(parameters); 25 | Assert.Equal(SamplingDecision.Drop, result.Decision); 26 | } 27 | } 28 | 29 | [Fact] 30 | public void AlwaysSampleRateAlwaysReturnsRecordAndSample() 31 | { 32 | var sampler = new DeterministicSampler(DeterministicSampler.AlwaysSample); 33 | for (int i = 0; i < 100; i++) 34 | { 35 | var traceID = ActivityTraceId.CreateRandom(); 36 | var parameters = new SamplingParameters( 37 | parentContext: default, 38 | traceId: traceID, 39 | name: "Span", 40 | kind: ActivityKind.Client 41 | ); 42 | 43 | var result = sampler.ShouldSample(parameters); 44 | Assert.Equal(SamplingDecision.RecordAndSample, result.Decision); 45 | } 46 | } 47 | 48 | [Fact] 49 | public void DeterministicSamplerResultVariesBasedOnTraceId() 50 | { 51 | const uint sampleRate = 2; 52 | var sampler = new DeterministicSampler(sampleRate); 53 | var count = 0; 54 | for (int i = 0; i < 100; i++) 55 | { 56 | var activityTraceID = ActivityTraceId.CreateRandom(); 57 | var parameters = new SamplingParameters( 58 | parentContext: default, 59 | traceId: activityTraceID, 60 | name: "Span", 61 | kind: ActivityKind.Client 62 | ); 63 | var result = sampler.ShouldSample(parameters); 64 | if (result.Decision == SamplingDecision.RecordAndSample) { 65 | count++; 66 | } 67 | } 68 | 69 | Assert.True(count > 25 && count < 75); 70 | } 71 | 72 | [Fact] 73 | public void DeterministicSamplerAddsSampleRateAttribute() 74 | { 75 | for (int i = 0; i < 100; i++) 76 | { 77 | var sampler = new DeterministicSampler((uint) i); 78 | var activityTraceID = ActivityTraceId.CreateRandom(); 79 | var parameters = new SamplingParameters( 80 | parentContext: default, 81 | traceId: activityTraceID, 82 | name: "Span", 83 | kind: ActivityKind.Client 84 | ); 85 | 86 | var result = sampler.ShouldSample(parameters); 87 | Assert.Collection(result.Attributes, 88 | item => Assert.Equal(new KeyValuePair(DeterministicSampler.SampleRateField, (uint) i), item) 89 | ); 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /smoke-tests/test_helpers/utilities.bash: -------------------------------------------------------------------------------- 1 | # UTILITY FUNCS 2 | 3 | spans_from_library_named() { 4 | spans_received | jq ".scopeSpans[] | select(.scope.name == \"$1\").spans[]" 5 | } 6 | 7 | metrics_from_library_named() { 8 | metrics_received | jq ".scopeMetrics[] | select(.scope.name == \"$1\").metrics[]" 9 | } 10 | 11 | spans_received() { 12 | jq ".resourceSpans[]?" ./collector/data.json 13 | } 14 | 15 | metrics_received() { 16 | jq ".resourceMetrics[]?" ./collector/data.json 17 | } 18 | 19 | # test span name 20 | span_names_for() { 21 | spans_from_library_named $1 | jq '.name' 22 | } 23 | 24 | # test span attributes 25 | span_attributes_for() { 26 | # $1 - library name 27 | 28 | spans_from_library_named $1 | \ 29 | jq ".attributes[]" 30 | } 31 | 32 | # test metric name 33 | metric_names_for() { 34 | metrics_from_library_named $1 | jq '.name' 35 | } 36 | 37 | # Arguments 38 | # $1 - retry limit (default 5); Nth retry sleeps for N seconds 39 | wait_for_metrics() { 40 | echo -n "# ⏳ Waiting for collector to receive metrics" >&3 41 | NEXT_WAIT_TIME=0 42 | MAX_RETRIES=${1:-5} 43 | until [ $NEXT_WAIT_TIME -eq $MAX_RETRIES ] || [ "$(metrics_received)" != "" ] 44 | do 45 | echo -n " ... $(( NEXT_WAIT_TIME++ ))s" >&3 46 | sleep $NEXT_WAIT_TIME 47 | done 48 | echo "" >&3 49 | [ $NEXT_WAIT_TIME -lt $MAX_RETRIES ] 50 | } 51 | 52 | # Arguments 53 | # $1 - retry limit (default 5); Nth retry sleeps for N seconds 54 | wait_for_data() { 55 | echo -n "# ⏳ Waiting for collector to receive data" >&3 56 | NEXT_WAIT_TIME=0 57 | MAX_RETRIES=${1:-5} 58 | until [ $NEXT_WAIT_TIME -eq $MAX_RETRIES ] || [ "$(wc -l ./collector/data.json | awk '{ print $1 }')" -ne 0 ] 59 | do 60 | echo -n " ... $(( NEXT_WAIT_TIME++ ))s" >&3 61 | sleep $NEXT_WAIT_TIME 62 | done 63 | echo "" >&3 64 | [ $NEXT_WAIT_TIME -lt $MAX_RETRIES ] 65 | } 66 | 67 | # Arguments 68 | # $1 - retry limit (default 5); Nth retry sleeps for N seconds 69 | wait_for_traces() { 70 | echo -n "# ⏳ Waiting for collector to receive traces" >&3 71 | NEXT_WAIT_TIME=0 72 | MAX_RETRIES=${1:-5} 73 | until [ $NEXT_WAIT_TIME -eq $MAX_RETRIES ] || [ "$(spans_received)" != "" ] 74 | do 75 | echo -n " ... $(( NEXT_WAIT_TIME++ ))s" >&3 76 | sleep $NEXT_WAIT_TIME 77 | done 78 | echo "" >&3 79 | [ $NEXT_WAIT_TIME -lt $MAX_RETRIES ] 80 | } 81 | 82 | wait_for_flush() { 83 | echo -n "# ⏳ Waiting for collector data flush" >&3 84 | NEXT_WAIT_TIME=0 85 | until [ $NEXT_WAIT_TIME -eq 5 ] || [ "$(wc -l ./collector/data.json | awk '{ print $1 }')" -eq 0 ] 86 | do 87 | echo -n " ... $(( NEXT_WAIT_TIME++ ))s" >&3 88 | sleep $NEXT_WAIT_TIME 89 | done 90 | echo "" >&3 91 | [ $NEXT_WAIT_TIME -lt 5 ] 92 | } 93 | 94 | # Wait loop for one of our example Dotnet apps to be started and ready to receive traffic. 95 | # 96 | # Arguments: 97 | # $1 - the name of the container/service in which the app is running 98 | wait_for_ready_app() { 99 | CONTAINER=${1:?container name is a required parameter} 100 | MAX_RETRIES=10 101 | echo -n "# 🍿 Setting up ${CONTAINER}" >&3 102 | NEXT_WAIT_TIME=0 103 | until [ $NEXT_WAIT_TIME -eq $MAX_RETRIES ] || [[ $(docker-compose logs ${CONTAINER} | grep "Now listening on:") ]] 104 | do 105 | echo -n " ... $(( NEXT_WAIT_TIME++ ))s" >&3 106 | sleep $NEXT_WAIT_TIME 107 | done 108 | echo "" >&3 109 | [ $NEXT_WAIT_TIME -lt $MAX_RETRIES ] 110 | } 111 | 112 | # Fail and display details if the expected and actual values do not 113 | # equal. Details include both values. 114 | # 115 | # Lifted and then drastically simplified from bats-assert * bats-support 116 | assert_equal() { 117 | if [[ $1 != "$2" ]]; then 118 | { 119 | echo 120 | echo "-- 💥 values are not equal 💥 --" 121 | echo "expected : $2" 122 | echo "actual : $1" 123 | echo "--" 124 | echo 125 | } >&2 # output error to STDERR 126 | return 1 127 | fi 128 | } -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry/MeterProviderBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Honeycomb.OpenTelemetry; 2 | using OpenTelemetry.Resources; 3 | using System; 4 | 5 | namespace OpenTelemetry.Metrics 6 | { 7 | /// 8 | /// Extension methods to configure to send metrics telemetry data to Honeycomb. 9 | /// 10 | public static class MeterProviderBuilderExtensions 11 | { 12 | /// 13 | /// Configures the to send metrics telemetry data to Honeycomb. 14 | /// 15 | public static MeterProviderBuilder AddHoneycomb(this MeterProviderBuilder builder, 16 | Action configureHoneycombOptions = null) 17 | { 18 | var honeycombOptions = new HoneycombOptions(); 19 | configureHoneycombOptions?.Invoke(honeycombOptions); 20 | return builder.AddHoneycomb(honeycombOptions); 21 | } 22 | 23 | /// 24 | /// Configures the to send metrics telemetry data to Honeycomb using an instance of . 25 | /// 26 | public static MeterProviderBuilder AddHoneycomb(this MeterProviderBuilder builder, HoneycombOptions options) 27 | { 28 | if (options is null) 29 | { 30 | options = new HoneycombOptions { }; 31 | } 32 | 33 | options.ApplyEnvironmentOptions(new EnvironmentOptions(Environment.GetEnvironmentVariables())); 34 | 35 | // only enable metrics if a metrics dataset is set 36 | if (!string.IsNullOrWhiteSpace(options.MetricsDataset)) 37 | { 38 | var metricsApiKey = options.GetMetricsApiKey(); 39 | var metricsEndpoint = options.GetMetricsEndpoint(); 40 | 41 | if (string.IsNullOrWhiteSpace(metricsApiKey)) 42 | { 43 | Console.WriteLine("WARN: missing metrics API key"); 44 | } 45 | 46 | builder 47 | .SetResourceBuilder( 48 | ResourceBuilder 49 | .CreateDefault() 50 | .AddHoneycombAttributes() 51 | .AddEnvironmentVariableDetector() 52 | .AddService(serviceName: options.ServiceName, serviceVersion: options.ServiceVersion) 53 | ) 54 | .AddHoneycombOtlpExporter(metricsApiKey, options.MetricsDataset, metricsEndpoint); 55 | 56 | builder.AddMeter(options.MetricsDataset); 57 | foreach (var meterName in options.MeterNames) 58 | { 59 | builder.AddMeter(meterName); 60 | } 61 | 62 | if (options.Debug) 63 | { 64 | builder.AddConsoleExporter(); 65 | } 66 | } 67 | 68 | return builder; 69 | } 70 | 71 | /// 72 | /// Configures the with an OTLP exporter that sends metrics telemetry to Honeycomb. 73 | /// 74 | public static MeterProviderBuilder AddHoneycombOtlpExporter(this MeterProviderBuilder builder, string apikey, string dataset = null, string endpoint = null) 75 | { 76 | if (string.IsNullOrWhiteSpace(endpoint)) 77 | { 78 | endpoint = HoneycombOptions.DefaultEndpoint; 79 | } 80 | 81 | return builder.AddOtlpExporter(otlpOptions => 82 | { 83 | otlpOptions.Endpoint = new Uri(endpoint); 84 | otlpOptions.Headers = HoneycombOptions.GetMetricsHeaders(apikey, dataset); 85 | }); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry/EnvironmentOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | 4 | namespace Honeycomb.OpenTelemetry 5 | { 6 | internal class EnvironmentOptions 7 | { 8 | private const string ApiKeyKey = "HONEYCOMB_API_KEY"; 9 | private const string TracesApiKeyKey = "HONEYCOMB_TRACES_API_KEY"; 10 | private const string MetricsApiKeyKey = "HONEYCOMB_METRICS_API_KEY"; 11 | private const string DatasetKey = "HONEYCOMB_DATASET"; 12 | private const string TracesDatasetKey = "HONEYCOMB_TRACES_DATASET"; 13 | private const string MetricsDatasetKey = "HONEYCOMB_METRICS_DATASET"; 14 | private const string ApiEndpointKey = "HONEYCOMB_API_ENDPOINT"; 15 | private const string TracesEndpointKey = "HONEYCOMB_TRACES_ENDPOINT"; 16 | private const string MetricsEndpointKey = "HONEYCOMB_METRICS_ENDPOINT"; 17 | private const string SampleRateKey = "HONEYCOMB_SAMPLE_RATE"; 18 | private const string ServiceNameKey = "OTEL_SERVICE_NAME"; 19 | private const string ServiceVersionKey = "SERVICE_VERSION"; 20 | private const string EnableLocalVisualizationsKey = "HONEYCOMB_ENABLE_LOCAL_VISUALIZATIONS"; 21 | private const string DebugKey = "DEBUG"; 22 | private const string OtelExporterOtlpProtocolKey = "OTEL_EXPORTER_OTLP_PROTOCOL"; 23 | private const uint DefaultSampleRate = 1; 24 | private const string DefaultApiEndpoint = "https://api.honeycomb.io:443"; 25 | private readonly IDictionary _environmentService; 26 | 27 | internal EnvironmentOptions() => new EnvironmentOptions(new Dictionary()); 28 | internal EnvironmentOptions(IDictionary service) 29 | { 30 | _environmentService = service; 31 | } 32 | 33 | internal string ApiKey => GetEnvironmentVariable(ApiKeyKey); 34 | internal string TracesApiKey => GetEnvironmentVariable(TracesApiKeyKey); 35 | internal string MetricsApiKey => GetEnvironmentVariable(MetricsApiKeyKey); 36 | internal string Dataset => GetEnvironmentVariable(DatasetKey); 37 | internal string TracesDataset => GetEnvironmentVariable(TracesDatasetKey); 38 | internal string MetricsDataset => GetEnvironmentVariable(MetricsDatasetKey); 39 | internal string ApiEndpoint => GetEnvironmentVariable(ApiEndpointKey); 40 | internal string TracesEndpoint => GetEnvironmentVariable(TracesEndpointKey); 41 | internal string MetricsEndpoint => GetEnvironmentVariable(MetricsEndpointKey); 42 | internal string ServiceName => GetEnvironmentVariable(ServiceNameKey); 43 | internal string ServiceVersion => GetEnvironmentVariable(ServiceVersionKey); 44 | internal string EnableLocalVisualizationsValue => GetEnvironmentVariable(EnableLocalVisualizationsKey); 45 | internal bool EnableLocalVisualizations => bool.TryParse(EnableLocalVisualizationsValue, out var enableLocalVisualizations) ? enableLocalVisualizations : false; 46 | internal string DebugValue => GetEnvironmentVariable(DebugKey); 47 | internal bool Debug => bool.TryParse(DebugValue, out var debug) ? debug : false; 48 | internal string SampleRateValue => GetEnvironmentVariable(SampleRateKey); 49 | internal uint SampleRate => uint.TryParse(SampleRateValue, out var sampleRate) ? sampleRate : DefaultSampleRate; 50 | internal string OtelExporterOtlpProtocol => GetEnvironmentVariable(OtelExporterOtlpProtocolKey); 51 | private string GetEnvironmentVariable(string key, string defaultValue = "") 52 | { 53 | var value = _environmentService[key]; 54 | if (value is string str && !string.IsNullOrWhiteSpace(str)) 55 | { 56 | return str; 57 | } 58 | 59 | return defaultValue; 60 | } 61 | 62 | internal static string GetErrorMessage(string humanKey, string key) 63 | { 64 | return ($"Missing {humanKey}. Specify {key} environment variable, or the associated property in appsettings.json or the command line"); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry/ConsoleTraceLinkExporter.cs: -------------------------------------------------------------------------------- 1 | using OpenTelemetry; 2 | using System; 3 | using System.Diagnostics; 4 | using System.Net.Http; 5 | using System.Text.Json; 6 | using System.Text.Json.Serialization; 7 | 8 | namespace Honeycomb.OpenTelemetry 9 | { 10 | /// 11 | /// Writes links to the Honeycomb UI for all root spans to the console 12 | /// 13 | internal class ConsoleTraceLinkExporter : BaseExporter 14 | { 15 | private const string ApiHost = "https://api.honeycomb.io"; 16 | private string _apiKey; 17 | private string _serviceName; 18 | private string _teamSlug; 19 | private string _environmentSlug; 20 | 21 | private bool IsEnabled = false; 22 | 23 | /// 24 | /// Initializes the class 25 | /// 26 | /// Settings for Link generation 27 | public ConsoleTraceLinkExporter(HoneycombOptions options) 28 | { 29 | _apiKey = options.ApiKey; 30 | _serviceName = options.ServiceName; 31 | try 32 | { 33 | InitTraceLinkParameters(); 34 | } 35 | catch (Exception) 36 | { 37 | Console.WriteLine("WARN: Failed to get data from Honeycomb Auth Endpoint"); 38 | } 39 | } 40 | 41 | private void InitTraceLinkParameters() 42 | { 43 | if (string.IsNullOrEmpty(_apiKey)) 44 | { 45 | return; 46 | } 47 | 48 | var httpClient = new HttpClient(); 49 | httpClient.BaseAddress = new Uri(ApiHost); 50 | httpClient.DefaultRequestHeaders.Add("X-Honeycomb-Team", _apiKey); 51 | 52 | var response = httpClient.GetAsync("/1/auth").GetAwaiter().GetResult(); 53 | if (!response.IsSuccessStatusCode) 54 | { 55 | Console.WriteLine("WARN: Didn't get a valid response from Honeycomb"); 56 | return; 57 | } 58 | 59 | var responseString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); 60 | var authResponse = JsonSerializer.Deserialize(responseString); 61 | _environmentSlug = authResponse.Environment.Slug; 62 | _teamSlug = authResponse.Team.Slug; 63 | if (string.IsNullOrEmpty(_environmentSlug) || 64 | string.IsNullOrEmpty(_teamSlug)) 65 | { 66 | Console.WriteLine("WARN: Team or Environment wasn't returned"); 67 | return; 68 | } 69 | IsEnabled = true; 70 | } 71 | 72 | /// 73 | public override ExportResult Export(in Batch batch) 74 | { 75 | if (!IsEnabled) 76 | { 77 | return ExportResult.Success; 78 | } 79 | 80 | foreach (var activity in batch) 81 | { 82 | if (string.IsNullOrEmpty(activity.ParentId)) 83 | { 84 | Console.WriteLine($"Trace for {activity.DisplayName}" + Environment.NewLine + 85 | $"Honeycomb link: {GetTraceLink(activity.TraceId.ToString())}"); 86 | } 87 | } 88 | return ExportResult.Success; 89 | } 90 | 91 | private string GetTraceLink(string traceId) => 92 | _apiKey.Length == 32 93 | ? $"http://ui.honeycomb.io/{_teamSlug}/datasets/{_serviceName}/trace?trace_id={traceId}" 94 | : $"http://ui.honeycomb.io/{_teamSlug}/environments/{_environmentSlug}/datasets/{_serviceName}/trace?trace_id={traceId}"; 95 | } 96 | 97 | internal class AuthResponse 98 | { 99 | [JsonPropertyName("environment")] 100 | public HoneycombEnvironment Environment { get; set; } 101 | 102 | [JsonPropertyName("team")] 103 | public Team Team { get; set; } 104 | } 105 | internal class HoneycombEnvironment 106 | { 107 | [JsonPropertyName("slug")] 108 | public string Slug { get; set; } 109 | } 110 | 111 | internal class Team 112 | { 113 | [JsonPropertyName("slug")] 114 | public string Slug { get; set; } 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | windows: circleci/windows@5.0.0 5 | bats: circleci/bats@1.0.0 6 | 7 | commands: 8 | setup: 9 | steps: 10 | - checkout 11 | - run: 12 | name: "Generate cache seed" 13 | command: | 14 | Get-ChildItem -Path $HOME\*.csproj -Recurse ` 15 | | Sort-Object Name ` 16 | | ForEach-Object { Get-Content $_ } ` 17 | | Out-File -FilePath .\cache-seed -Append 18 | - restore_cache: 19 | keys: 20 | - dotnet-packages-v1-{{ checksum "cache-seed" }} 21 | - run: 22 | name: "Install project dependencies" 23 | command: dotnet.exe restore 24 | - save_cache: 25 | paths: 26 | - C:\Users\circleci\.nuget\packages 27 | key: dotnet-packages-v1-{{ checksum "cache-seed" }} 28 | 29 | jobs: 30 | test: 31 | executor: 32 | name: windows/default 33 | steps: 34 | - setup 35 | - run: 36 | name: "Run tests" 37 | command: dotnet.exe test --no-restore 38 | package: 39 | executor: 40 | name: windows/default 41 | steps: 42 | - setup 43 | - run: 44 | name: "Create build directory" 45 | command: mkdir -p build 46 | shell: bash.exe 47 | - run: 48 | name: "Import GPG cert" 49 | command: echo $GPG_BASE64 | base64 --decode | gpg.exe --batch --no-tty --import --yes 50 | shell: bash.exe 51 | - run: 52 | name: "Decrypt SNK file" 53 | command: gpg.exe --decrypt --pinentry-mode loopback --passphrase $GPG_PASSPHRASE --output Honeycomb.OpenTelemetry.snk Honeycomb.OpenTelemetry.snk.gpg 54 | shell: bash.exe 55 | - run: 56 | name: "Build release package" 57 | command: dotnet.exe pack --configuration release --output build --no-restore -p:signed=true 58 | - persist_to_workspace: 59 | root: \ 60 | paths: 61 | - build\* 62 | - store_artifacts: 63 | path: build 64 | 65 | smoke_test: 66 | machine: 67 | image: ubuntu-2204:2024.01.1 68 | steps: 69 | - checkout 70 | - attach_workspace: 71 | at: ./ 72 | - bats/install 73 | - run: 74 | name: What's the BATS? 75 | command: | 76 | which bats 77 | bats --version 78 | - run: 79 | name: Smoke Test 80 | command: make smoke 81 | - store_test_results: 82 | path: ./smoke-tests/ 83 | - store_artifacts: 84 | path: ./smoke-tests/report.xml 85 | - store_artifacts: 86 | path: ./smoke-tests/collector/data-results 87 | - run: 88 | name: Extinguish the flames 89 | command: make unsmoke 90 | 91 | publish_github: 92 | docker: 93 | - image: cibuilds/github:0.13.0 94 | steps: 95 | - attach_workspace: 96 | at: ./ 97 | - run: 98 | name: "Publishing Release on GitHub" 99 | command: ghr -draft -n ${CIRCLE_TAG} -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} ${CIRCLE_TAG} build/ 100 | 101 | publish_nuget: 102 | executor: 103 | name: windows/default 104 | steps: 105 | - attach_workspace: 106 | at: .\ 107 | - run: 108 | name: "Publishing to nuget.org" 109 | command: dotnet.exe nuget push "build\*.nupkg" --api-key $env:NUGET_APIKEY --source https://api.nuget.org/v3/index.json 110 | 111 | # Apply this filter to jobs that should always run. 112 | filter_always: &filter_always 113 | filters: 114 | tags: 115 | only: /.*/ 116 | 117 | # Apply this filter to release-time jobs that should 118 | # only run when a version tag (v1.2.3) is pushed. 119 | filter_version_tag: &filter_version_tag 120 | filters: 121 | tags: 122 | only: /^v.*/ 123 | branches: 124 | ignore: /.*/ 125 | 126 | # Apply this filter to jobs that require secrets, which 127 | # are unavailable to PRs from forks and Dependabot. 128 | filter_exclude_forks: &filter_exclude_forks 129 | filters: 130 | tags: 131 | only: /.*/ 132 | branches: 133 | ignore: /^(pull|dependabot)\/.*$/ 134 | 135 | workflows: 136 | version: 2 137 | nightly: 138 | triggers: 139 | - schedule: 140 | cron: "0 0 * * *" 141 | filters: 142 | branches: 143 | only: 144 | - main 145 | jobs: 146 | - test 147 | - smoke_test: 148 | requires: 149 | - test 150 | 151 | build: 152 | jobs: 153 | - test: 154 | <<: *filter_always 155 | - smoke_test: 156 | requires: 157 | - test 158 | <<: *filter_always 159 | - package: 160 | context: Honeycomb Secrets for Public Repos 161 | requires: 162 | - test 163 | <<: *filter_exclude_forks 164 | - publish_github: 165 | context: Honeycomb Secrets for Public Repos 166 | requires: 167 | - smoke_test 168 | - package 169 | <<: *filter_version_tag 170 | - publish_nuget: 171 | context: Honeycomb Secrets for Public Repos 172 | requires: 173 | - smoke_test 174 | - package 175 | <<: *filter_version_tag 176 | -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry/ResourceBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Collections.Generic; 4 | using System.Reflection; 5 | 6 | namespace OpenTelemetry.Resources 7 | { 8 | /// 9 | /// Extension methods to configure with Honeycomb distro attributes. 10 | /// 11 | public static class ResourceBuilderExtensions 12 | { 13 | /// 14 | /// Configures the with Honeycomb attributes. 15 | /// 16 | public static ResourceBuilder AddHoneycombAttributes(this ResourceBuilder builder) 17 | { 18 | return builder 19 | .AddAttributes(new List> 20 | { 21 | new KeyValuePair("honeycomb.distro.language", "dotnet"), 22 | new KeyValuePair("honeycomb.distro.version", GetFileVersion()), 23 | new KeyValuePair("honeycomb.distro.runtime_version", 24 | Environment.Version.ToString()), 25 | }) 26 | .AddRuntimeResource() 27 | .AddOSResource(); 28 | } 29 | 30 | /// 31 | /// Determines process runtime resources and adds them to the . 32 | /// 33 | /// 34 | /// See https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/process/#process-runtimes 35 | /// 36 | private static ResourceBuilder AddRuntimeResource(this ResourceBuilder builder) 37 | { 38 | var frameworkDescription = RuntimeInformation.FrameworkDescription; 39 | 40 | var runtimeName = "unknown"; 41 | var runtimeVersion = "unknown"; 42 | 43 | if (!frameworkDescription.StartsWith(".NET")) 44 | { 45 | return builder; 46 | } 47 | 48 | if (frameworkDescription.StartsWith(".NET Core")) 49 | { 50 | runtimeName = ".NET Core"; 51 | runtimeVersion = frameworkDescription.Substring(".NET Core".Length); 52 | } 53 | else if (frameworkDescription.StartsWith(".NET Framework")) 54 | { 55 | runtimeName = ".NET Framework"; 56 | runtimeVersion = frameworkDescription.Substring(".NET Framework".Length); 57 | } 58 | else if (frameworkDescription.StartsWith(".NET Native")) 59 | { 60 | // I doubt we'll ever see a user match this, but it's a valid runtime, so... 61 | runtimeName = ".NET Native"; 62 | runtimeVersion = frameworkDescription.Substring(".NET Native".Length); 63 | } 64 | else 65 | { 66 | runtimeName = ".NET"; 67 | runtimeVersion = frameworkDescription.Substring(".NET".Length); 68 | } 69 | 70 | return builder 71 | .AddAttributes(new List> 72 | { 73 | new KeyValuePair("process.runtime.name", runtimeName), 74 | new KeyValuePair("process.runtime.version", runtimeVersion) 75 | }); 76 | } 77 | 78 | private static ResourceBuilder AddOSResource(this ResourceBuilder builder) 79 | { 80 | var osType = "unknown"; 81 | var osName = "unknown"; 82 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 83 | { 84 | osType = "windows"; 85 | osName = "Windows"; 86 | } 87 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 88 | { 89 | osType = "linux"; 90 | osName = "Linux"; 91 | } 92 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 93 | { 94 | osType = "darwin"; 95 | osName = "macOS"; 96 | } 97 | 98 | var versionWithPotentialWindowsServicePack = Environment.OSVersion.VersionString.IndexOf(" ") + 1; 99 | return builder 100 | .AddAttributes(new List> 101 | { 102 | new KeyValuePair("os.type", osType), 103 | new KeyValuePair("os.description", 104 | Environment.OSVersion.VersionString), 105 | new KeyValuePair("os.name", osName), 106 | new KeyValuePair("os.version", 107 | Environment.OSVersion.VersionString.Substring(versionWithPotentialWindowsServicePack)), 108 | }); 109 | } 110 | 111 | private static string GetFileVersion() 112 | { 113 | var version = typeof(Honeycomb.OpenTelemetry.HoneycombOptions) 114 | .Assembly 115 | .GetCustomAttribute() 116 | .InformationalVersion; 117 | 118 | // AssemblyInformationalVersionAttribute may include the latest commit hash in 119 | // the form `{version_prefix}{version_suffix}+{commit_hash}`. 120 | // We should trim the hash if present to just leave the version prefix and suffix 121 | var i = version.IndexOf("+"); 122 | return i > 0 123 | ? version.Substring(0, i) 124 | : version; 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry/TracerProviderBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Honeycomb.OpenTelemetry; 2 | using Microsoft.Extensions.Configuration; 3 | using OpenTelemetry.Resources; 4 | using System; 5 | using System.Text.Json; 6 | 7 | #if NET462 8 | using System.Collections.Generic; 9 | #endif 10 | 11 | namespace OpenTelemetry.Trace 12 | { 13 | /// 14 | /// Extension methods to configure to send telemetry data to Honeycomb. 15 | /// 16 | public static class TracerProviderBuilderExtensions 17 | { 18 | /// 19 | /// Configures the to send telemetry data to Honeycomb. 20 | /// 21 | /// being configured. 22 | /// Action delegate that configures a . 23 | /// The instance of to chain the calls. 24 | public static TracerProviderBuilder AddHoneycomb(this TracerProviderBuilder builder, 25 | Action configureHoneycombOptions = null) 26 | { 27 | var honeycombOptions = new HoneycombOptions { }; 28 | configureHoneycombOptions?.Invoke(honeycombOptions); 29 | return builder.AddHoneycomb(honeycombOptions); 30 | } 31 | 32 | /// 33 | /// Configures the to send telemetry data to Honeycomb. 34 | /// 35 | /// being configured. 36 | /// The to configure with 37 | /// The instance of to chain the calls. 38 | public static TracerProviderBuilder AddHoneycomb(this TracerProviderBuilder builder, IConfiguration configuration) 39 | { 40 | return builder.AddHoneycomb(configuration.GetSection(HoneycombOptions.ConfigSectionName).Get()); 41 | } 42 | 43 | /// 44 | /// Configures the to send telemetry data to Honeycomb using an instance of . 45 | /// 46 | public static TracerProviderBuilder AddHoneycomb(this TracerProviderBuilder builder, HoneycombOptions options) 47 | { 48 | if (options is null) 49 | { 50 | options = new HoneycombOptions { }; 51 | } 52 | 53 | options.ApplyEnvironmentOptions(new EnvironmentOptions(Environment.GetEnvironmentVariables())); 54 | 55 | var tracesEndpoint = options.GetTracesEndpoint(); 56 | var tracesApiKey = options.GetTracesApiKey(); 57 | var tracesDataset = options.GetTracesDataset(); 58 | 59 | // if serviceName is null, warn and set to default 60 | if (string.IsNullOrWhiteSpace(options.ServiceName)) 61 | { 62 | options.ServiceName = HoneycombOptions.SDefaultServiceName; 63 | Console.WriteLine($"WARN: {EnvironmentOptions.GetErrorMessage("service name", "OTEL_SERVICE_NAME")}. If left unset, this will show up in Honeycomb as unknown_service:."); 64 | } 65 | 66 | builder 67 | .AddSource(options.ServiceName) 68 | .SetResourceBuilder( 69 | options.ResourceBuilder 70 | .AddHoneycombAttributes() 71 | .AddService(serviceName: options.ServiceName, serviceVersion: options.ServiceVersion) 72 | .AddEnvironmentVariableDetector() 73 | ); 74 | 75 | if (options.AddDeterministicSampler) 76 | { 77 | builder.AddDeterministicSampler(options.SampleRate); 78 | } 79 | 80 | if (options.AddBaggageSpanProcessor) 81 | { 82 | builder.AddBaggageSpanProcessor(); 83 | } 84 | 85 | if (!string.IsNullOrWhiteSpace(tracesApiKey)) 86 | { 87 | builder.AddHoneycombOtlpExporter(tracesApiKey, tracesDataset, tracesEndpoint); 88 | } 89 | else 90 | { 91 | Console.WriteLine($"WARN: {EnvironmentOptions.GetErrorMessage("API Key", "HONEYCOMB_API_KEY")}."); 92 | } 93 | 94 | if (options.EnableLocalVisualizations) 95 | { 96 | builder.AddProcessor(new SimpleActivityExportProcessor(new ConsoleTraceLinkExporter(options))); 97 | } 98 | 99 | if (options.Debug) 100 | { 101 | builder.AddConsoleExporter(); 102 | Console.WriteLine("DEBUG: HoneycombOptions"); 103 | Console.WriteLine(JsonSerializer.Serialize(options, new JsonSerializerOptions { WriteIndented = true })); 104 | } 105 | 106 | // heads up: even if dataset is set, it will be ignored 107 | if (!string.IsNullOrWhiteSpace(tracesApiKey) & !HoneycombOptions.IsClassicKey(tracesApiKey) & (!string.IsNullOrWhiteSpace(tracesDataset))) 108 | { 109 | if (!string.IsNullOrWhiteSpace(options.ServiceName)) 110 | { 111 | Console.WriteLine($"WARN: Dataset is ignored in favor of service name. Data will be sent to service name: {options.ServiceName}"); 112 | } 113 | else 114 | { 115 | // should only get here if missing service name and dataset 116 | Console.WriteLine("WARN: Dataset is ignored in favor of service name."); 117 | } 118 | } 119 | 120 | return builder; 121 | } 122 | 123 | /// 124 | /// Configures the to add the span processor. 125 | /// 126 | public static TracerProviderBuilder AddBaggageSpanProcessor(this TracerProviderBuilder builder) 127 | { 128 | return builder.AddProcessor(new BaggageSpanProcessor()); 129 | } 130 | 131 | /// 132 | /// Configures the to add the trace sampler. 133 | /// 134 | public static TracerProviderBuilder AddDeterministicSampler(this TracerProviderBuilder builder, uint sampleRate) 135 | { 136 | return builder.SetSampler(new DeterministicSampler(sampleRate)); 137 | } 138 | 139 | /// 140 | /// Configures the with an OTLP exporter that sends trace telemetry to Honeycomb. 141 | /// 142 | public static TracerProviderBuilder AddHoneycombOtlpExporter(this TracerProviderBuilder builder, string apikey, string dataset = null, string endpoint = null) 143 | { 144 | return builder.AddOtlpExporter(otlpOptions => 145 | { 146 | otlpOptions.Endpoint = new Uri(endpoint); 147 | otlpOptions.Headers = HoneycombOptions.GetTraceHeaders(apikey, dataset); 148 | }); 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | 9 | # C# files 10 | [*.cs] 11 | 12 | #### Core EditorConfig Options #### 13 | 14 | # Indentation and spacing 15 | indent_size = 4 16 | indent_style = space 17 | tab_width = 4 18 | 19 | # New line preferences 20 | end_of_line = crlf 21 | insert_final_newline = false 22 | 23 | #### .NET Coding Conventions #### 24 | 25 | # Organize usings 26 | dotnet_separate_import_directive_groups = false 27 | dotnet_sort_system_directives_first = false 28 | file_header_template = unset 29 | 30 | # this. and Me. preferences 31 | dotnet_style_qualification_for_event = false:silent 32 | dotnet_style_qualification_for_field = false:silent 33 | dotnet_style_qualification_for_method = false:silent 34 | dotnet_style_qualification_for_property = false:silent 35 | 36 | # Language keywords vs BCL types preferences 37 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent 38 | dotnet_style_predefined_type_for_member_access = true:silent 39 | 40 | # Parentheses preferences 41 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent 42 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent 43 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent 44 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent 45 | 46 | # Modifier preferences 47 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent 48 | 49 | # Expression-level preferences 50 | dotnet_style_coalesce_expression = true:suggestion 51 | dotnet_style_collection_initializer = true:suggestion 52 | dotnet_style_explicit_tuple_names = true:suggestion 53 | dotnet_style_null_propagation = true:suggestion 54 | dotnet_style_object_initializer = true:suggestion 55 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 56 | dotnet_style_prefer_auto_properties = true:silent 57 | dotnet_style_prefer_compound_assignment = true:suggestion 58 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 59 | dotnet_style_prefer_conditional_expression_over_return = true:silent 60 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 61 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 62 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 63 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion 64 | dotnet_style_prefer_simplified_interpolation = true:suggestion 65 | 66 | # Field preferences 67 | dotnet_style_readonly_field = true:suggestion 68 | 69 | # Parameter preferences 70 | dotnet_code_quality_unused_parameters = all:suggestion 71 | 72 | # Suppression preferences 73 | dotnet_remove_unnecessary_suppression_exclusions = none 74 | 75 | #### C# Coding Conventions #### 76 | 77 | # var preferences 78 | csharp_style_var_elsewhere = false:silent 79 | csharp_style_var_for_built_in_types = false:silent 80 | csharp_style_var_when_type_is_apparent = false:silent 81 | 82 | # Expression-bodied members 83 | csharp_style_expression_bodied_accessors = true:silent 84 | csharp_style_expression_bodied_constructors = false:silent 85 | csharp_style_expression_bodied_indexers = true:silent 86 | csharp_style_expression_bodied_lambdas = true:silent 87 | csharp_style_expression_bodied_local_functions = false:silent 88 | csharp_style_expression_bodied_methods = false:silent 89 | csharp_style_expression_bodied_operators = false:silent 90 | csharp_style_expression_bodied_properties = true:silent 91 | 92 | # Pattern matching preferences 93 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 94 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 95 | csharp_style_prefer_not_pattern = true:suggestion 96 | csharp_style_prefer_pattern_matching = true:silent 97 | csharp_style_prefer_switch_expression = true:suggestion 98 | 99 | # Null-checking preferences 100 | csharp_style_conditional_delegate_call = true:suggestion 101 | 102 | # Modifier preferences 103 | csharp_prefer_static_local_function = true:suggestion 104 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent 105 | 106 | # Code-block preferences 107 | csharp_prefer_braces = true:silent 108 | csharp_prefer_simple_using_statement = true:suggestion 109 | 110 | # Expression-level preferences 111 | csharp_prefer_simple_default_expression = true:suggestion 112 | csharp_style_deconstructed_variable_declaration = true:suggestion 113 | csharp_style_inlined_variable_declaration = true:suggestion 114 | csharp_style_pattern_local_over_anonymous_function = true:suggestion 115 | csharp_style_prefer_index_operator = true:suggestion 116 | csharp_style_prefer_range_operator = true:suggestion 117 | csharp_style_throw_expression = true:suggestion 118 | csharp_style_unused_value_assignment_preference = discard_variable:suggestion 119 | csharp_style_unused_value_expression_statement_preference = discard_variable:silent 120 | 121 | #### C# Formatting Rules #### 122 | 123 | # New line preferences 124 | csharp_new_line_before_catch = true 125 | csharp_new_line_before_else = true 126 | csharp_new_line_before_finally = true 127 | csharp_new_line_before_members_in_anonymous_types = true 128 | csharp_new_line_before_members_in_object_initializers = true 129 | csharp_new_line_before_open_brace = all 130 | csharp_new_line_between_query_expression_clauses = true 131 | 132 | # Indentation preferences 133 | csharp_indent_block_contents = true 134 | csharp_indent_braces = false 135 | csharp_indent_case_contents = true 136 | csharp_indent_case_contents_when_block = true 137 | csharp_indent_labels = one_less_than_current 138 | csharp_indent_switch_labels = true 139 | 140 | # Space preferences 141 | csharp_space_after_cast = false 142 | csharp_space_after_colon_in_inheritance_clause = true 143 | csharp_space_after_comma = true 144 | csharp_space_after_dot = false 145 | csharp_space_after_keywords_in_control_flow_statements = true 146 | csharp_space_after_semicolon_in_for_statement = true 147 | csharp_space_around_binary_operators = before_and_after 148 | csharp_space_around_declaration_statements = false 149 | csharp_space_before_colon_in_inheritance_clause = true 150 | csharp_space_before_comma = false 151 | csharp_space_before_dot = false 152 | csharp_space_before_open_square_brackets = false 153 | csharp_space_before_semicolon_in_for_statement = false 154 | csharp_space_between_empty_square_brackets = false 155 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 156 | csharp_space_between_method_call_name_and_opening_parenthesis = false 157 | csharp_space_between_method_call_parameter_list_parentheses = false 158 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 159 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 160 | csharp_space_between_method_declaration_parameter_list_parentheses = false 161 | csharp_space_between_parentheses = false 162 | csharp_space_between_square_brackets = false 163 | 164 | # Wrapping preferences 165 | csharp_preserve_single_line_blocks = true 166 | csharp_preserve_single_line_statements = true 167 | 168 | #### Naming styles #### 169 | 170 | # Naming rules 171 | 172 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 173 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 174 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 175 | 176 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 177 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 178 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 179 | 180 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 181 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 182 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 183 | 184 | # Symbol specifications 185 | 186 | dotnet_naming_symbols.interface.applicable_kinds = interface 187 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 188 | dotnet_naming_symbols.interface.required_modifiers = 189 | 190 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 191 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 192 | dotnet_naming_symbols.types.required_modifiers = 193 | 194 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 195 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 196 | dotnet_naming_symbols.non_field_members.required_modifiers = 197 | 198 | # Naming styles 199 | 200 | dotnet_naming_style.pascal_case.required_prefix = 201 | dotnet_naming_style.pascal_case.required_suffix = 202 | dotnet_naming_style.pascal_case.word_separator = 203 | dotnet_naming_style.pascal_case.capitalization = pascal_case 204 | 205 | dotnet_naming_style.begins_with_i.required_prefix = I 206 | dotnet_naming_style.begins_with_i.required_suffix = 207 | dotnet_naming_style.begins_with_i.word_separator = 208 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 209 | 210 | # Xml project files 211 | [*.csproj] 212 | indent_size = 2 213 | 214 | [Makefile] 215 | indent_style = tab 216 | -------------------------------------------------------------------------------- /.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/master/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 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # Tye 66 | .tye/ 67 | 68 | # ASP.NET Scaffolding 69 | ScaffoldingReadMe.txt 70 | 71 | # StyleCop 72 | StyleCopReport.xml 73 | 74 | # Files built by Visual Studio 75 | *_i.c 76 | *_p.c 77 | *_h.h 78 | *.ilk 79 | *.meta 80 | *.obj 81 | *.iobj 82 | *.pch 83 | *.pdb 84 | *.ipdb 85 | *.pgc 86 | *.pgd 87 | *.rsp 88 | *.sbr 89 | *.tlb 90 | *.tli 91 | *.tlh 92 | *.tmp 93 | *.tmp_proj 94 | *_wpftmp.csproj 95 | *.log 96 | *.vspscc 97 | *.vssscc 98 | .builds 99 | *.pidb 100 | *.svclog 101 | *.scc 102 | 103 | # Chutzpah Test files 104 | _Chutzpah* 105 | 106 | # Visual C++ cache files 107 | ipch/ 108 | *.aps 109 | *.ncb 110 | *.opendb 111 | *.opensdf 112 | *.sdf 113 | *.cachefile 114 | *.VC.db 115 | *.VC.VC.opendb 116 | 117 | # Visual Studio profiler 118 | *.psess 119 | *.vsp 120 | *.vspx 121 | *.sap 122 | 123 | # Visual Studio Trace Files 124 | *.e2e 125 | 126 | # TFS 2012 Local Workspace 127 | $tf/ 128 | 129 | # Guidance Automation Toolkit 130 | *.gpState 131 | 132 | # ReSharper is a .NET coding add-in 133 | _ReSharper*/ 134 | *.[Rr]e[Ss]harper 135 | *.DotSettings.user 136 | 137 | # TeamCity is a build add-in 138 | _TeamCity* 139 | 140 | # DotCover is a Code Coverage Tool 141 | *.dotCover 142 | 143 | # AxoCover is a Code Coverage Tool 144 | .axoCover/* 145 | !.axoCover/settings.json 146 | 147 | # Coverlet is a free, cross platform Code Coverage Tool 148 | coverage*.json 149 | coverage*.xml 150 | coverage*.info 151 | 152 | # Visual Studio code coverage results 153 | *.coverage 154 | *.coveragexml 155 | 156 | # NCrunch 157 | _NCrunch_* 158 | .*crunch*.local.xml 159 | nCrunchTemp_* 160 | 161 | # MightyMoose 162 | *.mm.* 163 | AutoTest.Net/ 164 | 165 | # Web workbench (sass) 166 | .sass-cache/ 167 | 168 | # Installshield output folder 169 | [Ee]xpress/ 170 | 171 | # DocProject is a documentation generator add-in 172 | DocProject/buildhelp/ 173 | DocProject/Help/*.HxT 174 | DocProject/Help/*.HxC 175 | DocProject/Help/*.hhc 176 | DocProject/Help/*.hhk 177 | DocProject/Help/*.hhp 178 | DocProject/Help/Html2 179 | DocProject/Help/html 180 | 181 | # Click-Once directory 182 | publish/ 183 | 184 | # Publish Web Output 185 | *.[Pp]ublish.xml 186 | *.azurePubxml 187 | # Note: Comment the next line if you want to checkin your web deploy settings, 188 | # but database connection strings (with potential passwords) will be unencrypted 189 | *.pubxml 190 | *.publishproj 191 | 192 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 193 | # checkin your Azure Web App publish settings, but sensitive information contained 194 | # in these scripts will be unencrypted 195 | PublishScripts/ 196 | 197 | # NuGet Packages 198 | *.nupkg 199 | # NuGet Symbol Packages 200 | *.snupkg 201 | # The packages folder can be ignored because of Package Restore 202 | **/[Pp]ackages/* 203 | # except build/, which is used as an MSBuild target. 204 | !**/[Pp]ackages/build/ 205 | # Uncomment if necessary however generally it will be regenerated when needed 206 | #!**/[Pp]ackages/repositories.config 207 | # NuGet v3's project.json files produces more ignorable files 208 | *.nuget.props 209 | *.nuget.targets 210 | 211 | # Microsoft Azure Build Output 212 | csx/ 213 | *.build.csdef 214 | 215 | # Microsoft Azure Emulator 216 | ecf/ 217 | rcf/ 218 | 219 | # Windows Store app package directories and files 220 | AppPackages/ 221 | BundleArtifacts/ 222 | Package.StoreAssociation.xml 223 | _pkginfo.txt 224 | *.appx 225 | *.appxbundle 226 | *.appxupload 227 | 228 | # Visual Studio cache files 229 | # files ending in .cache can be ignored 230 | *.[Cc]ache 231 | # but keep track of directories ending in .cache 232 | !?*.[Cc]ache/ 233 | 234 | # Others 235 | ClientBin/ 236 | ~$* 237 | *~ 238 | *.dbmdl 239 | *.dbproj.schemaview 240 | *.jfm 241 | *.pfx 242 | *.publishsettings 243 | orleans.codegen.cs 244 | 245 | # Including strong name files can present a security risk 246 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 247 | *.snk 248 | 249 | # Since there are multiple workflows, uncomment next line to ignore bower_components 250 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 251 | #bower_components/ 252 | 253 | # RIA/Silverlight projects 254 | Generated_Code/ 255 | 256 | # Backup & report files from converting an old project file 257 | # to a newer Visual Studio version. Backup files are not needed, 258 | # because we have git ;-) 259 | _UpgradeReport_Files/ 260 | Backup*/ 261 | UpgradeLog*.XML 262 | UpgradeLog*.htm 263 | ServiceFabricBackup/ 264 | *.rptproj.bak 265 | 266 | # SQL Server files 267 | *.mdf 268 | *.ldf 269 | *.ndf 270 | 271 | # Business Intelligence projects 272 | *.rdl.data 273 | *.bim.layout 274 | *.bim_*.settings 275 | *.rptproj.rsuser 276 | *- [Bb]ackup.rdl 277 | *- [Bb]ackup ([0-9]).rdl 278 | *- [Bb]ackup ([0-9][0-9]).rdl 279 | 280 | # Microsoft Fakes 281 | FakesAssemblies/ 282 | 283 | # GhostDoc plugin setting file 284 | *.GhostDoc.xml 285 | 286 | # Node.js Tools for Visual Studio 287 | .ntvs_analysis.dat 288 | node_modules/ 289 | 290 | # Visual Studio 6 build log 291 | *.plg 292 | 293 | # Visual Studio 6 workspace options file 294 | *.opt 295 | 296 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 297 | *.vbw 298 | 299 | # Visual Studio LightSwitch build output 300 | **/*.HTMLClient/GeneratedArtifacts 301 | **/*.DesktopClient/GeneratedArtifacts 302 | **/*.DesktopClient/ModelManifest.xml 303 | **/*.Server/GeneratedArtifacts 304 | **/*.Server/ModelManifest.xml 305 | _Pvt_Extensions 306 | 307 | # Paket dependency manager 308 | .paket/paket.exe 309 | paket-files/ 310 | 311 | # FAKE - F# Make 312 | .fake/ 313 | 314 | # CodeRush personal settings 315 | .cr/personal 316 | 317 | # Python Tools for Visual Studio (PTVS) 318 | __pycache__/ 319 | *.pyc 320 | 321 | # Cake - Uncomment if you are using it 322 | # tools/** 323 | # !tools/packages.config 324 | 325 | # Tabs Studio 326 | *.tss 327 | 328 | # Telerik's JustMock configuration file 329 | *.jmconfig 330 | 331 | # BizTalk build output 332 | *.btp.cs 333 | *.btm.cs 334 | *.odx.cs 335 | *.xsd.cs 336 | 337 | # OpenCover UI analysis results 338 | OpenCover/ 339 | 340 | # Azure Stream Analytics local run output 341 | ASALocalRun/ 342 | 343 | # MSBuild Binary and Structured Log 344 | *.binlog 345 | 346 | # NVidia Nsight GPU debugger configuration file 347 | *.nvuser 348 | 349 | # MFractors (Xamarin productivity tool) working folder 350 | .mfractor/ 351 | 352 | # Local History for Visual Studio 353 | .localhistory/ 354 | 355 | # BeatPulse healthcheck temp database 356 | healthchecksdb 357 | 358 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 359 | MigrationBackup/ 360 | 361 | # Ionide (cross platform F# VS Code tools) working folder 362 | .ionide/ 363 | 364 | # Fody - auto-generated XML schema 365 | FodyWeavers.xsd 366 | 367 | ## 368 | ## Visual studio for Mac 369 | ## 370 | 371 | 372 | # globs 373 | Makefile.in 374 | *.userprefs 375 | *.usertasks 376 | config.make 377 | config.status 378 | aclocal.m4 379 | install-sh 380 | autom4te.cache/ 381 | *.tar.gz 382 | tarballs/ 383 | test-results/ 384 | 385 | # Mac bundle stuff 386 | *.dmg 387 | *.app 388 | 389 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore 390 | # General 391 | .DS_Store 392 | .AppleDouble 393 | .LSOverride 394 | 395 | # Icon must end with two \r 396 | Icon 397 | 398 | 399 | # Thumbnails 400 | ._* 401 | 402 | # Files that might appear in the root of a volume 403 | .DocumentRevisions-V100 404 | .fseventsd 405 | .Spotlight-V100 406 | .TemporaryItems 407 | .Trashes 408 | .VolumeIcon.icns 409 | .com.apple.timemachine.donotpresent 410 | 411 | # Directories potentially created on remote AFP share 412 | .AppleDB 413 | .AppleDesktop 414 | Network Trash Folder 415 | Temporary Items 416 | .apdisk 417 | 418 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore 419 | # Windows thumbnail cache files 420 | Thumbs.db 421 | ehthumbs.db 422 | ehthumbs_vista.db 423 | 424 | # Dump file 425 | *.stackdump 426 | 427 | # Folder config file 428 | [Dd]esktop.ini 429 | 430 | # Recycle Bin used on file shares 431 | $RECYCLE.BIN/ 432 | 433 | # Windows Installer files 434 | *.cab 435 | *.msi 436 | *.msix 437 | *.msm 438 | *.msp 439 | 440 | # Windows shortcuts 441 | *.lnk 442 | 443 | # JetBrains Rider 444 | .idea/ 445 | *.sln.iml 446 | 447 | ## 448 | ## Visual Studio Code 449 | ## 450 | .vscode/* 451 | !.vscode/settings.json 452 | !.vscode/tasks.json 453 | !.vscode/launch.json 454 | !.vscode/extensions.json 455 | 456 | ### temporary smoke-test files 457 | smoke-tests/collector/data.json 458 | smoke-tests/collector/data-results/*.json 459 | smoke-tests/report.xml 460 | smoke-tests/report.html 461 | 462 | # asdf local tools versions file 463 | .tool-versions -------------------------------------------------------------------------------- /honeycomb-opentelemetry.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.32916.344 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3E7EDB35-637A-402C-ABA6-EF8E4C55C051}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Honeycomb.OpenTelemetry", "src\Honeycomb.OpenTelemetry\Honeycomb.OpenTelemetry.csproj", "{061494E1-D5D7-479E-BE88-FE0E2F94D9F5}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{B622C013-E4C5-4632-A263-B652C38D2E27}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Honeycomb.OpenTelemetry.Tests", "test\Honeycomb.OpenTelemetry.Tests\Honeycomb.OpenTelemetry.Tests.csproj", "{DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{B2B54384-A507-44F4-B611-039F7CC27AC0}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "console", "examples\console\console.csproj", "{DC70B54C-4F4E-4826-A41B-99E976E9475A}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "aspnetcore", "examples\aspnetcore\aspnetcore.csproj", "{37D377D0-7C5A-4F44-B535-C9DA60FDB723}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "aspnetcoreredis", "examples\aspnetcore-redis\aspnetcoreredis.csproj", "{41B05546-CC58-4546-AC73-2497F7CD8FD8}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Honeycomb.OpenTelemetry.Instrumentation.AspNetCore", "src\Honeycomb.OpenTelemetry.Instrumentation.AspNetCore\Honeycomb.OpenTelemetry.Instrumentation.AspNetCore.csproj", "{DB772676-A314-44DC-8EBD-971FBE6953B9}" 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Honeycomb.OpenTelemetry.CommonInstrumentations", "src\Honeycomb.OpenTelemetry.CommonInstrumentations\Honeycomb.OpenTelemetry.CommonInstrumentations.csproj", "{CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}" 25 | EndProject 26 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "aspnetcore-fsharp", "examples\aspnetcore-fsharp\aspnetcore-fsharp.fsproj", "{72DF2078-62A4-4529-B439-BFFF4AD4C6B9}" 27 | EndProject 28 | Global 29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 30 | Debug|Any CPU = Debug|Any CPU 31 | Debug|x64 = Debug|x64 32 | Debug|x86 = Debug|x86 33 | Release|Any CPU = Release|Any CPU 34 | Release|x64 = Release|x64 35 | Release|x86 = Release|x86 36 | EndGlobalSection 37 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 38 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5}.Debug|x64.ActiveCfg = Debug|Any CPU 41 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5}.Debug|x64.Build.0 = Debug|Any CPU 42 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5}.Debug|x86.ActiveCfg = Debug|Any CPU 43 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5}.Debug|x86.Build.0 = Debug|Any CPU 44 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5}.Release|x64.ActiveCfg = Release|Any CPU 47 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5}.Release|x64.Build.0 = Release|Any CPU 48 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5}.Release|x86.ActiveCfg = Release|Any CPU 49 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5}.Release|x86.Build.0 = Release|Any CPU 50 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}.Debug|x64.ActiveCfg = Debug|Any CPU 53 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}.Debug|x64.Build.0 = Debug|Any CPU 54 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}.Debug|x86.ActiveCfg = Debug|Any CPU 55 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}.Debug|x86.Build.0 = Debug|Any CPU 56 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}.Release|Any CPU.Build.0 = Release|Any CPU 58 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}.Release|x64.ActiveCfg = Release|Any CPU 59 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}.Release|x64.Build.0 = Release|Any CPU 60 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}.Release|x86.ActiveCfg = Release|Any CPU 61 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E}.Release|x86.Build.0 = Release|Any CPU 62 | {DC70B54C-4F4E-4826-A41B-99E976E9475A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 63 | {DC70B54C-4F4E-4826-A41B-99E976E9475A}.Debug|Any CPU.Build.0 = Debug|Any CPU 64 | {DC70B54C-4F4E-4826-A41B-99E976E9475A}.Debug|x64.ActiveCfg = Debug|Any CPU 65 | {DC70B54C-4F4E-4826-A41B-99E976E9475A}.Debug|x64.Build.0 = Debug|Any CPU 66 | {DC70B54C-4F4E-4826-A41B-99E976E9475A}.Debug|x86.ActiveCfg = Debug|Any CPU 67 | {DC70B54C-4F4E-4826-A41B-99E976E9475A}.Debug|x86.Build.0 = Debug|Any CPU 68 | {DC70B54C-4F4E-4826-A41B-99E976E9475A}.Release|Any CPU.ActiveCfg = Release|Any CPU 69 | {DC70B54C-4F4E-4826-A41B-99E976E9475A}.Release|Any CPU.Build.0 = Release|Any CPU 70 | {DC70B54C-4F4E-4826-A41B-99E976E9475A}.Release|x64.ActiveCfg = Release|Any CPU 71 | {DC70B54C-4F4E-4826-A41B-99E976E9475A}.Release|x64.Build.0 = Release|Any CPU 72 | {DC70B54C-4F4E-4826-A41B-99E976E9475A}.Release|x86.ActiveCfg = Release|Any CPU 73 | {DC70B54C-4F4E-4826-A41B-99E976E9475A}.Release|x86.Build.0 = Release|Any CPU 74 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 75 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723}.Debug|Any CPU.Build.0 = Debug|Any CPU 76 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723}.Debug|x64.ActiveCfg = Debug|Any CPU 77 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723}.Debug|x64.Build.0 = Debug|Any CPU 78 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723}.Debug|x86.ActiveCfg = Debug|Any CPU 79 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723}.Debug|x86.Build.0 = Debug|Any CPU 80 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723}.Release|Any CPU.ActiveCfg = Release|Any CPU 81 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723}.Release|Any CPU.Build.0 = Release|Any CPU 82 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723}.Release|x64.ActiveCfg = Release|Any CPU 83 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723}.Release|x64.Build.0 = Release|Any CPU 84 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723}.Release|x86.ActiveCfg = Release|Any CPU 85 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723}.Release|x86.Build.0 = Release|Any CPU 86 | {41B05546-CC58-4546-AC73-2497F7CD8FD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 87 | {41B05546-CC58-4546-AC73-2497F7CD8FD8}.Debug|Any CPU.Build.0 = Debug|Any CPU 88 | {41B05546-CC58-4546-AC73-2497F7CD8FD8}.Debug|x64.ActiveCfg = Debug|Any CPU 89 | {41B05546-CC58-4546-AC73-2497F7CD8FD8}.Debug|x64.Build.0 = Debug|Any CPU 90 | {41B05546-CC58-4546-AC73-2497F7CD8FD8}.Debug|x86.ActiveCfg = Debug|Any CPU 91 | {41B05546-CC58-4546-AC73-2497F7CD8FD8}.Debug|x86.Build.0 = Debug|Any CPU 92 | {41B05546-CC58-4546-AC73-2497F7CD8FD8}.Release|Any CPU.ActiveCfg = Release|Any CPU 93 | {41B05546-CC58-4546-AC73-2497F7CD8FD8}.Release|Any CPU.Build.0 = Release|Any CPU 94 | {41B05546-CC58-4546-AC73-2497F7CD8FD8}.Release|x64.ActiveCfg = Release|Any CPU 95 | {41B05546-CC58-4546-AC73-2497F7CD8FD8}.Release|x64.Build.0 = Release|Any CPU 96 | {41B05546-CC58-4546-AC73-2497F7CD8FD8}.Release|x86.ActiveCfg = Release|Any CPU 97 | {41B05546-CC58-4546-AC73-2497F7CD8FD8}.Release|x86.Build.0 = Release|Any CPU 98 | {DB772676-A314-44DC-8EBD-971FBE6953B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 99 | {DB772676-A314-44DC-8EBD-971FBE6953B9}.Debug|Any CPU.Build.0 = Debug|Any CPU 100 | {DB772676-A314-44DC-8EBD-971FBE6953B9}.Debug|x64.ActiveCfg = Debug|Any CPU 101 | {DB772676-A314-44DC-8EBD-971FBE6953B9}.Debug|x64.Build.0 = Debug|Any CPU 102 | {DB772676-A314-44DC-8EBD-971FBE6953B9}.Debug|x86.ActiveCfg = Debug|Any CPU 103 | {DB772676-A314-44DC-8EBD-971FBE6953B9}.Debug|x86.Build.0 = Debug|Any CPU 104 | {DB772676-A314-44DC-8EBD-971FBE6953B9}.Release|Any CPU.ActiveCfg = Release|Any CPU 105 | {DB772676-A314-44DC-8EBD-971FBE6953B9}.Release|Any CPU.Build.0 = Release|Any CPU 106 | {DB772676-A314-44DC-8EBD-971FBE6953B9}.Release|x64.ActiveCfg = Release|Any CPU 107 | {DB772676-A314-44DC-8EBD-971FBE6953B9}.Release|x64.Build.0 = Release|Any CPU 108 | {DB772676-A314-44DC-8EBD-971FBE6953B9}.Release|x86.ActiveCfg = Release|Any CPU 109 | {DB772676-A314-44DC-8EBD-971FBE6953B9}.Release|x86.Build.0 = Release|Any CPU 110 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 111 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}.Debug|Any CPU.Build.0 = Debug|Any CPU 112 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}.Debug|x64.ActiveCfg = Debug|Any CPU 113 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}.Debug|x64.Build.0 = Debug|Any CPU 114 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}.Debug|x86.ActiveCfg = Debug|Any CPU 115 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}.Debug|x86.Build.0 = Debug|Any CPU 116 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}.Release|Any CPU.ActiveCfg = Release|Any CPU 117 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}.Release|Any CPU.Build.0 = Release|Any CPU 118 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}.Release|x64.ActiveCfg = Release|Any CPU 119 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}.Release|x64.Build.0 = Release|Any CPU 120 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}.Release|x86.ActiveCfg = Release|Any CPU 121 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F}.Release|x86.Build.0 = Release|Any CPU 122 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 123 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9}.Debug|Any CPU.Build.0 = Debug|Any CPU 124 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9}.Debug|x64.ActiveCfg = Debug|Any CPU 125 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9}.Debug|x64.Build.0 = Debug|Any CPU 126 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9}.Debug|x86.ActiveCfg = Debug|Any CPU 127 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9}.Debug|x86.Build.0 = Debug|Any CPU 128 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9}.Release|Any CPU.ActiveCfg = Release|Any CPU 129 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9}.Release|Any CPU.Build.0 = Release|Any CPU 130 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9}.Release|x64.ActiveCfg = Release|Any CPU 131 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9}.Release|x64.Build.0 = Release|Any CPU 132 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9}.Release|x86.ActiveCfg = Release|Any CPU 133 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9}.Release|x86.Build.0 = Release|Any CPU 134 | EndGlobalSection 135 | GlobalSection(SolutionProperties) = preSolution 136 | HideSolutionNode = FALSE 137 | EndGlobalSection 138 | GlobalSection(NestedProjects) = preSolution 139 | {061494E1-D5D7-479E-BE88-FE0E2F94D9F5} = {3E7EDB35-637A-402C-ABA6-EF8E4C55C051} 140 | {DE41D67B-F18B-4EAD-A1AC-D7AAB1DEB55E} = {B622C013-E4C5-4632-A263-B652C38D2E27} 141 | {DC70B54C-4F4E-4826-A41B-99E976E9475A} = {B2B54384-A507-44F4-B611-039F7CC27AC0} 142 | {37D377D0-7C5A-4F44-B535-C9DA60FDB723} = {B2B54384-A507-44F4-B611-039F7CC27AC0} 143 | {41B05546-CC58-4546-AC73-2497F7CD8FD8} = {B2B54384-A507-44F4-B611-039F7CC27AC0} 144 | {DB772676-A314-44DC-8EBD-971FBE6953B9} = {3E7EDB35-637A-402C-ABA6-EF8E4C55C051} 145 | {CA34C8B5-6C46-41C5-8931-AAFAD732DF5F} = {3E7EDB35-637A-402C-ABA6-EF8E4C55C051} 146 | {72DF2078-62A4-4529-B439-BFFF4AD4C6B9} = {B2B54384-A507-44F4-B611-039F7CC27AC0} 147 | EndGlobalSection 148 | GlobalSection(ExtensibilityGlobals) = postSolution 149 | SolutionGuid = {AFD90899-B909-432A-BBAA-BBC662E19E7C} 150 | EndGlobalSection 151 | EndGlobal 152 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/Honeycomb.OpenTelemetry/HoneycombOptions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using OpenTelemetry.Resources; 3 | using OpenTelemetry.Trace; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Diagnostics.Metrics; 7 | using System.Text.RegularExpressions; 8 | 9 | namespace Honeycomb.OpenTelemetry 10 | { 11 | /// 12 | /// Configuration options used to configure to send telemetry data to Honeycomb. 13 | /// 14 | public class HoneycombOptions 15 | { 16 | private const string OtlpVersion = "0.19.0"; 17 | private const string OtelExporterOtlpProtocolHttpProtobuf = "http/protobuf"; 18 | private const string OtelExporterOtlpProtocolHttpJson = "http/json"; 19 | private const string OtelExporterOtlpProtocolGrpc = "grpc"; 20 | private const string OtelExporterHttpTracesPath = "/v1/traces"; 21 | private const string OtelExporterHttpMetricsPath = "/v1/metrics"; 22 | private const string ClassicKeyRegex = "^[a-f0-9]*$"; 23 | private const string IngestClassicKeyRegex = "^hc[a-z]ic_[a-z0-9]*$"; 24 | private bool isHttp = false; 25 | 26 | /// 27 | /// Default service name if service name is not provided. 28 | /// 29 | internal static readonly string SDefaultServiceName = $"unknown_service:{System.Diagnostics.Process.GetCurrentProcess().ProcessName}"; 30 | internal static readonly string SDefaultServiceVersion = "unknown_service_version"; 31 | 32 | /// 33 | /// Name of the Honeycomb section of IConfiguration 34 | /// 35 | public const string ConfigSectionName = "Honeycomb"; 36 | 37 | /// 38 | /// Default API endpoint. 39 | /// 40 | public const string DefaultEndpoint = "https://api.honeycomb.io:443"; 41 | 42 | /// 43 | /// Default sample rate - sample everything. 44 | /// 45 | public const uint DefaultSampleRate = 1; 46 | 47 | /// 48 | /// API key used to send telemetry data to Honeycomb. 49 | /// 50 | /// 51 | public string ApiKey { get; set; } 52 | 53 | /// 54 | /// Returns whether the provided API key is a classic key. 55 | /// 56 | /// 57 | /// Classic configuration keys have 32 characters and classic ingest keys have 64 characters. 58 | /// 59 | internal static bool IsClassicKey(string apikey) 60 | { 61 | if (String.IsNullOrEmpty(apikey)) 62 | { 63 | return false; 64 | } 65 | else if (apikey.Length == 32) 66 | { 67 | return Regex.Match(apikey, ClassicKeyRegex).Success; 68 | } 69 | else if (apikey.Length == 64) 70 | { 71 | return Regex.Match(apikey, IngestClassicKeyRegex).Success; 72 | } 73 | return false; 74 | } 75 | 76 | /// 77 | /// Write links to honeycomb traces as they come in 78 | /// 79 | public bool EnableLocalVisualizations { get; set; } = false; 80 | 81 | /// 82 | /// API key used to send trace telemetry data to Honeycomb. Defaults to . 83 | /// 84 | public string TracesApiKey { get; set; } 85 | 86 | /// 87 | /// API key used to send metrics telemetry data to Honeycomb. Defaults to . 88 | /// 89 | public string MetricsApiKey { get; set; } 90 | 91 | /// 92 | /// Honeycomb dataset to store telemetry data. 93 | /// 94 | /// 95 | public string Dataset { get; set; } 96 | 97 | /// 98 | /// Honeycomb dataset to store trace telemetry data. Defaults to . 99 | /// 100 | public string TracesDataset { get; set; } 101 | 102 | /// 103 | /// Honeycomb dataset to store metrics telemetry data. Defaults to "null". 104 | /// 105 | /// Required to enable metrics. 106 | /// 107 | public string MetricsDataset { get; set; } 108 | 109 | /// 110 | /// API endpoint to send telemetry data. Defaults to . 111 | /// 112 | public string Endpoint { get; set; } = DefaultEndpoint; 113 | 114 | /// 115 | /// API endpoint to send telemetry data. Defaults to . 116 | /// 117 | public string TracesEndpoint { get; set; } 118 | 119 | /// 120 | /// API endpoint to send telemetry data. Defaults to . 121 | /// 122 | public string MetricsEndpoint { get; set; } 123 | 124 | /// 125 | /// Sample rate for sending telemetry data. Defaults to . 126 | /// 127 | /// See for more details on how sampling is applied. 128 | /// 129 | public uint SampleRate { get; set; } = DefaultSampleRate; 130 | 131 | /// 132 | /// Service name used to identify application. Defaults to unknown_process:processname. 133 | /// 134 | public string ServiceName { get; set; } = SDefaultServiceName; 135 | 136 | /// 137 | /// Service version. Defaults to application assembly information version. 138 | /// 139 | public string ServiceVersion { get; set; } = SDefaultServiceVersion; 140 | 141 | /// 142 | /// (Optional) Additional names for generating metrics. 143 | /// is configured as a meter name by default. 144 | /// 145 | public List MeterNames { get; set; } = new List(); 146 | 147 | /// 148 | /// The to use to add Resource attributes to. 149 | /// A custom ResouceBuilder can be used to set additional resources and then passed here to add 150 | /// Honeycomb attributes. 151 | /// 152 | public ResourceBuilder ResourceBuilder { get; set; } = ResourceBuilder.CreateDefault(); 153 | 154 | /// 155 | /// Determines whether the is added when configuring a . 156 | /// 157 | public bool AddBaggageSpanProcessor { get; set; } = true; 158 | 159 | /// 160 | /// Determines whether the sampler is added when configuring a . 161 | /// 162 | public bool AddDeterministicSampler { get; set; } = true; 163 | 164 | /// 165 | /// If set to true, enables the console span exporter for local debugging. 166 | /// 167 | public bool Debug { get; set; } = false; 168 | 169 | /// 170 | /// Applies environment variable option overrides. 171 | /// 172 | internal void ApplyEnvironmentOptions(EnvironmentOptions environmentOptions) 173 | { 174 | if (!string.IsNullOrWhiteSpace(environmentOptions.ApiKey)) 175 | { 176 | ApiKey = environmentOptions.ApiKey; 177 | } 178 | 179 | if (!string.IsNullOrWhiteSpace(environmentOptions.TracesApiKey)) 180 | { 181 | TracesApiKey = environmentOptions.TracesApiKey; 182 | } 183 | 184 | if (!string.IsNullOrWhiteSpace(environmentOptions.MetricsApiKey)) 185 | { 186 | MetricsApiKey = environmentOptions.MetricsApiKey; 187 | } 188 | 189 | if (!string.IsNullOrWhiteSpace(environmentOptions.ApiEndpoint)) 190 | { 191 | Endpoint = environmentOptions.ApiEndpoint; 192 | } 193 | 194 | if (!string.IsNullOrWhiteSpace(environmentOptions.Dataset)) 195 | { 196 | Dataset = environmentOptions.Dataset; 197 | } 198 | 199 | if (!string.IsNullOrWhiteSpace(environmentOptions.TracesDataset)) 200 | { 201 | TracesDataset = environmentOptions.TracesDataset; 202 | } 203 | 204 | if (!string.IsNullOrWhiteSpace(environmentOptions.MetricsDataset)) 205 | { 206 | MetricsDataset = environmentOptions.MetricsDataset; 207 | } 208 | 209 | if (!string.IsNullOrWhiteSpace(environmentOptions.TracesEndpoint)) 210 | { 211 | TracesEndpoint = environmentOptions.TracesEndpoint; 212 | } 213 | 214 | if (!string.IsNullOrWhiteSpace(environmentOptions.MetricsEndpoint)) 215 | { 216 | MetricsEndpoint = environmentOptions.MetricsEndpoint; 217 | } 218 | 219 | if (!string.IsNullOrWhiteSpace(environmentOptions.ServiceName)) 220 | { 221 | ServiceName = environmentOptions.ServiceName; 222 | } 223 | 224 | if (!string.IsNullOrWhiteSpace(environmentOptions.ServiceVersion)) 225 | { 226 | ServiceVersion = environmentOptions.ServiceVersion; 227 | } 228 | 229 | if (!string.IsNullOrWhiteSpace(environmentOptions.EnableLocalVisualizationsValue)) 230 | { 231 | EnableLocalVisualizations = environmentOptions.EnableLocalVisualizations; 232 | } 233 | 234 | if (!string.IsNullOrWhiteSpace(environmentOptions.DebugValue)) 235 | { 236 | Debug = environmentOptions.Debug; 237 | } 238 | 239 | if (!string.IsNullOrWhiteSpace(environmentOptions.SampleRateValue)) 240 | { 241 | SampleRate = environmentOptions.SampleRate; 242 | } 243 | 244 | if (environmentOptions.OtelExporterOtlpProtocol == OtelExporterOtlpProtocolHttpProtobuf || environmentOptions.OtelExporterOtlpProtocol == OtelExporterOtlpProtocolHttpJson) 245 | { 246 | isHttp = true; 247 | } 248 | } 249 | 250 | /// 251 | /// Gets the or falls back to the generic . 252 | /// 253 | internal string GetTracesEndpoint() 254 | { 255 | var endpoint = new UriBuilder(Endpoint); 256 | if (isHttp && (string.IsNullOrWhiteSpace(endpoint.Path) || endpoint.Path == "/")) 257 | { 258 | endpoint.Path = OtelExporterHttpTracesPath; 259 | } 260 | return TracesEndpoint ?? endpoint.ToString(); 261 | } 262 | 263 | internal string GetTracesApiKey() 264 | { 265 | return TracesApiKey ?? ApiKey; 266 | } 267 | 268 | internal string GetTracesDataset() 269 | { 270 | return TracesDataset ?? Dataset; 271 | } 272 | 273 | /// 274 | /// Gets the or falls back to the generic . 275 | /// 276 | internal string GetMetricsEndpoint() 277 | { 278 | var endpoint = new UriBuilder(Endpoint); 279 | if (isHttp && (string.IsNullOrWhiteSpace(endpoint.Path) || endpoint.Path == "/")) 280 | { 281 | endpoint.Path = OtelExporterHttpMetricsPath; 282 | } 283 | return MetricsEndpoint ?? endpoint.ToString(); 284 | } 285 | 286 | /// 287 | /// Gets the or falls back to the generic . 288 | /// 289 | internal string GetMetricsApiKey() 290 | { 291 | return MetricsApiKey ?? ApiKey; 292 | } 293 | 294 | internal string GetTraceHeaders() => GetTraceHeaders(TracesApiKey, TracesDataset); 295 | 296 | internal static string GetTraceHeaders(string apikey, string dataset) 297 | { 298 | var headers = new List 299 | { 300 | $"x-otlp-version={OtlpVersion}", 301 | $"x-honeycomb-team={apikey}" 302 | }; 303 | 304 | if (IsClassicKey(apikey)) 305 | { 306 | // if the key is legacy, add dataset to the header 307 | if (!string.IsNullOrWhiteSpace(dataset)) 308 | { 309 | headers.Add($"x-honeycomb-dataset={dataset}"); 310 | } 311 | else 312 | { 313 | // if legacy key and missing dataset, warn on missing dataset 314 | Console.WriteLine($"WARN: {EnvironmentOptions.GetErrorMessage("dataset", "HONEYCOMB_DATASET")}."); 315 | } 316 | } 317 | 318 | return string.Join(",", headers); 319 | } 320 | 321 | internal string GetMetricsHeaders() => GetMetricsHeaders(MetricsApiKey, MetricsDataset); 322 | 323 | internal static string GetMetricsHeaders(string apikey, string dataset) 324 | { 325 | var headers = new List 326 | { 327 | $"x-otlp-version={OtlpVersion}", 328 | $"x-honeycomb-team={apikey}", 329 | $"x-honeycomb-dataset={dataset}" 330 | }; 331 | 332 | return string.Join(",", headers); 333 | } 334 | } 335 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # honeycomb-opentelemetry-dotnet changelog 2 | 3 | ## [1.5.0/0.29.0-beta] - 2024-03-06 4 | 5 | ### Enhancements 6 | 7 | - feat: support classic ingest keys (#371) | @brookesargent 8 | 9 | ## [1.4.0/0.28.0-beta] - 2024-02-27 10 | 11 | ### Maintenance 12 | 13 | - docs: Update README with details on SDK builder overwriting issue (#351) | @MikeGoldsmith 14 | - maint: Bump OpenTelemetry dependencies (#365) | @MikeGoldsmith 15 | - maint: update codeowners to pipeline-team (#363) | @JamieDanielson 16 | - maint: update codeowners to pipeline (#362) | @JamieDanielson 17 | - maint: Bump Microsoft.Extensions.Configuration from 6.0.0 to 7.0.0 (#330) | @dependabot 18 | - maint(deps): bump System.Text.Json from 7.0.2 to 7.0.3 (#360) | @dependabot 19 | - maint(deps): bump coverlet.collector from 3.2.0 to 6.0.1 (#366) | @dependabot 20 | - maint(deps): bump Microsoft.NET.Test.Sdk from 17.5.0 to 17.6.3 (#359) | @dependabot 21 | - maint(deps): bump OpenTelemetry.Instrumentation.EntityFrameworkCore from 1.0.0-beta.5 to 1.0.0-beta.6 (#346) | @dependabot 22 | - maint(deps): bump Microsoft.NET.Test.Sdk from 17.4.1 to 17.5.0 (#344) | @dependabot 23 | - maint(deps): bump System.Text.Json from 7.0.0 to 7.0.2 (#343) | @dependabot 24 | 25 | ## [1.3.1/0.27.1-beta] - 2023-04-25 26 | 27 | ### Fixes 28 | 29 | - fix: De-bump Npgsql.OpenTelemetry to work with LTS EntityFramework (#348) | [@JamieDanielson](https://github.com/JamieDanielson) 30 | 31 | ## [1.3.0/0.27.0-beta] - 2023-03-02 32 | 33 | ### !!! Breaking Changes !!! 34 | 35 | ### Maintenance 36 | 37 | - maint: Rename AutoInstrumentations package to CommonInstrumentations (#327) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 38 | - renamed the package to make it more clear that this is common instrumentation, not technically "automatic" instrumentation. 39 | - `Honeycomb.OpenTelemetry.AutoInstrumentations` -> `Honeycomb.OpenTelemetry.CommonInstrumentations` 40 | - `AddAutoInstrumentations` -> `AddCommonInstrumentations` 41 | - maint: Update OpenTelemetry instrumentation packages (#334) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 42 | - The new `OpenTelemetry` packages change how tracing and metrics are setup 43 | - `AddOpenTelemetryTracing` -> `AddOpenTelemetry().WithTracing` 44 | - `AddOpenTelemetryMetrics` -> `AddOpenTelemetry().WithMetrics` 45 | - maint(deps): bump OpenTelemetry.Instrumentation.StackExchangeRedis from 1.0.0-rc9.7 to 1.0.0-rc9.8 (#345) 46 | - maint(deps): bump Microsoft.NET.Test.Sdk from 17.3.2 to 17.4.1 (#336) 47 | - maint: new signed snkgpg, use long cmd lines for clarity (#341) | [@JamieDanielson](https://github.com/JamieDanielson) 48 | 49 | ## [1.2.1/0.26.1-beta] - 2022-11-22 50 | 51 | ### Fixes 52 | 53 | - Only add Redis instrumentation if connection found in DI (#323) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 54 | 55 | ## [1.2.0/0.26.0-beta] - 2022-11-16 56 | 57 | ### Enhancements 58 | 59 | - Support IConfiguration with Honeycomb Options (#317) | [@pjwilliams2](https://github.com/pjwilliams2) 60 | 61 | ### Maintenance 62 | 63 | - Remove step from releasing (#312) | [@vreynolds](https://github.com/vreynolds) 64 | - Update README.md (#313) | [@isaacabraham](https://github.com/isaacabraham) 65 | - Fix metrics smoke tests (#320) | [@pkanal](https://github.com/pkanal) 66 | 67 | ### Dependencies 68 | 69 | - Bump instrumentation pacakges to 1.0.0-rc9.9 (#318) 70 | - Update aspnetcore instrumentation to 1.0.0-rc9.9 (#319) 71 | - Bump OpenTelemetry.Instrumentation.MySqlData from 1.0.0-beta.3 to 1.0.0-beta.4 (#314) 72 | - Bump OpenTelemetry.Instrumentation.AspNet from 1.0.0-rc9.5 to 1.0.0-rc9.6 (#289) 73 | - Bump Microsoft.NET.Test.Sdk from 17.3.1 to 17.3.2 (#315) 74 | - Bump coverlet.collector from 3.1.2 to 3.2.0 (#316) 75 | 76 | ## [1.1.0/0.25.0-beta] - 2022-10-27 77 | 78 | ### Fixes 79 | 80 | - De-bump Npgsql.OpenTelemetry to 6.0.7 to avoid collisions with LTS entityframework (#298) | @cartermp 81 | 82 | ### Maintenance 83 | 84 | - Update OTel hosting & instrumentation packages (#306) | @MikeGoldsmith 85 | - Add F# example? ( ・ω・) (#296) | @cartermp 86 | 87 | ## [1.0.0/0.24.0-beta] - 2022-09-30 88 | 89 | ### !!! Breaking Changes !!! 90 | 91 | ### Enhancements 92 | 93 | - Add support for `OTEL_SERVICE_NAME` environment variable (#245) | [@pkanal](https://github.com/pkanal) 94 | - Attempt to match Java distro resources (#249) | [@cartermp](https://github.com/cartermp) 95 | - Don't bundle instrumentation packages in distro (#250) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 96 | - Support debug option (#254) | [@cartermp](https://github.com/cartermp) 97 | - Add AspNetCore instrumentation extension to add baggage to new spans (#255) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 98 | - Set options with environment variables if they're present (#261) | [@cartermp](https://github.com/cartermp) 99 | - Add Honeycomb.OpenTelemetry.Autoinstrumentations #270 | [@cartermp](https://github.com/cartermp) 100 | - Append /v1/metrics to endpoint path if the protocol is HTTP (#284) | [@pkanal](https://github.com/pkanal) 101 | - Append /v1/traces path to http endpoint (#279) | [@pkanal](https://github.com/pkanal) 102 | - Remove custom command line argument parsing (#282) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 103 | - Add ConfigurationManager extensions methods (#280) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 104 | - Move extensions into owning class namespace & rename add instrumentations ext method (#276) 105 | - Add HONEYCOMB prefix to local visualizations env var (#275) | [@cartermp](https://github.com/cartermp) 106 | 107 | ### Maintenance 108 | 109 | - Specify OTel version in README (#246) | [@pkanal](https://github.com/pkanal) 110 | - Add grpc smoke tests (#264) | [@pkanal](https://github.com/pkanal) 111 | - Add http/protobuf smoke tests (#263) | [@pkanal](https://github.com/pkanal) 112 | - Add make targets for smoke tests & set up CI smoke tests (#268) | [@pkanal](https://github.com/pkanal) 113 | - Dockerize example and prep for smoke tests, target .NET6 (#243) | [@JamieDanielson](https://github.com/JamieDanielson) 114 | - Add Redis instrumentation example app (#242) | [@JamieDanielson](https://github.com/JamieDanielson) 115 | - Move aspnetcore samples to modern .NET 6-style apps (#271) | [@cartermp](https://github.com/cartermp) 116 | - Minor code formatting (#260) | [@cartermp](https://github.com/cartermp) 117 | - Idiomatic code formatting (#247) | [@cartermp](https://github.com/cartermp) 118 | - Add Tracer to DI in aspnet examples (#262) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 119 | - Update aspnetcore example to send metrics (#281) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 120 | - Update CircleCI config to publish tags correctly (#286) | [@pkanal](https://github.com/pkanal) 121 | 122 | ### Dependencies 123 | 124 | - Bump xunit from 2.4.1 to 2.4.2 (#259) 125 | - Bump System.Text.Json from 6.0.5 to 6.0.6 (#258) 126 | - Bump xunit.runner.visualstudio from 2.4.3 to 2.4.5 (#257) 127 | - Bump Microsoft.NET.Test.Sdk from 17.2.0 to 17.3.1 (#256) 128 | 129 | ## [0.23.0-beta] - 2022-08-03 130 | 131 | ### Enhancements 132 | 133 | - Added Console Trace link writer (#222) | [@martinjt](https://github.com/martinjt) 134 | 135 | ### Maintenance 136 | 137 | - Update minimum target framework from net461 to net462 (#226) | [@vreynolds](https://github.com/vreynolds) 138 | - Bump OpenTelemetry.Instrumentation.AspNet from 1.0.0-rc9.1 to 1.0.0-rc9.5 (#224) | [dependabot](https://github.com/dependabot) 139 | - Bump Microsoft.NET.Test.Sdk from 17.1.0 to 17.2.0 (#221) | [dependabot](https://github.com/dependabot) 140 | 141 | ## [0.22.0-beta] - 2022-07-01 142 | 143 | ### Enhancements 144 | 145 | - Add OTLP version to headers (HTTP & gRPC) (#205) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 146 | 147 | ### Maintenance 148 | 149 | - Update README to point to docs website for setup instructions (#208) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 150 | - Bump otel dependencies #213 | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 151 | - Bump Microsoft.NET.Test.Sdk from 17.0.0 to 17.1.0 (#195) 152 | 153 | ## [0.21.0-beta] - 2022-04-14 154 | 155 | ### Enhancements 156 | 157 | - Capture null options in IServiceColletion.AddHoneycomb (#184) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 158 | 159 | ### Fixes 160 | 161 | - Add support for providing ResouceBuilder as configuration option (#190) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 162 | 163 | ### Maintenance 164 | 165 | - Bump otel dependdencies (#193) 166 | - Bump OpenTelemetry.Instrumentation.AspNet from 1.0.0-rc8 to 1.0.0-rc9.1 (#186) 167 | - Bump coverlet.collector from 3.1.0 to 3.1.2 (#181) 168 | 169 | ## [0.20.0-beta] - 2022-03-07 170 | 171 | ### Fixes 172 | 173 | - Remove white space in default service.name (#182) 174 | 175 | ## [0.19.0-beta] - 2022-02-09 176 | 177 | ### Enhancements 178 | 179 | - Provide more feedback to users to help configure for use in E&S (#175) | [@JamieDanielson](https://github.com/JamieDanielson) 180 | 181 | ### Fixes 182 | 183 | - Validate that HoneycombOptions exists before we do anything (#171) | [@cartermp](https://github.com/cartermp) 184 | 185 | ### Maintenance 186 | 187 | - gh: add re-triage workflow (#166) | [@vreynolds](https://github.com/vreynolds) 188 | 189 | ## [0.18.0-beta] - 2021-12-23 190 | 191 | ### Fixes 192 | 193 | - remove parent-based sampler, sample with trace ID ratio only (#164) | [@vreynolds](https://github.com/vreynolds) 194 | 195 | ## [0.17.0-beta] - 2021-12-15 196 | 197 | ### Changed 198 | 199 | - Make API key and dataset optional (#161) | [@vreynolds](https://github.com/vreynolds) 200 | 201 | ### Maintenance 202 | 203 | - Update example core app to use metrics (#158) | [@vreynolds](https://github.com/vreynolds) 204 | 205 | ### Dependencies 206 | 207 | - Bump OpenTelemetry from 1.2.0-beta2.1 to 1.2.0-rc1 (#151) 208 | - Bump OpenTelemetry.Exporter.OpenTelemetryProtocol (#152) 209 | 210 | ## [0.16.0-beta] - 2021-12-06 211 | 212 | ### Improvements 213 | 214 | - Add support for enabling OTLP metrics (#146) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) [@vreynolds](https://github.com/vreynolds) 215 | - Parse missing command line arguments (#154) | [@vreynolds](https://github.com/vreynolds) 216 | 217 | ### Fixes 218 | 219 | - Re-add net461 target (#155) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 220 | - Trace extension should use trace config (#156) | [@vreynolds](https://github.com/vreynolds) 221 | 222 | ## [0.15.0-beta] - 2021-12-01 223 | 224 | ### Enhancements 225 | 226 | - Update DeterminisitcSampler to use OTel core Parent/TraceIDRatio samplers (#145) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 227 | 228 | ### Fixes 229 | 230 | - Fixed Redis auto-detection (#150) | [@JamieDanielson](https://github.com/JamieDanielson) 231 | 232 | ### Maintenance 233 | 234 | - Update dependabot.yml (#147) | [@vreynolds](https://github.com/vreynolds) 235 | - Update dependencies, remove netcoreapp2.1 (#144) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 236 | - Update docs when releasing (#142) | [@vreynolds](https://github.com/vreynolds) 237 | 238 | ## Dependencies 239 | 240 | - Bump Microsoft.NET.Test.Sdk from 16.11.0 to 17.0.0 (#148) 241 | 242 | ## [0.14.0-beta] - 2021-11-18 243 | 244 | ## Added 245 | 246 | - Allow disabling auto-instrumentations (#129) | [@ericsampson](https://github.com/ericsampson) 247 | 248 | ## Maintenance 249 | 250 | - Remove whitespace failing build (#137) | [@JamieDanielson](https://github.com/JamieDanielson) 251 | - Empower apply-labels action to apply labels (#131) | [@robbkidd](https://github.com/robbkidd) 252 | - Add prerelease flag to install command (#120) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 253 | - Add NOTICE (#114) | [@cartermp](https://github.com/cartermp) 254 | - Only add stale to info needed or revision needed (#115) | [@JamieDanielson](https://github.com/JamieDanielson) 255 | - Adds stalebot effective Sept 1 2021 (#113) | [@JamieDanielson](https://github.com/JamieDanielson) 256 | - Fix netcoreapp2.1 example (#102) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 257 | - Clarify renaming in changelog (#101) | [@cartermp](https://github.com/cartermp) 258 | 259 | ## Dependencies 260 | 261 | - Bump Microsoft.AspNetCore.Razor.Design from 2.1.2 to 2.2.0 (#104) 262 | - Bump coverlet.collector from 1.3.0 to 3.1.0 (#77) 263 | 264 | ## [0.13.0-beta] - 2021-08-26 265 | 266 | ## Added 267 | 268 | - Support for netcoreapp2.1 (#99) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 269 | - Rename `UseHoneycomb` to `AddHoneycomb` IServiceCollection extension method to be more idiomatic (#98) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 270 | 271 | ## Maintenance 272 | 273 | - Allow dependabot and forked PRs to run in CI (#97) | [@vreynolds](https://github.com/vreynolds) 274 | - Add issue and PR templates (#91) | [@vreynolds](https://github.com/vreynolds) 275 | - Add OSS lifecycle badge (#90) | [@vreynolds](https://github.com/vreynolds) 276 | - Add community health files (#89) | [@vreynolds](https://github.com/vreynolds) 277 | - Trim commit hash from honeycomb.distro.version attribute (#87) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 278 | 279 | ## Dependencies 280 | 281 | - Bump Microsoft.NET.Test.Sdk from 16.7.1 to 16.11.0 (#92) 282 | 283 | ## [0.12.0-beta] - 2021-07-29 284 | 285 | ## Added 286 | 287 | - Add ASP.NET instrumentation (#76, #80) | [@vreynolds](https://github.com/vreynolds) [@MikeGoldsmith](https://github.com/MikeGoldsmith) 288 | 289 | ## Maintenance 290 | 291 | - Only sign builds when publishing through CI (#81) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 292 | - Clarify releasing steps (#79) | [@vreynolds](https://github.com/vreynolds) 293 | 294 | ## [0.11.0-alpha] - 2021-07-27 295 | 296 | ### Added 297 | 298 | - Redis instrumentation (#66, #74) | [@vreynolds](https://github.com/vreynolds) 299 | 300 | ## [0.10.0-alpha] - 2021-07-15 301 | 302 | ### Added 303 | 304 | - Initial preview release of Honeycomb's OpenTelemetry distribution for .NET! 305 | 306 | ### Breaking Changes 307 | 308 | - As of this version, this project is now Honeycomb's OpenTelemetry distribution for .NET. 309 | If you are still using the [Honeycomb exporter](https://github.com/honeycombio/opentelemetry-dotnet) use version 0.9.0-pre. 310 | 311 | ## [0.9.0-pre] 312 | 313 | - Pre-release of an OpenTelemetry Exporter for Honeycomb. 314 | This was the last release of the Exporter published under the Honeycomb.OpenTelemetry Package name. 315 | -------------------------------------------------------------------------------- /test/Honeycomb.OpenTelemetry.Tests/HoneycombOptionsTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using System.Collections.Generic; 3 | using Xunit; 4 | 5 | namespace Honeycomb.OpenTelemetry.Tests 6 | { 7 | public class HoneycombOptionsHelperTests 8 | { 9 | [Fact] 10 | public void CanParseOptionsFromConfiguration() 11 | { 12 | var options = 13 | new ConfigurationBuilder() 14 | .AddJsonFile("appsettings.test.json") 15 | .Build() 16 | .GetSection(HoneycombOptions.ConfigSectionName) 17 | .Get() 18 | ; 19 | 20 | Assert.Equal("my-apikey", options.ApiKey); 21 | Assert.Equal("my-traces-apikey", options.TracesApiKey); 22 | Assert.Equal("my-metrics-apikey", options.MetricsApiKey); 23 | Assert.Equal("my-dataset", options.Dataset); 24 | Assert.Equal("my-traces-dataset", options.TracesDataset); 25 | Assert.Equal("my-metrics-dataset", options.MetricsDataset); 26 | Assert.Equal((uint)5, options.SampleRate); 27 | Assert.Equal("my-endpoint", options.Endpoint); 28 | Assert.Equal("my-traces-endpoint", options.TracesEndpoint); 29 | Assert.Equal("my-metrics-endpoint", options.MetricsEndpoint); 30 | Assert.Equal("my-service", options.ServiceName); 31 | Assert.Equal("my-version", options.ServiceVersion); 32 | Assert.Equal(new List { "meter1", "meter2" }, options.MeterNames); 33 | Assert.True(options.EnableLocalVisualizations); 34 | Assert.True(options.Debug); 35 | } 36 | 37 | [Fact] 38 | public void CanParseOptionsFromEnvironmentVariables() 39 | { 40 | // set up HoneycombOptions class 41 | var options = new HoneycombOptions { }; 42 | // env var values 43 | var values = new Dictionary 44 | { 45 | {"HONEYCOMB_API_KEY", "my-api-key-env-var"}, 46 | {"HONEYCOMB_TRACES_API_KEY", "my-traces-api-key-env-var"}, 47 | {"HONEYCOMB_METRICS_API_KEY", "my-metrics-api-key-env-var"}, 48 | {"HONEYCOMB_DATASET", "my-dataset-env-var"}, 49 | {"HONEYCOMB_TRACES_DATASET", "my-traces-dataset-env-var"}, 50 | {"HONEYCOMB_METRICS_DATASET", "my-metrics-dataset-env-var"}, 51 | {"HONEYCOMB_API_ENDPOINT", "my-endpoint-env-var"}, 52 | {"HONEYCOMB_TRACES_ENDPOINT", "my-traces-endpoint-env-var"}, 53 | {"HONEYCOMB_METRICS_ENDPOINT", "my-metrics-endpoint-env-var"}, 54 | {"HONEYCOMB_SAMPLE_RATE", "20"}, 55 | {"OTEL_SERVICE_NAME", "my-service-name-env-var"}, 56 | {"SERVICE_VERSION", "my-service-version-env-var"}, 57 | {"HONEYCOMB_ENABLE_LOCAL_VISUALIZATIONS", "false" }, 58 | {"DEBUG", "false"} 59 | }; 60 | 61 | // override HoneycombOptions with Environment options 62 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 63 | 64 | Assert.Equal("my-api-key-env-var", options.ApiKey); 65 | Assert.Equal("my-traces-api-key-env-var", options.TracesApiKey); 66 | Assert.Equal("my-metrics-api-key-env-var", options.MetricsApiKey); 67 | Assert.Equal("my-dataset-env-var", options.Dataset); 68 | Assert.Equal("my-traces-dataset-env-var", options.TracesDataset); 69 | Assert.Equal("my-metrics-dataset-env-var", options.MetricsDataset); 70 | Assert.Equal("my-endpoint-env-var", options.Endpoint); 71 | Assert.Equal("my-traces-endpoint-env-var", options.TracesEndpoint); 72 | Assert.Equal("my-metrics-endpoint-env-var", options.MetricsEndpoint); 73 | Assert.Equal((uint)20, options.SampleRate); 74 | Assert.Equal("my-service-name-env-var", options.ServiceName); 75 | Assert.Equal("my-service-version-env-var", options.ServiceVersion); 76 | Assert.False(options.EnableLocalVisualizations); 77 | Assert.False(options.Debug); 78 | } 79 | 80 | [Fact] 81 | public void CanOverrideConfigWithEnvVars() 82 | { 83 | // read options from appsettings.json file 84 | var options = new ConfigurationBuilder() 85 | .AddJsonFile("appsettings.test.json") 86 | .Build() 87 | .GetSection(HoneycombOptions.ConfigSectionName) 88 | .Get(); 89 | 90 | // env var values 91 | var values = new Dictionary 92 | { 93 | {"HONEYCOMB_API_KEY", "my-api-key-env-var"}, 94 | {"HONEYCOMB_TRACES_API_KEY", "my-traces-api-key-env-var"}, 95 | {"HONEYCOMB_METRICS_API_KEY", "my-metrics-api-key-env-var"}, 96 | {"HONEYCOMB_DATASET", "my-dataset-env-var"}, 97 | {"HONEYCOMB_TRACES_DATASET", "my-traces-dataset-env-var"}, 98 | {"HONEYCOMB_METRICS_DATASET", "my-metrics-dataset-env-var"}, 99 | {"HONEYCOMB_API_ENDPOINT", "my-endpoint-env-var"}, 100 | {"HONEYCOMB_TRACES_ENDPOINT", "my-traces-endpoint-env-var"}, 101 | {"HONEYCOMB_METRICS_ENDPOINT", "my-metrics-endpoint-env-var"}, 102 | {"HONEYCOMB_SAMPLE_RATE", "20"}, 103 | {"OTEL_SERVICE_NAME", "my-service-name-env-var"}, 104 | {"SERVICE_VERSION", "my-service-version-env-var"}, 105 | {"HONEYCOMB_ENABLE_LOCAL_VISUALIZATIONS", "false" }, 106 | {"DEBUG", "false"} 107 | }; 108 | 109 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 110 | 111 | Assert.Equal("my-api-key-env-var", options.ApiKey); 112 | Assert.Equal("my-traces-api-key-env-var", options.TracesApiKey); 113 | Assert.Equal("my-metrics-api-key-env-var", options.MetricsApiKey); 114 | Assert.Equal("my-dataset-env-var", options.Dataset); 115 | Assert.Equal("my-traces-dataset-env-var", options.TracesDataset); 116 | Assert.Equal("my-metrics-dataset-env-var", options.MetricsDataset); 117 | Assert.Equal("my-endpoint-env-var", options.Endpoint); 118 | Assert.Equal("my-traces-endpoint-env-var", options.TracesEndpoint); 119 | Assert.Equal("my-metrics-endpoint-env-var", options.MetricsEndpoint); 120 | Assert.Equal((uint)20, options.SampleRate); 121 | Assert.Equal("my-service-name-env-var", options.ServiceName); 122 | Assert.Equal("my-service-version-env-var", options.ServiceVersion); 123 | Assert.False(options.EnableLocalVisualizations); 124 | Assert.False(options.Debug); 125 | } 126 | 127 | [Fact] 128 | public void CanFallbackToDefault_Config() 129 | { 130 | // set up empty HoneycombOptions class 131 | var options = new HoneycombOptions { }; 132 | Assert.Null(options.ApiKey); 133 | Assert.Null(options.TracesApiKey); 134 | Assert.Null(options.MetricsApiKey); 135 | Assert.Null(options.Dataset); 136 | Assert.Null(options.TracesDataset); 137 | Assert.Null(options.MetricsDataset); 138 | Assert.Equal(HoneycombOptions.DefaultEndpoint, options.Endpoint); 139 | Assert.Null(options.TracesEndpoint); 140 | Assert.Null(options.MetricsEndpoint); 141 | Assert.Equal(HoneycombOptions.DefaultSampleRate, options.SampleRate); 142 | Assert.Equal(HoneycombOptions.SDefaultServiceName, options.ServiceName); 143 | Assert.Equal(HoneycombOptions.SDefaultServiceVersion, options.ServiceVersion); 144 | Assert.False(options.EnableLocalVisualizations); 145 | Assert.False(options.Debug); 146 | } 147 | 148 | [Fact] 149 | public void UsesGenericValuesIfTracesSpecificValuesAreNotSet_Config() 150 | { 151 | var options = new HoneycombOptions 152 | { 153 | Endpoint = "http://collector:4318", 154 | ApiKey = "my-api-key", 155 | Dataset = "my-dataset" 156 | }; 157 | 158 | Assert.Equal("http://collector:4318/", options.GetTracesEndpoint()); 159 | Assert.Equal("my-api-key", options.GetTracesApiKey()); 160 | Assert.Equal("my-dataset", options.GetTracesDataset()); 161 | } 162 | 163 | [Fact] 164 | public void UsesGenericValuesIfMetricsSpecificValuesAreNotSet_Config() 165 | { 166 | var options = new HoneycombOptions 167 | { 168 | Endpoint = "http://collector:4318", 169 | ApiKey = "my-api-key", 170 | Dataset = "my-dataset" 171 | }; 172 | 173 | Assert.Equal("http://collector:4318/", options.GetMetricsEndpoint()); 174 | Assert.Equal("my-api-key", options.GetMetricsApiKey()); 175 | // Should not fall override metrics dataset 176 | Assert.NotEqual("my-dataset", options.MetricsDataset); 177 | } 178 | 179 | [Fact] 180 | public void UsesTracesSpecificValuesIfSet_Config() 181 | { 182 | var options = new HoneycombOptions 183 | { 184 | TracesEndpoint = "http://collector:4318", 185 | TracesApiKey = "my-api-key", 186 | TracesDataset = "my-dataset" 187 | }; 188 | Assert.Equal("http://collector:4318", options.GetTracesEndpoint()); 189 | Assert.Equal("my-api-key", options.GetTracesApiKey()); 190 | Assert.Equal("my-dataset", options.GetTracesDataset()); 191 | } 192 | 193 | [Fact] 194 | public void UsesMetricsSpecificValuesIfSet_Config() 195 | { 196 | var options = new HoneycombOptions 197 | { 198 | MetricsEndpoint = "http://collector:4318", 199 | MetricsApiKey = "my-api-key", 200 | }; 201 | Assert.Equal("http://collector:4318", options.GetMetricsEndpoint()); 202 | Assert.Equal("my-api-key", options.GetMetricsApiKey()); 203 | } 204 | 205 | [Fact] 206 | public void UseTracesSpecificValuesOverGenericValues_Config() 207 | { 208 | var options = new HoneycombOptions 209 | { 210 | Endpoint = "http://collector:4318", 211 | ApiKey = "my-api-key", 212 | Dataset = "my-dataset", 213 | TracesEndpoint = "http://collector:4318/v1/traces", 214 | TracesApiKey = "my-api-key-traces", 215 | TracesDataset = "my-dataset-traces" 216 | }; 217 | 218 | Assert.Equal("http://collector:4318/v1/traces", options.GetTracesEndpoint()); 219 | Assert.Equal("my-api-key-traces", options.GetTracesApiKey()); 220 | Assert.Equal("my-dataset-traces", options.GetTracesDataset()); 221 | } 222 | 223 | [Fact] 224 | public void UseMetricsSpecificValuesOverGenericValues_Config() 225 | { 226 | var options = new HoneycombOptions 227 | { 228 | Endpoint = "http://collector:4318", 229 | ApiKey = "my-api-key", 230 | MetricsEndpoint = "http://collector:4318/v1/metrics", 231 | MetricsApiKey = "my-api-key-metrics", 232 | }; 233 | 234 | Assert.Equal("http://collector:4318/v1/metrics", options.GetMetricsEndpoint()); 235 | Assert.Equal("my-api-key-metrics", options.GetMetricsApiKey()); 236 | } 237 | 238 | [Fact] 239 | public void UsesGenericValuesIfTracesSpecificValuesAreNotSet_EnvVars() 240 | { 241 | var options = new HoneycombOptions { }; 242 | var values = new Dictionary 243 | { 244 | {"HONEYCOMB_API_KEY", "my-api-key-env-var"}, 245 | {"HONEYCOMB_DATASET", "my-dataset-env-var"}, 246 | {"HONEYCOMB_API_ENDPOINT", "http://collector:4318/"}, 247 | }; 248 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 249 | 250 | Assert.Equal("http://collector:4318/", options.GetTracesEndpoint()); 251 | Assert.Equal("my-api-key-env-var", options.GetTracesApiKey()); 252 | Assert.Equal("my-dataset-env-var", options.GetTracesDataset()); 253 | } 254 | 255 | [Fact] 256 | public void UsesGenericValuesIfMetricsSpecificValuesAreNotSet_EnvVars() 257 | { 258 | var options = new HoneycombOptions { }; 259 | var values = new Dictionary 260 | { 261 | {"HONEYCOMB_API_KEY", "my-api-key-env-var"}, 262 | {"HONEYCOMB_DATASET", "my-dataset-env-var"}, 263 | {"HONEYCOMB_API_ENDPOINT", "http://collector:4318/"}, 264 | }; 265 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 266 | 267 | Assert.Equal("http://collector:4318/", options.GetMetricsEndpoint()); 268 | Assert.Equal("my-api-key-env-var", options.GetMetricsApiKey()); 269 | } 270 | 271 | [Fact] 272 | public void UsesTracesSpecificValuesIfSet_EnvVars() 273 | { 274 | var options = new HoneycombOptions { }; 275 | var values = new Dictionary 276 | { 277 | {"HONEYCOMB_TRACES_API_KEY", "my-traces-api-key-env-var"}, 278 | {"HONEYCOMB_TRACES_DATASET", "my-traces-dataset-env-var"}, 279 | {"HONEYCOMB_TRACES_ENDPOINT", "http://collector:4318/v1/traces"}, 280 | }; 281 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 282 | 283 | Assert.Equal("http://collector:4318/v1/traces", options.GetTracesEndpoint()); 284 | Assert.Equal("my-traces-api-key-env-var", options.GetTracesApiKey()); 285 | Assert.Equal("my-traces-dataset-env-var", options.GetTracesDataset()); 286 | } 287 | 288 | [Fact] 289 | public void UsesMetricsSpecificValuesIfSet_EnvVars() 290 | { 291 | var options = new HoneycombOptions { }; 292 | var values = new Dictionary 293 | { 294 | {"HONEYCOMB_METRICS_API_KEY", "my-metrics-api-key-env-var"}, 295 | {"HONEYCOMB_METRICS_ENDPOINT", "http://collector:4318/v1/metrics"}, 296 | }; 297 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 298 | 299 | Assert.Equal("http://collector:4318/v1/metrics", options.GetMetricsEndpoint()); 300 | Assert.Equal("my-metrics-api-key-env-var", options.GetMetricsApiKey()); 301 | } 302 | 303 | [Fact] 304 | public void UseTracesSpecificValuesOverGenericValues_EnvVars() 305 | { 306 | var options = new HoneycombOptions { }; 307 | var values = new Dictionary 308 | { 309 | {"HONEYCOMB_API_KEY", "my-api-key-env-var"}, 310 | {"HONEYCOMB_DATASET", "my-dataset-env-var"}, 311 | {"HONEYCOMB_API_ENDPOINT", "http://collector:4318/"}, 312 | {"HONEYCOMB_TRACES_API_KEY", "my-traces-api-key-env-var"}, 313 | {"HONEYCOMB_TRACES_DATASET", "my-traces-dataset-env-var"}, 314 | {"HONEYCOMB_TRACES_ENDPOINT", "http://collector:4318/v1/traces"}, 315 | }; 316 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 317 | 318 | Assert.Equal("http://collector:4318/v1/traces", options.GetTracesEndpoint()); 319 | Assert.Equal("my-traces-api-key-env-var", options.GetTracesApiKey()); 320 | Assert.Equal("my-traces-dataset-env-var", options.GetTracesDataset()); 321 | } 322 | 323 | [Fact] 324 | public void UseMetricsSpecificValuesOverGenericValues_EnvVars() 325 | { 326 | var options = new HoneycombOptions { }; 327 | var values = new Dictionary 328 | { 329 | {"HONEYCOMB_API_KEY", "my-api-key-env-var"}, 330 | {"HONEYCOMB_API_ENDPOINT", "http://collector:4318/"}, 331 | {"HONEYCOMB_METRICS_API_KEY", "my-metrics-api-key-env-var"}, 332 | {"HONEYCOMB_METRICS_ENDPOINT", "http://collector:4318/v1/metrics"}, 333 | }; 334 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 335 | 336 | Assert.Equal("http://collector:4318/v1/metrics", options.GetMetricsEndpoint()); 337 | Assert.Equal("my-metrics-api-key-env-var", options.GetMetricsApiKey()); 338 | } 339 | 340 | [Theory] 341 | [InlineData("http/protobuf", "http://collector:4318", null)] 342 | [InlineData("http/json", "http://collector:4318", null)] 343 | [InlineData("http/protobuf", null, "http://collector:4318")] 344 | [InlineData("http/json", null, "http://collector:4318")] 345 | [InlineData("http/protobuf", "http://collector:4318", "http://collector:4318")] 346 | [InlineData("http/json", "http://collector:4318", "http://collector:4318")] 347 | public void AppendsTracesPathIfProtocolIsHttp(string protocol, string configEndpoint, string envVarEndpoint) 348 | { 349 | var options = new HoneycombOptions 350 | { 351 | Endpoint = configEndpoint 352 | }; 353 | var values = new Dictionary 354 | { 355 | {"OTEL_EXPORTER_OTLP_PROTOCOL", protocol}, 356 | {"HONEYCOMB_API_ENDPOINT", envVarEndpoint}, 357 | }; 358 | 359 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 360 | Assert.Equal($"{options.Endpoint}/v1/traces", options.GetTracesEndpoint()); 361 | } 362 | 363 | [Theory] 364 | [InlineData("http://collector:4317", null)] 365 | [InlineData(null, "http://collector:4317")] 366 | [InlineData("http://collector:4317", "http://collector:4317")] 367 | public void DoesNotAppendTracesPathIfProtocolIsGrpc(string configEndpoint, string envVarEndpoint) 368 | { 369 | var options = new HoneycombOptions 370 | { 371 | Endpoint = configEndpoint 372 | }; 373 | var values = new Dictionary 374 | { 375 | {"OTEL_EXPORTER_OTLP_PROTOCOL", "grpc"}, 376 | {"HONEYCOMB_API_ENDPOINT", envVarEndpoint}, 377 | }; 378 | 379 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 380 | Assert.Equal("http://collector:4317/", options.GetTracesEndpoint()); 381 | Assert.DoesNotContain("/v1/traces", options.GetTracesEndpoint()); 382 | } 383 | 384 | [Theory] 385 | [InlineData("http/protobuf", "http://collector:4318", null)] 386 | [InlineData("http/json", "http://collector:4318", null)] 387 | [InlineData("http/protobuf", null, "http://collector:4318")] 388 | [InlineData("http/json", null, "http://collector:4318")] 389 | [InlineData("http/protobuf", "http://collector:4318", "http://collector:4318")] 390 | [InlineData("http/json", "http://collector:4318", "http://collector:4318")] 391 | public void DoesNotAppendTracesPathToTracesEndpoints(string protocol, string configEndpoint, string envVarEndpoint) 392 | { 393 | var options = new HoneycombOptions 394 | { 395 | TracesEndpoint = configEndpoint 396 | }; 397 | var values = new Dictionary 398 | { 399 | {"OTEL_EXPORTER_OTLP_PROTOCOL", protocol}, 400 | {"HONEYCOMB_TRACES_ENDPOINT", envVarEndpoint}, 401 | 402 | }; 403 | 404 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 405 | Assert.Equal("http://collector:4318", options.GetTracesEndpoint()); 406 | Assert.DoesNotContain("/v1/traces", options.GetTracesEndpoint()); 407 | } 408 | 409 | [Theory] 410 | [InlineData("http/protobuf", "http://collector:4318/my-special-path", null)] 411 | [InlineData("http/json", "http://collector:4318/my-special-path", null)] 412 | [InlineData("http/protobuf", null, "http://collector:4318/my-special-path")] 413 | [InlineData("http/json", null, "http://collector:4318/my-special-path")] 414 | [InlineData("http/protobuf", "http://collector:4318/my-special-path", "http://collector:4318/my-special-path")] 415 | [InlineData("http/json", "http://collector:4318/my-special-path", "http://collector:4318/my-special-path")] 416 | public void DoesNotAppendTracesPathToGenericEndpointIfPathSpecified(string protocol, string configEndpoint, string envVarEndpoint) 417 | { 418 | var options = new HoneycombOptions 419 | { 420 | Endpoint = configEndpoint 421 | }; 422 | var values = new Dictionary 423 | { 424 | {"OTEL_EXPORTER_OTLP_PROTOCOL", protocol}, 425 | {"HONEYCOMB_API_ENDPOINT", envVarEndpoint}, 426 | }; 427 | 428 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 429 | Assert.Equal("http://collector:4318/my-special-path", options.GetTracesEndpoint()); 430 | Assert.DoesNotContain("/v1/traces", options.GetTracesEndpoint()); 431 | } 432 | 433 | [Theory] 434 | [InlineData("http/protobuf", "http://collector:4318", null)] 435 | [InlineData("http/json", "http://collector:4318", null)] 436 | [InlineData("http/protobuf", null, "http://collector:4318")] 437 | [InlineData("http/json", null, "http://collector:4318")] 438 | [InlineData("http/protobuf", "http://collector:4318", "http://collector:4318")] 439 | [InlineData("http/json", "http://collector:4318", "http://collector:4318")] 440 | public void AppendsMetricsPathIfProtocolIsHttp(string protocol, string configEndpoint, string envVarEndpoint) 441 | { 442 | var options = new HoneycombOptions 443 | { 444 | Endpoint = configEndpoint 445 | }; 446 | var values = new Dictionary 447 | { 448 | {"OTEL_EXPORTER_OTLP_PROTOCOL", protocol}, 449 | {"HONEYCOMB_API_ENDPOINT", envVarEndpoint}, 450 | }; 451 | 452 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 453 | Assert.Equal($"{options.Endpoint}/v1/metrics", options.GetMetricsEndpoint()); 454 | } 455 | 456 | [Theory] 457 | [InlineData("http://collector:4317", null)] 458 | [InlineData(null, "http://collector:4317")] 459 | [InlineData("http://collector:4317", "http://collector:4317")] 460 | public void DoesNotAppendMetricsPathIfProtocolIsGrpc(string configEndpoint, string envVarEndpoint) 461 | { 462 | var options = new HoneycombOptions 463 | { 464 | Endpoint = configEndpoint 465 | }; 466 | var values = new Dictionary 467 | { 468 | {"OTEL_EXPORTER_OTLP_PROTOCOL", "grpc"}, 469 | {"HONEYCOMB_API_ENDPOINT", envVarEndpoint}, 470 | }; 471 | 472 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 473 | Assert.Equal("http://collector:4317/", options.GetMetricsEndpoint()); 474 | Assert.DoesNotContain("/v1/metrics", options.GetMetricsEndpoint()); 475 | } 476 | 477 | [Theory] 478 | [InlineData("http/protobuf", "http://collector:4318", null)] 479 | [InlineData("http/json", "http://collector:4318", null)] 480 | [InlineData("http/protobuf", null, "http://collector:4318")] 481 | [InlineData("http/json", null, "http://collector:4318")] 482 | [InlineData("http/protobuf", "http://collector:4318", "http://collector:4318")] 483 | [InlineData("http/json", "http://collector:4318", "http://collector:4318")] 484 | public void DoesNotAppendMetricsPathToMetricsEndpoints(string protocol, string configEndpoint, string envVarEndpoint) 485 | { 486 | var options = new HoneycombOptions 487 | { 488 | MetricsEndpoint = configEndpoint 489 | }; 490 | var values = new Dictionary 491 | { 492 | {"OTEL_EXPORTER_OTLP_PROTOCOL", protocol}, 493 | {"HONEYCOMB_METRICS_ENDPOINT", envVarEndpoint}, 494 | 495 | }; 496 | 497 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 498 | Assert.Equal("http://collector:4318", options.GetMetricsEndpoint()); 499 | Assert.DoesNotContain("/v1/metrics", options.GetMetricsEndpoint()); 500 | } 501 | 502 | [Theory] 503 | [InlineData("http/protobuf", "http://collector:4318/my-special-path", null)] 504 | [InlineData("http/json", "http://collector:4318/my-special-path", null)] 505 | [InlineData("http/protobuf", null, "http://collector:4318/my-special-path")] 506 | [InlineData("http/json", null, "http://collector:4318/my-special-path")] 507 | [InlineData("http/protobuf", "http://collector:4318/my-special-path", "http://collector:4318/my-special-path")] 508 | [InlineData("http/json", "http://collector:4318/my-special-path", "http://collector:4318/my-special-path")] 509 | public void DoesNotAppendMetricsPathToGenericEndpointIfPathSpecified(string protocol, string configEndpoint, string envVarEndpoint) 510 | { 511 | var options = new HoneycombOptions 512 | { 513 | Endpoint = configEndpoint 514 | }; 515 | var values = new Dictionary 516 | { 517 | {"OTEL_EXPORTER_OTLP_PROTOCOL", protocol}, 518 | {"HONEYCOMB_API_ENDPOINT", envVarEndpoint}, 519 | }; 520 | 521 | options.ApplyEnvironmentOptions(new EnvironmentOptions(values)); 522 | Assert.Equal("http://collector:4318/my-special-path", options.GetMetricsEndpoint()); 523 | Assert.DoesNotContain("/v1/metrics", options.GetMetricsEndpoint()); 524 | } 525 | 526 | [Theory] 527 | [InlineData("", false)] 528 | [InlineData("12345678901234567890123456789012", true)] 529 | [InlineData("hcaic_1234567890123456789012345678901234567890123456789012345678", true)] 530 | [InlineData("kgvSpPwegJshQkuowXReLD", false)] 531 | [InlineData("hcaic_12345678901234567890123456", false)] 532 | [InlineData("hcxik_01hqk4k20cjeh63wca8vva5stw70nft6m5n8wr8f5mjx3762s8269j50wc", false)] 533 | public void IsClassicKey(string key, bool expected) 534 | { 535 | var options = new HoneycombOptions { ApiKey = key }; 536 | Assert.Equal(HoneycombOptions.IsClassicKey(key), expected); 537 | } 538 | } 539 | } 540 | --------------------------------------------------------------------------------