-
Notifications
You must be signed in to change notification settings - Fork 150
NLog properties with Microsoft Extension Logging
The official extension methods in Microsoft Extension Logging does not provide any obvious way to provide custom NLog properties.
But there are still different options available:
NLog 4.5 supports properties captured from structured logging message templates:
_logger.LogDebug("Logon from {userid}", request.UserId);
These properties can then be extracted using the ${event-properties} renderer.
NLog.Extensions.Logging ver. 1.0 supports async properties captured from the BeginScope input parameter:
using (_logger.BeginScope(new[] { new KeyValuePair<string, object>("userid", request.UserId) }))
{
_logger.LogDebug("Logon from {0}", request.UserId);
}
These async properties can then be extracted using the ${mdlc} renderer
Microsoft Extension Logging allows one to log any kind of TState-object, when using the direct Log-method instead of the extension methods.
NLog.Extensions.Logging ver. 1.0 will attempt to cast the TState-object into IEnumerable<KeyValuePair<string, object>>
, and if successful then include them as NLog LogEventInfo.Properties.
This can be used to create a custom logevent object that contains both a message and properties.
class MyLogEvent : IEnumerable<KeyValuePair<string, object>>
{
List<KeyValuePair<string, object>> _properties = new List<KeyValuePair<string, object>>();
public string Message { get; }
public MyLogEvent(string message)
{
Message = message;
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
return _properties.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public MyLogEvent AddProp(string name, object value)
{
_properties.Add(new KeyValuePair<string, object>(name, value));
return this;
}
public static Func<MyLogEvent, Exception, string> Formatter { get; } = (l, e) => l.Message;
}
_logger.Log( Microsoft.Extensions.Logging.LogLevel.Debug,
default(EventId),
new MyLogEvent($"Logon from {request.UserId}").AddProp("userid", request.UserId),
(Exception)null,
MyLogEvent.Formatter );
These properties can then be extracted using the ${event-properties} renderer.
Combines structured logging message template with additional properties. It wraps the message formatter from Microsoft Extension Logging, and allows injection of extra properties:
class MyLogEvent2 : IReadOnlyList<KeyValuePair<string, object>>
{
readonly string _format;
readonly object[] _parameters;
Microsoft.Extensions.Logging.Internal.FormattedLogValues LogValues => _logValues ??
(_logValues = new Microsoft.Extensions.Logging.Internal.FormattedLogValues(_format, _parameters));
Microsoft.Extensions.Logging.Internal.FormattedLogValues _logValues;
List<KeyValuePair<string, object>> _extraProperties;
public MyLogEvent2(string format, params object[] values)
{
_format = format;
_parameters = values;
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
if (MessagePropertyCount == 0)
{
if (ExtraPropertyCount > 0)
return _extraProperties.GetEnumerator();
else
return Enumerable.Empty<KeyValuePair<string, object>>().GetEnumerator();
}
else
{
if (ExtraPropertyCount > 0)
return _extraProperties.Concat(LogValues).GetEnumerator();
else
return LogValues.GetEnumerator();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private int MessagePropertyCount
{
get
{
if (LogValues.Count > 1 && !string.IsNullOrEmpty(LogValues[0].Key) && !char.IsDigit(LogValues[0].Key[0]))
return LogValues.Count;
else
return 0;
}
}
private int ExtraPropertyCount => _extraProperties?.Count ?? 0;
public int Count => MessagePropertyCount + ExtraPropertyCount;
public KeyValuePair<string, object> this[int index]
{
get
{
int extraCount = ExtraPropertyCount;
if (index < extraCount)
{
return _extraProperties[index];
}
else
{
return LogValues[index - extraCount];
}
}
}
public MyLogEvent2 AddProp(string name, object value)
{
var properties = _extraProperties ?? (_extraProperties = new List<KeyValuePair<string, object>>());
properties.Add(new KeyValuePair<string, object>(name, value));
return this;
}
public static Func<MyLogEvent2, Exception, string> Formatter { get; } = (l, e) => l.LogValues.ToString();
};
_logger.Log( Microsoft.Extensions.Logging.LogLevel.Debug,
default(EventId),
new MyLogEvent2("Logon from {userid}", request.UserId).AddProp("ipaddress", request.IpAddress),
(Exception)null,
MyLogEvent2.Formatter );
The properties can then be extracted using the ${event-properties} renderer.