Description
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.