Skip to content

Commit

Permalink
feat:Include APM Labels in forwarded application logs.
Browse files Browse the repository at this point in the history
  • Loading branch information
jaffinito committed Oct 15, 2024
1 parent b00edda commit fcfe46d
Show file tree
Hide file tree
Showing 25 changed files with 484 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using NewRelic.Agent.Extensions.Collections;
using NewRelic.Agent.Extensions.Logging;
using NewRelic.Agent.Core.SharedInterfaces;
using NewRelic.Agent.Core.Labels;

namespace NewRelic.Agent.Core.Aggregators
{
Expand All @@ -31,14 +32,17 @@ public class LogEventAggregator : AbstractAggregator<LogEventWireModel>, ILogEve
private const double ReservoirReductionSizeMultiplier = 0.5;

private readonly IAgentHealthReporter _agentHealthReporter;
private readonly ILabelsService _labelsService;

private ConcurrentPriorityQueue<PrioritizedNode<LogEventWireModel>> _logEvents = new ConcurrentPriorityQueue<PrioritizedNode<LogEventWireModel>>(0);
private int _logsDroppedCount;

public LogEventAggregator(IDataTransportService dataTransportService, IScheduler scheduler, IProcessStatic processStatic, IAgentHealthReporter agentHealthReporter)
public LogEventAggregator(IDataTransportService dataTransportService, IScheduler scheduler, IProcessStatic processStatic, IAgentHealthReporter agentHealthReporter,
ILabelsService labelsService)
: base(dataTransportService, scheduler, processStatic)
{
_agentHealthReporter = agentHealthReporter;
_labelsService = labelsService;
ResetCollections(_configuration.LogEventsMaxSamplesStored);
}

Expand Down Expand Up @@ -98,6 +102,7 @@ protected void InternalHarvest(string transactionId = null)
_configuration.ApplicationNames.ElementAt(0),
_configuration.EntityGuid,
hostname,
_configuration.IncludeLabelsEnabled ? _labelsService.GetFilteredLabels(_configuration.IncludeLabelsExclude) : [],
aggregatedEvents);

var responseStatus = DataTransportService.Send(modelsCollection, transactionId);
Expand Down
74 changes: 74 additions & 0 deletions src/Agent/NewRelic/Agent/Core/Config/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5457,6 +5457,8 @@ public partial class configurationApplicationLoggingForwarding

private configurationApplicationLoggingForwardingContextData contextDataField;

private configurationApplicationLoggingForwardingIncludeLabels includeLabelsField;

private bool enabledField;

private int maxSamplesStoredField;
Expand All @@ -5468,6 +5470,7 @@ public partial class configurationApplicationLoggingForwarding
/// </summary>
public configurationApplicationLoggingForwarding()
{
this.includeLabelsField = new configurationApplicationLoggingForwardingIncludeLabels();
this.contextDataField = new configurationApplicationLoggingForwardingContextData();
this.enabledField = true;
this.maxSamplesStoredField = 10000;
Expand All @@ -5485,6 +5488,18 @@ public configurationApplicationLoggingForwardingContextData contextData
}
}

public configurationApplicationLoggingForwardingIncludeLabels includeLabels
{
get
{
return this.includeLabelsField;
}
set
{
this.includeLabelsField = value;
}
}

[System.Xml.Serialization.XmlAttributeAttribute()]
[System.ComponentModel.DefaultValueAttribute(true)]
public bool enabled
Expand Down Expand Up @@ -5613,6 +5628,65 @@ public virtual configurationApplicationLoggingForwardingContextData Clone()
#endregion
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("Xsd2Code", "3.6.0.20097")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:newrelic-config")]
public partial class configurationApplicationLoggingForwardingIncludeLabels
{

private bool enabledField;

private string excludeField;

/// <summary>
/// configurationApplicationLoggingForwardingIncludeLabels class constructor
/// </summary>
public configurationApplicationLoggingForwardingIncludeLabels()
{
this.enabledField = false;
this.excludeField = "";
}

[System.Xml.Serialization.XmlAttributeAttribute()]
[System.ComponentModel.DefaultValueAttribute(false)]
public bool enabled
{
get
{
return this.enabledField;
}
set
{
this.enabledField = value;
}
}

[System.Xml.Serialization.XmlAttributeAttribute()]
[System.ComponentModel.DefaultValueAttribute("")]
public string exclude
{
get
{
return this.excludeField;
}
set
{
this.excludeField = value;
}
}

#region Clone method
/// <summary>
/// Create a clone of this configurationApplicationLoggingForwardingIncludeLabels object
/// </summary>
public virtual configurationApplicationLoggingForwardingIncludeLabels Clone()
{
return ((configurationApplicationLoggingForwardingIncludeLabels)(this.MemberwiseClone()));
}
#endregion
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("Xsd2Code", "3.6.0.20097")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
Expand Down
23 changes: 23 additions & 0 deletions src/Agent/NewRelic/Agent/Core/Config/Configuration.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -1816,6 +1816,29 @@
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="includeLabels" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>
Include configured labels with log records.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="enabled" type="xs:boolean" default="false">
<xs:annotation>
<xs:documentation>
Controls whether or not labels are included with log records. Defaults to false.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="exclude" type="xs:string" default="">
<xs:annotation>
<xs:documentation>
A comma-separated list of case-insensitive strings that define the labels that should NOT be added to log records.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="enabled" type="xs:boolean" default="true">
<xs:annotation>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2063,6 +2063,30 @@ public virtual HashSet<string> LogLevelDenyList
}
}

