From 9fcb417c70bc84f752867cf7ea5f6cd387745166 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Fri, 28 Apr 2023 10:07:31 -0700 Subject: [PATCH 1/3] Implement LoggerProviderSdk. --- .../Internal/OpenTelemetrySdkEventSource.cs | 21 ++ src/OpenTelemetry/Logs/LoggerProviderSdk.cs | 221 ++++++++++++++++++ 2 files changed, 242 insertions(+) diff --git a/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs b/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs index 872657af4d0..bac167db332 100644 --- a/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs +++ b/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs @@ -149,6 +149,15 @@ public void LoggerParseStateException(Exception exception) } } + [NonEvent] + public void LoggerProviderException(string methodName, Exception ex) + { + if (this.IsEnabled(EventLevel.Error, EventKeywords.All)) + { + this.LoggerProviderException(methodName, ex.ToInvariantString()); + } + } + [Event(4, Message = "Unknown error in SpanProcessor event '{0}': '{1}'.", Level = EventLevel.Error)] public void SpanProcessorException(string evnt, string ex) { @@ -299,6 +308,18 @@ public void LoggerParseStateException(string type, string error) this.WriteEvent(48, type, error); } + [Event(49, Message = "LoggerProviderSdk event: '{0}'", Level = EventLevel.Verbose)] + public void LoggerProviderSdkEvent(string message) + { + this.WriteEvent(49, message); + } + + [Event(50, Message = "Unknown error in LoggerProvider '{0}': '{1}'.", Level = EventLevel.Error)] + public void LoggerProviderException(string methodName, string ex) + { + this.WriteEvent(50, methodName, ex); + } + #if DEBUG public class OpenTelemetryEventListener : EventListener { diff --git a/src/OpenTelemetry/Logs/LoggerProviderSdk.cs b/src/OpenTelemetry/Logs/LoggerProviderSdk.cs index 5b108966aaa..c2c30cb138e 100644 --- a/src/OpenTelemetry/Logs/LoggerProviderSdk.cs +++ b/src/OpenTelemetry/Logs/LoggerProviderSdk.cs @@ -16,14 +16,235 @@ #nullable enable +using System.Diagnostics; +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Internal; +using OpenTelemetry.Resources; + namespace OpenTelemetry.Logs; +/// +/// SDK implementation. +/// internal sealed class LoggerProviderSdk : LoggerProvider { + internal readonly IServiceProvider ServiceProvider; + private readonly IDisposable? ownedServiceProvider; + private readonly List instrumentations = new(); + private ILogRecordPool? threadStaticPool = LogRecordThreadStaticPool.Instance; + private int shutdownCount; + private bool disposed; + public LoggerProviderSdk( IServiceProvider serviceProvider, bool ownsServiceProvider) { + Debug.Assert(serviceProvider != null, "serviceProvider was null"); + + var state = serviceProvider!.GetRequiredService(); + state.RegisterProvider(this); + + this.ServiceProvider = serviceProvider!; + + if (ownsServiceProvider) + { + this.ownedServiceProvider = serviceProvider as IDisposable; + Debug.Assert(this.ownedServiceProvider != null, "ownedServiceProvider was null"); + } + + OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent("Building TracerProvider."); + + var configureProviderBuilders = serviceProvider!.GetServices(); + foreach (var configureProviderBuilder in configureProviderBuilders) + { + configureProviderBuilder.ConfigureBuilder(serviceProvider!, state); + } + + StringBuilder processorsAdded = new StringBuilder(); + StringBuilder instrumentationFactoriesAdded = new StringBuilder(); + + var resourceBuilder = state.ResourceBuilder ?? ResourceBuilder.CreateDefault(); + resourceBuilder.ServiceProvider = serviceProvider; + this.Resource = resourceBuilder.Build(); + + foreach (var processor in state.Processors) + { + this.AddProcessor(processor); + processorsAdded.Append(processor.GetType()); + processorsAdded.Append(';'); + } + + foreach (var instrumentation in state.Instrumentation) + { + this.instrumentations.Add(instrumentation.Instance); + instrumentationFactoriesAdded.Append(instrumentation.Name); + instrumentationFactoriesAdded.Append(';'); + } + + if (processorsAdded.Length != 0) + { + processorsAdded.Remove(processorsAdded.Length - 1, 1); + OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent($"Processors added = \"{processorsAdded}\"."); + } + + if (instrumentationFactoriesAdded.Length != 0) + { + instrumentationFactoriesAdded.Remove(instrumentationFactoriesAdded.Length - 1, 1); + OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent($"Instrumentations added = \"{instrumentationFactoriesAdded}\"."); + } + + OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent("LoggerProviderSdk built successfully."); + } + + public Resource Resource { get; } + + public List Instrumentations => this.instrumentations; + + public BaseProcessor? Processor { get; private set; } + + public ILogRecordPool LogRecordPool => this.threadStaticPool ?? LogRecordSharedPool.Current; + + public void AddProcessor(BaseProcessor processor) + { + OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent("Started adding processor."); + + Guard.ThrowIfNull(processor); + + processor.SetParentProvider(this); + + StringBuilder processorAdded = new StringBuilder(); + + if (this.threadStaticPool != null && this.ContainsBatchProcessor(processor)) + { + OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent("Using shared thread pool."); + + this.threadStaticPool = null; + } + + if (this.Processor == null) + { + processorAdded.Append("Setting processor to "); + processorAdded.Append(processor); + + this.Processor = processor; + } + else if (this.Processor is CompositeProcessor compositeProcessor) + { + processorAdded.Append("Adding processor "); + processorAdded.Append(processor); + processorAdded.Append(" to composite processor"); + + compositeProcessor.AddProcessor(processor); + } + else + { + processorAdded.Append("Creating new composite processor with processor "); + processorAdded.Append(this.Processor); + processorAdded.Append(" and adding new processor "); + processorAdded.Append(processor); + + var newCompositeProcessor = new CompositeProcessor(new[] + { + this.Processor, + }); + newCompositeProcessor.SetParentProvider(this); + newCompositeProcessor.AddProcessor(processor); + this.Processor = newCompositeProcessor; + } + + OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent($"Completed adding processor = \"{processorAdded}\"."); + } + + public bool ForceFlush(int timeoutMilliseconds = Timeout.Infinite) + { + try + { + return this.Processor?.ForceFlush(timeoutMilliseconds) ?? true; + } + catch (Exception ex) + { + OpenTelemetrySdkEventSource.Log.LoggerProviderException(nameof(this.ForceFlush), ex); + return false; + } + } + + public bool Shutdown(int timeoutMilliseconds) + { + if (Interlocked.Increment(ref this.shutdownCount) > 1) + { + return false; // shutdown already called + } + + try + { + return this.Processor?.Shutdown(timeoutMilliseconds) ?? true; + } + catch (Exception ex) + { + OpenTelemetrySdkEventSource.Log.LoggerProviderException(nameof(this.Shutdown), ex); + return false; + } + } + + public bool ContainsBatchProcessor(BaseProcessor processor) + { + if (processor is BatchExportProcessor) + { + return true; + } + else if (processor is CompositeProcessor compositeProcessor) + { + var current = compositeProcessor.Head; + while (current != null) + { + if (this.ContainsBatchProcessor(current.Value)) + { + return true; + } + + current = current.Next; + } + } + + return false; + } + + /// + protected override bool TryCreateLogger(string? name, out Logger? logger) + { + // TODO: return new LoggerSdk(this, name); throw new NotImplementedException(); } + + /// + protected override void Dispose(bool disposing) + { + if (!this.disposed) + { + if (disposing) + { + if (this.instrumentations != null) + { + foreach (var item in this.instrumentations) + { + (item as IDisposable)?.Dispose(); + } + + this.instrumentations.Clear(); + } + + // Wait for up to 5 seconds grace period + this.Processor?.Shutdown(5000); + this.Processor?.Dispose(); + + this.ownedServiceProvider?.Dispose(); + } + + this.disposed = true; + OpenTelemetrySdkEventSource.Log.ProviderDisposed(nameof(LoggerProviderSdk)); + } + + base.Dispose(disposing); + } } From 6576a962b500a75c49c029a11854bb3e6ff303ad Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Fri, 28 Apr 2023 12:19:55 -0700 Subject: [PATCH 2/3] Code review. --- .../.publicApi/net462/PublicAPI.Unshipped.txt | 2 ++ .../.publicApi/net6.0/PublicAPI.Unshipped.txt | 2 ++ .../netstandard2.0/PublicAPI.Unshipped.txt | 2 ++ .../netstandard2.1/PublicAPI.Unshipped.txt | 2 ++ src/OpenTelemetry/BaseExportProcessor.cs | 6 ++++ src/OpenTelemetry/BaseProcessor.cs | 4 +++ src/OpenTelemetry/Logs/LoggerProviderSdk.cs | 31 ++++++------------- 7 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index f43534a60aa..ae90dbc9e28 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -35,6 +35,8 @@ OpenTelemetry.Metrics.ExponentialHistogramData.ZeroCount.get -> long OpenTelemetry.Metrics.MetricType.ExponentialHistogram = 80 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.TraceBasedExemplarFilter OpenTelemetry.Metrics.TraceBasedExemplarFilter.TraceBasedExemplarFilter() -> void +override OpenTelemetry.BaseExportProcessor.ToString() -> string! +override OpenTelemetry.BaseProcessor.ToString() -> string! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetExemplarFilter(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, OpenTelemetry.Metrics.ExemplarFilter! exemplarFilter) -> OpenTelemetry.Metrics.MeterProviderBuilder! ~abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(double value, System.ReadOnlySpan> tags) -> bool ~abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(long value, System.ReadOnlySpan> tags) -> bool diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index f43534a60aa..ae90dbc9e28 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -35,6 +35,8 @@ OpenTelemetry.Metrics.ExponentialHistogramData.ZeroCount.get -> long OpenTelemetry.Metrics.MetricType.ExponentialHistogram = 80 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.TraceBasedExemplarFilter OpenTelemetry.Metrics.TraceBasedExemplarFilter.TraceBasedExemplarFilter() -> void +override OpenTelemetry.BaseExportProcessor.ToString() -> string! +override OpenTelemetry.BaseProcessor.ToString() -> string! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetExemplarFilter(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, OpenTelemetry.Metrics.ExemplarFilter! exemplarFilter) -> OpenTelemetry.Metrics.MeterProviderBuilder! ~abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(double value, System.ReadOnlySpan> tags) -> bool ~abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(long value, System.ReadOnlySpan> tags) -> bool diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index f43534a60aa..ae90dbc9e28 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -35,6 +35,8 @@ OpenTelemetry.Metrics.ExponentialHistogramData.ZeroCount.get -> long OpenTelemetry.Metrics.MetricType.ExponentialHistogram = 80 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.TraceBasedExemplarFilter OpenTelemetry.Metrics.TraceBasedExemplarFilter.TraceBasedExemplarFilter() -> void +override OpenTelemetry.BaseExportProcessor.ToString() -> string! +override OpenTelemetry.BaseProcessor.ToString() -> string! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetExemplarFilter(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, OpenTelemetry.Metrics.ExemplarFilter! exemplarFilter) -> OpenTelemetry.Metrics.MeterProviderBuilder! ~abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(double value, System.ReadOnlySpan> tags) -> bool ~abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(long value, System.ReadOnlySpan> tags) -> bool diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index f43534a60aa..ae90dbc9e28 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -35,6 +35,8 @@ OpenTelemetry.Metrics.ExponentialHistogramData.ZeroCount.get -> long OpenTelemetry.Metrics.MetricType.ExponentialHistogram = 80 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.TraceBasedExemplarFilter OpenTelemetry.Metrics.TraceBasedExemplarFilter.TraceBasedExemplarFilter() -> void +override OpenTelemetry.BaseExportProcessor.ToString() -> string! +override OpenTelemetry.BaseProcessor.ToString() -> string! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetExemplarFilter(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, OpenTelemetry.Metrics.ExemplarFilter! exemplarFilter) -> OpenTelemetry.Metrics.MeterProviderBuilder! ~abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(double value, System.ReadOnlySpan> tags) -> bool ~abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(long value, System.ReadOnlySpan> tags) -> bool diff --git a/src/OpenTelemetry/BaseExportProcessor.cs b/src/OpenTelemetry/BaseExportProcessor.cs index 9684a764ae2..e1e715fa6c0 100644 --- a/src/OpenTelemetry/BaseExportProcessor.cs +++ b/src/OpenTelemetry/BaseExportProcessor.cs @@ -48,6 +48,7 @@ public abstract class BaseExportProcessor : BaseProcessor where T : class { protected readonly BaseExporter exporter; + private readonly string friendlyTypeName; private bool disposed; /// @@ -58,11 +59,16 @@ protected BaseExportProcessor(BaseExporter exporter) { Guard.ThrowIfNull(exporter); + this.friendlyTypeName = $"{this.GetType().Name}<{exporter.GetType().Name}>"; this.exporter = exporter; } internal BaseExporter Exporter => this.exporter; + /// + public override string ToString() + => this.friendlyTypeName; + /// public sealed override void OnStart(T data) { diff --git a/src/OpenTelemetry/BaseProcessor.cs b/src/OpenTelemetry/BaseProcessor.cs index 78e6c2daf88..8020a141b50 100644 --- a/src/OpenTelemetry/BaseProcessor.cs +++ b/src/OpenTelemetry/BaseProcessor.cs @@ -153,6 +153,10 @@ public void Dispose() GC.SuppressFinalize(this); } + /// + public override string ToString() + => this.typeName; + internal virtual void SetParentProvider(BaseProvider parentProvider) { this.ParentProvider = parentProvider; diff --git a/src/OpenTelemetry/Logs/LoggerProviderSdk.cs b/src/OpenTelemetry/Logs/LoggerProviderSdk.cs index c2c30cb138e..9baf8d47188 100644 --- a/src/OpenTelemetry/Logs/LoggerProviderSdk.cs +++ b/src/OpenTelemetry/Logs/LoggerProviderSdk.cs @@ -61,9 +61,6 @@ public LoggerProviderSdk( configureProviderBuilder.ConfigureBuilder(serviceProvider!, state); } - StringBuilder processorsAdded = new StringBuilder(); - StringBuilder instrumentationFactoriesAdded = new StringBuilder(); - var resourceBuilder = state.ResourceBuilder ?? ResourceBuilder.CreateDefault(); resourceBuilder.ServiceProvider = serviceProvider; this.Resource = resourceBuilder.Build(); @@ -71,10 +68,10 @@ public LoggerProviderSdk( foreach (var processor in state.Processors) { this.AddProcessor(processor); - processorsAdded.Append(processor.GetType()); - processorsAdded.Append(';'); } + StringBuilder instrumentationFactoriesAdded = new StringBuilder(); + foreach (var instrumentation in state.Instrumentation) { this.instrumentations.Add(instrumentation.Instance); @@ -82,12 +79,6 @@ public LoggerProviderSdk( instrumentationFactoriesAdded.Append(';'); } - if (processorsAdded.Length != 0) - { - processorsAdded.Remove(processorsAdded.Length - 1, 1); - OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent($"Processors added = \"{processorsAdded}\"."); - } - if (instrumentationFactoriesAdded.Length != 0) { instrumentationFactoriesAdded.Remove(instrumentationFactoriesAdded.Length - 1, 1); @@ -107,14 +98,10 @@ public LoggerProviderSdk( public void AddProcessor(BaseProcessor processor) { - OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent("Started adding processor."); - Guard.ThrowIfNull(processor); processor.SetParentProvider(this); - StringBuilder processorAdded = new StringBuilder(); - if (this.threadStaticPool != null && this.ContainsBatchProcessor(processor)) { OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent("Using shared thread pool."); @@ -122,27 +109,29 @@ public void AddProcessor(BaseProcessor processor) this.threadStaticPool = null; } + StringBuilder processorAdded = new StringBuilder(); + if (this.Processor == null) { - processorAdded.Append("Setting processor to "); + processorAdded.Append("Setting processor to '"); processorAdded.Append(processor); + processorAdded.Append('\''); this.Processor = processor; } else if (this.Processor is CompositeProcessor compositeProcessor) { - processorAdded.Append("Adding processor "); + processorAdded.Append("Adding processor '"); processorAdded.Append(processor); - processorAdded.Append(" to composite processor"); + processorAdded.Append("' to composite processor"); compositeProcessor.AddProcessor(processor); } else { - processorAdded.Append("Creating new composite processor with processor "); - processorAdded.Append(this.Processor); - processorAdded.Append(" and adding new processor "); + processorAdded.Append("Creating new composite processor and adding new processor '"); processorAdded.Append(processor); + processorAdded.Append('\''); var newCompositeProcessor = new CompositeProcessor(new[] { From 8ef395a8dd8d6d131fe9297e61ae94843a2158f6 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Fri, 28 Apr 2023 12:23:27 -0700 Subject: [PATCH 3/3] Tweak. --- src/OpenTelemetry/BaseExportProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/BaseExportProcessor.cs b/src/OpenTelemetry/BaseExportProcessor.cs index e1e715fa6c0..ebe282c33c2 100644 --- a/src/OpenTelemetry/BaseExportProcessor.cs +++ b/src/OpenTelemetry/BaseExportProcessor.cs @@ -59,7 +59,7 @@ protected BaseExportProcessor(BaseExporter exporter) { Guard.ThrowIfNull(exporter); - this.friendlyTypeName = $"{this.GetType().Name}<{exporter.GetType().Name}>"; + this.friendlyTypeName = $"{this.GetType().Name}{{{exporter.GetType().Name}}}"; this.exporter = exporter; }