diff --git a/dotnet/src/webdriver/Internal/Logging/LogContext.cs b/dotnet/src/webdriver/Internal/Logging/LogContext.cs
index bb4d9feede2c5..081ebbd4c5ab4 100644
--- a/dotnet/src/webdriver/Internal/Logging/LogContext.cs
+++ b/dotnet/src/webdriver/Internal/Logging/LogContext.cs
@@ -20,6 +20,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
#nullable enable
@@ -30,7 +31,7 @@ namespace OpenQA.Selenium.Internal.Logging
/// Represents a logging context that provides methods for creating sub-contexts, retrieving loggers, emitting log messages, and configuring minimum log levels.
///
///
- internal class LogContext : ILogContext
+ internal sealed class LogContext : ILogContext
{
private ConcurrentDictionary? _loggers;
@@ -46,7 +47,7 @@ public LogContext(LogEventLevel level, ILogContext? parentLogContext, Concurrent
_parentLogContext = parentLogContext;
- _loggers = loggers;
+ _loggers = CloneLoggers(loggers, level);
if (handlers is not null)
{
@@ -65,12 +66,7 @@ public ILogContext CreateContext()
public ILogContext CreateContext(LogEventLevel minimumLevel)
{
- ConcurrentDictionary? loggers = null;
-
- if (_loggers != null)
- {
- loggers = new ConcurrentDictionary(_loggers.Select(l => new KeyValuePair(l.Key, new Logger(l.Value.Issuer, minimumLevel))));
- }
+ ConcurrentDictionary? loggers = CloneLoggers(_loggers, minimumLevel);
var context = new LogContext(minimumLevel, this, loggers, Handlers);
@@ -98,7 +94,7 @@ public ILogger GetLogger(Type type)
public bool IsEnabled(ILogger logger, LogEventLevel level)
{
- return Handlers != null && level >= _level && level >= logger.Level;
+ return Handlers != null && level >= _level && (_loggers?.TryGetValue(logger.Issuer, out var loggerEntry) != true || level >= loggerEntry?.Level);
}
public void EmitMessage(ILogger logger, LogEventLevel level, string message)
@@ -155,5 +151,24 @@ public void Dispose()
Log.CurrentContext = _parentLogContext;
}
+
+ [return: NotNullIfNotNull(nameof(loggers))]
+ private static ConcurrentDictionary? CloneLoggers(ConcurrentDictionary? loggers, LogEventLevel minimumLevel)
+ {
+ if (loggers is null)
+ {
+ return null;
+ }
+
+ var cloned = new Dictionary(loggers.Count);
+
+ foreach (KeyValuePair logger in loggers)
+ {
+ var clonedLogger = new Logger(logger.Value.Issuer, minimumLevel);
+ cloned.Add(logger.Key, clonedLogger);
+ }
+
+ return new ConcurrentDictionary(cloned);
+ }
}
}
diff --git a/dotnet/test/common/Internal/Logging/LogTest.cs b/dotnet/test/common/Internal/Logging/LogTest.cs
index d872f665c094a..a7d67684c2609 100644
--- a/dotnet/test/common/Internal/Logging/LogTest.cs
+++ b/dotnet/test/common/Internal/Logging/LogTest.cs
@@ -28,13 +28,27 @@ public class LogTest
private TestLogHandler testLogHandler;
private ILogger logger;
+ private void ResetGlobalLog()
+ {
+ Log.SetLevel(LogEventLevel.Info);
+ Log.Handlers.Clear().Handlers.Add(new ConsoleLogHandler());
+ }
+
[SetUp]
public void SetUp()
{
+ ResetGlobalLog();
+
testLogHandler = new TestLogHandler();
logger = Log.GetLogger();
}
+ [TearDown]
+ public void TearDown()
+ {
+ ResetGlobalLog();
+ }
+
[Test]
public void LoggerShouldEmitEvent()
{
@@ -160,6 +174,16 @@ public void ContextShouldChangeLevel()
Assert.That(logger.Level, Is.EqualTo(LogEventLevel.Warn));
}
+ [Test]
+ public void ContextShouldEmitMessages()
+ {
+ using var context = Log.CreateContext(LogEventLevel.Trace).Handlers.Add(testLogHandler);
+
+ logger.Trace("test message");
+
+ Assert.That(testLogHandler.Events.Count, Is.EqualTo(1));
+ }
+
[Test]
public void ShouldCreateContextWithCustomHandler()
{