Optimize metrics loading (#1532)

This commit is contained in:
Rasmus Kuusmann 2022-11-02 17:36:56 +02:00 committed by GitHub
parent 885b2c4e43
commit 6f27769b7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 75 deletions

View File

@ -15,8 +15,8 @@
// </copyright>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using OpenTelemetry.AutoInstrumentation.Logging;
using OpenTelemetry.Metrics;
@ -25,13 +25,6 @@ namespace OpenTelemetry.AutoInstrumentation.Configuration;
internal static class EnvironmentConfigurationMetricHelper
{
private static readonly ILogger Logger = OtelLogging.GetLogger();
private static readonly Dictionary<MetricInstrumentation, Action<MeterProviderBuilder>> AddMeters = new()
{
[MetricInstrumentation.AspNet] = builder => builder.AddSdkAspNetInstrumentation(),
[MetricInstrumentation.HttpClient] = builder => builder.AddHttpClientInstrumentation(),
[MetricInstrumentation.NetRuntime] = builder => builder.AddRuntimeInstrumentation(),
[MetricInstrumentation.Process] = builder => builder.AddProcessInstrumentation(),
};
public static MeterProviderBuilder UseEnvironmentVariables(this MeterProviderBuilder builder, MetricSettings settings)
{
@ -41,31 +34,79 @@ internal static class EnvironmentConfigurationMetricHelper
foreach (var enabledMeter in settings.EnabledInstrumentations)
{
if (AddMeters.TryGetValue(enabledMeter, out var addMeter))
_ = enabledMeter switch
{
addMeter(builder);
}
MetricInstrumentation.AspNet => Wrappers.AddSdkAspNetInstrumentation(builder),
MetricInstrumentation.HttpClient => Wrappers.AddHttpClientInstrumentation(builder),
MetricInstrumentation.NetRuntime => Wrappers.AddRuntimeInstrumentation(builder),
MetricInstrumentation.Process => Wrappers.AddProcessInstrumentation(builder),
_ => null,
};
}
return builder;
}
public static MeterProviderBuilder AddSdkAspNetInstrumentation(this MeterProviderBuilder builder)
{
#if NET462
builder.AddAspNetInstrumentation();
#elif NETCOREAPP3_1_OR_GREATER
builder.AddMeter("OpenTelemetry.Instrumentation.AspNetCore");
#endif
return builder;
}
private static MeterProviderBuilder SetExporter(this MeterProviderBuilder builder, MetricSettings settings)
{
if (settings.ConsoleExporterEnabled)
{
builder.AddConsoleExporter((_, metricReaderOptions) =>
Wrappers.AddConsoleExporter(builder, settings);
}
return settings.MetricExporter switch
{
MetricsExporter.Prometheus => Wrappers.AddPrometheusExporter(builder),
MetricsExporter.Otlp => Wrappers.AddOtlpExporter(builder, settings),
MetricsExporter.None => builder,
_ => throw new ArgumentOutOfRangeException($"Metrics exporter '{settings.MetricExporter}' is incorrect")
};
}
/// <summary>
/// This class wraps external extension methods to ensure the dlls are not loaded, if not necessary.
/// .NET Framework is aggressively inlining these wrappers. Inlining must be disabled to ensure the wrapping effect.
/// </summary>
private static class Wrappers
{
// Meters
[MethodImpl(MethodImplOptions.NoInlining)]
public static MeterProviderBuilder AddSdkAspNetInstrumentation(MeterProviderBuilder builder)
{
#if NET462
builder.AddAspNetInstrumentation();
#elif NETCOREAPP3_1_OR_GREATER
builder.AddMeter("OpenTelemetry.Instrumentation.AspNetCore");
#endif
return builder;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static MeterProviderBuilder AddHttpClientInstrumentation(MeterProviderBuilder builder)
{
return builder.AddHttpClientInstrumentation();
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static MeterProviderBuilder AddRuntimeInstrumentation(MeterProviderBuilder builder)
{
return builder.AddRuntimeInstrumentation();
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static MeterProviderBuilder AddProcessInstrumentation(MeterProviderBuilder builder)
{
return builder.AddProcessInstrumentation();
}
// Exporters
[MethodImpl(MethodImplOptions.NoInlining)]
public static MeterProviderBuilder AddConsoleExporter(MeterProviderBuilder builder, MetricSettings settings)
{
return builder.AddConsoleExporter((_, metricReaderOptions) =>
{
if (settings.MetricExportInterval != null)
{
@ -74,45 +115,43 @@ internal static class EnvironmentConfigurationMetricHelper
});
}
switch (settings.MetricExporter)
[MethodImpl(MethodImplOptions.NoInlining)]
public static MeterProviderBuilder AddPrometheusExporter(MeterProviderBuilder builder)
{
case MetricsExporter.Prometheus:
Logger.Warning("Prometheus exporter is configured. It is intended for the inner dev loop. Do NOT use in production");
builder.AddPrometheusExporter(options =>
{
options.StartHttpListener = true;
options.ScrapeResponseCacheDurationMilliseconds = 300;
});
break;
case MetricsExporter.Otlp:
#if NETCOREAPP3_1
if (settings.Http2UnencryptedSupportEnabled)
{
// Adding the OtlpExporter creates a GrpcChannel.
// This switch must be set before creating a GrpcChannel/HttpClient when calling an insecure gRPC service.
// See: https://docs.microsoft.com/aspnet/core/grpc/troubleshoot#call-insecure-grpc-services-with-net-core-client
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
}
#endif
builder.AddOtlpExporter((options, metricReaderOptions) =>
{
if (settings.OtlpExportProtocol.HasValue)
{
options.Protocol = settings.OtlpExportProtocol.Value;
}
Logger.Warning("Prometheus exporter is configured. It is intended for the inner dev loop. Do NOT use in production");
if (settings.MetricExportInterval != null)
{
metricReaderOptions.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds = settings.MetricExportInterval;
}
});
break;
case MetricsExporter.None:
break;
default:
throw new ArgumentOutOfRangeException($"Metrics exporter '{settings.MetricExporter}' is incorrect");
return builder.AddPrometheusExporter(options =>
{
options.StartHttpListener = true;
options.ScrapeResponseCacheDurationMilliseconds = 300;
});
}
return builder;
[MethodImpl(MethodImplOptions.NoInlining)]
public static MeterProviderBuilder AddOtlpExporter(MeterProviderBuilder builder, MetricSettings settings)
{
#if NETCOREAPP3_1
if (settings.Http2UnencryptedSupportEnabled)
{
// Adding the OtlpExporter creates a GrpcChannel.
// This switch must be set before creating a GrpcChannel/HttpClient when calling an insecure gRPC service.
// See: https://docs.microsoft.com/aspnet/core/grpc/troubleshoot#call-insecure-grpc-services-with-net-core-client
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
}
#endif
return builder.AddOtlpExporter((options, metricReaderOptions) =>
{
if (settings.OtlpExportProtocol.HasValue)
{
options.Protocol = settings.OtlpExportProtocol.Value;
}
if (settings.MetricExportInterval != null)
{
metricReaderOptions.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds = settings.MetricExportInterval;
}
});
}
}
}

View File

@ -4,9 +4,7 @@
OpenTelemetry.AutoInstrumentation,
OpenTelemetry.AutoInstrumentation.Loader,
OpenTelemetry.AutoInstrumentation.StartupHook,
OpenTelemetry.Exporter.Console,
OpenTelemetry.Exporter.OpenTelemetryProtocol,
OpenTelemetry.Exporter.Prometheus,
OpenTelemetry.Instrumentation.GrpcNetClient,
OpenTelemetry.Instrumentation.Http,
OpenTelemetry.Instrumentation.Process,

View File

@ -3,9 +3,7 @@
OpenTelemetry.Api,
OpenTelemetry.AutoInstrumentation,
OpenTelemetry.AutoInstrumentation.Loader,
OpenTelemetry.Exporter.Console,
OpenTelemetry.Exporter.OpenTelemetryProtocol,
OpenTelemetry.Exporter.Prometheus,
OpenTelemetry.Instrumentation.AspNet,
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule,
OpenTelemetry.Instrumentation.GrpcNetClient,

View File

@ -4,11 +4,6 @@
OpenTelemetry.AutoInstrumentation,
OpenTelemetry.AutoInstrumentation.Loader,
OpenTelemetry.AutoInstrumentation.StartupHook,
OpenTelemetry.Exporter.Console,
OpenTelemetry.Exporter.OpenTelemetryProtocol,
OpenTelemetry.Exporter.Prometheus,
OpenTelemetry.Instrumentation.Http,
OpenTelemetry.Instrumentation.Process,
OpenTelemetry.Instrumentation.Runtime,
OpenTelemetry.Shims.OpenTracing
]

View File

@ -3,13 +3,6 @@
OpenTelemetry.Api,
OpenTelemetry.AutoInstrumentation,
OpenTelemetry.AutoInstrumentation.Loader,
OpenTelemetry.Exporter.Console,
OpenTelemetry.Exporter.OpenTelemetryProtocol,
OpenTelemetry.Exporter.Prometheus,
OpenTelemetry.Instrumentation.AspNet,
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule,
OpenTelemetry.Instrumentation.Http,
OpenTelemetry.Instrumentation.Process,
OpenTelemetry.Instrumentation.Runtime,
OpenTelemetry.Shims.OpenTracing
]

View File

@ -51,8 +51,11 @@ public class ModuleTests : TestHelper
public async Task Minimal()
{
SetEnvironmentVariable(ConfigurationKeys.Traces.Instrumentations, Constants.ConfigurationValues.None);
SetEnvironmentVariable(ConfigurationKeys.Metrics.Instrumentations, Constants.ConfigurationValues.None);
SetEnvironmentVariable(ConfigurationKeys.Traces.Exporter, Constants.ConfigurationValues.None);
SetEnvironmentVariable(ConfigurationKeys.Metrics.Exporter, Constants.ConfigurationValues.None);
SetEnvironmentVariable(ConfigurationKeys.Traces.ConsoleExporterEnabled, bool.FalseString);
SetEnvironmentVariable(ConfigurationKeys.Metrics.ConsoleExporterEnabled, bool.FalseString);
string verifyTestName =
#if NETFRAMEWORK