Skip to content

Commit

Permalink
Logger - SetProperty for updating the current Logger object instance
Browse files Browse the repository at this point in the history
  • Loading branch information
snakefoot committed Apr 14, 2019
1 parent 47f861d commit 7585208
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 35 deletions.
74 changes: 45 additions & 29 deletions src/NLog/Logger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,34 +67,6 @@ protected internal Logger()
_contextLogger = this;
}

/// <summary>
/// Creates new logger that automatically appends the specified property to all log events
/// </summary>
/// <param name="propertyKey">Property Name</param>
/// <param name="propertyValue">Property Value</param>
/// <returns>New Logger that automatically appends specified property</returns>
public Logger WithProperty(string propertyKey, object propertyValue)
{
if (string.IsNullOrEmpty(propertyKey))
throw new ArgumentException(nameof(propertyKey));

Logger newLogger = Factory.CreateNewLogger(GetType()) ?? new Logger();
newLogger.Initialize(Name, _configuration, Factory);
var contextProperties = _contextProperties != null
? new Dictionary<string, object>(_contextProperties)
: new Dictionary<string, object>();
contextProperties[propertyKey] = propertyValue;
newLogger._contextProperties = contextProperties;
newLogger._contextLogger = _contextLogger;
newLogger._isTraceEnabled = true;
newLogger._isDebugEnabled = true;
newLogger._isInfoEnabled = true;
newLogger._isWarnEnabled = true;
newLogger._isErrorEnabled = true;
newLogger._isFatalEnabled = true;
return newLogger;
}

/// <summary>
/// Occurs when logger configuration changes.
/// </summary>
Expand Down Expand Up @@ -125,6 +97,50 @@ public bool IsEnabled(LogLevel level)
return GetTargetsForLevel(level) != null;
}

/// <summary>
/// Creates new logger that automatically appends the specified property to all log events (without changing current logger)
/// </summary>
/// <param name="propertyKey">Property Name</param>
/// <param name="propertyValue">Property Value</param>
/// <returns>New Logger object that automatically appends specified property</returns>
public Logger WithProperty(string propertyKey, object propertyValue)
{
if (string.IsNullOrEmpty(propertyKey))
throw new ArgumentException(nameof(propertyKey));

Logger newLogger = Factory.CreateNewLogger(GetType()) ?? new Logger();
newLogger.Initialize(Name, _configuration, Factory);
newLogger._contextProperties = CopyOnWrite(propertyKey, propertyValue);
newLogger._contextLogger = _contextLogger; // Use the LoggerConfiguration of the parent Logger
return newLogger;
}

/// <summary>
/// Updates the specified context property for the current logger. The logger will append it for all log events
/// </summary>
/// <remarks>
/// Will affect all locations/contexts that makes use of the same named logger object.
/// </remarks>
/// <param name="propertyKey">Property Name</param>
/// <param name="propertyValue">Property Value</param>
public void SetProperty(string propertyKey, object propertyValue)
{
if (string.IsNullOrEmpty(propertyKey))
throw new ArgumentException(nameof(propertyKey));

_contextProperties = CopyOnWrite(propertyKey, propertyValue);
}

private Dictionary<string, object> CopyOnWrite(string propertyKey, object propertyValue)
{
var contextProperties = _contextProperties;
contextProperties = contextProperties != null
? new Dictionary<string, object>(contextProperties)
: new Dictionary<string, object>();
contextProperties[propertyKey] = propertyValue;
return contextProperties;
}

/// <summary>
/// Writes the specified diagnostic message.
/// </summary>
Expand Down Expand Up @@ -675,7 +691,7 @@ private TargetWithFilterChain GetTargetsForLevel(LogLevel level)
if (ReferenceEquals(_contextLogger, this))
return _configuration.GetTargetsForLevel(level);
else
return _contextLogger.GetTargetsForLevel(level);
return _contextLogger.GetTargetsForLevel(level); // Use the LoggerConfiguration of the parent Logger
}

