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
9 changes: 9 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,12 @@ dsm_throughput:
trigger:
include: .gitlab/benchmarks/dsm-throughput.yml
allow_failure: true


validate_supported_configurations_local_file:
stage: build
rules:
- when: on_success
extends: .validate_supported_configurations_local_file
variables:
LOCAL_JSON_PATH: "tracer/src/Datadog.Trace/Configuration/supported-configurations.json"
2 changes: 1 addition & 1 deletion .gitlab/one-pipeline.locked.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# DO NOT EDIT THIS FILE MANUALLY
# This file is auto-generated by automation.
include:
- remote: https://gitlab-templates.ddbuild.io/libdatadog/one-pipeline/ca/5ad4e568659a0e385e3cd429b7845ad8e2171cfe0e27ee5b9eeb4cd4b67825f5/one-pipeline.yml
- remote: https://gitlab-templates.ddbuild.io/libdatadog/one-pipeline/ca/b8fc1b7f45e49ddd65623f217f03c38def169aff6f2518380e5b415514e4cb81/one-pipeline.yml
167 changes: 167 additions & 0 deletions tracer/build/_build/Build.Steps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
Expand Down Expand Up @@ -2574,6 +2575,172 @@ string NormalizedPath(AbsolutePath ap)
await LogParser.ReportNativeMetrics(logDirectory);
});

public Target CheckConfigurationKeysAgainstJsonValidations => _ => _
.Description("Validates that all ConfigurationKeys constants are present in supported-configurations.json")
.After(CompileManagedSrc)
.Executes(() =>
{
var jsonPath = TracerDirectory / "src" / "Datadog.Trace" / "Configuration" / "supported-configurations.json";
if (!File.Exists(jsonPath))
{
Logger.Error("supported-configurations.json file not found at {JsonPath}", jsonPath);
return;
}

// Parse JSON to get supported configuration keys
var jsonContent = File.ReadAllText(jsonPath);
var jsonDoc = JsonDocument.Parse(jsonContent);
var canonicalKeysInJson = new HashSet<string>();
var aliasesInJson = new HashSet<string>();
var deprecationsInJson = new HashSet<string>();

// Add keys from supportedConfigurations section
if (jsonDoc.RootElement.TryGetProperty("supportedConfigurations", out var supportedConfigs))
{
foreach (var property in supportedConfigs.EnumerateObject())
{
canonicalKeysInJson.Add(property.Name);
deprecationsInJson.Add(property.Name);
}
}

// Add keys from aliases section (add elements in the arrays)
if (jsonDoc.RootElement.TryGetProperty("aliases", out var aliases))
{
foreach (var property in aliases.EnumerateObject())
{
// Add all alias keys from the array
if (property.Value.ValueKind == JsonValueKind.Array)
{
foreach (var aliasElement in property.Value.EnumerateArray())
{
if (aliasElement.ValueKind == JsonValueKind.String)
{
aliasesInJson.Add(aliasElement.GetString());
}
}
}
}
}

// Add keys from deprecations section (add the deprecated keys themselves)
if (jsonDoc.RootElement.TryGetProperty("deprecations", out var deprecations))
{
foreach (var property in deprecations.EnumerateObject())
{
deprecationsInJson.Add(property.Name);
}
}

// Load the net6.0 assembly for configuration key analysis
// Configuration keys are the same across all frameworks, so we only need one
const string targetFramework = "net6.0";
var assemblyPath = TracerDirectory / "src" / "Datadog.Trace" / "bin" / BuildConfiguration / targetFramework / "Datadog.Trace.dll";

if (!File.Exists(assemblyPath))
{
throw new InvalidOperationException($"Assembly not found at {assemblyPath} for framework {targetFramework}. Make sure CompileManagedSrc has run.");
}

Assembly tracerAssembly;
try
{
// Load the assembly directly - no complex resolution needed
tracerAssembly = Assembly.LoadFrom(assemblyPath);
Logger.Information("Using {Framework} assembly for configuration key analysis", targetFramework);
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to load assembly for {targetFramework}: {ex.Message}", ex);
}

// Use reflection to get all configuration keys from the ConfigurationKeys class
var configurationKeysInCode = new HashSet<string>();
var keyToFieldMap = new Dictionary<string, string>();

const string configKeysClassName = "Datadog.Trace.Configuration.ConfigurationKeys";
// Get the ConfigurationKeys type (includes all partial classes)
var configKeysType = tracerAssembly.GetType(configKeysClassName);
if (configKeysType == null)
{
throw new InvalidOperationException($"Could not find {configKeysClassName} type in assembly for framework {targetFramework}");
}

// Get all public const string fields from the type and all nested types (one level deep)
var allTypes = new List<Type> { configKeysType };
allTypes.AddRange(configKeysType.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic));

Logger.Information("Found {TypeCount} types to analyze (including nested classes)", allTypes.Count);

foreach (var type in allTypes)
{
var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(f => f.IsLiteral && !f.IsInitOnly && f.FieldType == typeof(string));

Logger.Information(" Type {TypeName} has {FieldCount} const string fields", type.Name, fields.Count());

foreach (var field in fields)
{
var value = (string)field.GetValue(null)!;
configurationKeysInCode.Add(value);

// Build a more descriptive path for nested classes
var typeName = type.DeclaringType != null ? $"ConfigurationKeys.{type.Name}" : "ConfigurationKeys";
keyToFieldMap[value] = $"{typeName}.{field.Name}";
}
}

Logger.Information("Found {KeyCount} configuration keys in {Framework}", configurationKeysInCode.Count, targetFramework);

if (!configurationKeysInCode.Any())
{
throw new InvalidOperationException($"Could not extract any configuration keys from {targetFramework} framework");
}

var canonicalAndDeprecationsInJson = canonicalKeysInJson.Concat(deprecationsInJson);
// Find keys that are in JSON but not defined in ConfigurationKeys
var missingFromCode = canonicalKeysInJson.Except(configurationKeysInCode).ToList();

var allKeysInJson = canonicalAndDeprecationsInJson.Concat(aliasesInJson);
// Find keys that are defined in ConfigurationKeys but missing from JSON
var missingFromJson = configurationKeysInCode.Except(allKeysInJson).ToList();
// Report results
if (missingFromJson.Any())
{
Logger.Error("Configuration keys defined in ConfigurationKeys but missing from supported-configurations.json:");
foreach (var key in missingFromJson.OrderBy(k => k))
{
var fieldInfo = keyToFieldMap.GetValueOrDefault(key, "Unknown");
Logger.Error(" - {Key} (defined as {FieldInfo})", key, fieldInfo);
}
}

if (missingFromCode.Any())
{
Logger.Warning("Configuration keys in supported-configurations.json but not defined in ConfigurationKeys:");
foreach (var key in missingFromCode.OrderBy(k => k))
{
Logger.Warning(" - {Key}", key);
}
}

if (!missingFromJson.Any() && !missingFromCode.Any())
{
Logger.Information("✅ All configuration keys are properly synchronized between ConfigurationKeys and supported-configurations.json");
Logger.Information("Total unique configuration keys found across all frameworks: {TotalKeys}", configurationKeysInCode.Count);
}
else
{
var totalIssues = missingFromJson.Count + missingFromCode.Count;
Logger.Error("❌ Found {TotalIssues} configuration key synchronization issues", totalIssues);

if (missingFromJson.Any())
{
throw new InvalidOperationException($"Found {missingFromJson.Count} configuration keys defined in ConfigurationKeys but missing from supported-configurations.json. Please add them to the JSON file.");
}
}
});

