Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tracer/src/Datadog.Trace/Debugger/DebuggerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ private static IDogStatsd GetDogStatsd(TracerSettings tracerSettings, string ser
tracerSettings.Manager.InitialMutableSettings,
tracerSettings.Manager.InitialExporterSettings,
includeDefaultTags: false,
tracerSettings.PropagateProcessTags ? ProcessTags.TagsList : [],
prefix: DebuggerSettings.DebuggerMetricPrefix);
}

Expand Down
27 changes: 15 additions & 12 deletions tracer/src/Datadog.Trace/DogStatsd/StatsdFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ internal static class StatsdFactory
{
private static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor(typeof(StatsdFactory));

internal static IDogStatsd CreateDogStatsdClient(MutableSettings settings, ExporterSettings exporter, bool includeDefaultTags, string? prefix = null)
internal static IDogStatsd CreateDogStatsdClient(MutableSettings settings, ExporterSettings exporter, bool includeDefaultTags, IList<string> processTags, string? prefix = null)
{
var customTagCount = settings.GlobalTags.Count;
var tagsCount = (includeDefaultTags ? 5 + customTagCount : 0) + processTags.Count;
var constantTags = new List<string>(tagsCount);
if (includeDefaultTags)
{
var customTagCount = settings.GlobalTags.Count;
var constantTags = new List<string>(5 + customTagCount)
{
"lang:.NET",
$"lang_interpreter:{FrameworkDescription.Instance.Name}",
$"lang_version:{FrameworkDescription.Instance.ProductVersion}",
$"tracer_version:{TracerConstants.AssemblyVersion}",
$"{Tags.RuntimeId}:{Tracer.RuntimeId}"
};
constantTags.Add("lang:.NET");
constantTags.Add($"lang_interpreter:{FrameworkDescription.Instance.Name}");
constantTags.Add($"lang_version:{FrameworkDescription.Instance.ProductVersion}");
constantTags.Add($"tracer_version:{TracerConstants.AssemblyVersion}");
constantTags.Add($"{Tags.RuntimeId}:{Tracer.RuntimeId}");
// update count above if adding new tags

if (customTagCount > 0)
{
Expand All @@ -43,11 +43,14 @@ internal static IDogStatsd CreateDogStatsdClient(MutableSettings settings, Expor
constantTags.Add($"{key}:{value}");
}
}
}

return CreateDogStatsdClient(settings, exporter, constantTags, prefix);
if (processTags.Count > 0)
{
constantTags.AddRange(processTags);
}

return CreateDogStatsdClient(settings, exporter, constantTags: null, prefix);
return CreateDogStatsdClient(settings, exporter, constantTags, prefix);
}

private static IDogStatsd CreateDogStatsdClient(MutableSettings settings, ExporterSettings exporter, List<string>? constantTags, string? prefix = null)
Expand Down
15 changes: 10 additions & 5 deletions tracer/src/Datadog.Trace/DogStatsd/StatsdManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#nullable enable

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Datadog.Trace.Configuration;
Expand Down Expand Up @@ -33,12 +34,13 @@ public StatsdManager(TracerSettings tracerSettings)
}

// Internal for testing
internal StatsdManager(TracerSettings tracerSettings, Func<MutableSettings, ExporterSettings, StatsdClientHolder> statsdFactory)
internal StatsdManager(TracerSettings tracerSettings, Func<MutableSettings, ExporterSettings, IList<string>, StatsdClientHolder> statsdFactory)
{
// The initial factory, assuming there's no updates
_factory = () => statsdFactory(
tracerSettings.Manager.InitialMutableSettings,
tracerSettings.Manager.InitialExporterSettings);
tracerSettings.Manager.InitialExporterSettings,
tracerSettings.PropagateProcessTags ? ProcessTags.TagsList : []);

// We don't create a new client unless we need one, and we rely on consumers of the manager to tell us when it's needed
_current = null;
Expand All @@ -60,7 +62,8 @@ internal StatsdManager(TracerSettings tracerSettings, Func<MutableSettings, Expo
ref _factory,
() => statsdFactory(
c.UpdatedMutable ?? c.PreviousMutable,
c.UpdatedExporter ?? c.PreviousExporter));
c.UpdatedExporter ?? c.PreviousExporter,
tracerSettings.PropagateProcessTags ? ProcessTags.TagsList : []));

