Skip to content

Commit 39b4fd0

Browse files
authored
NLogProviderOptions with support for CaptureEventId.EventId + EventName (#554)
1 parent 8fb3621 commit 39b4fd0

7 files changed

Lines changed: 67 additions & 49 deletions

File tree

src/NLog.Extensions.Logging/LayoutRenderers/MicrosoftConsoleLayoutRenderer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ protected override void Append(StringBuilder builder, LogEventInfo logEvent)
6666
private static int LookupEventId(LogEventInfo logEvent)
6767
{
6868
int eventId = 0;
69-
if (logEvent.HasProperties && (logEvent.Properties.TryGetValue("EventId_Id", out var eventIdValue) || logEvent.Properties.TryGetValue("EventId", out eventIdValue)))
69+
if (logEvent.HasProperties && (logEvent.Properties.TryGetValue(nameof(EventIdCaptureType.EventId_Id), out var eventIdValue) || logEvent.Properties.TryGetValue(nameof(EventIdCaptureType.EventId), out eventIdValue)))
7070
{
7171
if (eventIdValue is int)
7272
eventId = (int)eventIdValue;

src/NLog.Extensions.Logging/Layouts/MicrosoftConsoleJsonLayout.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ public MicrosoftConsoleJsonLayout()
2727
Attributes.Add(new JsonAttribute("Message", "${message}"));
2828
Attributes.Add(new JsonAttribute("Exception", "${replace-newlines:${exception:format=tostring,data}}"));
2929
var stateJsonLayout = new JsonLayout() { IncludeEventProperties = true };
30-
stateJsonLayout.ExcludeProperties.Add("EventId");
31-
stateJsonLayout.ExcludeProperties.Add("EventId_Id");
30+
stateJsonLayout.ExcludeProperties.Add(nameof(EventIdCaptureType.EventId));
31+
stateJsonLayout.ExcludeProperties.Add(nameof(EventIdCaptureType.EventId_Id));
3232
stateJsonLayout.Attributes.Add(new JsonAttribute("{OriginalFormat}", "${message:raw=true}"));
3333
Attributes.Add(new JsonAttribute("State", stateJsonLayout) { Encode = false });
3434
}
@@ -108,15 +108,15 @@ private static string LookupEventId(LogEventInfo logEvent)
108108
{
109109
if (logEvent.HasProperties)
110110
{
111-
if (logEvent.Properties.TryGetValue("EventId", out var eventObject))
111+
if (logEvent.Properties.TryGetValue(nameof(EventIdCaptureType.EventId), out var eventObject))
112112
{
113113
if (eventObject is int eventId)
114114
return ConvertEventId(eventId);
115115
else if (eventObject is Microsoft.Extensions.Logging.EventId eventIdStruct)
116116
return ConvertEventId(eventIdStruct.Id);
117117
}
118118

119-
if (logEvent.Properties.TryGetValue("EventId_Id", out var eventid) && eventid is int)
119+
if (logEvent.Properties.TryGetValue(nameof(EventIdCaptureType.EventId_Id), out var eventid) && eventid is int)
120120
{
121121
return ConvertEventId((int)eventid);
122122
}

src/NLog.Extensions.Logging/Logging/EventIdCaptureType.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,28 @@ public enum EventIdCaptureType
1313
/// </summary>
1414
None = 0,
1515
/// <summary>
16-
/// Capture entire <see cref="Microsoft.Extensions.Logging.EventId"/> as "EventId"-property (with boxing)
16+
/// Capture integer <see cref="Microsoft.Extensions.Logging.EventId.Id"/> as "EventId"-property
1717
/// </summary>
1818
EventId = 1,
1919
/// <summary>
20-
/// Capture <see cref="Microsoft.Extensions.Logging.EventId.Id"/> as "EventId_Id"-property.
20+
/// Capture string <see cref="Microsoft.Extensions.Logging.EventId.Name"/> as "EventName"-property
2121
/// </summary>
22-
EventId_Id = 2,
22+
EventName = 2,
2323
/// <summary>
24-
/// Capture <see cref="Microsoft.Extensions.Logging.EventId.Name"/> as "EventId_Name"-property.
24+
/// Capture struct <see cref="Microsoft.Extensions.Logging.EventId"/> as "EventId"-property (with boxing)
2525
/// </summary>
26-
EventId_Name = 4,
26+
EventIdStruct = 4,
2727
/// <summary>
28-
/// Capture all properties (Legacy)
28+
/// Capture integer <see cref="Microsoft.Extensions.Logging.EventId.Id"/> as "EventId_Id"-property (Legacy)
2929
/// </summary>
30-
All = EventId | EventId_Id | EventId_Name,
30+
EventId_Id = 8,
31+
/// <summary>
32+
/// Capture string <see cref="Microsoft.Extensions.Logging.EventId.Name"/> as "EventId_Name"-property (Legacy)
33+
/// </summary>
34+
EventId_Name = 16,
35+
/// <summary>
36+
/// Captures legacy properties (EventId-struct + EventId_Id + EventId_Name)
37+
/// </summary>
38+
Legacy = EventIdStruct | EventId_Id | EventId_Name,
3139
}
3240
}

src/NLog.Extensions.Logging/Logging/NLogLogger.cs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -299,23 +299,32 @@ private void CaptureEventIdProperties(LogEventInfo logEvent, EventId eventId)
299299
var captureEventId = _options.CaptureEventId;
300300
if (captureEventId != EventIdCaptureType.None && IncludeEventIdProperties(eventId))
301301
{
302-
// Attempt to reuse the same string-allocations based on the current <see cref="NLogProviderOptions.EventIdSeparator"/>
303-
var eventIdPropertyNames = _eventIdPropertyNames ?? new Tuple<string, string, string>(null, null, null);
304-
var eventIdSeparator = _options.EventIdSeparator ?? String.Empty;
305-
if (!ReferenceEquals(eventIdPropertyNames.Item1, eventIdSeparator))
302+
if ((captureEventId & EventIdCaptureType.EventId) != 0)
303+
logEvent.Properties[nameof(EventIdCaptureType.EventId)] = GetEventId(eventId.Id);
304+
305+
if ((captureEventId & EventIdCaptureType.EventName) != 0 && eventId.Name != null)
306+
logEvent.Properties[nameof(EventIdCaptureType.EventName)] = eventId.Name;
307+
308+
if ((captureEventId & EventIdCaptureType.Legacy) != 0)
306309
{
307-
// Perform atomic cache update of the string-allocations matching the current separator
308-
_eventIdPropertyNames = eventIdPropertyNames = CreateEventIdPropertyNames(eventIdSeparator);
309-
}
310+
// Attempt to reuse the same string-allocations based on the current <see cref="NLogProviderOptions.EventIdSeparator"/>
311+
var eventIdPropertyNames = _eventIdPropertyNames ?? new Tuple<string, string, string>(null, null, null);
312+
var eventIdSeparator = _options.EventIdSeparator ?? String.Empty;
313+
if (!ReferenceEquals(eventIdPropertyNames.Item1, eventIdSeparator))
314+
{
315+
// Perform atomic cache update of the string-allocations matching the current separator
316+
_eventIdPropertyNames = eventIdPropertyNames = CreateEventIdPropertyNames(eventIdSeparator);
317+
}
310318

311-
if ((captureEventId & EventIdCaptureType.EventId_Id) != 0)
312-
logEvent.Properties[eventIdPropertyNames.Item2] = eventId.Id == 0 ? ZeroEventId : GetEventId(eventId.Id);
319+
if ((captureEventId & EventIdCaptureType.EventId_Id) != 0)
320+
logEvent.Properties[eventIdPropertyNames.Item2] = GetEventId(eventId.Id);
313321

314-
if ((captureEventId & EventIdCaptureType.EventId_Name) != 0 && eventId.Name != null)
315-
logEvent.Properties[eventIdPropertyNames.Item3] = eventId.Name;
322+
if ((captureEventId & EventIdCaptureType.EventId_Name) != 0 && eventId.Name != null)
323+
logEvent.Properties[eventIdPropertyNames.Item3] = eventId.Name;
316324

317-
if ((captureEventId & EventIdCaptureType.EventId) != 0)
318-
logEvent.Properties[nameof(EventId)] = eventId;
325+
if ((captureEventId & EventIdCaptureType.EventIdStruct) != 0)
326+
logEvent.Properties[nameof(EventIdCaptureType.EventId)] = eventId;
327+
}
319328
}
320329
}
321330

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