/// <summary>
Expand Down
36 changes: 30 additions & 6 deletions tests/NLog.UnitTests/LoggerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2393,9 +2393,9 @@ public void LogEventTemplateShouldHaveProperties_even_when_changed()

static Logger GetContextLoggerFromTemporary(string loggerName)
{
var loggerRaw = LogManager.GetLogger(loggerName);
var loggerStage1 = loggerRaw.WithProperty("Stage", 1);
loggerRaw.Trace("{Stage}", "Connected");
var globalLogger = LogManager.GetLogger(loggerName);
var loggerStage1 = globalLogger.WithProperty("Stage", 1);
globalLogger.Trace("{Stage}", "Connected");
return loggerStage1;
}

Expand All @@ -2409,7 +2409,7 @@ public void LogEventTemplateShouldOverrideProperties()
config.LoggingRules.Add(new LoggingRule(uniqueLoggerName, LogLevel.Trace, target));
LogManager.Configuration = config;
Logger loggerStage1 = GetContextLoggerFromTemporary(uniqueLoggerName);
GC.Collect(); // Try and free loggerRaw
GC.Collect(); // Try and free globalLogger
var loggerStage2 = loggerStage1.WithProperty("Stage", 2);
Assert.Single(target.LastEvent.Properties);
AssertContainsInDictionary(target.LastEvent.Properties, "Stage", "Connected");
Expand All @@ -2436,16 +2436,40 @@ public void LoggerWithPropertyShouldInheritLogLevel()
config.LoggingRules.Add(new LoggingRule(uniqueLoggerName, LogLevel.Trace, target));
LogManager.Configuration = config;
Logger loggerStage1 = GetContextLoggerFromTemporary(uniqueLoggerName);
GC.Collect(); // Try and free loggerRaw
GC.Collect(); // Try and free globalLogger
Assert.Single(target.LastEvent.Properties);
AssertContainsInDictionary(target.LastEvent.Properties, "Stage", "Connected");
LogManager.Configuration.LoggingRules[0].DisableLoggingForLevel(LogLevel.Trace);
LogManager.ReconfigExistingLoggers(); // Refreshes the configuration of loggerRaw
LogManager.ReconfigExistingLoggers(); // Refreshes the configuration of globalLogger
var loggerStage2 = loggerStage1.WithProperty("Stage", 2);
loggerStage2.Trace("Login attempt from {userid}", "kermit");
AssertContainsInDictionary(target.LastEvent.Properties, "Stage", "Connected"); // Verify nothing writtne
loggerStage2.Debug("{Stage}", "Disconnected");
AssertContainsInDictionary(target.LastEvent.Properties, "Stage", "Disconnected");
}

[Fact]
public void LoggerSetPropertyChangesCurrentLogger()
{
string uniqueLoggerName = Guid.NewGuid().ToString();

var config = new LoggingConfiguration();
var target = new MyTarget();
config.LoggingRules.Add(new LoggingRule(uniqueLoggerName, LogLevel.Trace, target));
LogManager.Configuration = config;
var globalLogger = LogManager.GetLogger(uniqueLoggerName);
globalLogger.SetProperty("Stage", 1);
globalLogger.Trace("Login attempt from {userid}", "kermit");
AssertContainsInDictionary(target.LastEvent.Properties, "Stage", 1);
var loggerStage2 = globalLogger.WithProperty("Stage", 2);
loggerStage2.Trace("Hello from {userid}", "kermit");
AssertContainsInDictionary(target.LastEvent.Properties, "Stage", 2);
globalLogger.SetProperty("Stage", 4);
loggerStage2.SetProperty("Stage", 3);
loggerStage2.Trace("Goodbye from {userid}", "kermit");
AssertContainsInDictionary(target.LastEvent.Properties, "Stage", 3);
globalLogger.Trace("Logoff by {userid}", "kermit");
AssertContainsInDictionary(target.LastEvent.Properties, "Stage", 4);
}
}
}

0 comments on commit 7585208

Please sign in to comment.