From f7b88a36da17bfd0487d3f16527385b67110f34f Mon Sep 17 00:00:00 2001 From: Steve Gordon Date: Wed, 7 Feb 2024 15:15:36 +0100 Subject: [PATCH] Honour configured logging level --- .../Diagnostics/DiagnosticErrorLevels.cs | 25 +++++++- .../Diagnostics/LogFileWriter.cs | 58 ++++++++++++++++--- .../Diagnostics/LogLevel.cs | 14 +++++ .../Diagnostics/LoggingEventListener.cs | 39 ++++++------- 4 files changed, 105 insertions(+), 31 deletions(-) create mode 100644 src/Elastic.OpenTelemetry/Diagnostics/LogLevel.cs diff --git a/src/Elastic.OpenTelemetry/Diagnostics/DiagnosticErrorLevels.cs b/src/Elastic.OpenTelemetry/Diagnostics/DiagnosticErrorLevels.cs index 15675dd..977c32b 100644 --- a/src/Elastic.OpenTelemetry/Diagnostics/DiagnosticErrorLevels.cs +++ b/src/Elastic.OpenTelemetry/Diagnostics/DiagnosticErrorLevels.cs @@ -7,7 +7,30 @@ internal static class DiagnosticErrorLevels { public const string Critical = "Critical"; public const string Error = "Error"; - public const string Warning = "Warn"; + public const string Warning = "Warning"; public const string Info = "Info"; public const string Trace = "Trace"; + + public static LogLevel ToLogLevel(string logLevelString) => + logLevelString switch + { + Critical => LogLevel.Critical, + Error => LogLevel.Error, + Warning => LogLevel.Warning, + Info => LogLevel.Info, + Trace => LogLevel.Trace, + _ => LogLevel.Unknown, + }; + + public static string AsString(this LogLevel logLevel) => + logLevel switch + { + LogLevel.Critical => Critical, + LogLevel.Error => Error, + LogLevel.Warning => Warning, + LogLevel.Info => Info, + LogLevel.Trace => Trace, + LogLevel.Unknown => string.Empty, + _ => string.Empty + }; } diff --git a/src/Elastic.OpenTelemetry/Diagnostics/LogFileWriter.cs b/src/Elastic.OpenTelemetry/Diagnostics/LogFileWriter.cs index b1ce24d..cd64a8c 100644 --- a/src/Elastic.OpenTelemetry/Diagnostics/LogFileWriter.cs +++ b/src/Elastic.OpenTelemetry/Diagnostics/LogFileWriter.cs @@ -65,7 +65,8 @@ private LogFileWriter() foreach (var item in preAmble) { - WriteLogPrefix(DiagnosticErrorLevels.Info, builder); + // These preamble entries are ALWAYS logged, regardless of the configured log level + WriteLogPrefix(LogLevel.Info, builder); builder.Append(item); _streamWriter.WriteLine(builder.ToString()); builder.Clear(); @@ -77,17 +78,46 @@ private LogFileWriter() StringBuilderCache.Release(builder); } - private static void WriteLogPrefix(string logLevel, StringBuilder builder) => + private static readonly LogLevel ConfiguredLogLevel = GetConfiguredLogLevel(); + + public static LogLevel GetConfiguredLogLevel() + { + var logLevel = LogLevel.Info; + + var logLevelEnvironmentVariable = Environment.GetEnvironmentVariable(EnvironmentVariables.ElasticOtelLogLevelEnvironmentVariable); + + if (!string.IsNullOrEmpty(logLevelEnvironmentVariable)) + { + if (logLevelEnvironmentVariable.Equals(DiagnosticErrorLevels.Trace, StringComparison.OrdinalIgnoreCase)) + logLevel = LogLevel.Trace; + + else if (logLevelEnvironmentVariable.Equals(DiagnosticErrorLevels.Info, StringComparison.OrdinalIgnoreCase)) + logLevel = LogLevel.Info; + + else if (logLevelEnvironmentVariable.Equals(DiagnosticErrorLevels.Warning, StringComparison.OrdinalIgnoreCase)) + logLevel = LogLevel.Warning; + + else if (logLevelEnvironmentVariable.Equals(DiagnosticErrorLevels.Error, StringComparison.OrdinalIgnoreCase)) + logLevel = LogLevel.Error; + + else if (logLevelEnvironmentVariable.Equals(DiagnosticErrorLevels.Critical, StringComparison.OrdinalIgnoreCase)) + logLevel = LogLevel.Critical; + } + + return logLevel; + } + + private static void WriteLogPrefix(LogLevel logLevel, StringBuilder builder) => WriteLogPrefix(Environment.CurrentManagedThreadId, DateTime.UtcNow, logLevel, builder); - private static void WriteLogPrefix(int managedThreadId, DateTime dateTime, string level, StringBuilder builder) + private static void WriteLogPrefix(int managedThreadId, DateTime dateTime, LogLevel level, StringBuilder builder) { builder.Append('[') .Append(dateTime.ToString("yyyy-MM-dd HH:mm:ss.fff")) .Append("][") .Append(managedThreadId == -1 ? "-" : managedThreadId) .Append("][") - .Append(level) + .Append(level.AsString()) .Append(']'); var length = builder.Length; @@ -105,20 +135,30 @@ private static void WriteLogPrefix(int managedThreadId, DateTime dateTime, strin public Task WritingTask { get; } + public void WriteCriticalLogLine(IDiagnosticEvent diagnosticEvent, string message) => + WriteLogLine(diagnosticEvent, LogLevel.Critical, message); + public void WriteErrorLogLine(IDiagnosticEvent diagnosticEvent, string message) => - WriteLogLine(diagnosticEvent, DiagnosticErrorLevels.Error, message); + WriteLogLine(diagnosticEvent, LogLevel.Error, message); + + public void WriteWarningLogLine(IDiagnosticEvent diagnosticEvent, string message) => + WriteLogLine(diagnosticEvent, LogLevel.Warning, message); public void WriteInfoLogLine(IDiagnosticEvent diagnosticEvent, string message) => - WriteLogLine(diagnosticEvent, DiagnosticErrorLevels.Info, message); + WriteLogLine(diagnosticEvent, LogLevel.Info, message); public void WriteTraceLogLine(IDiagnosticEvent diagnosticEvent, string message) => - WriteLogLine(diagnosticEvent, DiagnosticErrorLevels.Trace, message); + WriteLogLine(diagnosticEvent, LogLevel.Trace, message); - public void WriteLogLine(IDiagnosticEvent diagnosticEvent, string logLevel, string message) => + public void WriteLogLine(IDiagnosticEvent diagnosticEvent, LogLevel logLevel, string message) => WriteLogLine(diagnosticEvent.Activity, diagnosticEvent.ManagedThreadId, diagnosticEvent.DateTime, logLevel, message); - public void WriteLogLine(Activity? activity, int managedThreadId, DateTime dateTime, string logLevel, string logLine) + public void WriteLogLine(Activity? activity, int managedThreadId, DateTime dateTime, LogLevel logLevel, string logLine) { + // We skip logging for any log level higher (numerically) than the configured log level + if (logLevel > ConfiguredLogLevel) + return; + var builder = StringBuilderCache.Acquire(); WriteLogPrefix(managedThreadId, dateTime, logLevel, builder); builder.Append(logLine); diff --git a/src/Elastic.OpenTelemetry/Diagnostics/LogLevel.cs b/src/Elastic.OpenTelemetry/Diagnostics/LogLevel.cs new file mode 100644 index 0000000..75fe2d3 --- /dev/null +++ b/src/Elastic.OpenTelemetry/Diagnostics/LogLevel.cs @@ -0,0 +1,14 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information +namespace Elastic.OpenTelemetry.Diagnostics; + +internal enum LogLevel +{ + Unknown = 0, + Critical = 1, + Error = 2, + Warning = 3, + Info = 4, + Trace = 5 +} diff --git a/src/Elastic.OpenTelemetry/Diagnostics/LoggingEventListener.cs b/src/Elastic.OpenTelemetry/Diagnostics/LoggingEventListener.cs index 40f0550..1d7c4cb 100644 --- a/src/Elastic.OpenTelemetry/Diagnostics/LoggingEventListener.cs +++ b/src/Elastic.OpenTelemetry/Diagnostics/LoggingEventListener.cs @@ -17,20 +17,17 @@ public LoggingEventListener(LogFileWriter logFileWriter) { _logFileWriter = logFileWriter; - var eventLevel = Environment.GetEnvironmentVariable(EnvironmentVariables.ElasticOtelLogLevelEnvironmentVariable); + var eventLevel = LogFileWriter.GetConfiguredLogLevel(); - if (!string.IsNullOrEmpty(eventLevel)) + _eventLevel = eventLevel switch { - _eventLevel = eventLevel.ToLowerInvariant() switch - { - "trace" => EventLevel.Verbose, - "info" => EventLevel.Informational, - "warning" => EventLevel.Warning, - "error" => EventLevel.Error, - "critical" => EventLevel.Critical, - _ => EventLevel.Informational // fallback to info level - }; - } + LogLevel.Trace => EventLevel.Verbose, + LogLevel.Info => EventLevel.Informational, + LogLevel.Warning => EventLevel.Warning, + LogLevel.Error => EventLevel.Error, + LogLevel.Critical => EventLevel.Critical, + _ => EventLevel.Informational // fallback to info level + }; } public override void Dispose() @@ -70,7 +67,7 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) // TODO - We can only get the OS thread ID from the args - Do we send that instead?? // As per this issue - https://github.com/dotnet/runtime/issues/13125 - OnEventWritten may be on a different thread // so we can't use the Environment.CurrentManagedThreadId value here. - _logFileWriter.WriteLogLine(null, -1, eventData.TimeStamp, GetLevel(eventData), StringBuilderCache.GetStringAndRelease(builder)); + _logFileWriter.WriteLogLine(null, -1, eventData.TimeStamp, GetLogLevel(eventData), StringBuilderCache.GetStringAndRelease(builder)); } catch (Exception) { @@ -78,16 +75,16 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) // likely a file access issue } - static string GetLevel(EventWrittenEventArgs eventData) => + static LogLevel GetLogLevel(EventWrittenEventArgs eventData) => eventData.Level switch { - EventLevel.Critical => DiagnosticErrorLevels.Critical, - EventLevel.Error => DiagnosticErrorLevels.Error, - EventLevel.Warning => DiagnosticErrorLevels.Warning, - EventLevel.Informational => DiagnosticErrorLevels.Info, - EventLevel.Verbose => DiagnosticErrorLevels.Trace, - EventLevel.LogAlways => "N/A", - _ => throw new Exception("Unhandled event data level") + EventLevel.Critical => LogLevel.Critical, + EventLevel.Error => LogLevel.Error, + EventLevel.Warning => LogLevel.Warning, + EventLevel.Informational => LogLevel.Info, + EventLevel.Verbose => LogLevel.Trace, + EventLevel.LogAlways => LogLevel.Unknown, + _ => LogLevel.Unknown }; static void CreateLogMessage(EventWrittenEventArgs eventData, StringBuilder builder)