public virtual bool IncludeLabelsEnabled
{
get
{
return LogEventCollectorEnabled &&
EnvironmentOverrides(_localConfiguration.applicationLogging.forwarding.includeLabels.enabled, "NEW_RELIC_APPLICATION_LOGGING_FORWARDING_INCLUDE_LABELS_ENABLED");
}
}

private HashSet<string> _includeLabelsExclude;
public virtual IEnumerable<string> IncludeLabelsExclude
{
get
{
_includeLabelsExclude = new HashSet<string>(
EnvironmentOverrides(_localConfiguration.applicationLogging.forwarding.includeLabels.exclude,
"NEW_RELIC_APPLICATION_LOGGING_FORWARDING_INCLUDE_LABELS_EXCLUDE")
?.Split(new[] { StringSeparators.CommaChar, ' ' }, StringSplitOptions.RemoveEmptyEntries)
?? Enumerable.Empty<string>());

return _includeLabelsExclude;
}
}

#endregion

private IEnumerable<IDictionary<string, string>> _ignoredInstrumentation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,12 @@ public ReportedConfiguration(IConfiguration configuration)
[JsonProperty("application_logging.forwarding.context_data.exclude")]
public IEnumerable<string> ContextDataExclude => _configuration.ContextDataExclude;

[JsonProperty("application_logging.forwarding.include_labels.enabled")]
public bool IncludeLabelsEnabled => _configuration.IncludeLabelsEnabled;

[JsonProperty("application_logging.forwarding.include_labels.exclude")]
public IEnumerable<string> IncludeLabelsExclude => _configuration.IncludeLabelsExclude;

[JsonProperty("metrics.harvest_cycle")]
public TimeSpan MetricsHarvestCycle => _configuration.MetricsHarvestCycle;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0


Expand All @@ -25,6 +25,7 @@ public class LogEventWireModelCollectionJsonConverter : JsonConverter<LogEventWi
private const string ErrorMessage = "error.message";
private const string ErrorClass = "error.class";
private const string Context = "context";
private const string LabelPrefix = "tags.";

