Skip to content

Commit 9b04c11

Browse files
authored
Avoid boxing when using positional logging parameters (#787)
1 parent 3555797 commit 9b04c11

File tree

3 files changed

+47
-29
lines changed

3 files changed

+47
-29
lines changed

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

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -64,44 +64,29 @@ public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, EventId
6464
switch (((IReadOnlyList<KeyValuePair<string, object?>>)state).Count)
6565
{
6666
case 0:
67-
if (captureEventId)
6867
{
6968
var formattedMessage = formatter(state, exception);
70-
var eventIdParameterCount = GetEventIdMessageParameters(eventId, out var eventIdArg1, out var eventIdArg2);
71-
if (eventIdParameterCount == 0)
72-
return new LogEventInfo(nLogLogLevel, _logger.Name, formattedMessage);
73-
else if (eventIdParameterCount == 1)
74-
return new LogEventInfo(nLogLogLevel, _logger.Name, formattedMessage, formattedMessage, [eventIdArg1]);
75-
else
76-
return new LogEventInfo(nLogLogLevel, _logger.Name, formattedMessage, formattedMessage, [eventIdArg1, eventIdArg2]);
69+
return CreateLogEventWithoutParameters(nLogLogLevel, eventId, captureEventId, formattedMessage);
7770
}
78-
return new LogEventInfo(nLogLogLevel, _logger.Name, formatter(state, exception));
7971
case 1:
8072
parameterCount = 1;
8173
if (OriginalFormatPropertyName.Equals(((IReadOnlyList<KeyValuePair<string, object?>>)state)[0].Key))
8274
{
8375
var formattedMessage = formatter(state, exception);
84-
if (captureEventId)
85-
{
86-
var eventIdParameterCount = GetEventIdMessageParameters(eventId, out var eventIdArg1, out var eventIdArg2);
87-
if (eventIdParameterCount == 0)
88-
return new LogEventInfo(nLogLogLevel, _logger.Name, formattedMessage);
89-
else if (eventIdParameterCount == 1)
90-
return new LogEventInfo(nLogLogLevel, _logger.Name, formattedMessage, formattedMessage, [eventIdArg1]);
91-
else
92-
return new LogEventInfo(nLogLogLevel, _logger.Name, formattedMessage, formattedMessage, [eventIdArg1, eventIdArg2]);
93-
}
94-
return new LogEventInfo(nLogLogLevel, _logger.Name, formattedMessage);
76+
return CreateLogEventWithoutParameters(nLogLogLevel, eventId, captureEventId, formattedMessage);
9577
}
9678
break;
9779
case 2:
9880
parameterCount = 2;
9981
if (_options.CaptureMessageTemplates && !_options.CaptureMessageParameters && !_options.ParseMessageTemplates && OriginalFormatPropertyName.Equals(((IReadOnlyList<KeyValuePair<string, object?>>)state)[1].Key))
10082
{
101-
var arg1 = NLogMessageParameterList.GetMessageTemplateParameter(((IReadOnlyList<KeyValuePair<string, object?>>)state)[0]);
83+
var arg1 = NLogMessageParameterList.GetMessageTemplateParameter(((IReadOnlyList<KeyValuePair<string, object?>>)state)[0], 0);
10284
if (arg1.Name is not null)
10385
{
10486
var formattedMessage = formatter(state, exception);
87+
if ("0".Equals(arg1.Name))
88+
return CreateLogEventWithoutParameters(nLogLogLevel, eventId, captureEventId, formattedMessage);
89+
10590
if (captureEventId)
10691
{
10792
var eventIdParameterCount = GetEventIdMessageParameters(eventId, out var eventIdArg1, out var eventIdArg2);
@@ -118,13 +103,16 @@ public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, EventId
118103
break;
119104
case 3:
120105
parameterCount = 3;
121-
if (_options.CaptureMessageTemplates && !_options.CaptureMessageParameters && !_options.ParseMessageTemplates && OriginalFormatPropertyName.Equals(((IReadOnlyList<KeyValuePair<string, object?>>)state)[1].Key))
106+
if (_options.CaptureMessageTemplates && !_options.CaptureMessageParameters && !_options.ParseMessageTemplates && OriginalFormatPropertyName.Equals(((IReadOnlyList<KeyValuePair<string, object?>>)state)[2].Key))
122107
{
123-
var arg1 = NLogMessageParameterList.GetMessageTemplateParameter(((IReadOnlyList<KeyValuePair<string, object?>>)state)[0]);
124-
var arg2 = NLogMessageParameterList.GetMessageTemplateParameter(((IReadOnlyList<KeyValuePair<string, object?>>)state)[1]);
108+
var arg1 = NLogMessageParameterList.GetMessageTemplateParameter(((IReadOnlyList<KeyValuePair<string, object?>>)state)[0], 0);
109+
var arg2 = NLogMessageParameterList.GetMessageTemplateParameter(((IReadOnlyList<KeyValuePair<string, object?>>)state)[1], 1);
125110
if (arg1.Name is not null && arg2.Name is not null)
126111
{
127112
var formattedMessage = formatter(state, exception);
113+
if ("0".Equals(arg1.Name) && "1".Equals(arg2.Name))
114+
return CreateLogEventWithoutParameters(nLogLogLevel, eventId, captureEventId, formattedMessage);
115+
128116
if (captureEventId)
129117
{
130118
var eventIdParameterCount = GetEventIdMessageParameters(eventId, out var eventIdArg1, out var eventIdArg2);
@@ -144,12 +132,15 @@ public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, EventId
144132
parameterCount = 4;
145133
if (_options.CaptureMessageTemplates && !_options.CaptureMessageParameters && !_options.ParseMessageTemplates && OriginalFormatPropertyName.Equals(((IReadOnlyList<KeyValuePair<string, object?>>)state)[3].Key))
146134
{
147-
var arg1 = NLogMessageParameterList.GetMessageTemplateParameter(((IReadOnlyList<KeyValuePair<string, object?>>)state)[0]);
148-
var arg2 = NLogMessageParameterList.GetMessageTemplateParameter(((IReadOnlyList<KeyValuePair<string, object?>>)state)[1]);
149-
var arg3 = NLogMessageParameterList.GetMessageTemplateParameter(((IReadOnlyList<KeyValuePair<string, object?>>)state)[1]);
135+
var arg1 = NLogMessageParameterList.GetMessageTemplateParameter(((IReadOnlyList<KeyValuePair<string, object?>>)state)[0], 0);
136+
var arg2 = NLogMessageParameterList.GetMessageTemplateParameter(((IReadOnlyList<KeyValuePair<string, object?>>)state)[1], 1);
137+
var arg3 = NLogMessageParameterList.GetMessageTemplateParameter(((IReadOnlyList<KeyValuePair<string, object?>>)state)[2], 2);
150138
if (arg1.Name is not null && arg2.Name is not null && arg3.Name is not null)
151139
{
152140
var formattedMessage = formatter(state, exception);
141+
if ("0".Equals(arg1.Name) && "1".Equals(arg2.Name) && "2".Equals(arg3.Name))
142+
return CreateLogEventWithoutParameters(nLogLogLevel, eventId, captureEventId, formattedMessage);
143+
153144
if (captureEventId)
154145
{
155146
var eventIdParameterCount = GetEventIdMessageParameters(eventId, out var eventIdArg1, out var eventIdArg2);
@@ -175,6 +166,21 @@ public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, EventId
175166

176167
return null;
177168
}
169+
170+
private LogEventInfo CreateLogEventWithoutParameters(LogLevel nLogLogLevel, in EventId eventId, bool captureEventId, string formattedMessage)
171+
{
172+
if (captureEventId)
173+
{
174+
var eventIdParameterCount = GetEventIdMessageParameters(eventId, out var eventIdArg1, out var eventIdArg2);
175+
if (eventIdParameterCount == 0)
176+
return new LogEventInfo(nLogLogLevel, _logger.Name, formattedMessage);
177+
else if (eventIdParameterCount == 1)
178+
return new LogEventInfo(nLogLogLevel, _logger.Name, formattedMessage, formattedMessage, [eventIdArg1]);
179+
else
180+
return new LogEventInfo(nLogLogLevel, _logger.Name, formattedMessage, formattedMessage, [eventIdArg1, eventIdArg2]);
181+
}
182+
return new LogEventInfo(nLogLogLevel, _logger.Name, formattedMessage);
183+
}
178184
#endif
179185

180186
private LogEventInfo CreateLogEventInfo<TState>(LogLevel nLogLogLevel, in EventId eventId, in TState state, Exception? exception, Func<TState, Exception?, string> formatter)

src/NLog.Extensions.Logging/Logging/NLogMessageParameterList.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,16 @@ public MessageTemplateParameter this[int index]
187187
set => throw new NotSupportedException();
188188
}
189189

190-
internal static MessageTemplateParameter GetMessageTemplateParameter(in KeyValuePair<string, object?> propertyValue)
190+
internal static MessageTemplateParameter GetMessageTemplateParameter(in KeyValuePair<string, object?> propertyValue, int index)
191191
{
192192
var propertyName = propertyValue.Key;
193193
if (propertyName is null || propertyName.Length == 0)
194194
return default;
195195
var firstChar = propertyName[0];
196-
if (char.IsDigit(firstChar) || GetCaptureType(firstChar) != CaptureType.Normal)
196+
if (char.IsDigit(firstChar) && (propertyName.Length != 1 || (firstChar - '0') != index))
197+
return default;
198+
199+
if (GetCaptureType(firstChar) != CaptureType.Normal)
197200
return default;
198201

199202
return new MessageTemplateParameter(propertyName, propertyValue.Value, null, CaptureType.Normal);

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,15 @@ public void TestTwoReverseParameters()
5555
Assert.Equal("NLog.Extensions.Logging.Tests.LoggerTests.Runner|DEBUG|message with id and 2 parameters|", runner.LastTargetMessage);
5656
}
5757

58+
[Fact]
59+
public void TestThreeParameters()
60+
{
61+
var runner = GetRunner();
62+
runner.Logger.LogDebug("message with {0} and {1} and {2} parameters", "id", "username", 3);
63+
64+
Assert.Equal("NLog.Extensions.Logging.Tests.LoggerTests.Runner|DEBUG|message with id and username and 3 parameters|", runner.LastTargetMessage);
65+
}
66+
5867
[Fact]
5968
public void TestStructuredLogging()
6069
{

0 commit comments

Comments
 (0)