private async Task CheckLogsForErrors(List<Regex> knownPatterns, bool allFilesMustExist, LogLevel minLogLevel, List<(string IgnoreReasonTag, Regex Regex)> reportablePatterns)
{
var logDirectory = BuildDataDirectory / "logs";
Expand Down
1 change: 1 addition & 0 deletions tracer/build/_build/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ void DeleteReparsePoints(string path)
.DependsOn(CreateRequiredDirectories)
.DependsOn(Restore)
.DependsOn(CompileManagedSrc)
.DependsOn(CheckConfigurationKeysAgainstJsonValidations)
.DependsOn(PublishManagedTracer)
.DependsOn(DownloadLibDdwaf)
.DependsOn(CopyLibDdwaf)
Expand Down
2 changes: 0 additions & 2 deletions tracer/missing-nullability-files.csv
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ src/Datadog.Trace/Configuration/ConfigurationKeys.AzureAppService.cs
src/Datadog.Trace/Configuration/ConfigurationKeys.Debugger.cs
src/Datadog.Trace/Configuration/ConfigurationKeys.DirectLogSubmission.cs
src/Datadog.Trace/Configuration/ConfigurationKeys.Exporter.cs
src/Datadog.Trace/Configuration/ConfigurationKeys.GCPFunction.cs
src/Datadog.Trace/Configuration/ConfigurationKeys.Iast.cs
src/Datadog.Trace/Configuration/ConfigurationKeys.Logging.cs
src/Datadog.Trace/Configuration/ConfigurationKeys.Rcm.cs
Expand All @@ -93,7 +92,6 @@ src/Datadog.Trace/Configuration/DeprecationMessages.cs
src/Datadog.Trace/Configuration/IDynamicConfigurationManager.cs
src/Datadog.Trace/Configuration/IntegrationRegistry.cs
src/Datadog.Trace/Configuration/TracerSettingsConstants.cs
src/Datadog.Trace/ContinuousProfiler/ConfigurationKeys.cs
src/Datadog.Trace/ContinuousProfiler/ContextTracker.cs
src/Datadog.Trace/ContinuousProfiler/IContextTracker.cs
src/Datadog.Trace/ContinuousProfiler/IProfilerStatus.cs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// </copyright>

using BenchmarkDotNet.Configs;
using Datadog.Trace.Configuration;
using Datadog.Trace.ContinuousProfiler;
using Datadog.Trace.ExtensionMethods;
using Datadog.Trace.Util;
Expand Down Expand Up @@ -33,14 +34,14 @@ internal static IConfig WithDatadog(this IConfig config, bool? enableProfiler)
{
var cfg = config.AddLogger(DatadogSessionLogger.Default);

enableProfiler ??= (EnvironmentHelpers.GetEnvironmentVariable(ConfigurationKeys.ProfilingEnabled) ?? string.Empty).ToBoolean() ?? false;
enableProfiler ??= (EnvironmentHelpers.GetEnvironmentVariable(ConfigurationKeys.Profiler.ProfilingEnabled) ?? string.Empty).ToBoolean() ?? false;
switch (enableProfiler)
{
case true:
cfg = cfg.WithOption(ConfigOptions.KeepBenchmarkFiles, true);
break;
case false:
EnvironmentHelpers.SetEnvironmentVariable(ConfigurationKeys.ProfilingEnabled, null);
EnvironmentHelpers.SetEnvironmentVariable(ConfigurationKeys.Profiler.ProfilingEnabled, null);
break;
}

Expand Down
4 changes: 2 additions & 2 deletions tracer/src/Datadog.Trace/ClrProfiler/Instrumentation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,8 @@ private static void StartDiagnosticManager()
var observers = new List<DiagnosticObserver>();

// get environment variables directly so we don't access Trace.Instance yet
var functionsExtensionVersion = EnvironmentHelpers.GetEnvironmentVariable(Datadog.Trace.Configuration.ConfigurationKeys.AzureFunctions.FunctionsExtensionVersion);
var functionsWorkerRuntime = EnvironmentHelpers.GetEnvironmentVariable(Datadog.Trace.Configuration.ConfigurationKeys.AzureFunctions.FunctionsWorkerRuntime);
var functionsExtensionVersion = EnvironmentHelpers.GetEnvironmentVariable(PlatformKeys.AzureFunctions.FunctionsExtensionVersion);
var functionsWorkerRuntime = EnvironmentHelpers.GetEnvironmentVariable(PlatformKeys.AzureFunctions.FunctionsWorkerRuntime);

if (!string.IsNullOrEmpty(functionsExtensionVersion) && !string.IsNullOrEmpty(functionsWorkerRuntime))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,6 @@ internal class AzureAppService
/// </summary>
internal const string SiteExtensionVersionKey = "DD_AAS_DOTNET_EXTENSION_VERSION";

/// <summary>
/// Example: 8c500027-5f00-400e-8f00-60000000000f+apm-dotnet-EastUSwebspace
/// Format: {subscriptionId}+{planResourceGroup}-{hostedInRegion}
/// </summary>
internal const string WebsiteOwnerNameKey = "WEBSITE_OWNER_NAME";

/// <summary>
/// This is the name of the resource group the site instance is assigned to.
/// </summary>
internal const string ResourceGroupKey = "WEBSITE_RESOURCE_GROUP";

/// <summary>
/// This is the unique name of the website instance within Azure App Services.
/// Its presence is used to determine if we are running in Azure App Services.
/// </summary>
internal const string SiteNameKey = "WEBSITE_SITE_NAME";

/// <summary>
/// The instance name in Azure where the traced application is running.
/// </summary>
internal const string InstanceNameKey = "COMPUTERNAME";

/// <summary>
/// The instance ID in Azure where the traced application is running.
/// </summary>
internal const string InstanceIdKey = "WEBSITE_INSTANCE_ID";

/// <summary>
/// The operating system in Azure where the traced application is running.
/// </summary>
internal const string OperatingSystemKey = "WEBSITE_OS";

/// <summary>
/// Used to force the loader to start the trace agent (in case automatic instrumentation is disabled)
/// </summary>
Expand All @@ -62,12 +30,6 @@ internal class AzureAppService
/// Used to force the loader to start dogstatsd (in case automatic instrumentation is disabled)
/// </summary>
public const string AasEnableCustomMetrics = "DD_AAS_ENABLE_CUSTOM_METRICS";

/// <summary>
/// Used to identify consumption plan functions. Consumption plans will either not have this variable,
/// or will have a value of "dynamic".
/// </summary>
public const string WebsiteSKU = "WEBSITE_SKU";
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// <copyright file="ConfigurationKeys.Profiler.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

#nullable enable

namespace Datadog.Trace.Configuration
{
internal static partial class ConfigurationKeys
{
internal static class Profiler
{
public const string ProfilingEnabled = "DD_PROFILING_ENABLED";
public const string CodeHotspotsEnabled = "DD_PROFILING_CODEHOTSPOTS_ENABLED";
public const string EndpointProfilingEnabled = "DD_PROFILING_ENDPOINT_COLLECTION_ENABLED";
public const string SsiDeployed = "DD_INJECTION_ENABLED";
public const string ProfilerManagedActivationEnabled = "DD_PROFILING_MANAGED_ACTIVATION_ENABLED";
}
}
}
Loading
Loading