Skip to content

Commit 1db5335

Browse files
authored
summary: Log Forwarding Updates
feat: Allow forwarding of logs where context data is present but the message and exception are missing. Previously, logs with no message or exception were not forwarded, even if they held context data. feat: Add a supportability metric (Supportability/Logging/Forwarding/Empty) when an "empty" log event is not forwarded. Resolves #1472
1 parent 8fe8d63 commit 1db5335

File tree

6 files changed

+103
-5
lines changed

6 files changed

+103
-5
lines changed

src/Agent/NewRelic/Agent/Core/Agent.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -439,14 +439,15 @@ public void RecordLogMessage(string frameworkName, object logEvent, Func<object,
439439

440440
var logMessage = getLogMessage(logEvent);
441441
var logException = getLogException(logEvent);
442+
var logContextData = _configurationService.Configuration.ContextDataEnabled ? getContextData(logEvent) : null;
442443

443-
// exit quickly if the message and exception are missing
444-
if (string.IsNullOrWhiteSpace(logMessage) && logException is null)
444+
// exit quickly if the message, exception and context data are missing
445+
if (string.IsNullOrWhiteSpace(logMessage) && logException is null && (logContextData is null || logContextData.Count == 0))
445446
{
447+
_agentHealthReporter.ReportLoggingEventsEmpty();
446448
return;
447449
}
448450

449-
var logContextData = _configurationService.Configuration.ContextDataEnabled ? getContextData(logEvent) : null;
450451
var timestamp = getTimestamp(logEvent).ToUnixTimeMilliseconds();
451452

452453
LogEventWireModel logEventWireModel;

src/Agent/NewRelic/Agent/Core/AgentHealth/AgentHealthReporter.cs

+5
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,11 @@ public void ReportLogForwardingEnabledWithFramework(string logFramework)
571571
_loggingForwardingEnabledWithFrameworksReported.TryAdd(logFramework, false);
572572
}
573573

574+
public void ReportLoggingEventsEmpty(int count = 1)
575+
{
576+
ReportSupportabilityCountMetric(MetricNames.SupportabilityLoggingEventEmpty);
577+
}
578+
574579
public void CollectLoggingMetrics()
575580
{
576581
var totalCount = 0;

src/Agent/NewRelic/Agent/Core/AgentHealth/IAgentHealthReporter.cs

+1
Original file line numberDiff line numberDiff line change
@@ -148,5 +148,6 @@ public interface IAgentHealthReporter : IOutOfBandMetricSource
148148
void ReportLoggingEventsDropped(int droppedCount);
149149
void ReportLogForwardingFramework(string logFramework);
150150
void ReportLogForwardingEnabledWithFramework(string logFramework);
151+
void ReportLoggingEventsEmpty(int count = 1);
151152
}
152153
}

src/Agent/NewRelic/Agent/Core/Metrics/MetricNames.cs

+2
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ static MetricNames()
199199
});
200200
}
201201