// check if we actually need to do an update or if noone is using the client yet
if (Volatile.Read(ref _isRequiredMask) != 0)
Expand Down Expand Up @@ -173,8 +176,10 @@ internal static bool HasImpactingChanges(TracerSettings.SettingsManager.SettingC
return hasChanges;
}

private static StatsdClientHolder CreateClient(MutableSettings settings, ExporterSettings exporter)
=> new(StatsdFactory.CreateDogStatsdClient(settings, exporter, includeDefaultTags: true));
private static StatsdClientHolder CreateClient(MutableSettings settings, ExporterSettings exporter, IList<string> processTags)
{
return new StatsdClientHolder(StatsdFactory.CreateDogStatsdClient(settings, exporter, includeDefaultTags: true, processTags));
}

private void EnsureClient(bool ensureCreated, bool forceRecreate)
{
Expand Down
6 changes: 3 additions & 3 deletions tracer/src/Datadog.Trace/ProcessTags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using Datadog.Trace.Configuration;
using Datadog.Trace.Processors;
using Datadog.Trace.Util;

namespace Datadog.Trace;

Expand All @@ -21,7 +21,7 @@ internal static class ProcessTags
public const string EntrypointWorkdir = "entrypoint.workdir";

// two views on the same data
public static readonly List<string> TagsList = GetTagsList();
public static readonly ReadOnlyCollection<string> TagsList = GetTagsList().AsReadOnly();
public static readonly string SerializedTags = GetSerializedTagsFromList(TagsList);

private static List<string> GetTagsList()
Expand Down Expand Up @@ -53,7 +53,7 @@ private static void AddNormalizedTag(this List<string> tags, string key, string?
tags.Add($"{key}:{normalizedValue}");
}

private static string GetSerializedTagsFromList(List<string> tags)
private static string GetSerializedTagsFromList(IEnumerable<string> tags)
{
return string.Join(",", tags);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@
using System.Linq;
using Datadog.Trace.Vendors.Newtonsoft.Json;

#nullable enable

namespace Datadog.Trace.RemoteConfigurationManagement.Protocol
{
internal sealed class RcmClientTracer
{
// Don't change this constructor - it's used by Newtonsoft.JSON for deserialization
// and that can mean the provided properties are not _really_ nullable, even though we "require" them to be
public RcmClientTracer(string runtimeId, string tracerVersion, string service, string env, string? appVersion, List<string> tags, List<string>? processTags)
public RcmClientTracer(string runtimeId, string tracerVersion, string service, string env, string? appVersion, List<string> tags, IList<string>? processTags)
{
RuntimeId = runtimeId;
Language = TracerConstants.Language;
Expand Down Expand Up @@ -46,7 +44,7 @@ public RcmClientTracer(string runtimeId, string tracerVersion, string service, s
public string? Service { get; }

[JsonProperty("process_tags")]
public List<string>? ProcessTags { get; }
public IList<string>? ProcessTags { get; }

[JsonProperty("extra_services")]
public string[]? ExtraServices { get; set; }
Expand All @@ -60,7 +58,7 @@ public RcmClientTracer(string runtimeId, string tracerVersion, string service, s
[JsonProperty("tags")]
public List<string> Tags { get; }

public static RcmClientTracer Create(string runtimeId, string tracerVersion, string service, string env, string? appVersion, ReadOnlyDictionary<string, string> globalTags, List<string>? processTags)
public static RcmClientTracer Create(string runtimeId, string tracerVersion, string service, string env, string? appVersion, ReadOnlyDictionary<string, string> globalTags, IList<string>? processTags)
=> new(runtimeId, tracerVersion, service, env, appVersion, GetTags(env, service, globalTags), processTags);

private static List<string> GetTags(string? environment, string? serviceVersion, ReadOnlyDictionary<string, string>? globalTags)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ private RemoteConfigurationManager(
TimeSpan pollInterval,
IGitMetadataTagsProvider gitMetadataTagsProvider,
IRcmSubscriptionManager subscriptionManager,
List<string>? processTags)
IList<string>? processTags)
{
_discoveryService = discoveryService;
_pollInterval = pollInterval;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,60 @@ public async Task NamedPipesSubmitsMetrics()
await RunTest();
}

[SkippableFact]
[Trait("Category", "EndToEnd")]
[Trait("RunOnWindows", "True")]
public async Task ProcessTagsIncludedInMetrics_WhenEnabled()
{
SkipOn.Platform(SkipOn.PlatformValue.MacOs);
EnvironmentHelper.EnableDefaultTransport();
SetEnvironmentVariable("DD_RUNTIME_METRICS_ENABLED", "1");
SetEnvironmentVariable("DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED", "1");
SetEnvironmentVariable("DD_SERVICE", "Samples.RuntimeMetrics");

using var agent = EnvironmentHelper.GetMockAgent(useStatsD: true);
using var processResult = await RunSampleAndWaitForExit(agent);
var requests = agent.StatsdRequests;

Assert.True(requests.Count > 0, "No metrics received");

var metrics = requests.SelectMany(x => x.Split('\n')).ToList();

// Verify process tags are present in the metrics
// Process tags include: entrypoint.basedir, entrypoint.workdir, and optionally entrypoint.name
metrics
.Should()
.OnlyContain(s => s.Contains("entrypoint.basedir:"), "entrypoint.basedir process tag should be present")
.And.OnlyContain(s => s.Contains("entrypoint.workdir:"), "entrypoint.workdir process tag should be present");
}

[SkippableFact]
[Trait("Category", "EndToEnd")]
[Trait("RunOnWindows", "True")]
public async Task ProcessTagsNotIncludedInMetrics_WhenDisabled()
{
SkipOn.Platform(SkipOn.PlatformValue.MacOs);
EnvironmentHelper.EnableDefaultTransport();
SetEnvironmentVariable("DD_RUNTIME_METRICS_ENABLED", "1");
SetEnvironmentVariable("DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED", "0");
SetEnvironmentVariable("DD_SERVICE", "Samples.RuntimeMetrics");

using var agent = EnvironmentHelper.GetMockAgent(useStatsD: true);
using var processResult = await RunSampleAndWaitForExit(agent);
var requests = agent.StatsdRequests;

Assert.True(requests.Count > 0, "No metrics received");

var metrics = requests.SelectMany(x => x.Split('\n')).ToList();

// Verify process tags are NOT present in the metrics when disabled
metrics
.Should()
.NotContain(s => s.Contains("entrypoint.basedir:"), "entrypoint.basedir should not be present when process tags are disabled")
.And.NotContain(s => s.Contains("entrypoint.workdir:"), "entrypoint.workdir should not be present when process tags are disabled")
.And.NotContain(s => s.Contains("entrypoint.name:"), "entrypoint.name should not be present when process tags are disabled");
}

private async Task RunTest()
{
var inputServiceName = "12_$#Samples.$RuntimeMetrics";
Expand Down
4 changes: 4 additions & 0 deletions tracer/test/Datadog.Trace.Tests/DogStatsDTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ public void CanCreateDogStatsD_UDP_FromTraceAgentSettings(string agentUri, strin
settings.Manager.InitialMutableSettings,
settings.Manager.InitialExporterSettings,
includeDefaultTags: true,
processTags: ["a:b", "c:d"],
prefix: null);

// If there's an error during configuration, we get a no-op instance, so using this as a test
Expand Down Expand Up @@ -168,6 +169,7 @@ public void CanCreateDogStatsD_NamedPipes_FromTraceAgentSettings()
settings.Manager.InitialMutableSettings,
settings.Manager.InitialExporterSettings,
includeDefaultTags: true,
processTags: ["a:b", "c:d"],
prefix: null);

// If there's an error during configuration, we get a no-op instance, so using this as a test
Expand Down Expand Up @@ -202,6 +204,7 @@ public void CanCreateDogStatsD_UDS_FromTraceAgentSettings()
settings.Manager.InitialMutableSettings,
settings.Manager.InitialExporterSettings,
includeDefaultTags: true,
processTags: ["a:b", "c:d"],
prefix: null);

// If there's an error during configuration, we get a no-op instance, so using this as a test
Expand Down Expand Up @@ -234,6 +237,7 @@ public void CanCreateDogStatsD_UDS_FallsBackToUdp_FromTraceAgentSettings()
settings.Manager.InitialMutableSettings,
settings.Manager.InitialExporterSettings,
includeDefaultTags: true,
processTags: ["a:b", "c:d"],
prefix: null);

// If there's an error during configuration, we get a no-op instance, so using this as a test
Expand Down
Loading
Loading