Skip to content

Commit

Permalink
[sdk-logs] Implement LoggerProviderSdk (#4453)
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeBlanch authored Apr 28, 2023
1 parent 361750c commit f772e93
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>.ToString() -> string!
override OpenTelemetry.BaseProcessor<T>.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<System.Collections.Generic.KeyValuePair<string, object>> tags) -> bool
~abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(long value, System.ReadOnlySpan<System.Collections.Generic.KeyValuePair<string, object>> tags) -> bool
Expand Down
2 changes: 2 additions & 0 deletions src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>.ToString() -> string!
override OpenTelemetry.BaseProcessor<T>.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<System.Collections.Generic.KeyValuePair<string, object>> tags) -> bool
~abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(long value, System.ReadOnlySpan<System.Collections.Generic.KeyValuePair<string, object>> tags) -> bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>.ToString() -> string!
override OpenTelemetry.BaseProcessor<T>.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<System.Collections.Generic.KeyValuePair<string, object>> tags) -> bool
~abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(long value, System.ReadOnlySpan<System.Collections.Generic.KeyValuePair<string, object>> tags) -> bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>.ToString() -> string!
override OpenTelemetry.BaseProcessor<T>.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<System.Collections.Generic.KeyValuePair<string, object>> tags) -> bool
~abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(long value, System.ReadOnlySpan<System.Collections.Generic.KeyValuePair<string, object>> tags) -> bool
Expand Down
6 changes: 6 additions & 0 deletions src/OpenTelemetry/BaseExportProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public abstract class BaseExportProcessor<T> : BaseProcessor<T>
where T : class
{
protected readonly BaseExporter<T> exporter;
private readonly string friendlyTypeName;
private bool disposed;

/// <summary>
Expand All @@ -58,11 +59,16 @@ protected BaseExportProcessor(BaseExporter<T> exporter)
{
Guard.ThrowIfNull(exporter);

this.friendlyTypeName = $"{this.GetType().Name}{{{exporter.GetType().Name}}}";
this.exporter = exporter;
}

internal BaseExporter<T> Exporter => this.exporter;

/// <inheritdoc />
public override string ToString()
=> this.friendlyTypeName;

/// <inheritdoc />
public sealed override void OnStart(T data)
{
Expand Down
4 changes: 4 additions & 0 deletions src/OpenTelemetry/BaseProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ public void Dispose()
GC.SuppressFinalize(this);
}

/// <inheritdoc/>
public override string ToString()
=> this.typeName;

internal virtual void SetParentProvider(BaseProvider parentProvider)
{
this.ParentProvider = parentProvider;
Expand Down
21 changes: 21 additions & 0 deletions src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,15 @@ public void LoggerParseStateException<TState>(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)
{
Expand Down Expand Up @@ -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
{
Expand Down
210 changes: 210 additions & 0 deletions src/OpenTelemetry/Logs/LoggerProviderSdk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,224 @@

#nullable enable

using System.Diagnostics;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Internal;
using OpenTelemetry.Resources;

namespace OpenTelemetry.Logs;

/// <summary>
/// SDK <see cref="LoggerProvider"/> implementation.
/// </summary>
internal sealed class LoggerProviderSdk : LoggerProvider
{
internal readonly IServiceProvider ServiceProvider;
private readonly IDisposable? ownedServiceProvider;
private readonly List<object> 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<LoggerProviderBuilderSdk>();
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<IConfigureLoggerProviderBuilder>();
foreach (var configureProviderBuilder in configureProviderBuilders)
{
configureProviderBuilder.ConfigureBuilder(serviceProvider!, state);
}

var resourceBuilder = state.ResourceBuilder ?? ResourceBuilder.CreateDefault();
resourceBuilder.ServiceProvider = serviceProvider;
this.Resource = resourceBuilder.Build();

foreach (var processor in state.Processors)
{
this.AddProcessor(processor);
}

StringBuilder instrumentationFactoriesAdded = new StringBuilder();

foreach (var instrumentation in state.Instrumentation)
{
this.instrumentations.Add(instrumentation.Instance);
instrumentationFactoriesAdded.Append(instrumentation.Name);
instrumentationFactoriesAdded.Append(';');
}

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<object> Instrumentations => this.instrumentations;

public BaseProcessor<LogRecord>? Processor { get; private set; }

public ILogRecordPool LogRecordPool => this.threadStaticPool ?? LogRecordSharedPool.Current;

public void AddProcessor(BaseProcessor<LogRecord> processor)
{
Guard.ThrowIfNull(processor);

processor.SetParentProvider(this);

if (this.threadStaticPool != null && this.ContainsBatchProcessor(processor))
{
OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent("Using shared thread pool.");

this.threadStaticPool = null;
}

StringBuilder processorAdded = new StringBuilder();

if (this.Processor == null)
{
processorAdded.Append("Setting processor to '");
processorAdded.Append(processor);
processorAdded.Append('\'');

this.Processor = processor;
}
else if (this.Processor is CompositeProcessor<LogRecord> compositeProcessor)
{
processorAdded.Append("Adding processor '");
processorAdded.Append(processor);
processorAdded.Append("' to composite processor");

compositeProcessor.AddProcessor(processor);
}
else
{
processorAdded.Append("Creating new composite processor and adding new processor '");
processorAdded.Append(processor);
processorAdded.Append('\'');

var newCompositeProcessor = new CompositeProcessor<LogRecord>(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<LogRecord> processor)
{
if (processor is BatchExportProcessor<LogRecord>)
{
return true;
}
else if (processor is CompositeProcessor<LogRecord> compositeProcessor)
{
var current = compositeProcessor.Head;
while (current != null)
{
if (this.ContainsBatchProcessor(current.Value))
{
return true;
}

current = current.Next;
}
}

return false;
}

/// <inheritdoc />
protected override bool TryCreateLogger(string? name, out Logger? logger)
{
// TODO: return new LoggerSdk(this, name);
throw new NotImplementedException();
}

/// <inheritdoc/>
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);
}
}

0 comments on commit f772e93

Please sign in to comment.