From ecc176f9ac1b31c413b9643e609b21e3d29c0330 Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Tue, 28 Jan 2025 15:51:28 +0100 Subject: [PATCH] upgrade(tracer): Support & use libdatadog's library_config crate --- .../CMakeLists.txt | 1 + .../Datadog.Profiler.Native/Configuration.cpp | 123 +++++++++-------- .../Datadog.Profiler.Native/Configuration.h | 5 +- .../ConfigurationTest.cpp | 44 +++++- .../Datadog.Profiler.Native.Tests.vcxproj | 1 + ...adog.Profiler.Native.Tests.vcxproj.filters | 3 + .../Shared.ManagedLibraryLoader.vcxitems | 2 + ...ared.ManagedLibraryLoader.vcxitems.filters | 6 + shared/src/native-src/library_config.cpp | 106 +++++++++++++++ shared/src/native-src/library_config.h | 36 +++++ .../dd_dotnet.ICrashReport.g.cs | 2 +- .../FileConfigurationSource.cs | 126 ++++++++++++++++++ .../GlobalConfigurationSource.cs | 3 +- ...blicApiUsageExtensions_EnumExtensions.g.cs | 6 +- ...blicApiUsageExtensions_EnumExtensions.g.cs | 6 +- ...blicApiUsageExtensions_EnumExtensions.g.cs | 6 +- ...blicApiUsageExtensions_EnumExtensions.g.cs | 6 +- .../Telemetry/Metrics/PublicApiUsage.cs | 1 + .../src/Datadog.Tracer.Native/CMakeLists.txt | 5 +- .../Datadog.Tracer.Native.def | 1 + .../Datadog.Tracer.Native.vcxproj | 2 + .../Datadog.Tracer.Native.vcxproj.filters | 6 + tracer/src/Datadog.Tracer.Native/interop.cpp | 36 ++++- .../Configuration/TracerSettingsTests.cs | 35 +++++ 24 files changed, 505 insertions(+), 63 deletions(-) create mode 100644 shared/src/native-src/library_config.cpp create mode 100644 shared/src/native-src/library_config.h create mode 100644 tracer/src/Datadog.Trace/Configuration/ConfigurationSources/FileConfigurationSource.cs diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CMakeLists.txt b/profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CMakeLists.txt index d9601b746f54..49b89697b1f6 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CMakeLists.txt +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CMakeLists.txt @@ -83,6 +83,7 @@ add_library(${PROFILER_STATIC_LIB_NAME} STATIC ${DOTNET_TRACER_REPO_ROOT_PATH}/shared/src/native-src/string.cpp ${DOTNET_TRACER_REPO_ROOT_PATH}/shared/src/native-src/util.cpp ${DOTNET_TRACER_REPO_ROOT_PATH}/shared/src/native-src/miniutf.cpp + ${DOTNET_TRACER_REPO_ROOT_PATH}/shared/src/native-src/library_config.cpp ) set_target_properties(${PROFILER_STATIC_LIB_NAME} PROPERTIES PREFIX "") diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.cpp b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.cpp index 3e6c88c1e4c2..876beceeb706 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.cpp +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.cpp @@ -12,6 +12,7 @@ #include "shared/src/native-src/dd_filesystem.hpp" // namespace fs is an alias defined in "dd_filesystem.hpp" +#include "shared/src/native-src/library_config.h" #include "shared/src/native-src/string.h" #include "shared/src/native-src/util.h" @@ -26,55 +27,61 @@ std::chrono::seconds const Configuration::DefaultDevUploadInterval = 20s; std::chrono::seconds const Configuration::DefaultProdUploadInterval = 60s; std::chrono::milliseconds const Configuration::DefaultCpuProfilingInterval = 9ms; +std::vector Configuration::_configFromFile = {}; + Configuration::Configuration() { - _debugLogEnabled = GetEnvironmentValue(EnvironmentVariables::DebugLogEnabled, GetDefaultDebugLogEnabled()); + if (_configFromFile.empty()) { + _configFromFile = shared::LibraryConfig::get_configuration(false); + } + + _debugLogEnabled = GetConfigValue(EnvironmentVariables::DebugLogEnabled, GetDefaultDebugLogEnabled()); _logDirectory = ExtractLogDirectory(); _pprofDirectory = ExtractPprofDirectory(); - _isOperationalMetricsEnabled = GetEnvironmentValue(EnvironmentVariables::OperationalMetricsEnabled, false); - _isNativeFrameEnabled = GetEnvironmentValue(EnvironmentVariables::NativeFramesEnabled, false); - _isCpuProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::CpuProfilingEnabled, true); - _isWallTimeProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::WallTimeProfilingEnabled, true); - _isExceptionProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::ExceptionProfilingEnabled, true); - _isAllocationProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::AllocationProfilingEnabled, false); + _isOperationalMetricsEnabled = GetConfigValue(EnvironmentVariables::OperationalMetricsEnabled, false); + _isNativeFrameEnabled = GetConfigValue(EnvironmentVariables::NativeFramesEnabled, false); + _isCpuProfilingEnabled = GetConfigValue(EnvironmentVariables::CpuProfilingEnabled, true); + _isWallTimeProfilingEnabled = GetConfigValue(EnvironmentVariables::WallTimeProfilingEnabled, true); + _isExceptionProfilingEnabled = GetConfigValue(EnvironmentVariables::ExceptionProfilingEnabled, true); + _isAllocationProfilingEnabled = GetConfigValue(EnvironmentVariables::AllocationProfilingEnabled, false); _isContentionProfilingEnabled = GetContention(); - _isGarbageCollectionProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::GCProfilingEnabled, true); - _isHeapProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::HeapProfilingEnabled, false); + _isGarbageCollectionProfilingEnabled = GetConfigValue(EnvironmentVariables::GCProfilingEnabled, true); + _isHeapProfilingEnabled = GetConfigValue(EnvironmentVariables::HeapProfilingEnabled, false); _uploadPeriod = ExtractUploadInterval(); _userTags = ExtractUserTags(); - _version = GetEnvironmentValue(EnvironmentVariables::Version, DefaultVersion); - _environmentName = GetEnvironmentValue(EnvironmentVariables::Environment, DefaultEnvironment); - _hostname = GetEnvironmentValue(EnvironmentVariables::Hostname, OpSysTools::GetHostname()); - _agentUrl = GetEnvironmentValue(EnvironmentVariables::AgentUrl, DefaultEmptyString); - _agentHost = GetEnvironmentValue(EnvironmentVariables::AgentHost, DefaultAgentHost); - _agentPort = GetEnvironmentValue(EnvironmentVariables::AgentPort, DefaultAgentPort); + _version = GetConfigValue(EnvironmentVariables::Version, DefaultVersion); + _environmentName = GetConfigValue(EnvironmentVariables::Environment, DefaultEnvironment); + _hostname = GetConfigValue(EnvironmentVariables::Hostname, OpSysTools::GetHostname()); + _agentUrl = GetConfigValue(EnvironmentVariables::AgentUrl, DefaultEmptyString); + _agentHost = GetConfigValue(EnvironmentVariables::AgentHost, DefaultAgentHost); + _agentPort = GetConfigValue(EnvironmentVariables::AgentPort, DefaultAgentPort); _site = ExtractSite(); - _apiKey = GetEnvironmentValue(EnvironmentVariables::ApiKey, DefaultEmptyString); - _serviceName = GetEnvironmentValue(EnvironmentVariables::ServiceName, OpSysTools::GetProcessName()); - _isAgentLess = GetEnvironmentValue(EnvironmentVariables::Agentless, false); - _exceptionSampleLimit = GetEnvironmentValue(EnvironmentVariables::ExceptionSampleLimit, 500); - _allocationSampleLimit = GetEnvironmentValue(EnvironmentVariables::AllocationSampleLimit, 2000); - _contentionSampleLimit = GetEnvironmentValue(EnvironmentVariables::ContentionSampleLimit, 3000); - _contentionDurationThreshold = GetEnvironmentValue(EnvironmentVariables::ContentionDurationThreshold, 100); + _apiKey = GetConfigValue(EnvironmentVariables::ApiKey, DefaultEmptyString); + _serviceName = GetConfigValue(EnvironmentVariables::ServiceName, OpSysTools::GetProcessName()); + _isAgentLess = GetConfigValue(EnvironmentVariables::Agentless, false); + _exceptionSampleLimit = GetConfigValue(EnvironmentVariables::ExceptionSampleLimit, 500); + _allocationSampleLimit = GetConfigValue(EnvironmentVariables::AllocationSampleLimit, 2000); + _contentionSampleLimit = GetConfigValue(EnvironmentVariables::ContentionSampleLimit, 3000); + _contentionDurationThreshold = GetConfigValue(EnvironmentVariables::ContentionDurationThreshold, 100); _cpuWallTimeSamplingRate = ExtractCpuWallTimeSamplingRate(); _walltimeThreadsThreshold = ExtractWallTimeThreadsThreshold(); _cpuThreadsThreshold = ExtractCpuThreadsThreshold(); _codeHotspotsThreadsThreshold = ExtractCodeHotspotsThreadsThreshold(); - _minimumCores = GetEnvironmentValue(EnvironmentVariables::CoreMinimumOverride, 1.0); - _namedPipeName = GetEnvironmentValue(EnvironmentVariables::NamedPipeName, DefaultEmptyString); - _isTimestampsAsLabelEnabled = GetEnvironmentValue(EnvironmentVariables::TimestampsAsLabelEnabled, true); - _useBacktrace2 = GetEnvironmentValue(EnvironmentVariables::UseBacktrace2, true); - _isAllocationRecorderEnabled = GetEnvironmentValue(EnvironmentVariables::AllocationRecorderEnabled, false); - _isDebugInfoEnabled = GetEnvironmentValue(EnvironmentVariables::DebugInfoEnabled, false); - _isGcThreadsCpuTimeEnabled = GetEnvironmentValue(EnvironmentVariables::GcThreadsCpuTimeEnabled, false); - _isThreadLifetimeEnabled = GetEnvironmentValue(EnvironmentVariables::ThreadLifetimeEnabled, false); - _gitRepositoryUrl = GetEnvironmentValue(EnvironmentVariables::GitRepositoryUrl, DefaultEmptyString); - _gitCommitSha = GetEnvironmentValue(EnvironmentVariables::GitCommitSha, DefaultEmptyString); - _isInternalMetricsEnabled = GetEnvironmentValue(EnvironmentVariables::InternalMetricsEnabled, false); - _isSystemCallsShieldEnabled = GetEnvironmentValue(EnvironmentVariables::SystemCallsShieldEnabled, true); + _minimumCores = GetConfigValue(EnvironmentVariables::CoreMinimumOverride, 1.0); + _namedPipeName = GetConfigValue(EnvironmentVariables::NamedPipeName, DefaultEmptyString); + _isTimestampsAsLabelEnabled = GetConfigValue(EnvironmentVariables::TimestampsAsLabelEnabled, true); + _useBacktrace2 = GetConfigValue(EnvironmentVariables::UseBacktrace2, true); + _isAllocationRecorderEnabled = GetConfigValue(EnvironmentVariables::AllocationRecorderEnabled, false); + _isDebugInfoEnabled = GetConfigValue(EnvironmentVariables::DebugInfoEnabled, false); + _isGcThreadsCpuTimeEnabled = GetConfigValue(EnvironmentVariables::GcThreadsCpuTimeEnabled, false); + _isThreadLifetimeEnabled = GetConfigValue(EnvironmentVariables::ThreadLifetimeEnabled, false); + _gitRepositoryUrl = GetConfigValue(EnvironmentVariables::GitRepositoryUrl, DefaultEmptyString); + _gitCommitSha = GetConfigValue(EnvironmentVariables::GitCommitSha, DefaultEmptyString); + _isInternalMetricsEnabled = GetConfigValue(EnvironmentVariables::InternalMetricsEnabled, false); + _isSystemCallsShieldEnabled = GetConfigValue(EnvironmentVariables::SystemCallsShieldEnabled, true); // Check CI Visibility mode - _isCIVisibilityEnabled = GetEnvironmentValue(EnvironmentVariables::CIVisibilityEnabled, false); + _isCIVisibilityEnabled = GetConfigValue(EnvironmentVariables::CIVisibilityEnabled, false); _internalCIVisibilitySpanId = uint64_t{0}; _cpuProfilingInterval = ExtractCpuProfilingInterval(); if (_isCIVisibilityEnabled) @@ -82,7 +89,7 @@ Configuration::Configuration() // We cannot write 0ull instead of std::uint64_t{0} because on Windows, compiling in x64, std::uint64_t == unsigned long long. // But on Linux, it's std::uint64_t == unsigned long (=> 0ul)and it fails to compile. // Here we create a 0 value of type std::uint64_t which will succeed the compilation - _internalCIVisibilitySpanId = GetEnvironmentValue(EnvironmentVariables::InternalCIVisibilitySpanId, uint64_t{0}); + _internalCIVisibilitySpanId = GetConfigValue(EnvironmentVariables::InternalCIVisibilitySpanId, uint64_t{0}); // If we detect CI Visibility we allow to reduce the minimum ms in sampling rate down to 1ms. _cpuWallTimeSamplingRate = ExtractCpuWallTimeSamplingRate(1); @@ -90,15 +97,15 @@ Configuration::Configuration() _cpuProfilingInterval = ExtractCpuProfilingInterval(1ms); } - _isEtwEnabled = GetEnvironmentValue(EnvironmentVariables::EtwEnabled, false); - _deploymentMode = GetEnvironmentValue(EnvironmentVariables::SsiDeployed, DeploymentMode::Manual); - _isEtwLoggingEnabled = GetEnvironmentValue(EnvironmentVariables::EtwLoggingEnabled, false); - _etwReplayEndpoint = GetEnvironmentValue(EnvironmentVariables::EtwReplayEndpoint, DefaultEmptyString); + _isEtwEnabled = GetConfigValue(EnvironmentVariables::EtwEnabled, false); + _deploymentMode = GetConfigValue(EnvironmentVariables::SsiDeployed, DeploymentMode::Manual); + _isEtwLoggingEnabled = GetConfigValue(EnvironmentVariables::EtwLoggingEnabled, false); + _etwReplayEndpoint = GetConfigValue(EnvironmentVariables::EtwReplayEndpoint, DefaultEmptyString); _enablementStatus = ExtractEnablementStatus(); _ssiLongLivedThreshold = ExtractSsiLongLivedThreshold(); - _isTelemetryToDiskEnabled = GetEnvironmentValue(EnvironmentVariables::TelemetryToDiskEnabled, false); - _isSsiTelemetryEnabled = GetEnvironmentValue(EnvironmentVariables::SsiTelemetryEnabled, false); - _cpuProfilerType = GetEnvironmentValue(EnvironmentVariables::CpuProfilerType, CpuProfilerType::ManualCpuTime); + _isTelemetryToDiskEnabled = GetConfigValue(EnvironmentVariables::TelemetryToDiskEnabled, false); + _isSsiTelemetryEnabled = GetConfigValue(EnvironmentVariables::SsiTelemetryEnabled, false); + _cpuProfilerType = GetConfigValue(EnvironmentVariables::CpuProfilerType, CpuProfilerType::ManualCpuTime); } fs::path Configuration::ExtractLogDirectory() @@ -347,7 +354,7 @@ tags Configuration::ExtractUserTags() std::string Configuration::GetDefaultSite() { - auto isDev = GetEnvironmentValue(EnvironmentVariables::DevelopmentConfiguration, false); + auto isDev = GetConfigValue(EnvironmentVariables::DevelopmentConfiguration, false); if (isDev) { @@ -467,14 +474,14 @@ std::chrono::milliseconds Configuration::ExtractCpuProfilingInterval(std::chrono { // For normal path (no CI-visibility), 9ms is the default and lowest value we can have // for CI-Visibility we allow it to be less - auto interval = GetEnvironmentValue(EnvironmentVariables::CpuProfilingInterval, DefaultCpuProfilingInterval); + auto interval = GetConfigValue(EnvironmentVariables::CpuProfilingInterval, DefaultCpuProfilingInterval); return std::max(interval, minimum); } std::chrono::nanoseconds Configuration::ExtractCpuWallTimeSamplingRate(int minimum) { // default sampling rate is 9 ms; could be changed via env vars but down to a minimum of 5 ms - int64_t rate = std::max(GetEnvironmentValue(EnvironmentVariables::CpuWallTimeSamplingRate, 9), minimum); + int64_t rate = std::max(GetConfigValue(EnvironmentVariables::CpuWallTimeSamplingRate, 9), minimum); rate *= 1000000; return std::chrono::nanoseconds(rate); } @@ -484,7 +491,7 @@ int32_t Configuration::ExtractWallTimeThreadsThreshold() // default threads to sample for wall time is 5; could be changed via env vars from 5 to 64 int32_t threshold = std::min( - std::max(GetEnvironmentValue(EnvironmentVariables::WalltimeThreadsThreshold, 5), 5), + std::max(GetConfigValue(EnvironmentVariables::WalltimeThreadsThreshold, 5), 5), 64); return threshold; } @@ -492,7 +499,7 @@ int32_t Configuration::ExtractWallTimeThreadsThreshold() int32_t Configuration::ExtractCodeHotspotsThreadsThreshold() { // default threads to sample for codehotspots is 10; could be changed via env vars but down to 1ms - int32_t threshold = std::max(GetEnvironmentValue(EnvironmentVariables::CodeHotspotsThreadsThreshold, 10), 1); + int32_t threshold = std::max(GetConfigValue(EnvironmentVariables::CodeHotspotsThreadsThreshold, 10), 1); return threshold; } @@ -501,7 +508,7 @@ int32_t Configuration::ExtractCpuThreadsThreshold() // default threads to sample for CPU profiling is 64; could be changed via env vars from 5 to 128 int32_t threshold = std::min( - std::max(GetEnvironmentValue(EnvironmentVariables::CpuTimeThreadsThreshold, 64), 5), + std::max(GetConfigValue(EnvironmentVariables::CpuTimeThreadsThreshold, 64), 5), 128); return threshold; } @@ -518,7 +525,7 @@ bool Configuration::GetContention() } // if not there, look at the deprecated one - return GetEnvironmentValue(EnvironmentVariables::DeprecatedContentionProfilingEnabled, lockContentionEnabled); + return GetConfigValue(EnvironmentVariables::DeprecatedContentionProfilingEnabled, lockContentionEnabled); } bool Configuration::GetDefaultDebugLogEnabled() @@ -665,8 +672,18 @@ static bool convert_to(shared::WSTRING const& s, DeploymentMode& result) template -T Configuration::GetEnvironmentValue(shared::WSTRING const& name, T const& defaultValue) -{ +T Configuration::GetConfigValue(shared::WSTRING const& name, T const& defaultValue) +{ + std::string nameStr = shared::ToString(name); + for (const auto& entry : _configFromFile) { + if (entry.key == nameStr) { + T result{}; + if (convert_to(shared::ToWSTRING(entry.value), result)) { + return result; + } + } + } + if (!shared::EnvironmentExist(name)) return defaultValue; T result{}; @@ -730,7 +747,7 @@ EnablementStatus Configuration::ExtractEnablementStatus() std::chrono::milliseconds Configuration::ExtractSsiLongLivedThreshold() const { auto const defaultValue = 30'000ms; - auto value = GetEnvironmentValue(EnvironmentVariables::SsiLongLivedThreshold, defaultValue); + auto value = GetConfigValue(EnvironmentVariables::SsiLongLivedThreshold, defaultValue); if (value < 0ms) return defaultValue; diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.h b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.h index 6f388654b377..d6ba35f3f0ac 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.h +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.h @@ -11,6 +11,7 @@ #include "CpuProfilerType.h" #include "IConfiguration.h" #include "TagsHelper.h" +#include "shared/src/native-src/library_config.h" #include "shared/src/native-src/string.h" #include "shared/src/native-src/dd_filesystem.hpp" @@ -95,7 +96,7 @@ class Configuration final : public IConfiguration static std::chrono::seconds GetDefaultUploadInterval(); static bool GetDefaultDebugLogEnabled(); template - static T GetEnvironmentValue(shared::WSTRING const& name, T const& defaultValue); + static T GetConfigValue(shared::WSTRING const& name, T const& defaultValue); template static bool IsEnvironmentValueSet(shared::WSTRING const& name, T& value); static std::chrono::nanoseconds ExtractCpuWallTimeSamplingRate(int minimum = 5); @@ -178,4 +179,6 @@ class Configuration final : public IConfiguration CpuProfilerType _cpuProfilerType; std::chrono::milliseconds _cpuProfilingInterval; + + static std::vector _configFromFile; }; diff --git a/profiler/test/Datadog.Profiler.Native.Tests/ConfigurationTest.cpp b/profiler/test/Datadog.Profiler.Native.Tests/ConfigurationTest.cpp index 87ea3687928a..ee57ed9f5023 100644 --- a/profiler/test/Datadog.Profiler.Native.Tests/ConfigurationTest.cpp +++ b/profiler/test/Datadog.Profiler.Native.Tests/ConfigurationTest.cpp @@ -7,8 +7,10 @@ #include "Configuration.h" #include "EnvironmentHelper.h" #include "EnvironmentVariables.h" +#include "FfiHelper.h" #include "OpSysTools.h" +#include "shared/src/native-src/library_config.h" #include "shared/src/native-src/string.h" #include "shared/src/native-src/util.h" @@ -1163,4 +1165,44 @@ TEST_F(ConfigurationTest, CheckSsiTelemetryIsEnabledIfTelemetryEnvVarIsEnabled) auto configuration = Configuration{}; auto expectedValue = true; ASSERT_THAT(configuration.IsSsiTelemetryEnabled(), expectedValue); -} \ No newline at end of file +} + +TEST_F(ConfigurationTest, CheckLibraryConfigWorksAsExpected) +{ + fs::path testDir = fs::temp_directory_path() / "test_config_dir"; + fs::create_directories(testDir); + ASSERT_TRUE(fs::exists(testDir)); + + auto configPath = (testDir / "config.yaml").string(); + auto previousPath = shared::LibraryConfig::config_path; + shared::LibraryConfig::config_path = configPath; + + // Ensure the directory is removed at the end of the test + struct TestCleaner { + fs::path dir; + std::string previousPath; + ~TestCleaner() { + fs::remove_all(dir); + shared::LibraryConfig::config_path = previousPath; + } + } testCleaner{testDir, previousPath}; + + std::ofstream configFile(configPath); + configFile << R"( +rules: +- selectors: + - origin: language + matches: ["dotnet"] + operator: equals + configuration: + DD_SERVICE: my_service +)"; + configFile.close(); + + auto configuration = Configuration{}; + #ifndef _WINDOWS + ASSERT_EQ(configuration.GetServiceName(), "my_service"); + #else + ASSERT_EQ(configuration.GetServiceName(), OpSysTools::GetProcessName()); + #endif +} diff --git a/profiler/test/Datadog.Profiler.Native.Tests/Datadog.Profiler.Native.Tests.vcxproj b/profiler/test/Datadog.Profiler.Native.Tests/Datadog.Profiler.Native.Tests.vcxproj index 1d5c271c1a3b..109254448f75 100644 --- a/profiler/test/Datadog.Profiler.Native.Tests/Datadog.Profiler.Native.Tests.vcxproj +++ b/profiler/test/Datadog.Profiler.Native.Tests/Datadog.Profiler.Native.Tests.vcxproj @@ -39,6 +39,7 @@ + diff --git a/profiler/test/Datadog.Profiler.Native.Tests/Datadog.Profiler.Native.Tests.vcxproj.filters b/profiler/test/Datadog.Profiler.Native.Tests/Datadog.Profiler.Native.Tests.vcxproj.filters index 657179a607f3..942f09596616 100644 --- a/profiler/test/Datadog.Profiler.Native.Tests/Datadog.Profiler.Native.Tests.vcxproj.filters +++ b/profiler/test/Datadog.Profiler.Native.Tests/Datadog.Profiler.Native.Tests.vcxproj.filters @@ -71,6 +71,9 @@ Referenced from: Datadog.Profiler.Native\Util + + Referenced from: Datadog.Profiler.Native\Util + Tests diff --git a/shared/src/native-src/Shared.ManagedLibraryLoader.vcxitems b/shared/src/native-src/Shared.ManagedLibraryLoader.vcxitems index 255463d38603..5b3c3abb396f 100644 --- a/shared/src/native-src/Shared.ManagedLibraryLoader.vcxitems +++ b/shared/src/native-src/Shared.ManagedLibraryLoader.vcxitems @@ -12,6 +12,7 @@ + @@ -21,6 +22,7 @@ + diff --git a/shared/src/native-src/Shared.ManagedLibraryLoader.vcxitems.filters b/shared/src/native-src/Shared.ManagedLibraryLoader.vcxitems.filters index 30a560c5acac..2a73b1c1c550 100644 --- a/shared/src/native-src/Shared.ManagedLibraryLoader.vcxitems.filters +++ b/shared/src/native-src/Shared.ManagedLibraryLoader.vcxitems.filters @@ -30,6 +30,9 @@ ManagedLibraryLoader-Dependencies + + ManagedLibraryLoader-Dependencies + @@ -62,6 +65,9 @@ ManagedLibraryLoader-Dependencies + + ManagedLibraryLoader-Dependencies + Logging diff --git a/shared/src/native-src/library_config.cpp b/shared/src/native-src/library_config.cpp new file mode 100644 index 000000000000..95d1367fe496 --- /dev/null +++ b/shared/src/native-src/library_config.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +// #include +#include "library_config.h" +#include +#include + +#include "util.h" + +// TODO: change path to new location & add Windows +// TODO: when libdatadog is bumped over 15.0.0 there will be two config paths +std::string shared::LibraryConfig::config_path = "/etc/datadog-agent/managed/datadog-apm-libraries/stable/libraries_config.yaml"; + +ddog_Slice_CharSlice +shared::LibraryConfig::to_slice_char_slice(const std::vector& vec) { + ddog_CharSlice* slices = new ddog_CharSlice[vec.size()]; + for (size_t i = 0; i < vec.size(); i++) { + slices[i] = to_char_slice(vec[i]); + } + return {slices, vec.size()}; +} + +ddog_CharSlice +shared::LibraryConfig::to_char_slice(std::string const& str) +{ + return {str.data(), str.size()}; +} + +#ifndef _WINDOWS +std::vector +shared::LibraryConfig::get_configuration(bool debug_logs) +{ + // Get environment + std::vector envp; + for (char **current = environ; *current; current++) { + envp.push_back(*current); + } + + // Get args (by reading /proc/self/cmdline) + std::vector args; + std::ifstream cmdline("/proc/self/cmdline", std::ios::in); + if (cmdline) { + std::string arg; + char ch; + while (cmdline.get(ch)) { + if (ch == '\0') { + if (!arg.empty()) { + args.push_back(arg); + arg.clear(); + } + } else { + arg.push_back(ch); + } + } + if (!arg.empty()) { + args.push_back(arg); + } + } + + // Get configuration + ddog_ProcessInfo process_info{ + .args = shared::LibraryConfig::to_slice_char_slice(args), + .envp = shared::LibraryConfig::to_slice_char_slice(envp), + .language = shared::LibraryConfig::to_char_slice("dotnet"), + }; + + ddog_Configurator *configurator = ddog_library_configurator_new(debug_logs); + ddog_Result_VecLibraryConfig config_result = ddog_library_configurator_get_path(configurator, process_info, shared::LibraryConfig::to_char_slice(shared::LibraryConfig::config_path)); + if (config_result.tag == DDOG_RESULT_VEC_LIBRARY_CONFIG_ERR_VEC_LIBRARY_CONFIG) { + ddog_Error err = config_result.err; + if (debug_logs) { + auto ddog_err = ddog_Error_message(&err); + std::string err_msg; + std::cerr << err_msg.assign(ddog_err.ptr, ddog_err.ptr + ddog_err.len) << std::endl; + } + ddog_Error_drop(&err); + return {}; + } + + // Format to return type + ddog_Vec_LibraryConfig configs = config_result.ok; + std::vector result(configs.len); + for (size_t i = 0; i < configs.len; i++) { + const ddog_LibraryConfig *cfg = &configs.ptr[i]; + ddog_CStr name = ddog_library_config_name_to_env(cfg->name); + const ddog_CString value = cfg->value; + result.push_back({ + .key = name.ptr, + .value = value.ptr, + }); + }; + + return result; +} +#else +std::vector +shared::LibraryConfig::get_configuration(bool debug_logs) +{ + // Configuration from file is not yet supported on Windows; once the paths + // are defined we can just remove that check + return {}; +} +#endif diff --git a/shared/src/native-src/library_config.h b/shared/src/native-src/library_config.h new file mode 100644 index 000000000000..dc029a82a453 --- /dev/null +++ b/shared/src/native-src/library_config.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace shared { + +typedef struct ConfigEntry { + std::string key; + std::string value; +} ConfigEntry; + +// FFI struct for managed .NET interop +// TODO: is this really needed? +typedef struct ConfigEntryFFI { + const char* key; + const char* value; +} ConfigEntryFFI; + +class LibraryConfig +{ + private: + static ddog_Slice_CharSlice to_slice_char_slice(const std::vector& vec); + static ddog_CharSlice to_char_slice(const std::string& str); + + public: + static std::vector get_configuration(bool debug_logs); + static std::string config_path; // Overridden in tests +}; + +} // namespace shared diff --git a/tracer/src/Datadog.Trace.Tools.dd_dotnet/Generated/Datadog.Trace.Tools.dd_dotnet.SourceGenerators/NativeObjectsGenerator/dd_dotnet.ICrashReport.g.cs b/tracer/src/Datadog.Trace.Tools.dd_dotnet/Generated/Datadog.Trace.Tools.dd_dotnet.SourceGenerators/NativeObjectsGenerator/dd_dotnet.ICrashReport.g.cs index 68068f1af7cb..d66e0aad8bbc 100644 --- a/tracer/src/Datadog.Trace.Tools.dd_dotnet/Generated/Datadog.Trace.Tools.dd_dotnet.SourceGenerators/NativeObjectsGenerator/dd_dotnet.ICrashReport.g.cs +++ b/tracer/src/Datadog.Trace.Tools.dd_dotnet/Generated/Datadog.Trace.Tools.dd_dotnet.SourceGenerators/NativeObjectsGenerator/dd_dotnet.ICrashReport.g.cs @@ -79,7 +79,7 @@ public void GetLastError(out nint a0, out int a1) } public void Panic() { - var func = (delegate* unmanaged[Stdcall])*(VTable + 5); + var func = (delegate* unmanaged[Stdcall])*(VTable + 5); var result = func(_implementation); if (result != 0) { diff --git a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/FileConfigurationSource.cs b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/FileConfigurationSource.cs new file mode 100644 index 000000000000..d0189faffe80 --- /dev/null +++ b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/FileConfigurationSource.cs @@ -0,0 +1,126 @@ +// +// 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. +// + +#nullable enable + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using Datadog.Trace.Configuration.ConfigurationSources.Telemetry; +using Datadog.Trace.Configuration.Telemetry; +using Datadog.Trace.Logging; +using Datadog.Trace.SourceGenerators; +using Datadog.Trace.Telemetry; +using Datadog.Trace.Telemetry.Metrics; +using Datadog.Trace.Vendors.Newtonsoft.Json; +using Datadog.Trace.Vendors.Newtonsoft.Json.Linq; + +namespace Datadog.Trace.Configuration +{ + /// + /// Represents a configuration source that + /// retrieves values from environment variables. + /// + internal class FileConfigurationSource : StringConfigurationSource + { + // Initial buffer size, large to make sure it's enough. We could check in the + // native code if the buffer is large enough and re-exec if not, but this will + // be done later. + private static readonly int _bufferSize = 100; + + // File path override for testing purposes + private string? _filePathOverride; + + private ConfigEntry[] _configList; + + public FileConfigurationSource(string? filePathOverride = null) + { + _filePathOverride = filePathOverride; + _configList = LoadConfiguration(); + } + + /// + internal override ConfigurationOrigins Origin => ConfigurationOrigins.EnvVars; // TODO CHANGEME + + private ConfigEntry[] LoadConfiguration() + { + int configEntriesCount = 0; + var configEntries = new NativeConfigEntry[_bufferSize]; + int result = FrameworkDescription.Instance.IsWindows() ? + Windows.LoadConfigurationFromDisk(_filePathOverride ?? string.Empty, _bufferSize, ref configEntriesCount, configEntries) : + NonWindows.LoadConfigurationFromDisk(_filePathOverride ?? string.Empty, _bufferSize, ref configEntriesCount, configEntries); + + if (result != 0 || configEntries == null) + { + throw new Exception($"Failed to load configuration data (code {result})."); + } + + var configList = new ConfigEntry[configEntriesCount]; + for (int i = 0; i < configEntriesCount; i++) + { + string key = Marshal.PtrToStringAnsi(configEntries[i].Key) ?? string.Empty; + string value = Marshal.PtrToStringAnsi(configEntries[i].Value) ?? string.Empty; + configList[i] = new ConfigEntry + { + Key = key, + Value = value, + }; + } + + return configList; + } + + /// + protected override string? GetString(string key) + { + if (string.IsNullOrEmpty(key)) + { + return null; + } + + foreach (var config in _configList) + { + if (config.Key == key) + { + return config.Value; + } + } + + return null; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NativeConfigEntry + { + public IntPtr Key; + public IntPtr Value; + } + + internal struct ConfigEntry + { + public string Key; + public string Value; + } + + // the "dll" extension is required on .NET Framework + // and optional on .NET Core + // These methods are rewritten by the native tracer to use the correct paths + private static partial class Windows + { + [DllImport("Datadog.Tracer.Native.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int LoadConfigurationFromDisk(string filePathOverride, int bufferSize, ref int configEntriesCount, [In, Out] NativeConfigEntry[] configEntries); + } + + // assume .NET Core if not running on Windows + // These methods are rewritten by the native tracer to use the correct paths + private static partial class NonWindows + { + [DllImport("/project/tracer/src/Datadog.Tracer.Native/build/bin/Datadog.Tracer.Native.so")] // TODO: change to Datadog.Tracer.Native (doesn't work locally?) + public static extern int LoadConfigurationFromDisk(string filePathOverride, int bufferSize, ref int configEntriesCount, [In, Out] NativeConfigEntry[] configEntries); + } + } +} diff --git a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/GlobalConfigurationSource.cs b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/GlobalConfigurationSource.cs index dc1b26213785..e2231c57f3a6 100644 --- a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/GlobalConfigurationSource.cs +++ b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/GlobalConfigurationSource.cs @@ -30,8 +30,9 @@ internal class GlobalConfigurationSource /// A new instance. internal static CompositeConfigurationSource CreateDefaultConfigurationSource() { - // env > AppSettings > datadog.json + // library_config yaml file > env > AppSettings > datadog.json var configurationSource = new CompositeConfigurationSource(); + configurationSource.Add(new FileConfigurationSource()); configurationSource.Add(new EnvironmentConfigurationSource()); #if NETFRAMEWORK diff --git a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs index 27fc69fd056e..a86cc23e56bd 100644 --- a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs @@ -17,7 +17,7 @@ internal static partial class PublicApiUsageExtensions /// The number of members in the enum. /// This is a non-distinct count of defined names. /// - public const int Length = 168; + public const int Length = 169; /// /// Returns the string representation of the value. @@ -124,6 +124,7 @@ public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.PublicApi Datadog.Trace.Telemetry.Metrics.PublicApiUsage.CustomTelemeteredConfigurationSource_Ctor => "name:customtelemeteredconfigurationsource_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.EnvironmentConfigurationSource_Ctor => "name:environmentconfigurationsource_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.NameValueConfigurationSource_Ctor => "name:namevalueconfigurationsource_ctor", + Datadog.Trace.Telemetry.Metrics.PublicApiUsage.FileConfigurationSource_Ctor => "name:fileconfigurationsource_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor => "name:tracersettings_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_Source => "name:tracersettings_ctor_source", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_UseDefaultSources => "name:tracersettings_ctor_usedefaultsources", @@ -305,6 +306,7 @@ public static Datadog.Trace.Telemetry.Metrics.PublicApiUsage[] GetValues() Datadog.Trace.Telemetry.Metrics.PublicApiUsage.CustomTelemeteredConfigurationSource_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.EnvironmentConfigurationSource_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.NameValueConfigurationSource_Ctor, + Datadog.Trace.Telemetry.Metrics.PublicApiUsage.FileConfigurationSource_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_Source, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_UseDefaultSources, @@ -486,6 +488,7 @@ public static string[] GetNames() nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.CustomTelemeteredConfigurationSource_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.EnvironmentConfigurationSource_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.NameValueConfigurationSource_Ctor), + nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.FileConfigurationSource_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_Source), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_UseDefaultSources), @@ -667,6 +670,7 @@ public static string[] GetDescriptions() "name:customtelemeteredconfigurationsource_ctor", "name:environmentconfigurationsource_ctor", "name:namevalueconfigurationsource_ctor", + "name:fileconfigurationsource_ctor", "name:tracersettings_ctor", "name:tracersettings_ctor_source", "name:tracersettings_ctor_usedefaultsources", diff --git a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs index 27fc69fd056e..a86cc23e56bd 100644 --- a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs @@ -17,7 +17,7 @@ internal static partial class PublicApiUsageExtensions /// The number of members in the enum. /// This is a non-distinct count of defined names. /// - public const int Length = 168; + public const int Length = 169; /// /// Returns the string representation of the value. @@ -124,6 +124,7 @@ public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.PublicApi Datadog.Trace.Telemetry.Metrics.PublicApiUsage.CustomTelemeteredConfigurationSource_Ctor => "name:customtelemeteredconfigurationsource_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.EnvironmentConfigurationSource_Ctor => "name:environmentconfigurationsource_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.NameValueConfigurationSource_Ctor => "name:namevalueconfigurationsource_ctor", + Datadog.Trace.Telemetry.Metrics.PublicApiUsage.FileConfigurationSource_Ctor => "name:fileconfigurationsource_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor => "name:tracersettings_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_Source => "name:tracersettings_ctor_source", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_UseDefaultSources => "name:tracersettings_ctor_usedefaultsources", @@ -305,6 +306,7 @@ public static Datadog.Trace.Telemetry.Metrics.PublicApiUsage[] GetValues() Datadog.Trace.Telemetry.Metrics.PublicApiUsage.CustomTelemeteredConfigurationSource_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.EnvironmentConfigurationSource_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.NameValueConfigurationSource_Ctor, + Datadog.Trace.Telemetry.Metrics.PublicApiUsage.FileConfigurationSource_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_Source, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_UseDefaultSources, @@ -486,6 +488,7 @@ public static string[] GetNames() nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.CustomTelemeteredConfigurationSource_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.EnvironmentConfigurationSource_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.NameValueConfigurationSource_Ctor), + nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.FileConfigurationSource_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_Source), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_UseDefaultSources), @@ -667,6 +670,7 @@ public static string[] GetDescriptions() "name:customtelemeteredconfigurationsource_ctor", "name:environmentconfigurationsource_ctor", "name:namevalueconfigurationsource_ctor", + "name:fileconfigurationsource_ctor", "name:tracersettings_ctor", "name:tracersettings_ctor_source", "name:tracersettings_ctor_usedefaultsources", diff --git a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs index 27fc69fd056e..a86cc23e56bd 100644 --- a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs @@ -17,7 +17,7 @@ internal static partial class PublicApiUsageExtensions /// The number of members in the enum. /// This is a non-distinct count of defined names. /// - public const int Length = 168; + public const int Length = 169; /// /// Returns the string representation of the value. @@ -124,6 +124,7 @@ public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.PublicApi Datadog.Trace.Telemetry.Metrics.PublicApiUsage.CustomTelemeteredConfigurationSource_Ctor => "name:customtelemeteredconfigurationsource_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.EnvironmentConfigurationSource_Ctor => "name:environmentconfigurationsource_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.NameValueConfigurationSource_Ctor => "name:namevalueconfigurationsource_ctor", + Datadog.Trace.Telemetry.Metrics.PublicApiUsage.FileConfigurationSource_Ctor => "name:fileconfigurationsource_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor => "name:tracersettings_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_Source => "name:tracersettings_ctor_source", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_UseDefaultSources => "name:tracersettings_ctor_usedefaultsources", @@ -305,6 +306,7 @@ public static Datadog.Trace.Telemetry.Metrics.PublicApiUsage[] GetValues() Datadog.Trace.Telemetry.Metrics.PublicApiUsage.CustomTelemeteredConfigurationSource_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.EnvironmentConfigurationSource_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.NameValueConfigurationSource_Ctor, + Datadog.Trace.Telemetry.Metrics.PublicApiUsage.FileConfigurationSource_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_Source, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_UseDefaultSources, @@ -486,6 +488,7 @@ public static string[] GetNames() nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.CustomTelemeteredConfigurationSource_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.EnvironmentConfigurationSource_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.NameValueConfigurationSource_Ctor), + nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.FileConfigurationSource_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_Source), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_UseDefaultSources), @@ -667,6 +670,7 @@ public static string[] GetDescriptions() "name:customtelemeteredconfigurationsource_ctor", "name:environmentconfigurationsource_ctor", "name:namevalueconfigurationsource_ctor", + "name:fileconfigurationsource_ctor", "name:tracersettings_ctor", "name:tracersettings_ctor_source", "name:tracersettings_ctor_usedefaultsources", diff --git a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs index 27fc69fd056e..a86cc23e56bd 100644 --- a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/PublicApiUsageExtensions_EnumExtensions.g.cs @@ -17,7 +17,7 @@ internal static partial class PublicApiUsageExtensions /// The number of members in the enum. /// This is a non-distinct count of defined names. /// - public const int Length = 168; + public const int Length = 169; /// /// Returns the string representation of the value. @@ -124,6 +124,7 @@ public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.PublicApi Datadog.Trace.Telemetry.Metrics.PublicApiUsage.CustomTelemeteredConfigurationSource_Ctor => "name:customtelemeteredconfigurationsource_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.EnvironmentConfigurationSource_Ctor => "name:environmentconfigurationsource_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.NameValueConfigurationSource_Ctor => "name:namevalueconfigurationsource_ctor", + Datadog.Trace.Telemetry.Metrics.PublicApiUsage.FileConfigurationSource_Ctor => "name:fileconfigurationsource_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor => "name:tracersettings_ctor", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_Source => "name:tracersettings_ctor_source", Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_UseDefaultSources => "name:tracersettings_ctor_usedefaultsources", @@ -305,6 +306,7 @@ public static Datadog.Trace.Telemetry.Metrics.PublicApiUsage[] GetValues() Datadog.Trace.Telemetry.Metrics.PublicApiUsage.CustomTelemeteredConfigurationSource_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.EnvironmentConfigurationSource_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.NameValueConfigurationSource_Ctor, + Datadog.Trace.Telemetry.Metrics.PublicApiUsage.FileConfigurationSource_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_Source, Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_UseDefaultSources, @@ -486,6 +488,7 @@ public static string[] GetNames() nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.CustomTelemeteredConfigurationSource_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.EnvironmentConfigurationSource_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.NameValueConfigurationSource_Ctor), + nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.FileConfigurationSource_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_Source), nameof(Datadog.Trace.Telemetry.Metrics.PublicApiUsage.TracerSettings_Ctor_UseDefaultSources), @@ -667,6 +670,7 @@ public static string[] GetDescriptions() "name:customtelemeteredconfigurationsource_ctor", "name:environmentconfigurationsource_ctor", "name:namevalueconfigurationsource_ctor", + "name:fileconfigurationsource_ctor", "name:tracersettings_ctor", "name:tracersettings_ctor_source", "name:tracersettings_ctor_usedefaultsources", diff --git a/tracer/src/Datadog.Trace/Telemetry/Metrics/PublicApiUsage.cs b/tracer/src/Datadog.Trace/Telemetry/Metrics/PublicApiUsage.cs index b0511851fdff..5a334fe24218 100644 --- a/tracer/src/Datadog.Trace/Telemetry/Metrics/PublicApiUsage.cs +++ b/tracer/src/Datadog.Trace/Telemetry/Metrics/PublicApiUsage.cs @@ -156,6 +156,7 @@ internal enum PublicApiUsage [Description("name:customtelemeteredconfigurationsource_ctor")] CustomTelemeteredConfigurationSource_Ctor, [Description("name:environmentconfigurationsource_ctor")] EnvironmentConfigurationSource_Ctor, [Description("name:namevalueconfigurationsource_ctor")] NameValueConfigurationSource_Ctor, + [Description("name:fileconfigurationsource_ctor")] FileConfigurationSource_Ctor, [Description("name:tracersettings_ctor")] TracerSettings_Ctor, [Description("name:tracersettings_ctor_source")] TracerSettings_Ctor_Source, diff --git a/tracer/src/Datadog.Tracer.Native/CMakeLists.txt b/tracer/src/Datadog.Tracer.Native/CMakeLists.txt index 21efbd5793c3..365f0d74fe79 100644 --- a/tracer/src/Datadog.Tracer.Native/CMakeLists.txt +++ b/tracer/src/Datadog.Tracer.Native/CMakeLists.txt @@ -163,6 +163,7 @@ add_library("Datadog.Tracer.Native.static" STATIC integration.cpp metadata_builder.cpp ${DOTNET_TRACER_REPO_ROOT_PATH}/shared/src/native-src/miniutf.cpp + ${DOTNET_TRACER_REPO_ROOT_PATH}/shared/src/native-src/library_config.cpp ${DOTNET_TRACER_REPO_ROOT_PATH}/shared/src/native-src/string.cpp ${DOTNET_TRACER_REPO_ROOT_PATH}/shared/src/native-src/util.cpp calltarget_tokens.cpp @@ -218,6 +219,7 @@ target_compile_definitions("Datadog.Tracer.Native.static" PUBLIC "-D_GLIBCXX_USE # Define linker libraries if (ISMACOS) target_link_libraries("Datadog.Tracer.Native.static" + libdatadog-lib # Should we for MacOS? managed-loader-objs coreclr re2-lib @@ -227,6 +229,7 @@ if (ISMACOS) ) elseif(ISLINUX) target_link_libraries("Datadog.Tracer.Native.static" + libdatadog-lib managed-loader-objs coreclr re2-lib @@ -239,7 +242,7 @@ elseif(ISLINUX) ) endif() -add_dependencies("Datadog.Tracer.Native.static" coreclr re2-lib spdlog-headers managed-loader-objs) +add_dependencies("Datadog.Tracer.Native.static" libdatadog-lib coreclr re2-lib spdlog-headers managed-loader-objs) # ****************************************************** # Define shared target diff --git a/tracer/src/Datadog.Tracer.Native/Datadog.Tracer.Native.def b/tracer/src/Datadog.Tracer.Native/Datadog.Tracer.Native.def index b2223eaf69fd..10aaeb03790b 100644 --- a/tracer/src/Datadog.Tracer.Native/Datadog.Tracer.Native.def +++ b/tracer/src/Datadog.Tracer.Native/Datadog.Tracer.Native.def @@ -26,3 +26,4 @@ EXPORTS GetUserStrings InitEmbeddedCallSiteDefinitions InitEmbeddedCallTargetDefinitions + LoadConfigurationFromDisk diff --git a/tracer/src/Datadog.Tracer.Native/Datadog.Tracer.Native.vcxproj b/tracer/src/Datadog.Tracer.Native/Datadog.Tracer.Native.vcxproj index 35df6c7fb87a..2677b1639266 100644 --- a/tracer/src/Datadog.Tracer.Native/Datadog.Tracer.Native.vcxproj +++ b/tracer/src/Datadog.Tracer.Native/Datadog.Tracer.Native.vcxproj @@ -272,6 +272,7 @@ + @@ -348,6 +349,7 @@ + diff --git a/tracer/src/Datadog.Tracer.Native/Datadog.Tracer.Native.vcxproj.filters b/tracer/src/Datadog.Tracer.Native/Datadog.Tracer.Native.vcxproj.filters index 6585950f55a6..730265dc7a4f 100644 --- a/tracer/src/Datadog.Tracer.Native/Datadog.Tracer.Native.vcxproj.filters +++ b/tracer/src/Datadog.Tracer.Native/Datadog.Tracer.Native.vcxproj.filters @@ -35,6 +35,9 @@ shared + + shared + Debugger @@ -158,6 +161,9 @@ shared + + shared + shared diff --git a/tracer/src/Datadog.Tracer.Native/interop.cpp b/tracer/src/Datadog.Tracer.Native/interop.cpp index 94eb445bb94d..f8fb88222e4a 100644 --- a/tracer/src/Datadog.Tracer.Native/interop.cpp +++ b/tracer/src/Datadog.Tracer.Native/interop.cpp @@ -9,7 +9,9 @@ #include "cor_profiler.h" #include "logger.h" #include "iast/hardcoded_secrets_method_analyzer.h" +#include #include "Generated/generated_definitions.h" +#include "../../../shared/src/native-src/library_config.h" #ifndef _WIN32 #include @@ -268,6 +270,38 @@ EXTERN_C BOOL STDAPICALLTYPE ShouldHeal(ModuleID moduleId, int methodToken, WCHA return trace::profiler->ShouldHeal(moduleId, methodToken, instrumentationId, products); } +EXTERN_C int STDAPICALLTYPE LoadConfigurationFromDisk(char* filePathOverride, int maxConfigEntries, int& configEntriesCount, + shared::ConfigEntryFFI* configEntries) +{ + if (configEntries == nullptr) { + return E_POINTER; + } + + auto previousPath = shared::LibraryConfig::config_path; + if (filePathOverride != nullptr && std::strlen(filePathOverride) > 0) { + shared::LibraryConfig::config_path = std::string(filePathOverride); + } + + auto configFromFile = shared::LibraryConfig::get_configuration(false); + configEntriesCount = configFromFile.size(); + if (configEntriesCount > maxConfigEntries) { + return E_OUTOFMEMORY; + } + + int index = 0; + for (const auto& configEntry : configFromFile) { + configEntries[index] = { + .key = strdup(configEntry.key.c_str()), + .value = strdup(configEntry.value.c_str()), + }; + index++; + } + + shared::LibraryConfig::config_path = previousPath; + return S_OK; +} + + #ifndef _WIN32 EXTERN_C void *dddlopen (const char *__file, int __mode) { @@ -288,4 +322,4 @@ EXTERN_C int dddlclose (void *handle) { return dlclose(handle); } -#endif \ No newline at end of file +#endif diff --git a/tracer/test/Datadog.Trace.Tests/Configuration/TracerSettingsTests.cs b/tracer/test/Datadog.Trace.Tests/Configuration/TracerSettingsTests.cs index 4044fc0612f1..4991e2729910 100644 --- a/tracer/test/Datadog.Trace.Tests/Configuration/TracerSettingsTests.cs +++ b/tracer/test/Datadog.Trace.Tests/Configuration/TracerSettingsTests.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.IO; using System.Linq; using System.Reflection; using Datadog.Trace.Agent; @@ -1334,6 +1335,40 @@ public void DDTagsTakesPrecedenceOverOTELTags() errorLog.ShouldHaveExpectedOtelMetric(Count.OpenTelemetryConfigHiddenByDatadogConfig, "OTEL_RESOURCE_ATTRIBUTES".ToLowerInvariant(), "DD_TAGS".ToLowerInvariant()); } + [Fact] + public void ValidateFileConfigurationSource() + { + var tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + Directory.CreateDirectory(tempDir); + var configFilePath = Path.Combine(tempDir, "library_config.yaml"); + Console.WriteLine($"Config file path: {configFilePath}"); + #pragma warning disable SA1118 + File.WriteAllText(configFilePath, @" +rules: + - selectors: + - origin: language + matches: + - dotnet + operator: equals + configuration: + DD_SERVICE: my-service +config_id: abc +"); + #pragma warning restore SA1118 + + var source = new FileConfigurationSource(configFilePath); + var tracerSettings = new TracerSettings(source); + + if (FrameworkDescription.Instance.IsWindows()) + { + tracerSettings.ServiceName.Should().Be(string.Empty); + } + else + { + tracerSettings.ServiceName.Should().Be("my-service"); + } + } + private void ValidateErrorStatusCodes(bool[] result, string newErrorKeyValue, string deprecatedErrorKeyValue, string expectedErrorRange) { if (newErrorKeyValue is not null || deprecatedErrorKeyValue is not null)