Skip to content

Commit

Permalink
NLogProviderOptions with support for CaptureEventId.EventId + EventName
Browse files Browse the repository at this point in the history
  • Loading branch information
snakefoot committed Nov 21, 2021
1 parent bce11f5 commit 3f4aa0d
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ protected override void Append(StringBuilder builder, LogEventInfo logEvent)
private static int LookupEventId(LogEventInfo logEvent)
{
int eventId = 0;
if (logEvent.HasProperties && (logEvent.Properties.TryGetValue("EventId_Id", out var eventIdValue) || logEvent.Properties.TryGetValue("EventId", out eventIdValue)))
if (logEvent.HasProperties && (logEvent.Properties.TryGetValue(nameof(EventIdCaptureType.EventId_Id), out var eventIdValue) || logEvent.Properties.TryGetValue(nameof(EventIdCaptureType.EventId), out eventIdValue)))
{
if (eventIdValue is int)
eventId = (int)eventIdValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public MicrosoftConsoleJsonLayout()
Attributes.Add(new JsonAttribute("Message", "${message}"));
Attributes.Add(new JsonAttribute("Exception", "${replace-newlines:${exception:format=tostring,data}}"));
var stateJsonLayout = new JsonLayout() { IncludeEventProperties = true };
stateJsonLayout.ExcludeProperties.Add("EventId");
stateJsonLayout.ExcludeProperties.Add("EventId_Id");
stateJsonLayout.ExcludeProperties.Add(nameof(EventIdCaptureType.EventId));
stateJsonLayout.ExcludeProperties.Add(nameof(EventIdCaptureType.EventId_Id));
stateJsonLayout.Attributes.Add(new JsonAttribute("{OriginalFormat}", "${message:raw=true}"));
Attributes.Add(new JsonAttribute("State", stateJsonLayout) { Encode = false });
}
Expand Down Expand Up @@ -108,15 +108,15 @@ private static string LookupEventId(LogEventInfo logEvent)
{
if (logEvent.HasProperties)
{
if (logEvent.Properties.TryGetValue("EventId", out var eventObject))
if (logEvent.Properties.TryGetValue(nameof(EventIdCaptureType.EventId), out var eventObject))
{
if (eventObject is int eventId)
return ConvertEventId(eventId);
else if (eventObject is Microsoft.Extensions.Logging.EventId eventIdStruct)
return ConvertEventId(eventIdStruct.Id);
}

if (logEvent.Properties.TryGetValue("EventId_Id", out var eventid) && eventid is int)
if (logEvent.Properties.TryGetValue(nameof(EventIdCaptureType.EventId_Id), out var eventid) && eventid is int)
{
return ConvertEventId((int)eventid);
}
Expand Down
22 changes: 15 additions & 7 deletions src/NLog.Extensions.Logging/Logging/EventIdCaptureType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,28 @@ public enum EventIdCaptureType
/// </summary>
None = 0,
/// <summary>
/// Capture entire <see cref="Microsoft.Extensions.Logging.EventId"/> as "EventId"-property (with boxing)
/// Capture integer <see cref="Microsoft.Extensions.Logging.EventId.Id"/> as "EventId"-property
/// </summary>
EventId = 1,
/// <summary>
/// Capture <see cref="Microsoft.Extensions.Logging.EventId.Id"/> as "EventId_Id"-property.
/// Capture string <see cref="Microsoft.Extensions.Logging.EventId.Name"/> as "EventName"-property
/// </summary>
EventId_Id = 2,
EventName = 2,
/// <summary>
/// Capture <see cref="Microsoft.Extensions.Logging.EventId.Name"/> as "EventId_Name"-property.
/// Capture struct <see cref="Microsoft.Extensions.Logging.EventId"/> as "EventId"-property (with boxing)
/// </summary>
EventId_Name = 4,
EventIdStruct = 4,
/// <summary>
/// Capture all properties (Legacy)
/// Capture integer <see cref="Microsoft.Extensions.Logging.EventId.Id"/> as "EventId_Id"-property (Legacy)
/// </summary>
All = EventId | EventId_Id | EventId_Name,
EventId_Id = 8,
/// <summary>
/// Capture string <see cref="Microsoft.Extensions.Logging.EventId.Name"/> as "EventId_Name"-property (Legacy)
/// </summary>
EventId_Name = 16,
/// <summary>
/// Captures legacy properties (EventId-struct + EventId_Id + EventId_Name)
/// </summary>
Legacy = EventIdStruct | EventId_Id | EventId_Name,
}
}
42 changes: 26 additions & 16 deletions src/NLog.Extensions.Logging/Logging/NLogLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,23 +299,32 @@ private void CaptureEventIdProperties(LogEventInfo logEvent, EventId eventId)
var captureEventId = _options.CaptureEventId;
if (captureEventId != EventIdCaptureType.None && IncludeEventIdProperties(eventId))
{
// Attempt to reuse the same string-allocations based on the current <see cref="NLogProviderOptions.EventIdSeparator"/>
var eventIdPropertyNames = _eventIdPropertyNames ?? new Tuple<string, string, string>(null, null, null);
var eventIdSeparator = _options.EventIdSeparator ?? String.Empty;
if (!ReferenceEquals(eventIdPropertyNames.Item1, eventIdSeparator))
if ((captureEventId & EventIdCaptureType.EventId) != 0)
logEvent.Properties[nameof(EventIdCaptureType.EventId)] = GetEventId(eventId.Id);

if ((captureEventId & EventIdCaptureType.EventName) != 0 && eventId.Name != null)
logEvent.Properties[nameof(EventIdCaptureType.EventName)] = eventId.Name;

if ((captureEventId & EventIdCaptureType.Legacy) != 0)
{
// Perform atomic cache update of the string-allocations matching the current separator
_eventIdPropertyNames = eventIdPropertyNames = CreateEventIdPropertyNames(eventIdSeparator);
}
// Attempt to reuse the same string-allocations based on the current <see cref="NLogProviderOptions.EventIdSeparator"/>
var eventIdPropertyNames = _eventIdPropertyNames ?? new Tuple<string, string, string>(null, null, null);
var eventIdSeparator = _options.EventIdSeparator ?? String.Empty;
if (!ReferenceEquals(eventIdPropertyNames.Item1, eventIdSeparator))
{
// Perform atomic cache update of the string-allocations matching the current separator
_eventIdPropertyNames = eventIdPropertyNames = CreateEventIdPropertyNames(eventIdSeparator);
}

if ((captureEventId & EventIdCaptureType.EventId_Id) != 0)
logEvent.Properties[eventIdPropertyNames.Item2] = eventId.Id == 0 ? ZeroEventId : GetEventId(eventId.Id);
if ((captureEventId & EventIdCaptureType.EventId_Id) != 0)
logEvent.Properties[eventIdPropertyNames.Item2] = GetEventId(eventId.Id);

if ((captureEventId & EventIdCaptureType.EventId_Name) != 0 && eventId.Name != null)
logEvent.Properties[eventIdPropertyNames.Item3] = eventId.Name;
if ((captureEventId & EventIdCaptureType.EventId_Name) != 0 && eventId.Name != null)
logEvent.Properties[eventIdPropertyNames.Item3] = eventId.Name;

if ((captureEventId & EventIdCaptureType.EventId) != 0)
logEvent.Properties[nameof(EventId)] = eventId;
if ((captureEventId & EventIdCaptureType.EventIdStruct) != 0)
logEvent.Properties[nameof(EventIdCaptureType.EventId)] = eventId;
}
}
}

