diff --git a/.github/workflows/bootstrap/action.yml b/.github/workflows/bootstrap/action.yml
index e47776ef..189ef688 100644
--- a/.github/workflows/bootstrap/action.yml
+++ b/.github/workflows/bootstrap/action.yml
@@ -38,12 +38,6 @@ runs:
uses: actions/setup-dotnet@v5
with:
global-json-file: ./global.json
- # 6.x is required for the release-notes tool.
- # 7.x is required for the dotnet-project-licenses tool.
- dotnet-version: |
- 6.x
- 7.x
- 8.x
- id: dotnet
shell: bash
diff --git a/Directory.Packages.props b/Directory.Packages.props
index c6af938e..f1cf9075 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -4,55 +4,50 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
+
-
-
+
-
+
-
diff --git a/build/patch-dotnet-auto-install.sh b/build/patch-dotnet-auto-install.sh
index 6ba36909..a73ca3bc 100644
--- a/build/patch-dotnet-auto-install.sh
+++ b/build/patch-dotnet-auto-install.sh
@@ -56,7 +56,7 @@ else
fi
test -z "$OTEL_DOTNET_AUTO_HOME" && OTEL_DOTNET_AUTO_HOME="$HOME/.otel-dotnet-auto"
-test -z "$VERSION" && VERSION="v1.9.0"
+test -z "$VERSION" && VERSION="v1.13.0"
DOWNLOAD_DIR="${DOWNLOAD_DIR:=${TMPDIR:=$(mktemp -d)}}"
diff --git a/build/scripts/Packaging.fs b/build/scripts/Packaging.fs
index 8172032d..8d603564 100644
--- a/build/scripts/Packaging.fs
+++ b/build/scripts/Packaging.fs
@@ -192,7 +192,11 @@ let stageArtifacts (assets:List) =
stagedZips |> List.iter (fun (asset, path) ->
- injectPluginFiles asset path "netstandard2.1" "net"
+ // We inject net8.0 as the minimum supported TFM version
+ // Previously we used netstandard2.1, but this causes issues with adding a handler for the HttpClient
+ // used for OTLP export as the SDK prefers the `Send` rather than `SendAsync` method which is only available in net8.0+ TFM
+ // Whe using netstandard2.1 there is no handler code to run so the default user agent is sent.
+ injectPluginFiles asset path "net8.0" "net"
if asset.Name.EndsWith "-windows.zip" then
injectPluginFiles asset path "net462" "netfx"
@@ -207,7 +211,8 @@ let stageArtifacts (assets:List) =
stagedZips
let redistribute (arguments:ParseResults) =
- exec { run "dotnet" "build" "src/Elastic.OpenTelemetry.AutoInstrumentation/Elastic.OpenTelemetry.AutoInstrumentation.csproj" "-f" "netstandard2.1" "-c" "release" }
+ // We build net8.0 as the minimum supported TFM version - See above for details
+ exec { run "dotnet" "build" "src/Elastic.OpenTelemetry.AutoInstrumentation/Elastic.OpenTelemetry.AutoInstrumentation.csproj" "-f" "net8.0" "-c" "release" }
exec { run "dotnet" "build" "src/Elastic.OpenTelemetry.AutoInstrumentation/Elastic.OpenTelemetry.AutoInstrumentation.csproj" "-f" "net462" "-c" "release" }
let assets = downloadArtifacts arguments
printfn ""
diff --git a/examples/Example.AutoInstrumentation/Dockerfile b/examples/Example.AutoInstrumentation/Dockerfile
index 61eb8b65..f9fbb611 100644
--- a/examples/Example.AutoInstrumentation/Dockerfile
+++ b/examples/Example.AutoInstrumentation/Dockerfile
@@ -1,5 +1,5 @@
-ARG OTEL_VERSION=1.12.0
-FROM mcr.microsoft.com/dotnet/runtime:9.0 AS base
+ARG OTEL_VERSION=1.13.0
+FROM mcr.microsoft.com/dotnet/runtime:10.0 AS base
ARG TARGETPLATFORM
ARG TARGETARCH
ARG TARGETVARIANT
diff --git a/examples/Example.AutoInstrumentation/Example.AutoInstrumentation.csproj b/examples/Example.AutoInstrumentation/Example.AutoInstrumentation.csproj
index b5aa541d..652283c1 100644
--- a/examples/Example.AutoInstrumentation/Example.AutoInstrumentation.csproj
+++ b/examples/Example.AutoInstrumentation/Example.AutoInstrumentation.csproj
@@ -2,7 +2,7 @@
Exe
- net9.0
+ net10.0
enable
enable
Linux
diff --git a/examples/Example.AutoInstrumentation/distribution.Dockerfile b/examples/Example.AutoInstrumentation/distribution.Dockerfile
index 2ce6c82b..ed285ed7 100644
--- a/examples/Example.AutoInstrumentation/distribution.Dockerfile
+++ b/examples/Example.AutoInstrumentation/distribution.Dockerfile
@@ -1,5 +1,5 @@
-ARG OTEL_VERSION=1.9.0
-FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+ARG OTEL_VERSION=1.13.0
+FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0 AS build
ARG TARGETPLATFORM
ARG TARGETARCH
ARG TARGETVARIANT
@@ -8,27 +8,19 @@ ENV _PROJECT="Example.AutoInstrumentation"
ENV _PROJECTPATH="${_PROJECT}/${_PROJECT}.csproj"
RUN apt-get update && apt-get install -y unzip
-
WORKDIR /work
-
COPY ["examples/${_PROJECTPATH}", "examples/${_PROJECT}/"]
RUN dotnet restore -a $TARGETARCH "examples/${_PROJECT}"
-
COPY .git .git
COPY examples/${_PROJECT} examples/${_PROJECT}
WORKDIR "/work/examples/${_PROJECT}"
RUN dotnet publish "${_PROJECT}.csproj" -c Release -a $TARGETARCH --no-restore -o /app/example
-
FROM build AS final
-
COPY ".artifacts/elastic-distribution" /distro/elastic
-
COPY --from=build /app/example /app/example
-
ENV OTEL_DOTNET_AUTO_HOME="/app/otel"
# Use already downloaded release assets (call ./build.sh redistribute locally if you run this dockerfile manually)
RUN DOWNLOAD_DIR="/distro/elastic" sh /distro/elastic/elastic-dotnet-auto-install.sh
-
ENV OTEL_LOG_LEVEL=debug
ENTRYPOINT ["sh", "/app/otel/instrument.sh", "dotnet", "/app/example/Example.AutoInstrumentation.dll"]
diff --git a/src/Elastic.OpenTelemetry.AutoInstrumentation/AutoInstrumentationPlugin.cs b/src/Elastic.OpenTelemetry.AutoInstrumentation/AutoInstrumentationPlugin.cs
index d7a31848..ad280d50 100644
--- a/src/Elastic.OpenTelemetry.AutoInstrumentation/AutoInstrumentationPlugin.cs
+++ b/src/Elastic.OpenTelemetry.AutoInstrumentation/AutoInstrumentationPlugin.cs
@@ -7,7 +7,6 @@
using Elastic.OpenTelemetry.Diagnostics;
using Elastic.OpenTelemetry.Exporters;
using Elastic.OpenTelemetry.Resources;
-using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using OpenTelemetry;
using OpenTelemetry.Exporter;
@@ -31,6 +30,17 @@ public class AutoInstrumentationPlugin
///
public AutoInstrumentationPlugin() => _components = ElasticOpenTelemetry.Bootstrap(SdkActivationMethod.AutoInstrumentation);
+ ///
+ /// Configure Resource Builder for Logs, Metrics and Traces
+ ///
+ /// to configure
+ /// Returns for chaining.
+ public ResourceBuilder ConfigureResource(ResourceBuilder builder)
+ {
+ builder.WithElasticDefaultsCore(_components, null, null);
+ return builder;
+ }
+
///
/// To configure tracing SDK before Auto Instrumentation configured SDK.
///
@@ -40,10 +50,7 @@ public TracerProviderBuilder BeforeConfigureTracerProvider(TracerProviderBuilder
try
{
- builder.ConfigureResource(r => r.WithElasticDefaultsCore(_components, null, null));
-
- builder.ConfigureServices(sc => sc.Configure(OtlpExporterDefaults.OtlpExporterOptions));
- logger.LogConfiguredOtlpExporterOptions();
+ logger.LogInformation("Configuring Elastic Distribution of OpenTelemetry .NET defaults for tracing auto-instrumentation.");
ElasticTracerProviderBuilderExtensions.AddActivitySourceWithLogging(builder, logger, "Elastic.Transport", "");
ElasticTracerProviderBuilderExtensions.AddElasticProcessorsCore(builder, null, _components, null);
@@ -62,42 +69,43 @@ public TracerProviderBuilder BeforeConfigureTracerProvider(TracerProviderBuilder
}
///
- /// To configure metrics SDK before Auto Instrumentation configured SDK.
+ /// Configure traces OTLP exporter options.
///
- public MeterProviderBuilder BeforeConfigureMeterProvider(MeterProviderBuilder builder)
- {
- var logger = _components.Logger;
-
- try
- {
- builder.ConfigureResource(r => r.WithElasticDefaultsCore(_components, null, null));
-
- builder.ConfigureServices(sc => sc
- .Configure(OtlpExporterDefaults.OtlpExporterOptions)
- .Configure(o => o.TemporalityPreference = MetricReaderTemporalityPreference.Delta));
- logger.LogConfiguredOtlpExporterOptions();
+ /// Otlp options.
+ public void ConfigureTracesOptions(OtlpExporterOptions options) => ConfigureOtlpExporter(options, "traces");
- logger.LogConfiguredSignalProvider(nameof(Signals.Metrics), nameof(MeterProviderBuilder), "");
-
- return builder;
- }
- catch (Exception ex)
- {
- logger.LogError(new EventId(521, "AutoInstrumentationTracerFailure"), ex,
- "Failed to register EDOT defaults for metrics auto-instrumentation to the MeterProviderBuilder.");
- }
+ ///
+ /// Configure metrics OTLP exporter options
+ ///
+ /// Otlp options
+ public void ConfigureMetricsOptions(OtlpExporterOptions options) => ConfigureOtlpExporter(options, "metrics");
- return builder;
+ ///
+ /// Configure metrics OTLP exporter options
+ ///
+ /// Otlp options
+ public void ConfigureMetricsOptions(MetricReaderOptions options)
+ {
+ var logger = _components.Logger;
+ options.TemporalityPreference = MetricReaderTemporalityPreference.Delta;
+ logger.LogInformation("Configured Elastic Distribution of OpenTelemetry .NET defaults for logging auto-instrumentation.");
}
///
- /// To configure logs SDK (the method name is the same as for other logs options).
+ /// Configure logging OTLP exporter options.
///
- public void ConfigureLogsOptions(OpenTelemetryLoggerOptions options) => options.WithElasticDefaults(_components.Logger);
+ /// Otlp options.
+ public void ConfigureLogsOptions(OtlpExporterOptions options) => ConfigureOtlpExporter(options, "logs");
///
- /// To configure Resource.
+ /// To configure logs SDK (the method name is the same as for other logs options).
///
- public ResourceBuilder ConfigureResource(ResourceBuilder builder) =>
- builder.WithElasticDefaultsCore(_components, null, null);
+ public void ConfigureLogsOptions(OpenTelemetryLoggerOptions options) => options.WithElasticDefaults(_components.Logger);
+
+ private void ConfigureOtlpExporter(OtlpExporterOptions options, string signal)
+ {
+ var logger = _components.Logger;
+ options.ConfigureElasticUserAgent();
+ logger.LogConfiguredOtlpExporterOptions(signal);
+ }
}
diff --git a/src/Elastic.OpenTelemetry.AutoInstrumentation/_instrument.sh b/src/Elastic.OpenTelemetry.AutoInstrumentation/_instrument.sh
index 478f34fb..10937afa 100755
--- a/src/Elastic.OpenTelemetry.AutoInstrumentation/_instrument.sh
+++ b/src/Elastic.OpenTelemetry.AutoInstrumentation/_instrument.sh
@@ -35,7 +35,7 @@ Attempting to detect the runtime and use the native profiler from corresponding
case $(uname -m) in
x86_64) ARCHITECTURE="x64" ;;
- aarch64) ARCHITECTURE="arm64" ;;
+ aarch64|arm64) ARCHITECTURE="arm64" ;;
esac
case "$ARCHITECTURE" in
diff --git a/src/Elastic.OpenTelemetry.Core/Diagnostics/FileLogger.cs b/src/Elastic.OpenTelemetry.Core/Diagnostics/FileLogger.cs
index 152d5693..c636bb5c 100644
--- a/src/Elastic.OpenTelemetry.Core/Diagnostics/FileLogger.cs
+++ b/src/Elastic.OpenTelemetry.Core/Diagnostics/FileLogger.cs
@@ -40,7 +40,7 @@ public FileLogger(CompositeElasticOpenTelemetryOptions options)
var process = Process.GetCurrentProcess();
// This naming resembles the naming structure for OpenTelemetry log files.
- var logFileName = $"edot-dotnet-{process.Id}-{process.ProcessName}-{DateTimeOffset.UtcNow:yyyyMMdd-hhMMssfffZ}.log";
+ var logFileName = $"edot-dotnet-{process.Id}-{process.ProcessName}-{DateTimeOffset.UtcNow:yyyyMMdd-HHmmssfffZ}.log";
var logDirectory = options.LogDirectory;
LogFilePath = Path.Combine(logDirectory, logFileName);
diff --git a/src/Elastic.OpenTelemetry.Core/Diagnostics/LoggerMessages.cs b/src/Elastic.OpenTelemetry.Core/Diagnostics/LoggerMessages.cs
index 2e8d6ab0..e4ac32af 100644
--- a/src/Elastic.OpenTelemetry.Core/Diagnostics/LoggerMessages.cs
+++ b/src/Elastic.OpenTelemetry.Core/Diagnostics/LoggerMessages.cs
@@ -57,9 +57,9 @@ internal static partial class LoggerMessages
"times across all {Target} instances.")]
public static partial void LogWithElasticDefaultsCallCount(this ILogger logger, int callCount, string target);
- [LoggerMessage(EventId = 12, EventName = "ConfiguredOtlpExporterOptions", Level = LogLevel.Debug, Message = "The `OtlpExporterOptions` have been configured to use the" +
+ [LoggerMessage(EventId = 12, EventName = "ConfiguredOtlpExporterOptions", Level = LogLevel.Debug, Message = "The `OtlpExporterOptions` for {Signal} have been configured to use the" +
"`ElasticUserAgentHandler` to set the EDOT .NET user agent.")]
- public static partial void LogConfiguredOtlpExporterOptions(this ILogger logger);
+ public static partial void LogConfiguredOtlpExporterOptions(this ILogger logger, string signal);
diff --git a/src/Elastic.OpenTelemetry.Core/Exporters/ElasticUserAgentHandler.cs b/src/Elastic.OpenTelemetry.Core/Exporters/ElasticUserAgentHandler.cs
index e27e4290..c481e835 100644
--- a/src/Elastic.OpenTelemetry.Core/Exporters/ElasticUserAgentHandler.cs
+++ b/src/Elastic.OpenTelemetry.Core/Exporters/ElasticUserAgentHandler.cs
@@ -5,18 +5,51 @@
#if NETFRAMEWORK
using System.Net.Http;
#endif
+#pragma warning disable IDE0130 // Namespace does not match folder structure
+
+using Microsoft.Extensions.Logging;
namespace Elastic.OpenTelemetry.Exporters;
+#pragma warning restore IDE0130 // Namespace does not match folder structure
-internal class ElasticUserAgentHandler(string userAgent) : HttpClientHandler
+///
+/// Sets a custom User-Agent header for outgoing HTTP requests.
+/// Uses DelegatingHandler with SocketsHttpHandler for .NET, and HttpClientHandler for .NET Framework.
+///
+internal class ElasticUserAgentHandler
+#if NET
+ : DelegatingHandler
+#else
+ : HttpClientHandler
+#endif
{
- private readonly string _userAgent = userAgent;
+ private readonly string _userAgent;
+
+#if NET
+ public ElasticUserAgentHandler(string userAgent) : base(new SocketsHttpHandler()) => _userAgent = userAgent;
+#else
+ public ElasticUserAgentHandler(string userAgent) => _userAgent = userAgent;
+#endif
protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ PrepareRequest(request);
+ return base.SendAsync(request, cancellationToken);
+ }
+
+#if NET
+ // This method is only available in .NET targets and is crucial to override for synchronous calls.
+ // The upstream SDK prefers synchronous calls in many scenarios and without this override, the User-Agent header would not be set correctly.
+ protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ PrepareRequest(request);
+ return base.Send(request, cancellationToken);
+ }
+#endif
+
+ private void PrepareRequest(HttpRequestMessage request)
{
request.Headers.Remove("User-Agent");
request.Headers.Add("User-Agent", _userAgent);
-
- return base.SendAsync(request, cancellationToken);
}
}
diff --git a/src/Elastic.OpenTelemetry.Core/Exporters/OtlpExporterDefaults.cs b/src/Elastic.OpenTelemetry.Core/Exporters/OtlpExporterDefaults.cs
index 6ca555de..0bc4ace8 100644
--- a/src/Elastic.OpenTelemetry.Core/Exporters/OtlpExporterDefaults.cs
+++ b/src/Elastic.OpenTelemetry.Core/Exporters/OtlpExporterDefaults.cs
@@ -9,16 +9,24 @@
using System.Net.Http;
#endif
+#pragma warning disable IDE0130 // Namespace does not match folder structure
namespace Elastic.OpenTelemetry.Exporters;
+#pragma warning restore IDE0130 // Namespace does not match folder structure
internal static class OtlpExporterDefaults
{
- internal static readonly HttpMessageHandler Handler = new ElasticUserAgentHandler($"elastic-otlp-dotnet/{VersionHelper.InformationalVersion}");
+ private static string UserAgent => $"elastic-otlp-dotnet/{VersionHelper.InformationalVersion}";
- public static void OtlpExporterOptions(OtlpExporterOptions options) =>
+ internal static void OtlpExporterOptions(OtlpExporterOptions options) =>
options.HttpClientFactory = () =>
{
- var client = new HttpClient(Handler);
+ var client = new HttpClient(new ElasticUserAgentHandler(UserAgent));
return client;
};
+
+ internal static OtlpExporterOptions ConfigureElasticUserAgent(this OtlpExporterOptions options)
+ {
+ OtlpExporterOptions(options);
+ return options;
+ }
}
diff --git a/src/Elastic.OpenTelemetry/Elastic.OpenTelemetry.csproj b/src/Elastic.OpenTelemetry/Elastic.OpenTelemetry.csproj
index 9da6874f..b978e247 100644
--- a/src/Elastic.OpenTelemetry/Elastic.OpenTelemetry.csproj
+++ b/src/Elastic.OpenTelemetry/Elastic.OpenTelemetry.csproj
@@ -26,7 +26,7 @@
-
+
diff --git a/src/Elastic.OpenTelemetry/Extensions/LoggerProviderBuilderExtensions.cs b/src/Elastic.OpenTelemetry/Extensions/LoggerProviderBuilderExtensions.cs
index 5cfae1aa..68825b26 100644
--- a/src/Elastic.OpenTelemetry/Extensions/LoggerProviderBuilderExtensions.cs
+++ b/src/Elastic.OpenTelemetry/Extensions/LoggerProviderBuilderExtensions.cs
@@ -381,7 +381,7 @@ static void ConfigureBuilder(BuilderContext builderContex
if (services is null)
{
builder.ConfigureServices(sc => sc.Configure(OtlpExporterDefaults.OtlpExporterOptions));
- logger.LogConfiguredOtlpExporterOptions();
+ logger.LogConfiguredOtlpExporterOptions("logs");
}
builder.ConfigureServices(sc => sc.Configure(o => o.WithElasticDefaults(logger)));
diff --git a/src/Elastic.OpenTelemetry/Extensions/MeterProviderBuilderExtensions.cs b/src/Elastic.OpenTelemetry/Extensions/MeterProviderBuilderExtensions.cs
index f3919099..02b7d2cf 100644
--- a/src/Elastic.OpenTelemetry/Extensions/MeterProviderBuilderExtensions.cs
+++ b/src/Elastic.OpenTelemetry/Extensions/MeterProviderBuilderExtensions.cs
@@ -379,7 +379,7 @@ static void ConfigureBuilder(BuilderContext builderContext
if (services is null)
{
builder.ConfigureServices(sc => sc.Configure(OtlpExporterDefaults.OtlpExporterOptions));
- logger.LogConfiguredOtlpExporterOptions();
+ logger.LogConfiguredOtlpExporterOptions("metrics");
}
builder.ConfigureServices(sc => sc.Configure(o =>
diff --git a/src/Elastic.OpenTelemetry/Extensions/ServiceCollectionExtensions.cs b/src/Elastic.OpenTelemetry/Extensions/ServiceCollectionExtensions.cs
index 4a725d91..33f9edae 100644
--- a/src/Elastic.OpenTelemetry/Extensions/ServiceCollectionExtensions.cs
+++ b/src/Elastic.OpenTelemetry/Extensions/ServiceCollectionExtensions.cs
@@ -316,7 +316,7 @@ internal static IOpenTelemetryBuilder AddElasticOpenTelemetryCore(
var logger = DeferredLogger.GetOrCreate(options);
services.Configure(OtlpExporterDefaults.OtlpExporterOptions);
- logger.LogConfiguredOtlpExporterOptions();
+ logger.LogConfiguredOtlpExporterOptions("all signals");
var builder = services.AddOpenTelemetry().WithElasticDefaultsCore(options, builderOptions);
diff --git a/src/Elastic.OpenTelemetry/Extensions/TracerProviderBuilderExtensions.cs b/src/Elastic.OpenTelemetry/Extensions/TracerProviderBuilderExtensions.cs
index 5a1b8d38..88bec52f 100644
--- a/src/Elastic.OpenTelemetry/Extensions/TracerProviderBuilderExtensions.cs
+++ b/src/Elastic.OpenTelemetry/Extensions/TracerProviderBuilderExtensions.cs
@@ -383,7 +383,7 @@ private static void ConfigureBuilder(BuilderContext build
if (services is null)
{
builder.ConfigureServices(sc => sc.Configure(OtlpExporterDefaults.OtlpExporterOptions));
- logger.LogConfiguredOtlpExporterOptions();
+ logger.LogConfiguredOtlpExporterOptions("traces");
}
#if NET9_0_OR_GREATER