340349
private static object GetEventId(int eventId)
341350
{
342-
if (eventId >= 0 && eventId < EventIdBoxing.Length)
351+
if (eventId == 0)
352+
return ZeroEventId;
353+
if (eventId > 0 && eventId < EventIdBoxing.Length)
343354
return EventIdBoxing[eventId];
344-
else
345-
return eventId;
355+
return eventId;
346356
}
347357

348358
private static void CaptureMessageProperties(LogEventInfo logEvent, IEnumerable<KeyValuePair<string, object>> messageProperties)

src/NLog.Extensions.Logging/Logging/NLogProviderOptions.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,22 @@ namespace NLog.Extensions.Logging
88
public class NLogProviderOptions
99
{
1010
/// <summary>
11-
/// Separator between for EventId.Id and EventId.Name. Default to _
11+
/// Control capture of <see cref="Microsoft.Extensions.Logging.EventId"/> as "EventId"-property.
1212
/// </summary>
13-
public string EventIdSeparator { get; set; } = "_";
13+
public EventIdCaptureType CaptureEventId { get; set; } = EventIdCaptureType.EventId | EventIdCaptureType.EventName;
1414

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

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

2828
/// <summary>
2929
/// Enable structured logging by capturing message template parameters with support for "@" and "$". Enables use of ${message:raw=true}

test/NLog.Extensions.Logging.Tests/Extensions/ConfigureExtensionsTests.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ public void AddNLog_LoggerFactory_LogInfo_ShouldLogToNLog()
3232

3333
[Theory]
3434
[InlineData("EventId", "eventId_2", true)]
35-
[InlineData("EventId_Name", "eventId_2", true)]
35+
[InlineData("EventName", "", true)]
3636
[InlineData("EventId_Id", "2", true)]
37-
[InlineData("EventId", "", false)]
38-
[InlineData("EventId_Name", "eventId_2", false)]
39-
[InlineData("EventId_Id", "2", false)]
37+
[InlineData("EventId_Name", "eventId_2", true)]
38+
[InlineData("EventId", "2", false)]
39+
[InlineData("EventName", "eventId_2", false)]
40+
[InlineData("EventId_Id", "", false)]
41+
[InlineData("EventId_Name", "", false)]
4042
[Obsolete("Instead use ILoggingBuilder.AddNLog() or IHostBuilder.UseNLog()")]
4143
public void AddNLog_LoggerFactory_LogInfoWithEventId_ShouldLogToNLogWithEventId(string eventPropery, string expectedEventInLog, bool captureEntireEventId)
4244
{
@@ -45,7 +47,7 @@ public void AddNLog_LoggerFactory_LogInfoWithEventId_ShouldLogToNLogWithEventId(
4547
var config = CreateConfigWithMemoryTarget(out var memoryTarget, $"${{event-properties:{eventPropery}}} - ${{message}}");
4648

4749
// Act
48-
loggerFactory.AddNLog(new NLogProviderOptions { EventIdSeparator = "_", CaptureEventId = captureEntireEventId ? EventIdCaptureType.All : EventIdCaptureType.EventId_Id | EventIdCaptureType.EventId_Name });
50+
loggerFactory.AddNLog(new NLogProviderOptions { EventIdSeparator = "_", CaptureEventId = captureEntireEventId ? EventIdCaptureType.Legacy : (EventIdCaptureType.EventId | EventIdCaptureType.EventName) });
4951
LogManager.Configuration = config;
5052
var logger = loggerFactory.CreateLogger("logger1");
5153
logger.LogInformation(new EventId(2, "eventId_2"), "test message with {0} arg", 1);
@@ -97,17 +99,19 @@ public void AddNLog_LoggingBuilder_LogInfo_ShouldLogToNLog()
9799

98100
[Theory]
99101
[InlineData("EventId", "eventId2", true)]
102+
[InlineData("EventName", "", true)]
100103
[InlineData("EventId_Name", "eventId2", true)]
101104
[InlineData("EventId_Id", "2", true)]
102-
[InlineData("EventId", "", false)]
103-
[InlineData("EventId_Name", "eventId2", false)]
104-
[InlineData("EventId_Id", "2", false)]
105+
[InlineData("EventId", "2", false)]
106+
[InlineData("EventName", "eventId2", false)]
107+
[InlineData("EventId_Id", "", false)]
108+
[InlineData("EventId_Name", "", false)]
105109
public void AddNLog_LoggingBuilder_LogInfoWithEventId_ShouldLogToNLogWithEventId(string eventPropery, string expectedEventInLog, bool captureEntireEventId)
106110
{
107111
// Arrange
108112
ILoggingBuilder builder = new LoggingBuilderStub();
109113
var config = CreateConfigWithMemoryTarget(out var memoryTarget, $"${{event-properties:{eventPropery}}} - ${{message}}");
110-
var options = new NLogProviderOptions { EventIdSeparator = "_", CaptureEventId = captureEntireEventId ? EventIdCaptureType.All : EventIdCaptureType.EventId_Id | EventIdCaptureType.EventId_Name };
114+
var options = new NLogProviderOptions { EventIdSeparator = "_", CaptureEventId = captureEntireEventId ? EventIdCaptureType.Legacy : (EventIdCaptureType.EventId | EventIdCaptureType.EventName) };
111115

112116
// Act
113117
builder.AddNLog(config, options);
Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
autoReload="true" >
5-
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
64

75
<!-- the targets to write to -->
86
<targets>
97
<!-- write logs to file -->
108
<target xsi:type="Memory" name="target1"
11-
layout="${logger}|${uppercase:${level}}|${message} ${exception}|${event-properties:EventId_Id}${event-properties:ParameterCount}${scopeproperty:item=scope1}" />
12-
9+
layout="${logger}|${uppercase:${level}}|${message} ${exception}|${event-properties:EventId}${event-properties:ParameterCount}${scopeproperty:item=scope1}" />
1310
</targets>
1411

1512
<!-- rules to map from logger name to target -->
1613
<rules>
1714
<logger name="*" minlevel="Trace" writeTo="target1" />
18-
1915
</rules>
2016
</nlog>

0 commit comments

Comments
 (0)