Expand All @@ -339,10 +348,11 @@ private static Tuple<string, string, string> CreateEventIdPropertyNames(string e

private static object GetEventId(int eventId)
{
if (eventId >= 0 && eventId < EventIdBoxing.Length)
if (eventId == 0)
return ZeroEventId;
if (eventId > 0 && eventId < EventIdBoxing.Length)
return EventIdBoxing[eventId];
else
return eventId;
return eventId;
}

private static void CaptureMessageProperties(LogEventInfo logEvent, IEnumerable<KeyValuePair<string, object>> messageProperties)
Expand Down
12 changes: 6 additions & 6 deletions src/NLog.Extensions.Logging/Logging/NLogProviderOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ namespace NLog.Extensions.Logging
public class NLogProviderOptions
{
/// <summary>
/// Separator between for EventId.Id and EventId.Name. Default to _
/// Control capture of <see cref="Microsoft.Extensions.Logging.EventId"/> as "EventId"-property.
/// </summary>
public string EventIdSeparator { get; set; } = "_";
public EventIdCaptureType CaptureEventId { get; set; } = EventIdCaptureType.EventId | EventIdCaptureType.EventName;

/// <summary>
/// Skip capture of "EventId_Id" and "EventId_Name" as <see cref="LogEventInfo.Properties" /> when <c>default(EventId)</c>
/// Skip capture of <see cref="Microsoft.Extensions.Logging.EventId"/> in <see cref="LogEventInfo.Properties" /> when <c>default(EventId)</c>
/// </summary>
public bool IgnoreEmptyEventId { get; set; } = true;

/// <summary>
/// Control capture of <see cref="Microsoft.Extensions.Logging.EventId"/> as "EventId"-property.
/// Separator between for EventId.Id and EventId.Name. Default to _
/// </summary>
/// <remarks>
/// Enabling capture of the entire "EventId" will increase memory allocation and gives a performance hit. Faster to use "EventId_Id" + "EventId_Name".
/// Only relevant for <see cref="EventIdCaptureType.EventId_Id"/>, <see cref="EventIdCaptureType.EventId_Name"/> or <see cref="EventIdCaptureType.Legacy"/>
/// </remarks>
public EventIdCaptureType CaptureEventId { get; set; } = EventIdCaptureType.EventId_Id | EventIdCaptureType.EventId_Name;
public string EventIdSeparator { get; set; } = "_";

/// <summary>
/// Enable structured logging by capturing message template parameters with support for "@" and "$". Enables use of ${message:raw=true}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ public void AddNLog_LoggerFactory_LogInfo_ShouldLogToNLog()

[Theory]
[InlineData("EventId", "eventId_2", true)]
[InlineData("EventId_Name", "eventId_2", true)]
[InlineData("EventName", "", true)]
[InlineData("EventId_Id", "2", true)]
[InlineData("EventId", "", false)]
[InlineData("EventId_Name", "eventId_2", false)]
[InlineData("EventId_Id", "2", false)]
[InlineData("EventId_Name", "eventId_2", true)]
[InlineData("EventId", "2", false)]
[InlineData("EventName", "eventId_2", false)]
[InlineData("EventId_Id", "", false)]
[InlineData("EventId_Name", "", false)]
[Obsolete("Instead use ILoggingBuilder.AddNLog() or IHostBuilder.UseNLog()")]
public void AddNLog_LoggerFactory_LogInfoWithEventId_ShouldLogToNLogWithEventId(string eventPropery, string expectedEventInLog, bool captureEntireEventId)
{
Expand All @@ -45,7 +47,7 @@ public void AddNLog_LoggerFactory_LogInfoWithEventId_ShouldLogToNLogWithEventId(
var config = CreateConfigWithMemoryTarget(out var memoryTarget, $"${{event-properties:{eventPropery}}} - ${{message}}");

// Act
loggerFactory.AddNLog(new NLogProviderOptions { EventIdSeparator = "_", CaptureEventId = captureEntireEventId ? EventIdCaptureType.All : EventIdCaptureType.EventId_Id | EventIdCaptureType.EventId_Name });
loggerFactory.AddNLog(new NLogProviderOptions { EventIdSeparator = "_", CaptureEventId = captureEntireEventId ? EventIdCaptureType.Legacy : (EventIdCaptureType.EventId | EventIdCaptureType.EventName) });
LogManager.Configuration = config;
var logger = loggerFactory.CreateLogger("logger1");
logger.LogInformation(new EventId(2, "eventId_2"), "test message with {0} arg", 1);
Expand Down Expand Up @@ -98,17 +100,19 @@ public void AddNLog_LoggingBuilder_LogInfo_ShouldLogToNLog()

[Theory]
[InlineData("EventId", "eventId2", true)]
[InlineData("EventName", "", true)]
[InlineData("EventId_Name", "eventId2", true)]
[InlineData("EventId_Id", "2", true)]
[InlineData("EventId", "", false)]
[InlineData("EventId_Name", "eventId2", false)]
[InlineData("EventId_Id", "2", false)]
[InlineData("EventId", "2", false)]
[InlineData("EventName", "eventId2", false)]
[InlineData("EventId_Id", "", false)]
[InlineData("EventId_Name", "", false)]
public void AddNLog_LoggingBuilder_LogInfoWithEventId_ShouldLogToNLogWithEventId(string eventPropery, string expectedEventInLog, bool captureEntireEventId)
{
// Arrange
ILoggingBuilder builder = new LoggingBuilderStub();
var config = CreateConfigWithMemoryTarget(out var memoryTarget, $"${{event-properties:{eventPropery}}} - ${{message}}");
var options = new NLogProviderOptions { EventIdSeparator = "_", CaptureEventId = captureEntireEventId ? EventIdCaptureType.All : EventIdCaptureType.EventId_Id | EventIdCaptureType.EventId_Name };
var options = new NLogProviderOptions { EventIdSeparator = "_", CaptureEventId = captureEntireEventId ? EventIdCaptureType.Legacy : (EventIdCaptureType.EventId | EventIdCaptureType.EventName) };

// Act
builder.AddNLog(config, options);
Expand Down
8 changes: 2 additions & 6 deletions test/NLog.Extensions.Logging.Tests/nlog.config
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true" >

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<!-- the targets to write to -->
<targets>
<!-- write logs to file -->
<target xsi:type="Memory" name="target1"
layout="${logger}|${uppercase:${level}}|${message} ${exception}|${event-properties:EventId_Id}${event-properties:ParameterCount}${scopeproperty:item=scope1}" />

layout="${logger}|${uppercase:${level}}|${message} ${exception}|${event-properties:EventId}${event-properties:ParameterCount}${scopeproperty:item=scope1}" />
</targets>

<!-- rules to map from logger name to target -->
<rules>
<logger name="*" minlevel="Trace" writeTo="target1" />

</rules>
</nlog>

0 comments on commit 3f4aa0d

Please sign in to comment.