{"id":21327428,"url":"https://github.com/erni-academy/poc-dotnet-distributed-telemetry","last_synced_at":"2026-04-09T12:15:39.899Z","repository":{"id":113746318,"uuid":"530676570","full_name":"ERNI-Academy/poc-dotnet-distributed-telemetry","owner":"ERNI-Academy","description":"Example of distributed tracing in .NET, using W3C Trace Context and OpenTelemetry.","archived":false,"fork":false,"pushed_at":"2023-03-15T01:53:05.000Z","size":2752,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-08T02:37:59.310Z","etag":null,"topics":["azure-monitor","distributed-telemetry","docker","docker-compose","dotnet","grafana","jaeger","jaegertracing","logging","loki","opentelemetry","opentelemetry-collector","postgresql","postgresql-database","rabbitmq","tracing"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ERNI-Academy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.md","dei":null}},"created_at":"2022-08-30T13:45:46.000Z","updated_at":"2022-08-31T10:33:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"d1b7d1a8-7c37-4d3c-ad10-d1a513c55352","html_url":"https://github.com/ERNI-Academy/poc-dotnet-distributed-telemetry","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ERNI-Academy/poc-dotnet-distributed-telemetry","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ERNI-Academy%2Fpoc-dotnet-distributed-telemetry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ERNI-Academy%2Fpoc-dotnet-distributed-telemetry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ERNI-Academy%2Fpoc-dotnet-distributed-telemetry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ERNI-Academy%2Fpoc-dotnet-distributed-telemetry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ERNI-Academy","download_url":"https://codeload.github.com/ERNI-Academy/poc-dotnet-distributed-telemetry/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ERNI-Academy%2Fpoc-dotnet-distributed-telemetry/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28132549,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-30T02:00:05.476Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure-monitor","distributed-telemetry","docker","docker-compose","dotnet","grafana","jaeger","jaegertracing","logging","loki","opentelemetry","opentelemetry-collector","postgresql","postgresql-database","rabbitmq","tracing"],"created_at":"2024-11-21T21:17:15.872Z","updated_at":"2025-12-30T21:05:05.585Z","avatar_url":"https://github.com/ERNI-Academy.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# About Dotnet Distributed Tracing POC\n\nExample of distributed tracing in .NET, using W3C Trace Context and OpenTelemetry.\n\n\u003c!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --\u003e\n[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg)](#contributors)\n\u003c!-- ALL-CONTRIBUTORS-BADGE:END --\u003e\n\n[![SonarCloud Scan API](https://github.com/ERNI-Academy/poc-dotnet-distributed-telemetry/actions/workflows/build.yml/badge.svg)](https://github.com/ERNI-Academy/poc-dotnet-distributed-telemetry/actions/workflows/build.yml)\n\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ERNI-Academy_poc-dotnet-distributed-telemetry\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ERNI-Academy_poc-dotnet-distributed-telemetry)\n[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=ERNI-Academy_poc-dotnet-distributed-telemetry\u0026metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=ERNI-Academy_poc-dotnet-distributed-telemetry)\n[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=ERNI-Academy_poc-dotnet-distributed-telemetry\u0026metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=ERNI-Academy_poc-dotnet-distributed-telemetry)\n[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=ERNI-Academy_poc-dotnet-distributed-telemetry\u0026metric=code_smells)](https://sonarcloud.io/summary/new_code?id=ERNI-Academy_poc-dotnet-distributed-telemetry)\n[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=ERNI-Academy_poc-dotnet-distributed-telemetry\u0026metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=ERNI-Academy_poc-dotnet-distributed-telemetry)\n\n## OpenTelemetry Collector example\n\nWith many instrumented components, and many destinations, you can quickly get complex many-to-many connections (as can be seen in the complex OpenTelemetry example, with only three components and two destinations).\n\nTo address this, and then range of different custom protocols used, OpenTelemetry not only has a standardised way to define traces, metrics, and logs, but also a common OpenTelemetry Protocol, and a Collector service/agent.\n\nThis allows a much cleaner instrumentation architecture, with application components forwarding messages to the Collector (possibly using OTLP, although some legacy protocols are also supported), and then the Collector having exporters available for many destination systems.\n\n![Diagram showing components Demo.WebApp, Demo.Service, and Demo.Worker, connecting to a Collector, which then forwards to Jaeger, Loki, and Azure Monitor](./docs/generated/collector-tracing.png)\n\nIn the longer term, destination systems have started to support OTLP directly, although it may still be useful to have local agents for batching and augmentation pipelines.\n\n## Requirements\n\n* Dotnet 6.0 SDK, https://docs.microsoft.com/en-us/dotnet/core/install/linux-ubuntu\n* Node.JS and npm (Node Package Manager), for node, to run the web front end (`sudo apt install nodejs npm`)\n* Docker (with docker compose), for local services, https://docs.docker.com/engine/install/ubuntu/\n* Azure subscription, for cloud services\n* Powershell, for running scripts, https://docs.microsoft.com/en-us/powershell/scripting/install/install-ubuntu\n* Azure CLI, to create cloud resources, https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-linux\n\nIf running the existing service (not making changes), make sure you run `npm install` to install dependencies and `az extension add -n application-insights` to add the Azure CLI app insights extension.\n\nFor existing dotnet applications, make sure you do `dotnet tool restore` for the needed tools.\n\n## Demonstration\n\nThis demonstration follows on from the above, and shows the results of Collector.\n\nTo build it yourself from scratch, see below.\n\nBefore running the demo, start all the docker dependencies (above) and use the script to create the needed Azure resources.\n\n```powershell\naz login\n$VerbosePreference = 'Continue'\n./deploy-infrastructure.ps1\n```\n\nRun the complex demo:\n\n```bash\n./start-collector-demo.sh\n```\n\nBrowse to `https://localhost:44303`, and then Fetch Data to see messages. Check Jaeger at `http://localhost:16686/`.\n\nFor Grafana (for Loki logs) browse to `http://localhost:3000/` then select Explore \u003e Loki and enter a query:\n\n```promql\n{service_name=~\"Demo.*\"} | json traceid=\"traceid\"\n```\n\nEnable Unique labels, then open a log and select to show only body.\n\nOr a more advanced query (and click select Show all detected fields).\n\n```promql\n{service_name=~\"Demo.*\"} | json traceid=\"traceid\", id=`attributes[\"Id\"]`, name=`attributes[\"Name\"]`, version=`resources[\"service.version\"]`, body=\"body\" | line_format \"{{.severity | upper}}: {{.name}}{{if .id}}[{{.id}}] {{end}}{{.body}}\" | label_format id=\"\", body=\"\"\n```\n\nCheck Azure Monitor at `https://portal.azure.com/` opening the log analytics workbench \u003e Logs.\n\n```kusto\nunion AppDependencies, AppRequests, AppTraces, AppExceptions\n| where TimeGenerated  \u003e ago(1h)\n| sort by TimeGenerated desc\n| project TimeGenerated, OperationId, SeverityLevel, Message, Type, AppRoleName, Properties.SpanId, ParentId\n```\n\nAlso look at Application Insights for End-to-end tracing \u003e operation \u003e Drill into \u003e sample.\n\nAnd also Applicatin Insights \u003e Application map.\n\n\n## Details\n\n### Run local services (RabbitMQ, PostgreSQL, Jaeger, and Loki)\n\nFor this example, you also need to run Rabbit MQ, for a service bus, and PostgreSQL, for a database.\n\nYou also need to be running local OpenTelemetry collector to send  log messages to, and for instrumentation destinations we also have Jaeger for traces, along with Loki (with MinIO storage and Grafana front end) for logs.\n\nYou can start the dependencies via docker compose:\n\n```bash\ndocker compose -p demo up -d\n```\n\n### Jaeger\n\nFor more details see https://www.jaegertracing.io/\n\nTo check the Jaeger UI, browse to `http://localhost:16686/`\n\n\nThe OpenTelemetry Collector service will also be run in docker, but it will be run separately, after the application is configured.\n\n### RabbitMQ\n\nFor more details see https://www.rabbitmq.com/\n\nTo check the RabbitMQ console, browse to `http://localhost:15672`\n\n### PostgreSQL and Adminer\n\nFor more details see https://www.postgresql.org/\n\nTo check the Adminer console, browse to `http://localhost:8080`\n\n### Set up Azure Monitor workbench and Application Insights\n\nLog in to your Azure resources if necessary\n\n```powershell\naz login\n```\n\nThen use the script to create the required resources, which will also output the required connection string.\n\n```powershell\n$VerbosePreference = 'Continue'\n./deploy-infrastructure.ps1\n```\n\nThis will create an Azure Monitor Log Analytics Workspace, and then an Application Insights instance connected to it.\n\nYou can log in to the Azure portal to check the logging components were created at `https://portal.azure.com`\n\n\n### Used Nuget packages\n\n* [MassTransit.RabbitMQ](https://www.nuget.org/packages/MassTransit.RabbitMQ/)\n\n* [Npgsql.EntityFrameworkCore.PostgreSQL](https://www.nuget.org/packages/Npgsql.EntityFrameworkCore.PostgreSQL)\n* [Npgsql.OpenTelemetry](https://www.nuget.org/packages/Npgsql.OpenTelemetry)\n\n* [OpenTelemetry.Contrib.Instrumentation.EntityFrameworkCore](https://www.nuget.org/packages/OpenTelemetry.Contrib.Instrumentation.EntityFrameworkCore)\n* [OpenTelemetry.Exporter.Console](https://www.nuget.org/packages/OpenTelemetry.Exporter.Console)\n* [OpenTelemetry.Exporter.OpenTelemetryProtocol](https://www.nuget.org/packages/OpenTelemetry.Exporter.OpenTelemetryProtocol)\n* [OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs](https://www.nuget.org/packages/OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs)\n* [OpenTelemetry.Extensions.Hosting](https://www.nuget.org/packages/OpenTelemetry.Extensions.Hosting)\n* [OpenTelemetry.Instrumentation.AspNetCore](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.AspNetCore)\n* [OpenTelemetry.Instrumentation.Http](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Http)\n\n### Add configuration\n\nAdd a configuration section to `appsettings.Development.json`, with the default OTLP port:\n\n```json\n  \"OpenTelemetry\": {\n    \"OtlpExporter\": {\n      \"Endpoint\": \"http://localhost:4317/\",\n      \"ExportProcessorType\": \"Batch\",\n      \"Protocol\": \"grpc\"\n    }\n  }\n```\n\n### OpenTelemetry collector tracing\n\nIn `Program.cs`, in the OpenTelemetry configuration, include `AddOtlpExporter()`, binding the options to the configuration section:\n\n```csharp\nusing OpenTelemetry.Resources;\nusing OpenTelemetry.Trace;\n...\n\nbuilder.Services.AddOpenTelemetryTracing(tracerProviderBuilder =\u003e\n{\n    tracerProviderBuilder\n        ...\n        .AddOtlpExporter(otlpExporterOptions =\u003e\n        {\n            builder.Configuration.GetSection(\"OpenTelemetry:OtlpExporter\").Bind(otlpExporterOptions);\n        });\n});\n```\n\n### OpenTelemetry collector logging\n\nConfigure logging with `AddOpenTelemetry()`, and then configure `AddOtlpExporter()`, with the same options section. Also turn on settings to include formatted messages, scopes, and state values.\n\n```csharp\nusing OpenTelemetry.Logs;\n...\n\nbuilder.Logging\n    .AddOpenTelemetry(configure =\u003e\n    {\n        configure\n            .SetResourceBuilder(resourceBuilder)\n            .AddOtlpExporter(otlpExporterOptions =\u003e\n            {\n                builder.Configuration.GetSection(\"OpenTelemetry:OtlpExporter\").Bind(otlpExporterOptions);\n            });\n        configure.IncludeFormattedMessage = true;\n        configure.IncludeScopes = true;\n        configure.ParseStateValues = true;\n    });\n```\n\n### Configure the collector service\n\nBefore running the collector, you need to create a configuration file, `otel-collector-config.yaml`, with an OTLP receiver and the exporters you need, e.g. Jaeger, Loki, and Azure Monitor.\n\nThe settings for Azure Monitor are defined as environment variables, allowing them to be easily passed in.\n\n```yaml\nreceivers:\n  otlp:\n    protocols:\n      grpc:\n      http:\n\nprocessors:\n  batch:\n\nexporters:\n  azuremonitor:\n    instrumentation_key: \"${AZ_INSTRUMENTATION_KEY}\"\n  jaeger:\n    endpoint: jaeger:14250\n    tls:\n      insecure: true\n  logging:\n    logLevel: info\n  loki:\n    endpoint: http://loki:3100/loki/api/v1/push\n    format: json\n    labels:\n      resource:\n        deployment.environment: \"deployment_environment\"\n        host.name: \"host_name\"\n        service.name: \"service_name\"\n        service.namespace: \"service_namespace\"\n      record:\n        severity: \"severity\"\n    tenant_id: tenant1\n    tls:\n      insecure: true\n\nservice:\n  pipelines:\n    traces:\n      receivers: [otlp]\n      processors: [batch]\n      exporters: [logging, jaeger, azuremonitor]\n    logs:\n      receivers: [otlp]\n      processors: []\n      exporters: [logging, loki, azuremonitor]\n```\n\n## Run the example\n\n### Run the OpenTelemetry Collector\n\nYou need to pass in the configuration values for Azure Monitor when running the collector container.This uses the Azure CLI, running in PowerShell.\n\n```powershell\n$ai = az monitor app-insights component show -a appi-tracedemo-dev -g rg-tracedemo-dev-001 | ConvertFrom-Json\n$ai.instrumentationKey\ndocker run -it --rm `\n  -e \"AZ_INSTRUMENTATION_KEY=$($ai.instrumentationKey)\" `\n  --network demo_default `\n  -p 4317:4317 `\n  -v \"$(Join-Path (Get-Location) 'otel-collector-config.yaml'):/etc/otelcol-contrib/config.yaml\" `\n  otel/opentelemetry-collector-contrib:0.50.0\n```\n\n### Run the services\n\nIn separate terminals run the service:\n\n```powershell\ndotnet run --project Demo.Service --urls \"https://*:44301\" --environment Development\n```\n\nTo run the web app front end you need to configure the web API address it will use via an environment variable:\n\n```powershell\n$ENV:ASPNETCORE_URLS = \"http://localhost:8002\"\nnpm run start --prefix Demo.WebApp/ClientApp\n```\n\nThen run the web api in a third terminal:\n\n```powershell\ndotnet run --project Demo.WebApp --urls \"http://*:8002\" --environment Development\n```\n\nAnd run the worker app in a fourth terminal\n\n```powershell\ndotnet run --project Demo.Worker --environment Development\n```\n\nGenerate some activity via the front end at `https://localhost:44303/fetch-data`.\n\n## View Results\n\n### Jaeger traces\n\nTo see traces in Jaeger, open the interface at \u003chttp://localhost:16686/\u003e, select the service Demo.WebApp and search, which will show you a graph of all traces that service is involved in, along with some key details such as the number of spans and number of errors.\n\n![](images/otel-jaeger-summary.png)\n\nYou can click through a specific trace to see the timeline of hierarchical spans, distributed across the services. You can then drill down into specific span attributes.\n\nNote that the asychronous worker does not complete processing the RabbitMQ message until after the primary span is complete.\n\n![](images/otel-jaeger-trace.png)\n\nJaeger can also so the system architecture, derived from the message relationships between the services.\n\n![](images/otel-jaeger-architecture.png)\n\n\n### Loki logs (via Grafana)\n\nTo see the logs in Loki, open Grafana at \u003chttp://localhost:3000/\u003e, and go to the Explore page, then ensure Loki is selected in the drop down.\n\nYou can select a stream based on labels, e.g. `service_name`, `deployment_environment`, `host_name`, or `severity` (these are defined in `otel-collector-config.yaml`). You can also use the Log Browser to select the stream values you are interested in.\n\nThe selected streams can then be further filtered (e.g. on trace ID), parsed, and formatted.\n\nFor example, to select the Demo services and parse the trace ID from the JSON data, use the following query:\n\n```text\n{service_name=~\"Demo.*\"} | json traceid=\"traceid\"\n```\n\nGrafana will show a Log Volume graph, which is useful if you are filtering for conditions such as errors.\n\n![Loki, in Grafana, with a graph of events](./images/otel-loki-graph.png)\n\nBelow the graph the (raw) log data is shown. For simple scanning, turn on Unique Labels, which will show the other labels, including the parsed traceid, and then open one of the messages and select the \"Show this field\" icon (an eye) next to the body field.\n\nThis cleans up the display and shows key fields (the severity is also indicated in colour on the left), and the log message.\n\n![Loki, in Grafana, showing log messages](./images/otel-loki-logs.png)\n\nThe trace IDs can be used to correlate log messages from the same operation.\n\n#### Extracting the message\n\nThe LogQL pipeline can be used to manipulate the output, e.g. the following extracts the traceid, body, and other attrbutes from the JSON message, formats the line with several of the fields, then removes those fields so that 'Unique Labels' can be used to view the remaining (e.g. service and trace ID).\n\n```promql\n{service_name=~\"Demo.*\"} | json traceid=\"traceid\", id=`attributes[\"Id\"]`, name=`attributes[\"Name\"]`, version=`resources[\"service.version\"]`, body=\"body\" | line_format \"{{.severity | upper}}: {{.name}}{{if .id}}[{{.id}}] {{end}}{{.body}}\" | label_format id=\"\", name=\"\", body=\"\", severity=\"\"\n```\n\n### View results in Azure Monitor\n\nLog in to Azure Portal, https://portal.azure.com/\n\n#### Logs\n\nOpen the Log Analytics workspace that was created. The default will be under\nHome \u003e Resource groups \u003e rg-tracedemo-dev-001 \u003e log-tracedemo-dev\n\nSelect General \u003e Logs from the left. Dismiss the Queries popup to get to an empty editor.\n\nYou can use a query like this to view your logs.\n\n```promql\nunion AppDependencies, AppRequests, AppTraces, AppExceptions\n| where TimeGenerated  \u003e ago(1h)\n| sort by TimeGenerated desc\n| project TimeGenerated, OperationId, SeverityLevel, Message, Type, AppRoleName, Properties.SpanId, ParentId\n```\n\nYou will see the related logs have the same OperationId (trace ID).  AppDependencies and AppRequests represent trace parent/child relationships, while AppTraces are the log messages.\n\n![Azure Monitor logs, from OpenTelemetry](./images/otel-azure-logs.png)\n\n#### Performance\n\nOpen the Application Insights that was created. The default will be under\nHome \u003e Resource groups \u003e rg-tracedemo-dev-001 \u003e appi-tracedemo-dev\n\nSelect Investigate \u003e Performance in the left hand menu, then Operation Name \"GET WeatherForecast/Get\" (the top level operation requesting the page). The right hand side will show the instances.\n\nClick on \"Drill into... N Samples\" in the bottom right, then select the recent operation.\n\nThe page will show the End-to-end transaction with the correlation Operation ID (the same as the console), along with a hierarchical timeline of events.\n\nThere will be a top level event for **localhost:44302** with two children for the **Message** and **localhost:44301** (the back end service).\n\nThe \"View all telemetry\" button will show all the messages, including traces.\n\n![Azure Monitor App Insights tracing, from OpenTelemetry](./images/otel-azure-tracing.png)\n\n#### Application Map\n\nSelect Investigate \u003e Application Map in the left hand menu for a picture of how your services collaborate, showing how components are related by messages.\n\nFor this simple application, the Hierarchical View clearly shows how the WebApp calls the Service, and also sends a message to the Worker.\n\n![Azure Monitor App Insights application map, from OpenTelemetry](./images/otel-azure-map.png)\n\n## Contributing\n\nPlease see our [Contribution Guide](CONTRIBUTING.md) to learn how to contribute.\n\n## License\n\n![MIT](https://img.shields.io/badge/License-MIT-blue.svg)\n\n(LICENSE) © 2022 [ERNI - Swiss Software Engineering](https://www.betterask.erni)\n\n## Code of conduct\n\nPlease see our [Code of Conduct](CODE_OF_CONDUCT.md)\n\n## Stats\n![https://repobeats.axiom.co/api/embed/9edd500d800670de009832156a5ef438d92c00fa.svg](https://repobeats.axiom.co/api/embed/9edd500d800670de009832156a5ef438d92c00fa.svg)\n\n## Follow us\n\n[![Twitter Follow](https://img.shields.io/twitter/follow/ERNI?style=social)](https://www.twitter.com/ERNI)\n[![Twitch Status](https://img.shields.io/twitch/status/erni_academy?label=Twitch%20Erni%20Academy\u0026style=social)](https://www.twitch.tv/erni_academy)\n[![YouTube Channel Views](https://img.shields.io/youtube/channel/views/UCkdDcxjml85-Ydn7Dc577WQ?label=Youtube%20Erni%20Academy\u0026style=social)](https://www.youtube.com/channel/UCkdDcxjml85-Ydn7Dc577WQ)\n[![Linkedin](https://img.shields.io/badge/linkedin-35k-green?style=social\u0026logo=Linkedin)](https://www.linkedin.com/company/erni)\n\n## Contact\n\n📧 [esp-services@betterask.erni](mailto:esp-services@betterask.erni)\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/Rabosa616\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/12774781?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eRabosa616\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/ERNI-Academy/poc-dotnet-distributed-telemetry/commits?author=Rabosa616\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#content-Rabosa616\" title=\"Content\"\u003e🖋\u003c/a\u003e \u003ca href=\"https://github.com/ERNI-Academy/poc-dotnet-distributed-telemetry/commits?author=Rabosa616\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#design-Rabosa616\" title=\"Design\"\u003e🎨\u003c/a\u003e \u003ca href=\"#ideas-Rabosa616\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#maintenance-Rabosa616\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e \u003ca href=\"https://github.com/ERNI-Academy/poc-dotnet-distributed-telemetry/commits?author=Rabosa616\" title=\"Tests\"\u003e⚠️\u003c/a\u003e \u003ca href=\"#example-Rabosa616\" title=\"Examples\"\u003e💡\u003c/a\u003e \u003ca href=\"https://github.com/ERNI-Academy/poc-dotnet-distributed-telemetry/pulls?q=is%3Apr+reviewed-by%3ARabosa616\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferni-academy%2Fpoc-dotnet-distributed-telemetry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ferni-academy%2Fpoc-dotnet-distributed-telemetry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferni-academy%2Fpoc-dotnet-distributed-telemetry/lists"}