From dd158f26d49972c0623838c0636cddecae8e051a Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Thu, 11 May 2023 12:51:41 -0700 Subject: [PATCH 1/2] Added LoggerProvider extensions to SDK. --- .../Logs/LoggerProviderExtensions.cs | 114 ++++++++++++++++++ .../Logs/LoggerProviderExtensionsTests.cs | 112 +++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 src/OpenTelemetry/Logs/LoggerProviderExtensions.cs create mode 100644 test/OpenTelemetry.Tests/Logs/LoggerProviderExtensionsTests.cs diff --git a/src/OpenTelemetry/Logs/LoggerProviderExtensions.cs b/src/OpenTelemetry/Logs/LoggerProviderExtensions.cs new file mode 100644 index 00000000000..9bd310b8938 --- /dev/null +++ b/src/OpenTelemetry/Logs/LoggerProviderExtensions.cs @@ -0,0 +1,114 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#nullable enable + +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Logs; + +/// +/// Contains extension methods for the class. +/// +internal static class LoggerProviderExtensions +{ + /// + /// Add a processor to the . + /// + /// + /// Note: The supplied will be + /// automatically disposed when then the is disposed. + /// + /// instance on which ForceFlush will be called. + /// Log processor to add. + /// The supplied for chaining. + public static LoggerProvider AddProcessor(this LoggerProvider provider, BaseProcessor processor) + { + Guard.ThrowIfNull(provider); + Guard.ThrowIfNull(processor); + + if (provider is LoggerProviderSdk loggerProviderSdk) + { + loggerProviderSdk.AddProcessor(processor); + } + + return provider; + } + + /// + /// Flushes all the processors registered under , blocks the current thread + /// until flush completed, shutdown signaled or timed out. + /// + /// instance on which ForceFlush will be called. + /// + /// The number (non-negative) of milliseconds to wait, or + /// Timeout.Infinite to wait indefinitely. + /// + /// + /// Returns true when force flush succeeded; otherwise, false. + /// + /// + /// Thrown when the timeoutMilliseconds is smaller than -1. + /// + /// + /// This function guarantees thread-safety. + /// + public static bool ForceFlush(this LoggerProvider provider, int timeoutMilliseconds = Timeout.Infinite) + { + Guard.ThrowIfNull(provider); + Guard.ThrowIfInvalidTimeout(timeoutMilliseconds); + + if (provider is LoggerProviderSdk loggerProviderSdk) + { + return loggerProviderSdk.ForceFlush(timeoutMilliseconds); + } + + return true; + } + + /// + /// Attempts to shutdown the , blocks the current thread until + /// shutdown completed or timed out. + /// + /// instance on which Shutdown will be called. + /// + /// The number (non-negative) of milliseconds to wait, or + /// Timeout.Infinite to wait indefinitely. + /// + /// + /// Returns true when shutdown succeeded; otherwise, false. + /// + /// + /// Thrown when the timeoutMilliseconds is smaller than -1. + /// + /// + /// This function guarantees thread-safety. Only the first call will + /// win, subsequent calls will be no-op. + /// + public static bool Shutdown(this LoggerProvider provider, int timeoutMilliseconds = Timeout.Infinite) + { + Guard.ThrowIfNull(provider); + Guard.ThrowIfInvalidTimeout(timeoutMilliseconds); + + if (provider is LoggerProviderSdk loggerProviderSdk) + { + return loggerProviderSdk.Shutdown(timeoutMilliseconds); + } + + return true; + } +} diff --git a/test/OpenTelemetry.Tests/Logs/LoggerProviderExtensionsTests.cs b/test/OpenTelemetry.Tests/Logs/LoggerProviderExtensionsTests.cs new file mode 100644 index 00000000000..52e8ddf7065 --- /dev/null +++ b/test/OpenTelemetry.Tests/Logs/LoggerProviderExtensionsTests.cs @@ -0,0 +1,112 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#nullable enable + +using Xunit; + +namespace OpenTelemetry.Logs.Tests; + +public class LoggerProviderExtensionsTests +{ + [Fact] + public void AddProcessorTest() + { + using var provider = Sdk.CreateLoggerProviderBuilder() + .Build(); + + Assert.NotNull(provider); + + var providerSdk = provider as LoggerProviderSdk; + + Assert.NotNull(providerSdk); + + Assert.Null(providerSdk.Processor); + + provider.AddProcessor(new TestProcessor()); + + Assert.NotNull(providerSdk.Processor); + } + + [Fact] + public void ForceFlushTest() + { + var exporter = new TestExporter(); + + using var provider = Sdk.CreateLoggerProviderBuilder() + .AddProcessor( + new BatchLogRecordExportProcessor( + exporter, + scheduledDelayMilliseconds: int.MaxValue)) + .Build(); + + Assert.NotNull(provider); + + var providerSdk = provider as LoggerProviderSdk; + + Assert.NotNull(providerSdk); + + var logger = providerSdk.GetLogger(); + + Assert.NotNull(logger); + + logger.EmitLog(new LogRecordData { Body = "Hello world" }); + + Assert.Empty(exporter.LogRecords); + + Assert.True(provider.ForceFlush()); + + Assert.Single(exporter.LogRecords); + } + + [Fact] + public void ShutdownTest() + { + using var provider = Sdk.CreateLoggerProviderBuilder() + .Build(); + + Assert.NotNull(provider); + + var providerSdk = provider as LoggerProviderSdk; + + Assert.NotNull(providerSdk); + + Assert.Equal(0, providerSdk.ShutdownCount); + + Assert.True(provider.Shutdown()); + + Assert.Equal(1, providerSdk.ShutdownCount); + } + + private sealed class TestProcessor : BaseProcessor + { + } + + private sealed class TestExporter : BaseExporter + { + public List LogRecords { get; } = new(); + + public override ExportResult Export(in Batch batch) + { + foreach (var logRecord in batch) + { + this.LogRecords.Add(logRecord); + } + + return ExportResult.Success; + } + } +} From e3dbcd452df6540f1a1b991b715bdaad2ae1f963 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Thu, 11 May 2023 15:08:02 -0700 Subject: [PATCH 2/2] Expose a few internals from LoggerProviderSdk for testing. --- src/OpenTelemetry/Logs/LoggerProviderSdk.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/OpenTelemetry/Logs/LoggerProviderSdk.cs b/src/OpenTelemetry/Logs/LoggerProviderSdk.cs index 0e87d21f30d..c860d525a9b 100644 --- a/src/OpenTelemetry/Logs/LoggerProviderSdk.cs +++ b/src/OpenTelemetry/Logs/LoggerProviderSdk.cs @@ -30,11 +30,12 @@ namespace OpenTelemetry.Logs; internal sealed class LoggerProviderSdk : LoggerProvider { internal readonly IServiceProvider ServiceProvider; - private readonly IDisposable? ownedServiceProvider; + internal readonly IDisposable? OwnedServiceProvider; + internal bool Disposed; + internal int ShutdownCount; + private readonly List instrumentations = new(); private ILogRecordPool? threadStaticPool = LogRecordThreadStaticPool.Instance; - private int shutdownCount; - private bool disposed; public LoggerProviderSdk( IServiceProvider serviceProvider, @@ -49,8 +50,8 @@ public LoggerProviderSdk( if (ownsServiceProvider) { - this.ownedServiceProvider = serviceProvider as IDisposable; - Debug.Assert(this.ownedServiceProvider != null, "ownedServiceProvider was null"); + this.OwnedServiceProvider = serviceProvider as IDisposable; + Debug.Assert(this.OwnedServiceProvider != null, "ownedServiceProvider was null"); } OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent("Building TracerProvider."); @@ -160,7 +161,7 @@ public bool ForceFlush(int timeoutMilliseconds = Timeout.Infinite) public bool Shutdown(int timeoutMilliseconds) { - if (Interlocked.Increment(ref this.shutdownCount) > 1) + if (Interlocked.Increment(ref this.ShutdownCount) > 1) { return false; // shutdown already called } @@ -209,7 +210,7 @@ protected override bool TryCreateLogger(string? name, out Logger? logger) /// protected override void Dispose(bool disposing) { - if (!this.disposed) + if (!this.Disposed) { if (disposing) { @@ -227,10 +228,10 @@ protected override void Dispose(bool disposing) this.Processor?.Shutdown(5000); this.Processor?.Dispose(); - this.ownedServiceProvider?.Dispose(); + this.OwnedServiceProvider?.Dispose(); } - this.disposed = true; + this.Disposed = true; OpenTelemetrySdkEventSource.Log.ProviderDisposed(nameof(LoggerProviderSdk)); }