202+
202203
public static MetricName GetCustom(string suffix)
203204
{
204205
return MetricName.Create(Custom, suffix);
@@ -1045,6 +1046,7 @@ public static string GetPerDestinationAreaDataUsageMetricName(string destination
10451046
public const string SupportabilityLoggingEventsSent = SupportabilityLoggingEventsPs + Forwarding + PathSeparator + "Sent";
10461047
public const string SupportabilityLoggingEventsCollected = SupportabilityLoggingEventsPs + Forwarding + PathSeparator + "Seen";
10471048
public const string SupportabilityLoggingEventsDropped = SupportabilityLoggingEventsPs + Forwarding + PathSeparator + "Dropped";
1049+
public const string SupportabilityLoggingEventEmpty = SupportabilityLoggingEventsPs + Forwarding + PathSeparator + "Empty";
10481050

10491051
public static string GetLoggingMetricsLinesBySeverityName(string logLevel)
10501052
{

tests/Agent/UnitTests/Core.UnitTest/AgentHealth/AgentHealthReporterTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ public void ReportLoggingSupportabilityMetrics()
312312
_agentHealthReporter.ReportLoggingEventCollected();
313313
_agentHealthReporter.ReportLoggingEventsSent(2);
314314
_agentHealthReporter.ReportLoggingEventsDropped(3);
315+
_agentHealthReporter.ReportLoggingEventsEmpty();
315316
_agentHealthReporter.ReportLogForwardingFramework("log4net");
316317

317318
_agentHealthReporter.ReportLogForwardingEnabledWithFramework("Framework1");
@@ -325,6 +326,7 @@ public void ReportLoggingSupportabilityMetrics()
325326
{ "Supportability/Logging/Forwarding/Seen", 1 },
326327
{ "Supportability/Logging/Forwarding/Sent", 2 },
327328
{ "Supportability/Logging/Forwarding/Dropped", 3 },
329+
{ "Supportability/Logging/Forwarding/Empty", 1 },
328330
{ "Supportability/Logging/Metrics/DotNET/enabled", 1 },
329331
{ "Supportability/Logging/Forwarding/DotNET/enabled", 1 },
330332
{ "Supportability/Logging/LocalDecorating/DotNET/enabled", 1 },

tests/Agent/UnitTests/Core.UnitTest/Wrapper/AgentWrapperApi/AgentWrapperApiTests.cs

+89-2
Original file line numberDiff line numberDiff line change
@@ -1351,7 +1351,50 @@ public void RecordLogMessage_NoTransaction_NoMessage_WithException_Success()
13511351
}
13521352

13531353
[Test]
1354-
public void RecordLogMessage_NoTransaction_NoMessage_NoException_DropsEvent()
1354+
public void RecordLogMessage_NoTransaction_NoMessage_NoException_WithContextData_Success()
1355+
{
1356+
Mock.Arrange(() => _configurationService.Configuration.LogEventCollectorEnabled)
1357+
.Returns(true);
1358+
Mock.Arrange(() => _configurationService.Configuration.ContextDataEnabled)
1359+
.Returns(true);
1360+
1361+
var timestamp = DateTime.Now;
1362+
var timestampUnix = timestamp.ToUnixTimeMilliseconds();
1363+
var level = "DEBUG";
1364+
string message = null;
1365+
var contextData = new Dictionary<string, object>() { { "key1", "value1" }, { "key2", 1 } };
1366+
1367+
Func<object, string> getLevelFunc = (l) => level;
1368+
Func<object, DateTime> getTimestampFunc = (l) => timestamp;
1369+
Func<object, string> getMessageFunc = (l) => message;
1370+
Func<object, Exception> getLogExceptionFunc = (l) => null;
1371+
Func<object, Dictionary<string, object>> getContextDataFunc = (l) => contextData;
1372+
1373+
var spanId = "spanid";
1374+
var traceId = "traceid";
1375+
var loggingFramework = "testFramework";
1376+
1377+
var xapi = _agent as IAgentExperimental;
1378+
xapi.RecordLogMessage(loggingFramework, new object(), getTimestampFunc, getLevelFunc, getMessageFunc, getLogExceptionFunc, getContextDataFunc, spanId, traceId);
1379+
1380+
// Access the private collection of events to get the number of add attempts.
1381+
var privateAccessor = new PrivateAccessor(_logEventAggregator);
1382+
var logEvents = privateAccessor.GetField("_logEvents") as ConcurrentPriorityQueue<PrioritizedNode<LogEventWireModel>>;
1383+
1384+
var logEvent = logEvents?.FirstOrDefault()?.Data;
1385+
Assert.AreEqual(1, logEvents.Count);
1386+
Assert.IsNotNull(logEvent);
1387+
Assert.AreEqual(timestampUnix, logEvent.TimeStamp);
1388+
Assert.AreEqual(level, logEvent.Level);
1389+
Assert.AreEqual(message, logEvent.Message);
1390+
Assert.AreEqual(spanId, logEvent.SpanId);
1391+
Assert.AreEqual(traceId, logEvent.TraceId);
1392+
Assert.AreEqual(contextData, logEvent.ContextData);
1393+
Assert.IsNotNull(logEvent.Priority);
1394+
}
1395+
1396+
[Test]
1397+
public void RecordLogMessage_NoTransaction_NoMessage_NoException_NoContextData_DropsEvent()
13551398
{
13561399
Mock.Arrange(() => _configurationService.Configuration.LogEventCollectorEnabled)
13571400
.Returns(true);
@@ -1473,7 +1516,51 @@ public void RecordLogMessage_WithTransaction_NoMessage_WithException_Success()
14731516
}
14741517

14751518
[Test]
1476-
public void RecordLogMessage_WithTransaction_NoMessage_NoException_DropsEvent()
1519+
public void RecordLogMessage_WithTransaction_NoMessage_NoException_WithContextData_Success()
1520+
{
1521+
Mock.Arrange(() => _configurationService.Configuration.LogEventCollectorEnabled)
1522+
.Returns(true);
1523+
Mock.Arrange(() => _configurationService.Configuration.ContextDataEnabled)
1524+
.Returns(true);
1525+
1526+
var timestamp = DateTime.Now;
1527+
var timestampUnix = timestamp.ToUnixTimeMilliseconds();
1528+
var level = "DEBUG";
1529+
string message = null;
1530+
var contextData = new Dictionary<string, object>() { { "key1", "value1" }, { "key2", 1 } };
1531+
1532+
Func<object, string> getLevelFunc = (l) => level;
1533+
Func<object, DateTime> getTimestampFunc = (l) => timestamp;
1534+
Func<object, string> getMessageFunc = (l) => message;
1535+
Func<object, Exception> getLogExceptionFunc = (l) => null;
1536+
Func<object, Dictionary<string, object>> getContextDataFunc = (l) => contextData;
1537+
1538+
var spanId = "spanid";
1539+
var traceId = "traceid";
1540+
var loggingFramework = "testFramework";
1541+
1542+
SetupTransaction();
1543+
var transaction = _transactionService.GetCurrentInternalTransaction();
1544+
var priority = transaction.Priority;
1545+
1546+
var xapi = _agent as IAgentExperimental;
1547+
xapi.RecordLogMessage(loggingFramework, new object(), getTimestampFunc, getLevelFunc, getMessageFunc, getLogExceptionFunc, getContextDataFunc, spanId, traceId);
1548+
1549+
var harvestedLogEvents = transaction.HarvestLogEvents();
1550+
var logEvent = harvestedLogEvents.FirstOrDefault();
1551+
Assert.AreEqual(1, harvestedLogEvents.Count);
1552+
Assert.IsNotNull(logEvent);
1553+
Assert.AreEqual(timestampUnix, logEvent.TimeStamp);
1554+
Assert.AreEqual(level, logEvent.Level);
1555+
Assert.AreEqual(message, logEvent.Message);
1556+
Assert.AreEqual(spanId, logEvent.SpanId);
1557+
Assert.AreEqual(traceId, logEvent.TraceId);
1558+
Assert.AreEqual(contextData, logEvent.ContextData);
1559+
Assert.AreEqual(priority, logEvent.Priority);
1560+
}
1561+
1562+
[Test]
1563+
public void RecordLogMessage_WithTransaction_NoMessage_NoException_NoContextData_DropsEvent()
14771564
{
14781565
Mock.Arrange(() => _configurationService.Configuration.LogEventCollectorEnabled)
14791566
.Returns(true);

0 commit comments

Comments
 (0)