Skip to content

Commit

Permalink
Logger - WithProperty for adding Logger specific properties that are …
Browse files Browse the repository at this point in the history
…included for all LogEvents
  • Loading branch information
snakefoot committed Apr 10, 2019
1 parent 171e681 commit b44e2a2
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 82 deletions.
16 changes: 0 additions & 16 deletions src/NLog/Internal/LoggerConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,5 @@ public TargetWithFilterChain GetTargetsForLevel(LogLevel level)
}
return _targetsByLevel[level.Ordinal];
}

/// <summary>
/// Determines whether the specified level is enabled.
/// </summary>
/// <param name="level">The level.</param>
/// <returns>
/// A value of <c>true</c> if the specified level is enabled; otherwise, <c>false</c>.
/// </returns>
public bool IsEnabled(LogLevel level)
{
if (level == LogLevel.Off)
{
return false;
}
return _targetsByLevel[level.Ordinal] != null;
}
}
}
3 changes: 1 addition & 2 deletions src/NLog/LogFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ public Logger GetCurrentClassLogger(Type loggerType)
/// are not guaranteed to return the same logger reference.</returns>
public Logger GetLogger(string name)
{
return GetLoggerThreadSafe(name, typeof(Logger));
return GetLoggerThreadSafe(name, Logger.DefaultLoggerType);
}

/// <summary>
Expand Down Expand Up @@ -431,7 +431,6 @@ public void ReconfigExistingLoggers()
lock (_syncRoot)
{
_config?.InitializeAll();

loggers = _loggerCache.GetLoggers();
}

Expand Down
12 changes: 6 additions & 6 deletions src/NLog/Logger-generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public partial class Logger
/// <returns>A value of <see langword="true" /> if logging is enabled for the <c>Trace</c> level, otherwise it returns <see langword="false" />.</returns>
public bool IsTraceEnabled
{
get { return _isTraceEnabled; }
get { return _contextLogger._isTraceEnabled; }
}

/// <summary>
Expand All @@ -57,7 +57,7 @@ public bool IsTraceEnabled
/// <returns>A value of <see langword="true" /> if logging is enabled for the <c>Debug</c> level, otherwise it returns <see langword="false" />.</returns>
public bool IsDebugEnabled
{
get { return _isDebugEnabled; }
get { return _contextLogger._isDebugEnabled; }
}

/// <summary>
Expand All @@ -66,7 +66,7 @@ public bool IsDebugEnabled
/// <returns>A value of <see langword="true" /> if logging is enabled for the <c>Info</c> level, otherwise it returns <see langword="false" />.</returns>
public bool IsInfoEnabled
{
get { return _isInfoEnabled; }
get { return _contextLogger._isInfoEnabled; }
}

/// <summary>
Expand All @@ -75,7 +75,7 @@ public bool IsInfoEnabled
/// <returns>A value of <see langword="true" /> if logging is enabled for the <c>Warn</c> level, otherwise it returns <see langword="false" />.</returns>
public bool IsWarnEnabled
{
get { return _isWarnEnabled; }
get { return _contextLogger._isWarnEnabled; }
}

/// <summary>
Expand All @@ -84,7 +84,7 @@ public bool IsWarnEnabled
/// <returns>A value of <see langword="true" /> if logging is enabled for the <c>Error</c> level, otherwise it returns <see langword="false" />.</returns>
public bool IsErrorEnabled
{
get { return _isErrorEnabled; }
get { return _contextLogger._isErrorEnabled; }
}

/// <summary>
Expand All @@ -93,7 +93,7 @@ public bool IsErrorEnabled
/// <returns>A value of <see langword="true" /> if logging is enabled for the <c>Fatal</c> level, otherwise it returns <see langword="false" />.</returns>
public bool IsFatalEnabled
{
get { return _isFatalEnabled; }
get { return _contextLogger._isFatalEnabled; }
}


Expand Down
4 changes: 2 additions & 2 deletions src/NLog/Logger-generated.tt
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ namespace NLog
var levels = new string[]{"Trace", "Debug", "Info", "Warn", "Error", "Fatal"};