public override LogEventWireModelCollection ReadJson(JsonReader reader, Type objectType, LogEventWireModelCollection existingValue, bool hasExistingValue, JsonSerializer serializer)
{
Expand All @@ -50,6 +51,16 @@ private static void WriteJsonImpl(JsonWriter jsonWriter, LogEventWireModelCollec
jsonWriter.WriteValue(value.EntityGuid);
jsonWriter.WritePropertyName(Hostname);
jsonWriter.WriteValue(value.Hostname);

if (value.Labels != null)
{
foreach (var label in value.Labels)
{
jsonWriter.WritePropertyName(LabelPrefix + label.Type);
jsonWriter.WriteValue(label.Value);
}
}

jsonWriter.WriteEndObject();
jsonWriter.WriteEndObject();

Expand Down
2 changes: 2 additions & 0 deletions src/Agent/NewRelic/Agent/Core/Labels/ILabelsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ namespace NewRelic.Agent.Core.Labels
public interface ILabelsService : IDisposable
{
IEnumerable<Label> Labels { get; }

IEnumerable<Label> GetFilteredLabels(IEnumerable<string> labelsToExclude);
}
}
12 changes: 10 additions & 2 deletions src/Agent/NewRelic/Agent/Core/Labels/LabelsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,34 @@ public class LabelsService : ILabelsService

private readonly IConfigurationService _configurationService;

public IEnumerable<Label> Labels { get { return GetLabelsFromConfiguration(); } }
public IEnumerable<Label> Labels { get { return GetLabelsFromConfiguration([]); } }

public IEnumerable<Label> GetFilteredLabels(IEnumerable<string> labelsToExclude)
{
return GetLabelsFromConfiguration(labelsToExclude);
}

public LabelsService(IConfigurationService configurationService)
{
_configurationService = configurationService;
}

private IEnumerable<Label> GetLabelsFromConfiguration()
private IEnumerable<Label> GetLabelsFromConfiguration(IEnumerable<string> labelsToExclude)
{
var labelsString = _configurationService.Configuration.Labels;
if (string.IsNullOrEmpty(labelsString))
return Enumerable.Empty<Label>();

labelsToExclude ??= [];

try
{
var labels = labelsString
.Trim()
.Trim(StringSeparators.SemiColon)
.Split(StringSeparators.SemiColon)
.Select(CreateLabelFromString)
.Where(label => !labelsToExclude.Contains(label.Type, StringComparer.OrdinalIgnoreCase))
.GroupBy(label => label.Type)
.Select(labelGrouping => labelGrouping.Last())
.Take(MaxLabels)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using NewRelic.Agent.Core.JsonConverters;
using NewRelic.Agent.Core.Labels;
using Newtonsoft.Json;
using System.Collections.Generic;

Expand All @@ -13,14 +14,17 @@ public class LogEventWireModelCollection
public string EntityName { get; }
public string EntityGuid { get; }
public string Hostname { get; }
public IEnumerable<Label> Labels { get; }

public IList<LogEventWireModel> LoggingEvents { get; }

public LogEventWireModelCollection(string entityName, string entityGuid, string hostname, IList<LogEventWireModel> loggingEvents)
public LogEventWireModelCollection(string entityName, string entityGuid, string hostname,
IEnumerable<Label> labels, IList<LogEventWireModel> loggingEvents)
{
EntityName = entityName;
EntityGuid = entityGuid;
Hostname = hostname;
Labels = labels;
LoggingEvents = loggingEvents;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,10 @@ public interface IConfiguration
bool LogDecoratorEnabled { get; }
HashSet<string> LogLevelDenyList { get; }
bool ContextDataEnabled { get; }
bool IncludeLabelsEnabled { get; }
IEnumerable<string> ContextDataInclude { get; }
IEnumerable<string> ContextDataExclude { get; }
IEnumerable<string> IncludeLabelsExclude { get; }
bool AppDomainCachingDisabled { get; }
bool ForceNewTransactionOnNewThread { get; }
bool CodeLevelMetricsEnabled { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;
using System.Collections.Generic;
using System.Linq;

namespace NewRelic.Agent.IntegrationTestHelpers
{
Expand Down Expand Up @@ -503,5 +504,30 @@ public NewRelicConfigModifier SetDisableFileSystemWatcher(bool enabled = true)
CommonUtils.ModifyOrCreateXmlAttributeInNewRelicConfig(_configFilePath, new[] { "configuration", "service" }, "disableFileSystemWatcher", enabled.ToString().ToLower());
return this;
}

public NewRelicConfigModifier EnableApplicationLoggingForwardIncludeLabels(bool enabled = true)
{
CommonUtils.ModifyOrCreateXmlAttributeInNewRelicConfig(_configFilePath, new[] { "configuration", "applicationLogging", "forwarding", "includeLabels" }, "enabled", enabled.ToString().ToLower());
return this;
}

public NewRelicConfigModifier SetApplicationLoggingForwardIncludeLabelsExcludes(string excludes)
{
CommonUtils.ModifyOrCreateXmlAttributeInNewRelicConfig(_configFilePath, new[] { "configuration", "applicationLogging", "forwarding", "includeLabels" }, "exclude", excludes);
return this;
}

public NewRelicConfigModifier SetLabels(string labels)
{
CommonUtils.AddXmlNodeInNewRelicConfig(_configFilePath, new[] { "configuration" }, "labels", labels);
return this;
}

public NewRelicConfigModifier SetLabels(Dictionary<string, string> labels)
{
var labelsString = string.Join(";", labels.Select(x => x.Key + ":" + x.Value).ToArray());
CommonUtils.AddXmlNodeInNewRelicConfig(_configFilePath, new[] { "configuration" }, "labels", labelsString);
return this;
}
}
}
Loading

0 comments on commit fcfe46d

Please sign in to comment.