From 63f8b37506a00cb18c83ba1513e4031b0fb342aa Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Wed, 15 Jun 2022 10:50:00 -0700 Subject: [PATCH 1/6] Add helper ctors & forceflush on OpenTelemetryLoggerProvider. --- .../.publicApi/net462/PublicAPI.Shipped.txt | 2 +- .../.publicApi/net462/PublicAPI.Unshipped.txt | 3 ++ .../netstandard2.0/PublicAPI.Shipped.txt | 2 +- .../netstandard2.0/PublicAPI.Unshipped.txt | 3 ++ src/OpenTelemetry/BaseProcessor.cs | 19 ++++++- .../Internal/OpenTelemetrySdkEventSource.cs | 6 +++ .../Logs/OpenTelemetryLoggerProvider.cs | 49 +++++++++++++++++++ 7 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Shipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Shipped.txt index 56774a7fc4d..4ada116f14e 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Shipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Shipped.txt @@ -5,7 +5,7 @@ ~OpenTelemetry.BaseExporter.ParentProvider.get -> OpenTelemetry.BaseProvider ~OpenTelemetry.BaseExportProcessor ~OpenTelemetry.BaseExportProcessor.BaseExportProcessor(OpenTelemetry.BaseExporter exporter) -> void -~OpenTelemetry.BaseProcessor.ParentProvider.get -> OpenTelemetry.BaseProvider +OpenTelemetry.BaseProcessor.ParentProvider.get -> OpenTelemetry.BaseProvider? ~OpenTelemetry.Batch ~OpenTelemetry.Batch.Batch(T[] items, int count) -> void ~OpenTelemetry.Batch.Enumerator.Current.get -> T diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index e69de29bb2d..7ead6b2aa97 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -0,0 +1,3 @@ +OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool +OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void +OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void \ No newline at end of file diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Shipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Shipped.txt index 56774a7fc4d..4ada116f14e 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Shipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Shipped.txt @@ -5,7 +5,7 @@ ~OpenTelemetry.BaseExporter.ParentProvider.get -> OpenTelemetry.BaseProvider ~OpenTelemetry.BaseExportProcessor ~OpenTelemetry.BaseExportProcessor.BaseExportProcessor(OpenTelemetry.BaseExporter exporter) -> void -~OpenTelemetry.BaseProcessor.ParentProvider.get -> OpenTelemetry.BaseProvider +OpenTelemetry.BaseProcessor.ParentProvider.get -> OpenTelemetry.BaseProvider? ~OpenTelemetry.Batch ~OpenTelemetry.Batch.Batch(T[] items, int count) -> void ~OpenTelemetry.Batch.Enumerator.Current.get -> T diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index e69de29bb2d..7ead6b2aa97 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -0,0 +1,3 @@ +OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool +OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void +OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void \ No newline at end of file diff --git a/src/OpenTelemetry/BaseProcessor.cs b/src/OpenTelemetry/BaseProcessor.cs index 4115b108ee6..02df50e39bf 100644 --- a/src/OpenTelemetry/BaseProcessor.cs +++ b/src/OpenTelemetry/BaseProcessor.cs @@ -14,6 +14,8 @@ // limitations under the License. // +#nullable enable + using System; using System.Threading; using OpenTelemetry.Internal; @@ -26,12 +28,21 @@ namespace OpenTelemetry /// The type of object to be processed. public abstract class BaseProcessor : IDisposable { + private readonly string typeName; private int shutdownCount; + /// + /// Initializes a new instance of the class. + /// + public BaseProcessor() + { + this.typeName = this.GetType().Name; + } + /// /// Gets the parent . /// - public BaseProvider ParentProvider { get; private set; } + public BaseProvider? ParentProvider { get; private set; } /// /// Called synchronously when a telemetry object is started. @@ -86,7 +97,11 @@ public bool ForceFlush(int timeoutMilliseconds = Timeout.Infinite) try { - return this.OnForceFlush(timeoutMilliseconds); + bool result = this.OnForceFlush(timeoutMilliseconds); + + OpenTelemetrySdkEventSource.Log.ProcessorForceFlushInvoked(this.typeName, result); + + return result; } catch (Exception ex) { diff --git a/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs b/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs index 0db72d4cba7..1dcd65fd94b 100644 --- a/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs +++ b/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs @@ -390,6 +390,12 @@ public void UnsupportedAttributeType(string type, string key) this.WriteEvent(42, type.ToString(), key); } + [Event(43, Message = "ForceFlush invoked for processor type '{0}' returned result '{1}'.", Level = EventLevel.Verbose)] + public void ProcessorForceFlushInvoked(string processorType, bool result) + { + this.WriteEvent(43, processorType, result); + } + #if DEBUG public class OpenTelemetryEventListener : EventListener { diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs b/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs index 0c33a7268a3..858cff42d59 100644 --- a/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs +++ b/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs @@ -16,7 +16,9 @@ #nullable enable +using System; using System.Collections; +using System.Threading; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using OpenTelemetry.Internal; @@ -54,6 +56,23 @@ public OpenTelemetryLoggerProvider(IOptionsMonitor o { } + /// + /// Initializes a new instance of the class. + /// + /// configuration callback. + public OpenTelemetryLoggerProvider(Action configure) + : this(BuildOptions(configure ?? throw new ArgumentNullException(nameof(configure)))) + { + } + + /// + /// Initializes a new instance of the class. + /// + public OpenTelemetryLoggerProvider() + : this(BuildOptions(configure: null)) + { + } + internal OpenTelemetryLoggerProvider(OpenTelemetryLoggerOptions options) { Guard.ThrowIfNull(options); @@ -112,6 +131,29 @@ public ILogger CreateLogger(string categoryName) return logger; } + /// + /// Flushes all the processors registered under , blocks the current thread + /// until flush completed, shutdown signaled or timed out. + /// + /// + /// 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 bool ForceFlush(int timeoutMilliseconds = Timeout.Infinite) + { + return this.Processor?.ForceFlush(timeoutMilliseconds) ?? true; + } + internal OpenTelemetryLoggerProvider AddProcessor(BaseProcessor processor) { Guard.ThrowIfNull(processor); @@ -156,5 +198,12 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } + + private static OpenTelemetryLoggerOptions BuildOptions(Action? configure = null) + { + OpenTelemetryLoggerOptions options = new(); + configure?.Invoke(options); + return options; + } } } From 2529c436d708ff0233e7e982b00e565be5426960 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Wed, 15 Jun 2022 11:31:25 -0700 Subject: [PATCH 2/6] CHANGELOG update. --- src/OpenTelemetry/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index cbd76ab1688..791dff1f1c5 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -11,6 +11,9 @@ null-valued tag. ([#3325](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3325)) +* Added `ForceFlush` and helper ctors on `OpenTelemetryLoggerProvider` + ([#3364](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3364)) + ## 1.3.0 Released 2022-Jun-03 From 50de897007ee29df001537b6df5859e058b07159 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Wed, 15 Jun 2022 11:52:11 -0700 Subject: [PATCH 3/6] Unit tests. --- .../Logs/OpenTelemetryLoggerProviderTests.cs | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs diff --git a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs new file mode 100644 index 00000000000..6e1ee8624bb --- /dev/null +++ b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs @@ -0,0 +1,103 @@ +// +// 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. +// + +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using OpenTelemetry.Resources; +using Xunit; + +namespace OpenTelemetry.Logs.Tests +{ + public sealed class OpenTelemetryLoggerProviderTests + { + [Fact] + public void DefaultCtorTests() + { + OpenTelemetryLoggerOptions defaults = new(); + + using OpenTelemetryLoggerProvider provider = new(); + + Assert.Equal(defaults.IncludeScopes, provider.IncludeScopes); + Assert.Equal(defaults.IncludeFormattedMessage, provider.IncludeFormattedMessage); + Assert.Equal(defaults.ParseStateValues, provider.ParseStateValues); + Assert.Null(provider.Processor); + Assert.NotNull(provider.Resource); + } + + [Fact] + public void ConfigureCtorTests() + { + OpenTelemetryLoggerOptions defaults = new(); + + using OpenTelemetryLoggerProvider provider = new(options => + { + options.IncludeScopes = !defaults.IncludeScopes; + options.IncludeFormattedMessage = !defaults.IncludeFormattedMessage; + options.ParseStateValues = !defaults.ParseStateValues; + + options.SetResourceBuilder(ResourceBuilder + .CreateEmpty() + .AddAttributes(new[] { new KeyValuePair("key1", "value1") })); + + options.AddInMemoryExporter(new List()); + }); + + Assert.Equal(!defaults.IncludeScopes, provider.IncludeScopes); + Assert.Equal(!defaults.IncludeFormattedMessage, provider.IncludeFormattedMessage); + Assert.Equal(!defaults.ParseStateValues, provider.ParseStateValues); + Assert.NotNull(provider.Processor); + Assert.NotNull(provider.Resource); + Assert.Contains(provider.Resource.Attributes, value => value.Key == "key1" && (string)value.Value == "value1"); + } + + [Fact] + public void ForceFlushTest() + { + using OpenTelemetryLoggerProvider provider1 = new(); + Assert.True(provider1.ForceFlush()); + + var exporter = new TestExporter(); + + using OpenTelemetryLoggerProvider provider2 = new(options => options + .AddProcessor(new BatchLogRecordExportProcessor(exporter))); + + var logger = provider2.CreateLogger("TestLogger"); + + logger.LogInformation("hello world"); + + Assert.Empty(exporter.ExportedItems); + + Assert.True(provider2.ForceFlush()); + + Assert.Single(exporter.ExportedItems); + } + + private sealed class TestExporter : BaseExporter + { + public List ExportedItems { get; } = new(); + + public override ExportResult Export(in Batch batch) + { + foreach (LogRecord logRecord in batch) + { + this.ExportedItems.Add(logRecord); + } + + return ExportResult.Success; + } + } + } +} From e112377e2415be32d7cc23a1440f9c1050107000 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Wed, 15 Jun 2022 14:42:25 -0700 Subject: [PATCH 4/6] Code review. --- .../Logs/OpenTelemetryLoggerProviderTests.cs | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs index 6e1ee8624bb..c78b660a2e1 100644 --- a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs +++ b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs @@ -16,6 +16,7 @@ using System.Collections.Generic; using Microsoft.Extensions.Logging; +using OpenTelemetry.Exporter; using OpenTelemetry.Resources; using Xunit; @@ -66,38 +67,26 @@ public void ConfigureCtorTests() [Fact] public void ForceFlushTest() { - using OpenTelemetryLoggerProvider provider1 = new(); - Assert.True(provider1.ForceFlush()); + OpenTelemetryLoggerProvider provider = new(); + Assert.True(provider.ForceFlush()); + provider.Dispose(); - var exporter = new TestExporter(); + List exportedItems = new(); - using OpenTelemetryLoggerProvider provider2 = new(options => options - .AddProcessor(new BatchLogRecordExportProcessor(exporter))); + provider = new(options => options + .AddProcessor(new BatchLogRecordExportProcessor(new InMemoryExporter(exportedItems)))); - var logger = provider2.CreateLogger("TestLogger"); + var logger = provider.CreateLogger("TestLogger"); logger.LogInformation("hello world"); - Assert.Empty(exporter.ExportedItems); + Assert.Empty(exportedItems); - Assert.True(provider2.ForceFlush()); + Assert.True(provider.ForceFlush()); - Assert.Single(exporter.ExportedItems); - } - - private sealed class TestExporter : BaseExporter - { - public List ExportedItems { get; } = new(); - - public override ExportResult Export(in Batch batch) - { - foreach (LogRecord logRecord in batch) - { - this.ExportedItems.Add(logRecord); - } + Assert.Single(exportedItems); - return ExportResult.Success; - } + provider.Dispose(); } } } From 483a4b737578a76afd8ba08f3b404eee5ebaca69 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Wed, 15 Jun 2022 14:44:35 -0700 Subject: [PATCH 5/6] Code review. --- .../Logs/OpenTelemetryLoggerProviderTests.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs index c78b660a2e1..330fa4b50e7 100644 --- a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs +++ b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs @@ -67,14 +67,13 @@ public void ConfigureCtorTests() [Fact] public void ForceFlushTest() { - OpenTelemetryLoggerProvider provider = new(); + using OpenTelemetryLoggerProvider provider = new(); + Assert.True(provider.ForceFlush()); - provider.Dispose(); List exportedItems = new(); - provider = new(options => options - .AddProcessor(new BatchLogRecordExportProcessor(new InMemoryExporter(exportedItems)))); + provider.AddProcessor(new BatchLogRecordExportProcessor(new InMemoryExporter(exportedItems))); var logger = provider.CreateLogger("TestLogger"); @@ -85,8 +84,6 @@ public void ForceFlushTest() Assert.True(provider.ForceFlush()); Assert.Single(exportedItems); - - provider.Dispose(); } } } From 2ea06e13fcbd59227254d379f4237d6e60b01112 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Thu, 16 Jun 2022 14:59:04 -0700 Subject: [PATCH 6/6] Tweak. --- src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs b/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs index 5e18ce13428..c057445c84b 100644 --- a/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs +++ b/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs @@ -201,7 +201,7 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - private static OpenTelemetryLoggerOptions BuildOptions(Action? configure = null) + private static OpenTelemetryLoggerOptions BuildOptions(Action? configure) { OpenTelemetryLoggerOptions options = new(); configure?.Invoke(options);