foreach(var level in levels)
{
{
#>
/// <summary>
/// Gets a value indicating whether logging is enabled for the <c><#=level#></c> level.
/// </summary>
/// <returns>A value of <see langword="true" /> if logging is enabled for the <c><#=level#></c> level, otherwise it returns <see langword="false" />.</returns>
public bool Is<#=level#>Enabled
{
get { return _is<#=level#>Enabled; }
get { return _contextLogger._is<#=level#>Enabled; }
}

<#
Expand Down
157 changes: 110 additions & 47 deletions src/NLog/Logger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,24 @@
namespace NLog
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using NLog.Internal;

#if NET4_5
using System.Threading.Tasks;
#endif
using JetBrains.Annotations;
using NLog.Internal;

/// <summary>
/// Provides logging interface and utility functions.
/// </summary>
[CLSCompliant(true)]
public partial class Logger : ILogger
{
private readonly Type _loggerType = typeof(Logger);

private volatile LoggerConfiguration _configuration;
internal static readonly Type DefaultLoggerType = typeof(Logger);
private Logger _contextLogger;
private Dictionary<string, object> _contextProperties;
private LoggerConfiguration _configuration;
private volatile bool _isTraceEnabled;
private volatile bool _isDebugEnabled;
private volatile bool _isInfoEnabled;
Expand All @@ -62,6 +64,35 @@ public partial class Logger : ILogger
/// </summary>
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>
Expand Down Expand Up @@ -100,11 +131,12 @@ public bool IsEnabled(LogLevel level)
/// <param name="logEvent">Log event.</param>
public void Log(LogEventInfo logEvent)
{
if (IsEnabled(logEvent.Level))
var targetsForLevel = IsEnabled(logEvent.Level) ? GetTargetsForLevel(logEvent.Level) : null;
if (targetsForLevel != null)
{
if (logEvent.LoggerName == null)
logEvent.LoggerName = Name;
WriteToTargets(logEvent);
WriteToTargets(logEvent, targetsForLevel);
}
}

Expand All @@ -115,11 +147,12 @@ public void Log(LogEventInfo logEvent)
/// <param name="logEvent">Log event.</param>
public void Log(Type wrapperType, LogEventInfo logEvent)
{
if (IsEnabled(logEvent.Level))
var targetsForLevel = IsEnabled(logEvent.Level) ? GetTargetsForLevel(logEvent.Level) : null;
if (targetsForLevel != null)
{
if (logEvent.LoggerName == null)
logEvent.LoggerName = Name;
WriteToTargets(wrapperType, logEvent);
WriteToTargets(wrapperType, logEvent, targetsForLevel);
}
}

Expand Down Expand Up @@ -392,25 +425,23 @@ public void Log<TArgument>(LogLevel level, [Localizable(false)] string message,
}
}

private void WriteToTargets(LogLevel level, Exception ex, [Localizable(false)] string message, object[] args)
{
LoggerImpl.Write(_loggerType, GetTargetsForLevel(level), PrepareLogEventInfo(LogEventInfo.Create(level, Name, ex, Factory.DefaultCultureInfo, message, args)), Factory);
}

private void WriteToTargets(LogLevel level, Exception ex, IFormatProvider formatProvider, [Localizable(false)] string message, object[] args)
{
LoggerImpl.Write(_loggerType, GetTargetsForLevel(level), PrepareLogEventInfo(LogEventInfo.Create(level, Name, ex, formatProvider, message, args)), Factory);
}


private LogEventInfo PrepareLogEventInfo(LogEventInfo logEvent)
{
if (logEvent.FormatProvider == null)
{
logEvent.FormatProvider = Factory.DefaultCultureInfo;
}
if (_contextProperties != null)
{
foreach (var property in _contextProperties)
{
if (!logEvent.Properties.ContainsKey(property.Key))
{
logEvent.Properties[property.Key] = property.Value;
}
}
}
return logEvent;

}

#endregion
Expand Down Expand Up @@ -557,58 +588,94 @@ internal void Initialize(string name, LoggerConfiguration loggerConfiguration, L
SetConfiguration(loggerConfiguration);
}

internal void WriteToTargets(LogLevel level, IFormatProvider formatProvider, [Localizable(false)] string message, object[] args)
private void WriteToTargets(LogLevel level, [Localizable(false)] string message, object[] args)
{
WriteToTargets(level, Factory.DefaultCultureInfo, message, args);
}

private void WriteToTargets(LogLevel level, IFormatProvider formatProvider, [Localizable(false)] string message, object[] args)
{
LoggerImpl.Write(_loggerType, GetTargetsForLevel(level), PrepareLogEventInfo(LogEventInfo.Create(level, Name, formatProvider, message, args)), Factory);
var targetsForLevel = GetTargetsForLevel(level);
if (targetsForLevel != null)
{
var logEvent = LogEventInfo.Create(level, Name, formatProvider, message, args);
WriteToTargets(logEvent, targetsForLevel);
}
}

private void WriteToTargets(LogLevel level, IFormatProvider formatProvider, [Localizable(false)] string message)
{
// please note that this overload calls the overload of LogEventInfo.Create with object[] parameter on purpose -
// to avoid unnecessary string.Format (in case of calling Create(LogLevel, string, IFormatProvider, object))
var logEvent = LogEventInfo.Create(level, Name, formatProvider, message, (object[])null);
LoggerImpl.Write(_loggerType, GetTargetsForLevel(level), PrepareLogEventInfo(logEvent), Factory);
var targetsForLevel = GetTargetsForLevel(level);
if (targetsForLevel != null)
{
// please note that this overload calls the overload of LogEventInfo.Create with object[] parameter on purpose -
// to avoid unnecessary string.Format (in case of calling Create(LogLevel, string, IFormatProvider, object))
var logEvent = LogEventInfo.Create(level, Name, formatProvider, message, (object[])null);
WriteToTargets(logEvent, targetsForLevel);
}
}

private void WriteToTargets<T>(LogLevel level, IFormatProvider formatProvider, T value)
{
var logEvent = PrepareLogEventInfo(LogEventInfo.Create(level, Name, formatProvider, value));
LoggerImpl.Write(_loggerType, GetTargetsForLevel(level), logEvent, Factory);
var targetsForLevel = GetTargetsForLevel(level);
if (targetsForLevel != null)
{
var logEvent = LogEventInfo.Create(level, Name, formatProvider, value);
WriteToTargets(logEvent, targetsForLevel);
}
}

internal void WriteToTargets(LogLevel level, [Localizable(false)] string message, object[] args)
private void WriteToTargets(LogLevel level, Exception ex, [Localizable(false)] string message, object[] args)
{
WriteToTargets(level, Factory.DefaultCultureInfo, message, args);
var targetsForLevel = GetTargetsForLevel(level);
if (targetsForLevel != null)
{
var logEvent = LogEventInfo.Create(level, Name, ex, Factory.DefaultCultureInfo, message, args);
WriteToTargets(logEvent, targetsForLevel);
}
}

private void WriteToTargets(LogEventInfo logEvent)
private void WriteToTargets(LogLevel level, Exception ex, IFormatProvider formatProvider, [Localizable(false)] string message, object[] args)
{
LoggerImpl.Write(_loggerType, GetTargetsForLevel(logEvent.Level), PrepareLogEventInfo(logEvent), Factory);
var targetsForLevel = GetTargetsForLevel(level);
if (targetsForLevel != null)
{
var logEvent = LogEventInfo.Create(level, Name, ex, formatProvider, message, args);
WriteToTargets(logEvent, targetsForLevel);
}
}

private void WriteToTargets(Type wrapperType, LogEventInfo logEvent)
private void WriteToTargets([NotNull] LogEventInfo logEvent, [NotNull] TargetWithFilterChain targetsForLevel)
{
LoggerImpl.Write(wrapperType ?? _loggerType, GetTargetsForLevel(logEvent.Level), PrepareLogEventInfo(logEvent), Factory);
LoggerImpl.Write(DefaultLoggerType, targetsForLevel, PrepareLogEventInfo(logEvent), Factory);
}

private void WriteToTargets(Type wrapperType, [NotNull] LogEventInfo logEvent, [NotNull] TargetWithFilterChain targetsForLevel)
{
LoggerImpl.Write(wrapperType ?? DefaultLoggerType, targetsForLevel, PrepareLogEventInfo(logEvent), Factory);
}

internal void SetConfiguration(LoggerConfiguration newConfiguration)
{
_configuration = newConfiguration;

// pre-calculate 'enabled' flags
_isTraceEnabled = newConfiguration.IsEnabled(LogLevel.Trace);
_isDebugEnabled = newConfiguration.IsEnabled(LogLevel.Debug);
_isInfoEnabled = newConfiguration.IsEnabled(LogLevel.Info);
_isWarnEnabled = newConfiguration.IsEnabled(LogLevel.Warn);
_isErrorEnabled = newConfiguration.IsEnabled(LogLevel.Error);
_isFatalEnabled = newConfiguration.IsEnabled(LogLevel.Fatal);
_isTraceEnabled = IsEnabled(LogLevel.Trace);
_isDebugEnabled = IsEnabled(LogLevel.Debug);
_isInfoEnabled = IsEnabled(LogLevel.Info);
_isWarnEnabled = IsEnabled(LogLevel.Warn);
_isErrorEnabled = IsEnabled(LogLevel.Error);
_isFatalEnabled = IsEnabled(LogLevel.Fatal);

OnLoggerReconfigured(EventArgs.Empty);
}

private TargetWithFilterChain GetTargetsForLevel(LogLevel level)
{
return _configuration.GetTargetsForLevel(level);
if (ReferenceEquals(_contextLogger, this))
return _configuration.GetTargetsForLevel(level);
else
return _contextLogger.GetTargetsForLevel(level);
}

/// <summary>
Expand All @@ -617,11 +684,7 @@ private TargetWithFilterChain GetTargetsForLevel(LogLevel level)
/// <param name="e">Event arguments</param>
protected virtual void OnLoggerReconfigured(EventArgs e)
{
var reconfigured = LoggerReconfigured;
if (reconfigured != null)
{
reconfigured(this, e);
}
LoggerReconfigured?.Invoke(this, e);
}
}
}

0 comments on commit b44e2a2

Please sign in to comment.