diff --git a/src/CodingWithCalvin.Otel4Vsix/CodingWithCalvin.Otel4Vsix.csproj b/src/CodingWithCalvin.Otel4Vsix/CodingWithCalvin.Otel4Vsix.csproj
index ccdf83b..dc31886 100644
--- a/src/CodingWithCalvin.Otel4Vsix/CodingWithCalvin.Otel4Vsix.csproj
+++ b/src/CodingWithCalvin.Otel4Vsix/CodingWithCalvin.Otel4Vsix.csproj
@@ -9,7 +9,7 @@
false
CodingWithCalvin.Otel4Vsix
- 0.0.15-local
+ 0.0.1
Calvin A. Allen
Coding With Calvin
CodingWithCalvin.Otel4Vsix
@@ -40,10 +40,10 @@
-
+
diff --git a/src/CodingWithCalvin.Otel4Vsix/Exporters/DebugActivityExporter.cs b/src/CodingWithCalvin.Otel4Vsix/Exporters/DebugActivityExporter.cs
new file mode 100644
index 0000000..9b81d79
--- /dev/null
+++ b/src/CodingWithCalvin.Otel4Vsix/Exporters/DebugActivityExporter.cs
@@ -0,0 +1,53 @@
+using System.Diagnostics;
+using System.Text;
+using OpenTelemetry;
+
+namespace CodingWithCalvin.Otel4Vsix.Exporters;
+
+///
+/// An activity exporter that writes trace data to .
+/// Output appears in the Visual Studio Output window when debugging.
+///
+internal sealed class DebugActivityExporter : BaseExporter
+{
+ private readonly string _prefix;
+
+ public DebugActivityExporter(string serviceName, string serviceVersion)
+ {
+ _prefix = $"[{serviceName} v{serviceVersion}]";
+ }
+
+ ///
+ public override ExportResult Export(in Batch batch)
+ {
+ foreach (var activity in batch)
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine($"{_prefix} [TRACE] {activity.DisplayName}");
+ sb.AppendLine($" TraceId: {activity.TraceId}");
+ sb.AppendLine($" SpanId: {activity.SpanId}");
+ sb.AppendLine($" Duration: {activity.Duration.TotalMilliseconds:F2}ms");
+ sb.AppendLine($" Status: {activity.Status}");
+
+ if (activity.Tags != null)
+ {
+ foreach (var tag in activity.Tags)
+ {
+ sb.AppendLine($" {tag.Key}: {tag.Value}");
+ }
+ }
+
+ if (activity.Events != null)
+ {
+ foreach (var evt in activity.Events)
+ {
+ sb.AppendLine($" Event: {evt.Name} at {evt.Timestamp}");
+ }
+ }
+
+ System.Diagnostics.Trace.WriteLine(sb.ToString());
+ }
+
+ return ExportResult.Success;
+ }
+}
diff --git a/src/CodingWithCalvin.Otel4Vsix/Exporters/DebugLoggerProvider.cs b/src/CodingWithCalvin.Otel4Vsix/Exporters/DebugLoggerProvider.cs
new file mode 100644
index 0000000..aeac2b3
--- /dev/null
+++ b/src/CodingWithCalvin.Otel4Vsix/Exporters/DebugLoggerProvider.cs
@@ -0,0 +1,75 @@
+using System;
+using Microsoft.Extensions.Logging;
+
+namespace CodingWithCalvin.Otel4Vsix.Exporters;
+
+///
+/// A logger provider that writes to .
+///
+internal sealed class DebugLoggerProvider : ILoggerProvider
+{
+ private readonly string _serviceName;
+ private readonly string _serviceVersion;
+
+ public DebugLoggerProvider(string serviceName, string serviceVersion)
+ {
+ _serviceName = serviceName;
+ _serviceVersion = serviceVersion;
+ }
+
+ public ILogger CreateLogger(string categoryName) => new DebugLogger(_serviceName, _serviceVersion, categoryName);
+
+ public void Dispose() { }
+}
+
+///
+/// A logger that writes to .
+///
+internal sealed class DebugLogger : ILogger
+{
+ private readonly string _prefix;
+ private readonly string _categoryName;
+
+ public DebugLogger(string serviceName, string serviceVersion, string categoryName)
+ {
+ _prefix = $"[{serviceName} v{serviceVersion}]";
+ _categoryName = categoryName;
+ }
+
+ public IDisposable BeginScope(TState state) => NullScope.Instance;
+
+ public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
+
+ public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
+ {
+ if (!IsEnabled(logLevel))
+ {
+ return;
+ }
+
+ var message = formatter(state, exception);
+ var levelStr = logLevel switch
+ {
+ LogLevel.Trace => "TRACE",
+ LogLevel.Debug => "DEBUG",
+ LogLevel.Information => "INFO",
+ LogLevel.Warning => "WARN",
+ LogLevel.Error => "ERROR",
+ LogLevel.Critical => "CRIT",
+ _ => "NONE"
+ };
+
+ System.Diagnostics.Trace.WriteLine($"{_prefix} [{levelStr}] {_categoryName}: {message}");
+
+ if (exception != null)
+ {
+ System.Diagnostics.Trace.WriteLine($" Exception: {exception}");
+ }
+ }
+
+ private sealed class NullScope : IDisposable
+ {
+ public static readonly NullScope Instance = new NullScope();
+ public void Dispose() { }
+ }
+}
diff --git a/src/CodingWithCalvin.Otel4Vsix/Exporters/DebugMetricExporter.cs b/src/CodingWithCalvin.Otel4Vsix/Exporters/DebugMetricExporter.cs
new file mode 100644
index 0000000..ce7aa72
--- /dev/null
+++ b/src/CodingWithCalvin.Otel4Vsix/Exporters/DebugMetricExporter.cs
@@ -0,0 +1,77 @@
+using System.Text;
+using OpenTelemetry;
+using OpenTelemetry.Metrics;
+
+namespace CodingWithCalvin.Otel4Vsix.Exporters;
+
+///
+/// A metric exporter that writes metric data to .
+/// Output appears in the Visual Studio Output window when debugging.
+///
+internal sealed class DebugMetricExporter : BaseExporter
+{
+ private readonly string _prefix;
+
+ public DebugMetricExporter(string serviceName, string serviceVersion)
+ {
+ _prefix = $"[{serviceName} v{serviceVersion}]";
+ }
+
+ ///
+ public override ExportResult Export(in Batch batch)
+ {
+ foreach (var metric in batch)
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine($"{_prefix} [METRIC] {metric.Name}");
+
+ if (!string.IsNullOrEmpty(metric.Unit))
+ {
+ sb.AppendLine($" Unit: {metric.Unit}");
+ }
+
+ if (!string.IsNullOrEmpty(metric.Description))
+ {
+ sb.AppendLine($" Description: {metric.Description}");
+ }
+
+ foreach (var metricPoint in metric.GetMetricPoints())
+ {
+ sb.Append(" ");
+
+ switch (metric.MetricType)
+ {
+ case MetricType.LongSum:
+ case MetricType.LongSumNonMonotonic:
+ sb.AppendLine($"Value: {metricPoint.GetSumLong()}");
+ break;
+ case MetricType.DoubleSum:
+ case MetricType.DoubleSumNonMonotonic:
+ sb.AppendLine($"Value: {metricPoint.GetSumDouble()}");
+ break;
+ case MetricType.LongGauge:
+ sb.AppendLine($"Value: {metricPoint.GetGaugeLastValueLong()}");
+ break;
+ case MetricType.DoubleGauge:
+ sb.AppendLine($"Value: {metricPoint.GetGaugeLastValueDouble()}");
+ break;
+ case MetricType.Histogram:
+ sb.AppendLine($"Count: {metricPoint.GetHistogramCount()}, Sum: {metricPoint.GetHistogramSum()}");
+ break;
+ default:
+ sb.AppendLine($"Type: {metric.MetricType}");
+ break;
+ }
+
+ foreach (var tag in metricPoint.Tags)
+ {
+ sb.AppendLine($" {tag.Key}: {tag.Value}");
+ }
+ }
+
+ System.Diagnostics.Trace.WriteLine(sb.ToString());
+ }
+
+ return ExportResult.Success;
+ }
+}
diff --git a/src/CodingWithCalvin.Otel4Vsix/TelemetryBuilder.cs b/src/CodingWithCalvin.Otel4Vsix/TelemetryBuilder.cs
new file mode 100644
index 0000000..e343127
--- /dev/null
+++ b/src/CodingWithCalvin.Otel4Vsix/TelemetryBuilder.cs
@@ -0,0 +1,289 @@
+using System;
+using System.Runtime.InteropServices;
+using EnvDTE;
+using EnvDTE80;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+
+namespace CodingWithCalvin.Otel4Vsix;
+
+///
+/// Fluent builder for configuring and initializing OpenTelemetry in Visual Studio extensions.
+///
+public sealed class TelemetryBuilder
+{
+ private readonly TelemetryConfiguration _configuration = new TelemetryConfiguration();
+
+ ///
+ /// Sets the service name used to identify this extension in telemetry.
+ ///
+ /// The service name.
+ /// The builder for chaining.
+ public TelemetryBuilder WithServiceName(string serviceName)
+ {
+ _configuration.ServiceName = serviceName;
+ return this;
+ }
+
+ ///
+ /// Sets the service version.
+ ///
+ /// The service version.
+ /// The builder for chaining.
+ public TelemetryBuilder WithServiceVersion(string serviceVersion)
+ {
+ _configuration.ServiceVersion = serviceVersion;
+ return this;
+ }
+
+ ///
+ /// Configures OTLP export using HTTP/protobuf protocol.
+ ///
+ /// The OTLP HTTP endpoint (e.g., "https://api.honeycomb.io").
+ /// The builder for chaining.
+ public TelemetryBuilder WithOtlpHttp(string endpoint)
+ {
+ _configuration.OtlpEndpoint = endpoint;
+ _configuration.UseOtlpHttp = true;
+ return this;
+ }
+
+ ///
+ /// Configures OTLP export using gRPC protocol.
+ ///
+ /// The OTLP gRPC endpoint (e.g., "http://localhost:4317").
+ /// The builder for chaining.
+ public TelemetryBuilder WithOtlpGrpc(string endpoint)
+ {
+ _configuration.OtlpEndpoint = endpoint;
+ _configuration.UseOtlpHttp = false;
+ return this;
+ }
+
+ ///
+ /// Adds a header to OTLP export requests.
+ ///
+ /// The header name.
+ /// The header value.
+ /// The builder for chaining.
+ public TelemetryBuilder WithHeader(string key, string value)
+ {
+ _configuration.OtlpHeaders[key] = value;
+ return this;
+ }
+
+ ///
+ /// Adds a resource attribute to all telemetry.
+ ///
+ /// The attribute name.
+ /// The attribute value.
+ /// The builder for chaining.
+ public TelemetryBuilder WithResourceAttribute(string key, object value)
+ {
+ _configuration.ResourceAttributes[key] = value;
+ return this;
+ }
+
+ ///
+ /// Adds Visual Studio version and edition as resource attributes by querying VS services.
+ ///
+ /// The async service provider (typically the AsyncPackage).
+ /// The builder for chaining.
+ ///
+ /// Adds the following resource attributes:
+ ///
+ /// - vs.version - The full Visual Studio version (e.g., "17.12.35521.163")
+ /// - vs.edition - The Visual Studio edition (e.g., "Community", "Professional", "Enterprise")
+ ///
+ /// This method queries DTE for the edition and IVsShell for the full release version.
+ ///
+ public TelemetryBuilder WithVisualStudioAttributes(IAsyncServiceProvider serviceProvider)
+ {
+ ThreadHelper.JoinableTaskFactory.Run(async () =>
+ {
+ await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var vsEdition = "unknown";
+ var vsVersion = "unknown";
+
+ var dte = await serviceProvider.GetServiceAsync(typeof(DTE)) as DTE2;
+ if (dte != null)
+ {
+ vsEdition = dte.Edition ?? "unknown";
+ }
+
+ var shell = await serviceProvider.GetServiceAsync(typeof(SVsShell)) as IVsShell;
+ if (shell != null && shell.GetProperty((int)__VSSPROPID5.VSSPROPID_ReleaseVersion, out var versionObj) == 0)
+ {
+ vsVersion = versionObj as string ?? "unknown";
+ }
+
+ _configuration.ResourceAttributes["vs.version"] = vsVersion;
+ _configuration.ResourceAttributes["vs.edition"] = vsEdition;
+ });
+
+ return this;
+ }
+
+ ///
+ /// Adds Visual Studio version and edition as resource attributes.
+ ///
+ /// The Visual Studio version (e.g., "17.12").
+ /// The Visual Studio edition (e.g., "Community", "Professional", "Enterprise").
+ /// The builder for chaining.
+ ///
+ /// Adds the following resource attributes:
+ ///
+ /// - vs.version - The Visual Studio version
+ /// - vs.edition - The Visual Studio edition
+ ///
+ ///
+ public TelemetryBuilder WithVisualStudioAttributes(string version, string edition)
+ {
+ _configuration.ResourceAttributes["vs.version"] = version ?? "unknown";
+ _configuration.ResourceAttributes["vs.edition"] = edition ?? "unknown";
+ return this;
+ }
+
+ ///
+ /// Adds environment attributes for OS and architecture.
+ ///
+ /// The builder for chaining.
+ ///
+ /// Adds the following resource attributes:
+ ///
+ /// - os.version - The operating system version
+ /// - host.arch - The processor architecture (e.g., "X64", "Arm64")
+ ///
+ ///
+ public TelemetryBuilder WithEnvironmentAttributes()
+ {
+ _configuration.ResourceAttributes["os.version"] = Environment.OSVersion.Version.ToString();
+ _configuration.ResourceAttributes["host.arch"] = RuntimeInformation.ProcessArchitecture.ToString();
+ return this;
+ }
+
+ ///
+ /// Sets the telemetry mode.
+ ///
+ /// The telemetry mode. Defaults to .
+ /// The builder for chaining.
+ public TelemetryBuilder WithMode(TelemetryMode mode)
+ {
+ _configuration.Mode = mode;
+ return this;
+ }
+
+ ///
+ /// Enables or disables tracing.
+ ///
+ /// True to enable tracing, false to disable.
+ /// The builder for chaining.
+ public TelemetryBuilder WithTracing(bool enabled = true)
+ {
+ _configuration.EnableTracing = enabled;
+ return this;
+ }
+
+ ///
+ /// Enables or disables metrics collection.
+ ///
+ /// True to enable metrics, false to disable.
+ /// The builder for chaining.
+ public TelemetryBuilder WithMetrics(bool enabled = true)
+ {
+ _configuration.EnableMetrics = enabled;
+ return this;
+ }
+
+ ///
+ /// Enables or disables logging.
+ ///
+ /// True to enable logging, false to disable.
+ /// The builder for chaining.
+ public TelemetryBuilder WithLogging(bool enabled = true)
+ {
+ _configuration.EnableLogging = enabled;
+ return this;
+ }
+
+ ///
+ /// Sets the trace sampling ratio.
+ ///
+ /// The sampling ratio (0.0 to 1.0). 1.0 samples all traces.
+ /// The builder for chaining.
+ public TelemetryBuilder WithTraceSamplingRatio(double ratio)
+ {
+ _configuration.TraceSamplingRatio = ratio;
+ return this;
+ }
+
+ ///
+ /// Enables or disables the global exception handler.
+ ///
+ /// True to enable, false to disable.
+ /// The builder for chaining.
+ public TelemetryBuilder WithGlobalExceptionHandler(bool enabled = true)
+ {
+ _configuration.EnableGlobalExceptionHandler = enabled;
+ return this;
+ }
+
+ ///
+ /// Sets an exception filter function.
+ ///
+ /// Function that returns true to track the exception, false to ignore.
+ /// The builder for chaining.
+ public TelemetryBuilder WithExceptionFilter(Func filter)
+ {
+ _configuration.ExceptionFilter = filter;
+ return this;
+ }
+
+ ///
+ /// Enables or disables Visual Studio context in telemetry.
+ ///
+ /// True to include VS context, false to exclude.
+ /// The builder for chaining.
+ public TelemetryBuilder WithVisualStudioContext(bool enabled = true)
+ {
+ _configuration.IncludeVisualStudioContext = enabled;
+ return this;
+ }
+
+ ///
+ /// Sets the export timeout.
+ ///
+ /// The timeout in milliseconds.
+ /// The builder for chaining.
+ public TelemetryBuilder WithExportTimeout(int timeoutMilliseconds)
+ {
+ _configuration.ExportTimeoutMilliseconds = timeoutMilliseconds;
+ return this;
+ }
+
+ ///
+ /// Builds the configuration and initializes telemetry.
+ ///
+ ///
+ /// When is set (the default), the effective mode is
+ /// determined by inspecting the configuration:
+ ///
+ /// - If an OTLP endpoint is configured, telemetry is exported via OTLP.
+ /// - Otherwise, telemetry is written to the debug output window.
+ ///
+ ///
+ public void Initialize()
+ {
+ VsixTelemetry.Initialize(_configuration);
+ }
+
+ ///
+ /// Builds and returns the configuration without initializing.
+ ///
+ /// The built configuration.
+ public TelemetryConfiguration Build()
+ {
+ return _configuration;
+ }
+}
diff --git a/src/CodingWithCalvin.Otel4Vsix/TelemetryConfiguration.cs b/src/CodingWithCalvin.Otel4Vsix/TelemetryConfiguration.cs
index 55cd19c..f15339a 100644
--- a/src/CodingWithCalvin.Otel4Vsix/TelemetryConfiguration.cs
+++ b/src/CodingWithCalvin.Otel4Vsix/TelemetryConfiguration.cs
@@ -8,6 +8,24 @@ namespace CodingWithCalvin.Otel4Vsix;
///
public sealed class TelemetryConfiguration
{
+ ///
+ /// Gets or sets the telemetry mode.
+ ///
+ ///
+ ///
+ /// When set to (the default), the library automatically
+ /// determines the mode based on configuration state:
+ ///
+ ///
+ /// - If an OTLP endpoint is configured, uses .
+ /// - Otherwise, uses .
+ ///
+ ///
+ /// This allows consumers to conditionally set the endpoint for different build configurations.
+ ///
+ ///
+ public TelemetryMode Mode { get; set; } = TelemetryMode.Auto;
+
///
/// Gets or sets the service name used to identify this extension in telemetry.
///
diff --git a/src/CodingWithCalvin.Otel4Vsix/TelemetryMode.cs b/src/CodingWithCalvin.Otel4Vsix/TelemetryMode.cs
new file mode 100644
index 0000000..c527277
--- /dev/null
+++ b/src/CodingWithCalvin.Otel4Vsix/TelemetryMode.cs
@@ -0,0 +1,30 @@
+namespace CodingWithCalvin.Otel4Vsix;
+
+///
+/// Specifies the telemetry export mode.
+///
+public enum TelemetryMode
+{
+ ///
+ /// Automatically determines the mode based on configuration state.
+ /// If an OTLP endpoint is configured, uses .
+ /// Otherwise, uses .
+ ///
+ Auto,
+
+ ///
+ /// Telemetry is completely disabled. No data is collected or exported.
+ ///
+ Disabled,
+
+ ///
+ /// Telemetry is written to the debug output window via .
+ /// Useful for local development in Visual Studio.
+ ///
+ Debug,
+
+ ///
+ /// Telemetry is exported via OTLP to the configured endpoint.
+ ///
+ Otlp
+}
diff --git a/src/CodingWithCalvin.Otel4Vsix/VsixTelemetry.cs b/src/CodingWithCalvin.Otel4Vsix/VsixTelemetry.cs
index 7baaaf9..4e78866 100644
--- a/src/CodingWithCalvin.Otel4Vsix/VsixTelemetry.cs
+++ b/src/CodingWithCalvin.Otel4Vsix/VsixTelemetry.cs
@@ -4,6 +4,7 @@
using System.Diagnostics.Metrics;
using System.Linq;
using CodingWithCalvin.Otel4Vsix.Exceptions;
+using CodingWithCalvin.Otel4Vsix.Exporters;
using CodingWithCalvin.Otel4Vsix.Logging;
using CodingWithCalvin.Otel4Vsix.Tracing;
using Microsoft.Extensions.Logging;
@@ -29,6 +30,7 @@ public static class VsixTelemetry
private static readonly object _lock = new object();
private static volatile bool _isInitialized;
private static TelemetryConfiguration _configuration;
+ private static TelemetryMode _effectiveMode;
private static ActivitySourceProvider _activitySourceProvider;
private static Metrics.MetricsProvider _metricsProvider;
private static Logging.LoggerProvider _loggerProvider;
@@ -42,6 +44,27 @@ public static class VsixTelemetry
///
public static bool IsInitialized => _isInitialized;
+ ///
+ /// Gets the effective telemetry mode after Auto resolution.
+ ///
+ public static TelemetryMode EffectiveMode => _effectiveMode;
+
+ ///
+ /// Creates a new for fluent configuration.
+ ///
+ /// A new builder instance.
+ ///
+ ///
+ /// VsixTelemetry.Configure()
+ /// .WithServiceName("MyExtension")
+ /// .WithServiceVersion("1.0.0")
+ /// .WithOtlpHttp("https://api.honeycomb.io")
+ /// .WithHeader("x-honeycomb-team", apiKey)
+ /// .Initialize();
+ ///
+ ///
+ public static TelemetryBuilder Configure() => new TelemetryBuilder();
+
///
/// Gets the for creating traces.
///
@@ -116,9 +139,38 @@ public static void Initialize(TelemetryConfiguration configuration)
}
_configuration = configuration;
+ _effectiveMode = ResolveEffectiveMode(configuration);
+
+ // If disabled, mark as initialized but don't set up providers
+ if (_effectiveMode == TelemetryMode.Disabled)
+ {
+ _isInitialized = true;
+ return;
+ }
+
InitializeProviders();
_isInitialized = true;
+
+ // Log initialization in Debug mode
+ if (_effectiveMode == TelemetryMode.Debug)
+ {
+ System.Diagnostics.Trace.WriteLine(
+ $"[{_configuration.ServiceName} v{_configuration.ServiceVersion}] Telemetry initialized (Mode: {_effectiveMode})");
+ }
+ }
+ }
+
+ private static TelemetryMode ResolveEffectiveMode(TelemetryConfiguration configuration)
+ {
+ if (configuration.Mode != TelemetryMode.Auto)
+ {
+ return configuration.Mode;
}
+
+ // Auto mode: if endpoint is configured, use Otlp; otherwise Debug
+ return !string.IsNullOrWhiteSpace(configuration.OtlpEndpoint)
+ ? TelemetryMode.Otlp
+ : TelemetryMode.Debug;
}
///
@@ -469,8 +521,8 @@ private static TracerProvider BuildTracerProvider(ResourceBuilder resourceBuilde
.AddSource(_configuration.ServiceName)
.SetSampler(new TraceIdRatioBasedSampler(_configuration.TraceSamplingRatio));
- // Add OTLP exporter if endpoint is configured
- if (!string.IsNullOrWhiteSpace(_configuration.OtlpEndpoint))
+ // Add OTLP exporter only in Otlp mode
+ if (_effectiveMode == TelemetryMode.Otlp && !string.IsNullOrWhiteSpace(_configuration.OtlpEndpoint))
{
builder.AddOtlpExporter(options =>
{
@@ -478,10 +530,11 @@ private static TracerProvider BuildTracerProvider(ResourceBuilder resourceBuilde
});
}
- // Add console exporter if enabled
- if (_configuration.EnableConsoleExporter)
+ // Add debug exporter in Debug mode
+ if (_effectiveMode == TelemetryMode.Debug)
{
- builder.AddConsoleExporter();
+ builder.AddProcessor(new SimpleActivityExportProcessor(
+ new DebugActivityExporter(_configuration.ServiceName, _configuration.ServiceVersion)));
}
return builder.Build();
@@ -493,8 +546,8 @@ private static OpenTelemetry.Metrics.MeterProvider BuildMeterProvider(ResourceBu
.SetResourceBuilder(resourceBuilder)
.AddMeter(_configuration.ServiceName);
- // Add OTLP exporter if endpoint is configured
- if (!string.IsNullOrWhiteSpace(_configuration.OtlpEndpoint))
+ // Add OTLP exporter only in Otlp mode
+ if (_effectiveMode == TelemetryMode.Otlp && !string.IsNullOrWhiteSpace(_configuration.OtlpEndpoint))
{
builder.AddOtlpExporter(options =>
{
@@ -502,10 +555,11 @@ private static OpenTelemetry.Metrics.MeterProvider BuildMeterProvider(ResourceBu
});
}
- // Add console exporter if enabled
- if (_configuration.EnableConsoleExporter)
+ // Add debug exporter in Debug mode
+ if (_effectiveMode == TelemetryMode.Debug)
{
- builder.AddConsoleExporter();
+ builder.AddReader(new PeriodicExportingMetricReader(
+ new DebugMetricExporter(_configuration.ServiceName, _configuration.ServiceVersion), 10000));
}
return builder.Build();
@@ -515,14 +569,15 @@ private static ILoggerFactory BuildLoggerFactory(ResourceBuilder resourceBuilder
{
return Microsoft.Extensions.Logging.LoggerFactory.Create(builder =>
{
+ builder.SetMinimumLevel(LogLevel.Trace);
builder.AddOpenTelemetry(options =>
{
options.SetResourceBuilder(resourceBuilder);
options.IncludeFormattedMessage = true;
options.IncludeScopes = true;
- // Add OTLP exporter if endpoint is configured
- if (!string.IsNullOrWhiteSpace(_configuration.OtlpEndpoint))
+ // Add OTLP exporter only in Otlp mode
+ if (_effectiveMode == TelemetryMode.Otlp && !string.IsNullOrWhiteSpace(_configuration.OtlpEndpoint))
{
options.AddOtlpExporter(exporterOptions =>
{
@@ -530,12 +585,13 @@ private static ILoggerFactory BuildLoggerFactory(ResourceBuilder resourceBuilder
});
}
- // Add console exporter if enabled
- if (_configuration.EnableConsoleExporter)
- {
- options.AddConsoleExporter();
- }
});
+
+ // Add debug logging in Debug mode
+ if (_effectiveMode == TelemetryMode.Debug)
+ {
+ builder.AddProvider(new DebugLoggerProvider(_configuration.ServiceName, _configuration.ServiceVersion));
+ }
});
}