-
Couldn't load subscription status.
- Fork 123
Add NLog instrumentation for OpenTelemetry .NET Auto-Instrumentation #4371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 7 commits
12b3643
dd0eee6
1b5ee77
489fa3b
638a6aa
206be87
799ef71
4401757
0fcf644
4ffa40a
f6cd7d5
665fb09
3a79c85
f6957e6
b078f85
4a0d5a3
bf571f5
16b004e
e650142
c41f73c
e66da6a
3d5aff8
ad1c62f
54dd6da
0602818
903ab69
4702a68
951c355
29d4251
29bde76
911fbd8
60311e1
d912c7e
c6b7bde
fad8ea4
e3d9274
e95e972
62f933d
33546ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -246,6 +246,9 @@ EndProject | |
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SdkVersionAnalyzer", "tools\SdkVersionAnalyzer\SdkVersionAnalyzer.csproj", "{C75FA076-D460-414B-97F7-6F8D0E85AE74}" | ||
| EndProject | ||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.Log4NetBridge", "test\test-applications\integrations\TestApplication.Log4NetBridge\TestApplication.Log4NetBridge.csproj", "{926B7C03-42C2-4192-94A7-CD0B1C693279}" | ||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.NLogBridge", "test\test-applications\integrations\TestApplication.NLogBridge\TestApplication.NLogBridge.csproj", "{A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}" | ||
| EndProject | ||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTelemetry.AutoInstrumentation.NLogTarget", "src\OpenTelemetry.AutoInstrumentation.NLogTarget\OpenTelemetry.AutoInstrumentation.NLogTarget.csproj", "{3C7A3F7B-77E5-4C55-9B2D-1A4A9E7B1D33}" | ||
|
||
| EndProject | ||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.SelectiveSampler", "test\test-applications\integrations\TestApplication.SelectiveSampler\TestApplication.SelectiveSampler.csproj", "{FD1A1ABD-6A48-4E94-B5F7-2081AFCD1BBB}" | ||
| EndProject | ||
|
|
@@ -1533,6 +1536,22 @@ Global | |
| {926B7C03-42C2-4192-94A7-CD0B1C693279}.Release|x64.Build.0 = Release|Any CPU | ||
| {926B7C03-42C2-4192-94A7-CD0B1C693279}.Release|x86.ActiveCfg = Release|Any CPU | ||
| {926B7C03-42C2-4192-94A7-CD0B1C693279}.Release|x86.Build.0 = Release|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Debug|ARM64.ActiveCfg = Debug|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Debug|ARM64.Build.0 = Debug|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Debug|x64.Build.0 = Debug|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Debug|x86.Build.0 = Debug|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Release|Any CPU.Build.0 = Release|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Release|ARM64.ActiveCfg = Release|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Release|ARM64.Build.0 = Release|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Release|x64.ActiveCfg = Release|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Release|x64.Build.0 = Release|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Release|x86.ActiveCfg = Release|Any CPU | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D}.Release|x86.Build.0 = Release|Any CPU | ||
| {FD1A1ABD-6A48-4E94-B5F7-2081AFCD1BBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
| {FD1A1ABD-6A48-4E94-B5F7-2081AFCD1BBB}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
| {FD1A1ABD-6A48-4E94-B5F7-2081AFCD1BBB}.Debug|ARM64.ActiveCfg = Debug|Any CPU | ||
|
|
@@ -1639,6 +1658,7 @@ Global | |
| {AA3E0C5C-A4E2-46AB-BD18-2D30D3ABF692} = {E409ADD3-9574-465C-AB09-4324D205CC7C} | ||
| {C75FA076-D460-414B-97F7-6F8D0E85AE74} = {00F4C92D-6652-4BD8-A334-B35D3E711BE6} | ||
| {926B7C03-42C2-4192-94A7-CD0B1C693279} = {E409ADD3-9574-465C-AB09-4324D205CC7C} | ||
| {A7B8C9D0-1E2F-3A4B-5C6D-7E8F9A0B1C2D} = {E409ADD3-9574-465C-AB09-4324D205CC7C} | ||
| {FD1A1ABD-6A48-4E94-B5F7-2081AFCD1BBB} = {E409ADD3-9574-465C-AB09-4324D205CC7C} | ||
| EndGlobalSection | ||
| GlobalSection(ExtensibilityGlobals) = postSolution | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| #nullable enable |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #nullable enable | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.Attributes.get -> System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext!>! | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.Endpoint.get -> string | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.Endpoint.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.Headers.get -> string | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.Headers.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeEventParameters.get -> bool | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeEventParameters.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeEventProperties.get -> bool | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeEventProperties.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeFormattedMessage.get -> bool | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeFormattedMessage.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeScopeProperties.get -> bool | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeScopeProperties.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.MaxExportBatchSize.get -> int | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.MaxExportBatchSize.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.MaxQueueSize.get -> int | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.MaxQueueSize.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.OpenTelemetryTarget() -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.Resources.get -> System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext!>! | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.ScheduledDelayMilliseconds.get -> int | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.ScheduledDelayMilliseconds.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.ServiceName.get -> string | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.ServiceName.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.UseHttp.get -> bool | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.UseHttp.set -> void |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| #nullable enable |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #nullable enable | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.Attributes.get -> System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext!>! | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.Endpoint.get -> string? | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.Endpoint.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.Headers.get -> string? | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.Headers.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeEventParameters.get -> bool | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeEventParameters.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeEventProperties.get -> bool | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeEventProperties.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeFormattedMessage.get -> bool | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeFormattedMessage.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeScopeProperties.get -> bool | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.IncludeScopeProperties.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.MaxExportBatchSize.get -> int | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.MaxExportBatchSize.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.MaxQueueSize.get -> int | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.MaxQueueSize.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.OpenTelemetryTarget() -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.Resources.get -> System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext!>! | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.ScheduledDelayMilliseconds.get -> int | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.ScheduledDelayMilliseconds.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.ServiceName.get -> string? | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.ServiceName.set -> void | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.UseHttp.get -> bool | ||
| OpenTelemetry.AutoInstrumentation.NLogTarget.OpenTelemetryTarget.UseHttp.set -> void |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| <PropertyGroup> | ||
| <TargetFrameworks>$(TargetFrameworks)</TargetFrameworks> | ||
| <GenerateDocumentationFile>false</GenerateDocumentationFile> | ||
| <IsPackable>true</IsPackable> | ||
| <Description>OpenTelemetry NLog target that forwards NLog LogEvents to OpenTelemetry Logs.</Description> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\OpenTelemetry.AutoInstrumentation\OpenTelemetry.AutoInstrumentation.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="NLog" /> | ||
| </ItemGroup> | ||
| </Project> | ||
|
|
zacharycmontoya marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,211 @@ | ||
| // Copyright The OpenTelemetry Authors | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| using System; | ||
| using System.Collections.Concurrent; | ||
| using System.Collections.Generic; | ||
| using System.Diagnostics; | ||
| using NLog; | ||
| using NLog.Config; | ||
| using NLog.Targets; | ||
| using OpenTelemetry; | ||
| using OpenTelemetry.AutoInstrumentation; | ||
| using OpenTelemetry.AutoInstrumentation.Configurations; | ||
| using OpenTelemetry.Logs; | ||
|
|
||
| namespace OpenTelemetry.AutoInstrumentation.NLogTarget; | ||
|
|
||
| [Target("OpenTelemetryTarget")] | ||
| public sealed class OpenTelemetryTarget : TargetWithContext | ||
| { | ||
| private static readonly ConcurrentDictionary<string, object> LoggerCache = new(StringComparer.Ordinal); | ||
| private static LoggerProvider? _loggerProvider; | ||
| private static Func<string?, object?>? _getLoggerFactory; | ||
|
|
||
| public OpenTelemetryTarget() | ||
| { | ||
| Layout = "${message}"; | ||
| } | ||
|
|
||
| [RequiredParameter] | ||
| public string? Endpoint { get; set; } | ||
|
||
|
|
||
| public string? Headers { get; set; } | ||
|
||
|
|
||
| public bool UseHttp { get; set; } = true; | ||
|
|
||
| public string? ServiceName { get; set; } | ||
|
||
|
|
||
| [ArrayParameter(typeof(TargetPropertyWithContext), "attribute")] | ||
| public IList<TargetPropertyWithContext> Attributes { get; } = new List<TargetPropertyWithContext>(); | ||
|
||
|
|
||
| [ArrayParameter(typeof(TargetPropertyWithContext), "resource")] | ||
| public IList<TargetPropertyWithContext> Resources { get; } = new List<TargetPropertyWithContext>(); | ||
|
|
||
| public bool IncludeFormattedMessage { get; set; } = true; | ||
|
|
||
| public new bool IncludeEventProperties { get; set; } = true; | ||
|
||
|
|
||
| public new bool IncludeScopeProperties { get; set; } = true; | ||
|
||
|
|
||
| public bool IncludeEventParameters { get; set; } = true; | ||
|
|
||
| public int ScheduledDelayMilliseconds { get; set; } = 5000; | ||
|
|
||
| public int MaxQueueSize { get; set; } = 2048; | ||
|
|
||
| public int MaxExportBatchSize { get; set; } = 512; | ||
|
|
||
| protected override void InitializeTarget() | ||
| { | ||
| base.InitializeTarget(); | ||
|
|
||
| if (_loggerProvider != null) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| var createLoggerProviderBuilderMethod = typeof(Sdk).GetMethod("CreateLoggerProviderBuilder", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)!; | ||
| var loggerProviderBuilder = (LoggerProviderBuilder)createLoggerProviderBuilderMethod.Invoke(null, null)!; | ||
|
|
||
| loggerProviderBuilder = loggerProviderBuilder | ||
| .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(Instrumentation.GeneralSettings.Value.EnabledResourceDetectors)); | ||
|
|
||
| loggerProviderBuilder = loggerProviderBuilder.AddOtlpExporter(options => | ||
| { | ||
| var endpoint = Endpoint; | ||
|
||
| if (string.IsNullOrEmpty(endpoint)) | ||
| { | ||
| endpoint = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT"); | ||
| } | ||
|
|
||
| if (!string.IsNullOrEmpty(endpoint)) | ||
| { | ||
| options.Endpoint = new Uri(endpoint!, UriKind.RelativeOrAbsolute); | ||
| } | ||
|
|
||
| if (!string.IsNullOrEmpty(Headers)) | ||
| { | ||
| options.Headers = Headers; | ||
| } | ||
|
|
||
| options.Protocol = UseHttp ? OpenTelemetry.Exporter.OtlpExportProtocol.HttpProtobuf : OpenTelemetry.Exporter.OtlpExportProtocol.Grpc; | ||
| options.BatchExportProcessorOptions.ScheduledDelayMilliseconds = ScheduledDelayMilliseconds; | ||
| options.BatchExportProcessorOptions.MaxQueueSize = MaxQueueSize; | ||
| options.BatchExportProcessorOptions.MaxExportBatchSize = MaxExportBatchSize; | ||
| }); | ||
|
|
||
| _loggerProvider = loggerProviderBuilder.Build(); | ||
| _getLoggerFactory = CreateGetLoggerDelegate(_loggerProvider); | ||
| } | ||
|
|
||
| protected override void Write(LogEventInfo logEvent) | ||
| { | ||
| if (_loggerProvider is null) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| if (Sdk.SuppressInstrumentation) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| var logger = GetOrCreateLogger(logEvent.LoggerName); | ||
|
|
||
| // Build properties from event properties and context | ||
| var properties = new List<KeyValuePair<string, object?>>(); | ||
|
||
| if (IncludeEventProperties && logEvent.HasProperties && logEvent.Properties is not null) | ||
|
||
| { | ||
| foreach (var kvp in logEvent.Properties) | ||
| { | ||
| properties.Add(new KeyValuePair<string, object?>(Convert.ToString(kvp.Key)!, kvp.Value)); | ||
| } | ||
| } | ||
|
|
||
| // Scope properties can be added via explicit <attribute> entries or NLog's contexts (GDC/MDLC) | ||
| foreach (var attribute in Attributes) | ||
| { | ||
| var value = attribute.Layout?.Render(logEvent); | ||
|
||
| if (!string.IsNullOrEmpty(attribute.Name)) | ||
| { | ||
| properties.Add(new KeyValuePair<string, object?>(attribute.Name!, value)); | ||
| } | ||
| } | ||
|
|
||
| var body = IncludeFormattedMessage ? logEvent.FormattedMessage : Convert.ToString(logEvent.Message); | ||
|
||
|
|
||
| var severityText = logEvent.Level.Name; | ||
| var severityNumber = MapLogLevelToSeverity(logEvent.Level); | ||
|
|
||
| var current = Activity.Current; | ||
|
||
|
|
||
| // Emit using internal helpers via reflection delegate | ||
| var renderedMessage = logEvent.FormattedMessage; | ||
|
||
| var args = IncludeEventParameters && logEvent.Parameters is object[] p ? p : null; | ||
|
||
|
|
||
| OpenTelemetry.AutoInstrumentation.Instrumentations.NLog.Bridge.OpenTelemetryLogHelpers.LogEmitter?.Invoke( | ||
| logger, | ||
| body, | ||
| logEvent.TimeStamp, | ||
| severityText, | ||
| severityNumber, | ||
| logEvent.Exception, | ||
| properties, | ||
| current, | ||
| args, | ||
| renderedMessage); | ||
| } | ||
|
|
||
| private static int MapLogLevelToSeverity(LogLevel level) | ||
| { | ||
| // Map NLog ordinals 0..5 to OTEL severity 1..24 approximate buckets | ||
| return level.Ordinal switch | ||
| { | ||
| 0 => 1, // Trace | ||
| 1 => 5, // Debug | ||
| 2 => 9, // Info | ||
| 3 => 13, // Warn | ||
| 4 => 17, // Error | ||
| 5 => 21, // Fatal | ||
| _ => 9 | ||
| }; | ||
| } | ||
|
|
||
| private static Func<string?, object?>? CreateGetLoggerDelegate(LoggerProvider loggerProvider) | ||
| { | ||
| try | ||
| { | ||
| var methodInfo = typeof(LoggerProvider) | ||
| .GetMethod("GetLogger", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new[] { typeof(string) }, null)!; | ||
| return (Func<string?, object?>)methodInfo.CreateDelegate(typeof(Func<string?, object?>), loggerProvider); | ||
| } | ||
| catch | ||
| { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| private object GetOrCreateLogger(string? loggerName) | ||
| { | ||
| var key = loggerName ?? string.Empty; | ||
| if (LoggerCache.TryGetValue(key, out var logger)) | ||
| { | ||
| return logger; | ||
| } | ||
|
|
||
| var factory = _getLoggerFactory; | ||
| if (factory is null) | ||
| { | ||
| return new object(); | ||
|
||
| } | ||
|
|
||
| logger = factory(loggerName); | ||
| if (logger is not null) | ||
| { | ||
| LoggerCache[key] = logger; | ||
| } | ||
|
|
||
| return logger ?? new object(); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.