Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using System;
using System.Diagnostics.Metrics;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;

namespace LaunchDarkly.Observability
{
Expand All @@ -18,6 +22,9 @@ public class BaseBuilder<TBuilder> where TBuilder : BaseBuilder<TBuilder>
private string _serviceName = string.Empty;
private string _environment = string.Empty;
private string _serviceVersion = string.Empty;
private Action<TracerProviderBuilder> _extendedTracerConfiguration;
private Action<LoggerProviderBuilder> _extendedLoggerConfiguration;
private Action<MeterProviderBuilder> _extendedMeterConfiguration;

protected BaseBuilder()
{
Expand Down Expand Up @@ -92,6 +99,123 @@ public TBuilder WithEnvironment(string environment)
return (TBuilder)this;
}

/// <summary>
/// Method which extends the configuration of the tracer provider.
/// <para>
/// The basic tracer options will already be configured by the LaunchDarkly Observability plugin. This method
/// should be used to extend that configuration with additional instrumentation or additional activity sources.
/// </para>
/// <para>
/// By default tracing will be configured with the following instrumentation:
/// <list type="bullet">
/// <item>HTTP Client Instrumentation</item>
/// <item>GRPC Client Instrumentation</item>
/// <item>WCF Instrumentation</item>
/// <item>Quart Instrumentation</item>
/// <item>AspNetCore Instrumentation</item>
/// <item>SQL Client Instrumentation</item>
/// </list>
/// </para>
/// <para>
/// Configuring exporters or processors may interfere with the operation of the plugin and is not recommended.
/// </para>
/// </summary>
/// <example>
/// Add additional activity sources:
/// <code>
/// ObservabilityConfig.Builder()
/// .WithExtendedTracingConfig(builder =>
/// {
/// // Activities started by this activity source will be in exported spans.
/// builder.AddSource("my-custom-activity-source");
/// });
/// </code>
/// </example>
/// <example>
/// Add additional instrumentation.
/// <code>
/// ObservabilityConfig.Builder()
/// .WithExtendedTracingConfig(builder =>
/// {
/// builder.AddMyInstrumentation()
/// });
/// </code>
/// </example>
/// <param name="extendedTracerConfiguration">A function used to extend the tracing configuration.</param>
/// <returns>A reference to this builder.</returns>
public TBuilder WithExtendedTracingConfig(Action<TracerProviderBuilder> extendedTracerConfiguration)
{
_extendedTracerConfiguration = extendedTracerConfiguration;
return (TBuilder)this;
}

/// <summary>
/// Method which extends the configuration of the logger provider.
/// <para>
/// The basic logger options will already be configured by the LaunchDarkly Observability plugin. This method
/// should be used to extend that configuration with additional instrumentation.
/// </para>
/// <para>
/// Configuring exporters or processors may interfere with the operation of the plugin and is not recommended.
/// </para>
/// </summary>
/// <example>
/// Adding custom instrumentation:
/// <code>
/// ObservabilityConfig.Builder()
/// .WithExtendedLoggerConfiguration(builder =>
/// {
/// builder.AddMyInstrumentation();
/// });
/// </code>
/// </example>
/// <param name="extendedLoggerConfiguration">A function used to extend the logging configuration.</param>
/// <returns>A reference to this builder.</returns>
public TBuilder WithExtendedLoggerConfiguration(Action<LoggerProviderBuilder> extendedLoggerConfiguration)
{
_extendedLoggerConfiguration = extendedLoggerConfiguration;
return (TBuilder)this;
}

/// <summary>
/// Method which extends the configuration of the meter provider.
/// <para>
/// The basic meter options will already be configured by the LaunchDarkly Observability plugin. This method
/// should be used to extend that configuration with additional meters, views, or custom instrumentation.
/// </para>
/// <para>
/// By default, metrics will be configured with the following instrumentation:
/// <list type="bullet">
/// <item>Runtime Instrumentation (GC, thread pool, JIT statistics)</item>
/// <item>Process Instrumentation (CPU, memory, handle counts)</item>
/// <item>HTTP Client Instrumentation (request counts, durations)</item>
/// <item>AspNetCore Instrumentation (request rates, response times)</item>
/// <item>SQL Client Instrumentation (query execution times, connection pool metrics)</item>
/// </list>
/// </para>
/// <para>
/// Configuring exporters or processors may interfere with the operation of the plugin and is not recommended.
/// </para>
/// </summary>
/// <example>
/// Adding custom instrumentation:
/// <code>
/// ObservabilityConfig.Builder()
/// .WithExtendedMeterConfiguration(builder =>
/// {
/// // Add meters from your custom instrumentation
/// builder.AddMyInstrumentation();
/// });
/// </code>
/// </example>
/// <param name="extendedMeterConfiguration">A function used to extend the metrics configuration.</param>
/// <returns>A reference to this builder.</returns>
public TBuilder WithExtendedMeterConfiguration(Action<MeterProviderBuilder> extendedMeterConfiguration)
{
_extendedMeterConfiguration = extendedMeterConfiguration;
return (TBuilder)this;
}

/// <summary>
/// Build an immutable <see cref="ObservabilityConfig"/> instance.
/// </summary>
Expand All @@ -110,7 +234,10 @@ internal ObservabilityConfig BuildConfig(string sdkKey)
_serviceName,
_environment,
_serviceVersion,
sdkKey);
sdkKey,
_extendedTracerConfiguration,
_extendedLoggerConfiguration,
_extendedMeterConfiguration);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,23 @@ namespace LaunchDarkly.Observability
{
internal static class DefaultNames
{
public const string MeterName = "launchdarkly-plugin-default-metrics";
public const string ActivitySourceName = "launchdarkly-plugin-default-activity";
public const string DefaultLoggerName = "launchdarkly-plugin-default-logger";
public static string MeterNameOrDefault(string meterName)
Comment thread
kinyoklion marked this conversation as resolved.
{
return string.IsNullOrWhiteSpace(meterName) ? MeterName : meterName;
}

public static string ActivitySourceNameOrDefault(string sourceName)
{
return string.IsNullOrWhiteSpace(sourceName) ? ActivitySourceName : sourceName;
}

public static string LoggerNameOrDefault(string name)
{
return string.IsNullOrWhiteSpace(name) ? LoggerName : name;
}

private const string MeterName = "launchdarkly-plugin-default-metrics";
private const string ActivitySourceName = "launchdarkly-plugin-default-activity";
private const string LoggerName = "launchdarkly-plugin-default-logger";
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;

namespace LaunchDarkly.Observability
{
Expand Down Expand Up @@ -40,21 +43,43 @@ public struct ObservabilityConfig
/// The LaunchDarkly SDK key.
/// </summary>
public string SdkKey { get; }

/// <summary>
/// Function which extends the configuration of the tracer provider.
/// </summary>
public Action<TracerProviderBuilder> ExtendedTracerConfiguration { get; }

/// <summary>
/// Function which extends the configuration of the logger provider.
/// </summary>
public Action<LoggerProviderBuilder> ExtendedLoggerConfiguration { get; }

/// <summary>
/// Function which extends the configuration of the meter provider.
/// </summary>
public Action<MeterProviderBuilder> ExtendedMeterConfiguration { get; }

internal ObservabilityConfig(
string otlpEndpoint,
string backendUrl,
string serviceName,
string environment,
string serviceVersion,
string sdkKey)
string sdkKey,
Action<TracerProviderBuilder> extendedTracerConfiguration,
Action<LoggerProviderBuilder> extendedLoggerConfiguration,
Action<MeterProviderBuilder> extendedMeterConfiguration
)
{
OtlpEndpoint = otlpEndpoint;
BackendUrl = backendUrl;
ServiceName = serviceName;
Environment = environment;
ServiceVersion = serviceVersion;
SdkKey = sdkKey;
ExtendedTracerConfiguration = extendedTracerConfiguration;
ExtendedLoggerConfiguration = extendedLoggerConfiguration;
ExtendedMeterConfiguration = extendedMeterConfiguration;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ internal static void AddLaunchDarklyObservabilityWithConfig(this IServiceCollect
.AddWcfInstrumentation()
.AddQuartzInstrumentation()
.AddAspNetCoreInstrumentation(options => { options.RecordException = true; })
.AddSqlClientInstrumentation(options => { options.SetDbStatementForText = true; });
.AddSqlClientInstrumentation(options => { options.SetDbStatementForText = true; })
.AddSource(DefaultNames.ActivitySourceNameOrDefault(config.ServiceName));
Comment thread
kinyoklion marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.

// Always use sampling exporter for traces
var samplingTraceExporter = new SamplingTraceExporter(sampler, new OtlpExporterOptions
Expand All @@ -123,6 +124,7 @@ internal static void AddLaunchDarklyObservabilityWithConfig(this IServiceCollect

tracing.AddProcessor(new BatchActivityExportProcessor(samplingTraceExporter, MaxQueueSize,
FlushIntervalMs, ExportTimeoutMs, MaxExportBatchSize));
config.ExtendedTracerConfiguration?.Invoke(tracing);
}).WithLogging(logging =>
{
logging.SetResourceBuilder(resourceBuilder)
Expand All @@ -135,10 +137,11 @@ internal static void AddLaunchDarklyObservabilityWithConfig(this IServiceCollect
options.BatchExportProcessorOptions.MaxQueueSize = MaxQueueSize;
options.BatchExportProcessorOptions.ScheduledDelayMilliseconds = FlushIntervalMs;
});
config.ExtendedLoggerConfiguration?.Invoke(logging);
}).WithMetrics(metrics =>
{
metrics.SetResourceBuilder(resourceBuilder)
.AddMeter(config.ServiceName ?? DefaultNames.MeterName)
.AddMeter(DefaultNames.MeterNameOrDefault(config.ServiceName))
.AddRuntimeInstrumentation()
.AddProcessInstrumentation()
.AddHttpClientInstrumentation()
Expand All @@ -149,6 +152,7 @@ internal static void AddLaunchDarklyObservabilityWithConfig(this IServiceCollect
Endpoint = new Uri(config.OtlpEndpoint + MetricsPath),
Protocol = ExportProtocol
})));
config.ExtendedMeterConfiguration?.Invoke(metrics);
});

// Attach a hosted service which will allow us to get a logger provider instance from the built
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ private class Instance

internal Instance(ObservabilityConfig config, ILoggerProvider loggerProvider)
{
Meter = new Meter(config.ServiceName ?? DefaultNames.MeterName,
Meter = new Meter(DefaultNames.MeterNameOrDefault(config.ServiceName),
config.ServiceVersion);
ActivitySource = new ActivitySource(config.ServiceName ?? DefaultNames.ActivitySourceName,
ActivitySource = new ActivitySource(DefaultNames.ActivitySourceNameOrDefault(config.ServiceName),
config.ServiceVersion);
if (loggerProvider != null)
{
Logger = loggerProvider.CreateLogger(config.ServiceName ?? DefaultNames.DefaultLoggerName);
Logger = loggerProvider.CreateLogger(DefaultNames.LoggerNameOrDefault(config.ServiceName));
}
}
}
Expand Down
Loading
Loading