Skip to content

Commit 6196af5

Browse files
authored
fix: Nested logging contexts should not disable context data for Microsoft.Extensions.Logging (2508) (#2516)
1 parent 669e194 commit 6196af5

File tree

15 files changed

+193
-49
lines changed

15 files changed

+193
-49
lines changed

src/Agent/NewRelic/Agent/Core/Logging/Logger.cs

+29-6
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,47 @@ public bool IsEnabledFor(Level level)
3434
public void Log(Level level, string message)
3535
{
3636
if (!IsEnabledFor(level)) return;
37-
var messageString = message.ToString();
3837

3938
switch (level)
4039
{
4140
case Level.Finest:
42-
_logger.Verbose(messageString);
41+
_logger.Verbose(message);
4342
break;
4443
case Level.Debug:
45-
_logger.Debug(messageString);
44+
_logger.Debug(message);
4645
break;
4746
case Level.Info:
48-
_logger.Information(messageString);
47+
_logger.Information(message);
4948
break;
5049
case Level.Warn:
51-
_logger.Warning(messageString);
50+
_logger.Warning(message);
5251
break;
5352
case Level.Error:
54-
_logger.Error(messageString);
53+
_logger.Error(message);
54+
break;
55+
}
56+
}
57+
58+
public void Log(Level level, Exception ex, string message)
59+
{
60+
if (!IsEnabledFor(level)) return;
61+
62+
switch (level)
63+
{
64+
case Level.Finest:
65+
_logger.Verbose(ex, message);
66+
break;
67+
case Level.Debug:
68+
_logger.Debug(ex, message);
69+
break;
70+
case Level.Info:
71+
_logger.Information(ex, message);
72+
break;
73+
case Level.Warn:
74+
_logger.Warning(ex, message);
75+
break;
76+
case Level.Error:
77+
_logger.Error(ex, message);
5578
break;
5679
}
5780
}

src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Logging/ILogger.cs

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright 2020 New Relic, Inc. All rights reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
using System;
5+
46
namespace NewRelic.Agent.Extensions.Logging
57
{
68
public enum Level
@@ -16,5 +18,6 @@ public interface ILogger
1618
{
1719
bool IsEnabledFor(Level level);
1820
void Log(Level level, string message);
21+
void Log(Level level, Exception ex, string message);
1922
}
2023
}

src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/MicrosoftExtensionsLogging/MicrosoftLoggingWrapper.cs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2020 New Relic, Inc. All rights reserved.
1+
// Copyright 2020 New Relic, Inc. All rights reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

44
using System;
@@ -59,7 +59,7 @@ private void RecordLogMessage(MethodCall methodCall, MEL.ILogger logger, IAgent
5959
Func<object, string> getLevelFunc = mc => ((MethodCall)mc).MethodArguments[0].ToString();
6060
Func<object, string> getRenderedMessageFunc = mc => ((MethodCall)mc).MethodArguments[2].ToString();
6161
Func<object, Exception> getLogExceptionFunc = mc => ((MethodCall)mc).MethodArguments[3] as Exception; // using "as" since we want a null if missing
62-
Func<object, Dictionary<string, object>> getContextDataFunc = nothx => GetContextData(logger, agent);
62+
Func<object, Dictionary<string, object>> getContextDataFunc = _ => GetContextData(logger, agent);
6363

6464
var xapi = agent.GetExperimentalApi();
6565
xapi.RecordLogMessage(WrapperName, methodCall, getTimestampFunc, getLevelFunc, getRenderedMessageFunc, getLogExceptionFunc, getContextDataFunc, agent.TraceMetadata.SpanId, agent.TraceMetadata.TraceId);
@@ -83,7 +83,7 @@ private static Dictionary<string, object> GetContextData(MEL.ILogger logger, IAg
8383

8484
// Get the last ScopeLogger in the array (logger.ScopeLoggers[loggers.Length-1])
8585
// If there is more than one scope logger, the last logger is the one with the ExternalScopeProvider set
86-
object lastLogger = loggers.GetValue(loggers.Length-1);
86+
object lastLogger = loggers.GetValue(loggers.Length - 1);
8787

8888
// Get the scope provider from that logger (logger.ScopeLoggers[loggers.Length-1].ExternalScopeProvider)
8989
var scopeProviderPI = _scopeProviderPropertyInfo ??= lastLogger.GetType().GetProperty("ExternalScopeProvider");
@@ -97,12 +97,12 @@ private static Dictionary<string, object> GetContextData(MEL.ILogger logger, IAg
9797
{
9898
foreach (var kvp in kvps)
9999
{
100-
accumulatedKvps.Add(kvp.Key, kvp.Value);
100+
accumulatedKvps[kvp.Key] = kvp.Value; // use this notation to ensure we keep the last value in case nested scopes have the same key
101101
}
102102
}
103103
else if (scopeObject is KeyValuePair<string, object> kvp)
104104
{
105-
accumulatedKvps.Add(kvp.Key, kvp.Value);
105+
accumulatedKvps[kvp.Key] = kvp.Value; // use this notation to ensure we keep the last value in case nested scopes have the same key
106106
}
107107
// Possibly handle case of IEnumerable<KeyValuePair<object, object>>, etc (not now though)
108108
}, harvestedKvps);
@@ -111,7 +111,7 @@ private static Dictionary<string, object> GetContextData(MEL.ILogger logger, IAg
111111
}
112112
catch (Exception e)
113113
{
114-
agent.Logger.Log(Level.Warn, $"Unexpected exception while attempting to get context data. Context data is not supported for this logging framework. Exception: {e}");
114+
agent.Logger.Log(Level.Warn, e, $"Unexpected exception while attempting to get context data. Context data is not supported for this logging framework.");
115115
_contextDataNotSupported = true;
116116
return null;
117117
}

0 commit comments

Comments
 (0)