Skip to content

[bug] OpenTelemetry.Exporter.OpenTelemetryProtocol fails silently on .NET 5.0 #6291

Open
@MartenM

Description

@MartenM

Package

OpenTelemetry.Exporter.OpenTelemetryProtocol

Package Version

Package Name Version
Microsoft.Extensions.Hosting 9.0.5
OpenTelemetry 1.12.0
OpenTelemetry.Exporter.Console 1.12.0
OpenTelemetry.Exporter.OpenTelemetryProtocol 1.12.0
OpenTelemetry.Extensions.Hosting 1.12.0

Runtime Version

net5.0

Description

I am working on adding traceability to a range of our services. Some of these services run on .NET 5.0. Given that we want to update our services (at some point) I decided to use the latest OTEL versions.

The console exporter shows traces successfully, so one would assume everything works smoothly. However I cannot get the OpenTelemetry.Exporter.OpenTelemetryProtocol to work properly. It simply won't send any traces. It wouldn't have been an issue if it failed, but currently it's not sending traces without any visible errors. It has took me longer than I did like to admit that the .NET version is the culprit here (read, hours). Especially since the console exporter is working just fine by the looks of it.

I have included an example. The traces won't be send on .NET5.0 but on .NET8.0 it works properly.

Steps to Reproduce

I have included a minimal (not working) example program:

Program.cs

using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using OpenTelemetry;
using OpenTelemetry.Trace;

namespace TestApp1
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var host = Host.CreateDefaultBuilder(args)
                .ConfigureLogging((builder =>
                {
                    builder.ClearProviders();
                    builder.AddConsole();
                }))
                .ConfigureServices(((context, services) =>
                {
                    var traceProvider = Sdk.CreateTracerProviderBuilder();
                    traceProvider.AddSource("TestApp.Counting");

                    traceProvider.AddOtlpExporter();
                    traceProvider.AddConsoleExporter();
                    
                    services.AddSingleton(traceProvider.Build());

                    services.AddHostedService<CountService>();
                }))
                .Build();
            
            await host.RunAsync();
        }
    }
}

CountService.cs

using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace TestApp1
{
    /// <summary>
    /// Simple counting service. Will terminate the application once it reaches 10.
    /// </summary>
    public class CountService : BackgroundService
    {
        private ILogger<CountService> _logger;
        private ActivitySource _activitySource = new("TestApp.Counting");
    
        private IHostApplicationLifetime  _applicationLifetime;

        public CountService(ILogger<CountService> logger, IHostApplicationLifetime  applicationLifetime)
        {
            _logger = logger;
            _applicationLifetime = applicationLifetime;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Starting CountService");
        
            await Task.Delay(1000, stoppingToken);
            for (int i = 0; i < 10; i++)
            {
                await DoCount(i, stoppingToken);
            }
        
            _logger.LogInformation("Finished counting!");
            _applicationLifetime.StopApplication();
        }

        private async Task DoCount(int count, CancellationToken stoppingToken)
        {
            using (var activity = _activitySource.StartActivity(ActivityKind.Internal))
            {
                _logger.LogInformation("Counted: {Count}", count);
                await Task.Delay(1000, stoppingToken);

                activity?.SetStatus(ActivityStatusCode.Ok);
            };
        
        }
    }
}

Using the following ENV variables:

Environment Variable Value
OTEL_EXPORTER_OTLP_ENDPOINT http://localhost:4317
OTEL_SERVICE_NAME opcua.net5.0
OTEL_TRACES_EXPORTER otlp
otel collector setup

docker-compose.yml

services:
  otel-collector:
    image: otel/opentelemetry-collector-contrib
    volumes:
      - ./otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml
    ports:
      - 1888:1888 # pprof extension
      - 8888:8888 # Prometheus metrics exposed by the Collector
      - 8889:8889 # Prometheus exporter metrics
      - 13133:13133 # health_check extension
      - 4317:4317 # OTLP gRPC receiver
      - 4318:4318 # OTLP http receiver
      - 55679:55679 # zpages extension

otel-collector-config.yaml

exporters:
  debug:
    verbosity: detailed

processors:
  batch: {}
  # Default memory limiter configuration for the collector based on k8s resource limits.
  memory_limiter:
    # check_interval is the time between measurements of memory usage.
    check_interval: 5s
    # By default limit_mib is set to 80% of ".Values.resources.limits.memory"
    limit_percentage: 80
    # By default spike_limit_mib is set to 25% of ".Values.resources.limits.memory"
    spike_limit_percentage: 25
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318
service:
  telemetry:
  pipelines:
    traces:
      exporters:
        - debug
      processors:
        - memory_limiter
        - batch
      receivers:
        - otlp

Expected Result

Traces are transmitted to any otel collector OR an error indicating that the exporter won't work.

Actual Result

No traces are being received (or even send?) without any errors indicating that setup has failed.
Otel diagnostics result:

If you are seeing this message, it means that the OpenTelemetry SDK has successfully created the log file used to write self-diagnostic logs. This file will be appended with logs as they appear. If you do not see any logs following this line, it means no logs of the configured LogLevel is occurring. You may change the LogLevel to show lower log levels, so that logs of lower severities will be shown.
2025-05-20T13:25:07.6319943Z:HTTP request to {0} failed. Exception: {1}{http://localhost:4317/opentelemetry.proto.collector.trace.v1.TraceService/Export}{System.Net.Http.HttpRequestException: An error occurred while sending the request.
 ---> System.IO.IOException: The response ended prematurely.
   at System.Net.Http.HttpConnection.FillAsync(Boolean async)
   at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean async, Boolean foldedHeadersAllowed)
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)
   at OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.OtlpExportClient.SendHttpRequest(HttpRequestMessage request, CancellationToken cancellationToken)
   at OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.OtlpGrpcExportClient.SendExportRequest(Byte[] buffer, Int32 contentLength, DateTime deadlineUtc, CancellationToken cancellationToken)}
2025-05-20T13:25:12.6422391Z:HTTP request to {0} failed. Exception: {1}{http://localhost:4317/opentelemetry.proto.collector.trace.v1.TraceService/Export}{System.Net.Http.HttpRequestException: An error occurred while sending the request.
 ---> System.IO.IOException: The response ended prematurely.
   at System.Net.Http.HttpConnection.FillAsync(Boolean async)
   at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean async, Boolean foldedHeadersAllowed)
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)
   at OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.OtlpExportClient.SendHttpRequest(HttpRequestMessage request, CancellationToken cancellationToken)
   at OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.OtlpGrpcExportClient.SendExportRequest(Byte[] buffer, Int32 contentLength, DateTime deadlineUtc, CancellationToken cancellationToken)}
   

Additional Context

I understand that .NET 5.0 is no priority. However since the package does indicate it supports it people may expect it too work. Throwing an error would resolve this issue too in my opinion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds-triageNew issues which have not been classified or triaged by a community memberpkg:OpenTelemetry.Exporter.OpenTelemetryProtocolIssues related to OpenTelemetry.Exporter.OpenTelemetryProtocol NuGet package

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions