From 48ca7e578d3b2c86c228c7c1f8bb0b89d7167b5c Mon Sep 17 00:00:00 2001 From: wan <26727996+wantsui@users.noreply.github.com> Date: Thu, 4 Dec 2025 14:02:01 -0500 Subject: [PATCH 1/5] Add process tags to instrumentation telemetry. --- lib/datadog/core/telemetry/request.rb | 11 ++++ sig/datadog/core/telemetry/request.rbs | 1 + .../telemetry/integration/telemetry_spec.rb | 64 +++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/lib/datadog/core/telemetry/request.rb b/lib/datadog/core/telemetry/request.rb index 213831e02d7..6469c15f2b2 100644 --- a/lib/datadog/core/telemetry/request.rb +++ b/lib/datadog/core/telemetry/request.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require_relative '../environment/platform' +require_relative '../environment/process' require_relative '../utils/hash' module Datadog @@ -23,6 +24,7 @@ def build_payload(event, seq_id, api_version: 'v2', debug: false) seq_id: seq_id, tracer_time: Core::Utils::Time.now.to_i, } + tag_process_tags!(hash) hash.compact! hash end @@ -64,6 +66,15 @@ def host kernel_version: Core::Environment::Platform.kernel_version } end + + def tag_process_tags!(hash) + return unless Datadog.configuration.experimental_propagate_process_tags_enabled + + process_tags = Core::Environment::Process.serialized + return if process_tags.empty? + + hash[:process_tags] = process_tags + end end end end diff --git a/sig/datadog/core/telemetry/request.rbs b/sig/datadog/core/telemetry/request.rbs index 3828e1e4515..3b2830b4a40 100644 --- a/sig/datadog/core/telemetry/request.rbs +++ b/sig/datadog/core/telemetry/request.rbs @@ -8,6 +8,7 @@ module Datadog def self.application: -> ::Hash[Symbol, untyped] def self.host: -> ::Hash[Symbol, untyped] + def self.tag_process_tags!: (Hash[Symbol, untyped] hash) -> void end end end diff --git a/spec/datadog/core/telemetry/integration/telemetry_spec.rb b/spec/datadog/core/telemetry/integration/telemetry_spec.rb index 1793b4760ae..240a232e235 100644 --- a/spec/datadog/core/telemetry/integration/telemetry_spec.rb +++ b/spec/datadog/core/telemetry/integration/telemetry_spec.rb @@ -367,6 +367,70 @@ include_examples 'telemetry integration tests' end + context 'when process tags propagation is enabled' do + include_context 'agent mode' + include_context 'disable profiling' + + let(:settings) do + Datadog::Core::Configuration::Settings.new.tap do |settings| + settings.agent.port = http_server_port + settings.telemetry.enabled = true + settings.telemetry.dependency_collection = true + end + end + + it 'includes process tags in the payload when the process tags have values' do + allow(Datadog.configuration).to receive(:experimental_propagate_process_tags_enabled).and_return(true) + + component.start(false, components: Datadog.send(:components)) + component.flush + expect(sent_payloads.length).to eq 2 + + payload = sent_payloads[0] + expect(payload.fetch(:payload)).to include('process_tags' => String) + expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.workdir') + expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.basedir') + expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.type') + expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.name') + end + + it 'does not include process_tags when serialized value is empty' do + allow(Datadog.configuration).to receive(:experimental_propagate_process_tags_enabled).and_return(true) + allow(Datadog::Core::Environment::Process).to receive(:serialized).and_return('') + + component.start(false, components: Datadog.send(:components)) + component.flush + expect(sent_payloads.length).to eq 2 + + payload = sent_payloads[0] + expect(payload.fetch(:payload)).not_to have_key('process_tags') + end + end + + context 'when process tags propagation is disabled' do + include_context 'agent mode' + include_context 'disable profiling' + + let(:settings) do + Datadog::Core::Configuration::Settings.new.tap do |settings| + settings.agent.port = http_server_port + settings.telemetry.enabled = true + settings.telemetry.dependency_collection = true + end + end + + it 'does not include process_tags in the payload' do + allow(Datadog.configuration).to receive(:experimental_propagate_process_tags_enabled).and_return(false) + + component.start(false, components: Datadog.send(:components)) + component.flush + expect(sent_payloads.length).to eq 2 + + payload = sent_payloads[0] + expect(payload.fetch(:payload)).not_to have_key('process_tags') + end + end + context 'when events are enqueued prior to start' do # The mode is irrelevant for these tests, there is no need to test # both modes therefore we choose an arbitrary one here. From 3ba9f6188e6173ff0779ecc3f1db041b2404973c Mon Sep 17 00:00:00 2001 From: wan <26727996+wantsui@users.noreply.github.com> Date: Thu, 4 Dec 2025 14:31:29 -0500 Subject: [PATCH 2/5] Move test placement --- .../telemetry/integration/telemetry_spec.rb | 114 ++++++++---------- 1 file changed, 50 insertions(+), 64 deletions(-) diff --git a/spec/datadog/core/telemetry/integration/telemetry_spec.rb b/spec/datadog/core/telemetry/integration/telemetry_spec.rb index 240a232e235..f81804e778d 100644 --- a/spec/datadog/core/telemetry/integration/telemetry_spec.rb +++ b/spec/datadog/core/telemetry/integration/telemetry_spec.rb @@ -298,6 +298,56 @@ ) end end + + describe 'process tags' do + include_context 'disable profiling' + + before do + settings.telemetry.dependency_collection = true + end + + context 'when process tags propagation is enabled' do + it 'includes process tags in the payload when the process tags have values' do + allow(Datadog.configuration).to receive(:experimental_propagate_process_tags_enabled).and_return(true) + + component.start(false, components: Datadog.send(:components)) + component.flush + expect(sent_payloads.length).to eq 2 + + payload = sent_payloads[0] + expect(payload.fetch(:payload)).to include('process_tags' => String) + expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.workdir') + expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.basedir') + expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.type') + expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.name') + end + + it 'does not include process_tags when serialized value is empty' do + allow(Datadog.configuration).to receive(:experimental_propagate_process_tags_enabled).and_return(true) + allow(Datadog::Core::Environment::Process).to receive(:serialized).and_return('') + + component.start(false, components: Datadog.send(:components)) + component.flush + expect(sent_payloads.length).to eq 2 + + payload = sent_payloads[0] + expect(payload.fetch(:payload)).not_to have_key('process_tags') + end + end + + context 'when process tags propagation is disabled' do + it 'does not include process_tags in the payload' do + allow(Datadog.configuration).to receive(:experimental_propagate_process_tags_enabled).and_return(false) + + component.start(false, components: Datadog.send(:components)) + component.flush + expect(sent_payloads.length).to eq 2 + + payload = sent_payloads[0] + expect(payload.fetch(:payload)).not_to have_key('process_tags') + end + end + end end let(:handler_proc) do @@ -367,70 +417,6 @@ include_examples 'telemetry integration tests' end - context 'when process tags propagation is enabled' do - include_context 'agent mode' - include_context 'disable profiling' - - let(:settings) do - Datadog::Core::Configuration::Settings.new.tap do |settings| - settings.agent.port = http_server_port - settings.telemetry.enabled = true - settings.telemetry.dependency_collection = true - end - end - - it 'includes process tags in the payload when the process tags have values' do - allow(Datadog.configuration).to receive(:experimental_propagate_process_tags_enabled).and_return(true) - - component.start(false, components: Datadog.send(:components)) - component.flush - expect(sent_payloads.length).to eq 2 - - payload = sent_payloads[0] - expect(payload.fetch(:payload)).to include('process_tags' => String) - expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.workdir') - expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.basedir') - expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.type') - expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.name') - end - - it 'does not include process_tags when serialized value is empty' do - allow(Datadog.configuration).to receive(:experimental_propagate_process_tags_enabled).and_return(true) - allow(Datadog::Core::Environment::Process).to receive(:serialized).and_return('') - - component.start(false, components: Datadog.send(:components)) - component.flush - expect(sent_payloads.length).to eq 2 - - payload = sent_payloads[0] - expect(payload.fetch(:payload)).not_to have_key('process_tags') - end - end - - context 'when process tags propagation is disabled' do - include_context 'agent mode' - include_context 'disable profiling' - - let(:settings) do - Datadog::Core::Configuration::Settings.new.tap do |settings| - settings.agent.port = http_server_port - settings.telemetry.enabled = true - settings.telemetry.dependency_collection = true - end - end - - it 'does not include process_tags in the payload' do - allow(Datadog.configuration).to receive(:experimental_propagate_process_tags_enabled).and_return(false) - - component.start(false, components: Datadog.send(:components)) - component.flush - expect(sent_payloads.length).to eq 2 - - payload = sent_payloads[0] - expect(payload.fetch(:payload)).not_to have_key('process_tags') - end - end - context 'when events are enqueued prior to start' do # The mode is irrelevant for these tests, there is no need to test # both modes therefore we choose an arbitrary one here. From b08f00b344597d7c98f11e8050734bd3d4d23195 Mon Sep 17 00:00:00 2001 From: wan <26727996+wantsui@users.noreply.github.com> Date: Thu, 4 Dec 2025 21:02:58 -0500 Subject: [PATCH 3/5] Refactor tests based on feedback and change the process tags level to be under application instead. --- lib/datadog/core/telemetry/request.rb | 11 ++++-- sig/datadog/core/telemetry/request.rbs | 2 +- .../telemetry/integration/telemetry_spec.rb | 37 ++++++++++--------- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/lib/datadog/core/telemetry/request.rb b/lib/datadog/core/telemetry/request.rb index 6469c15f2b2..6ac7b911ec2 100644 --- a/lib/datadog/core/telemetry/request.rb +++ b/lib/datadog/core/telemetry/request.rb @@ -24,7 +24,6 @@ def build_payload(event, seq_id, api_version: 'v2', debug: false) seq_id: seq_id, tracer_time: Core::Utils::Time.now.to_i, } - tag_process_tags!(hash) hash.compact! hash end @@ -45,7 +44,7 @@ def application tracer_version = "#{tracer_version}-ci-#{::Datadog::CI::VERSION::STRING}" end - { + app = { env: config.env, language_name: Core::Environment::Ext::LANG, language_version: Core::Environment::Ext::LANG_VERSION, @@ -55,6 +54,10 @@ def application service_version: config.version, tracer_version: tracer_version } + + tag_process_tags!(app) + + app end def host @@ -67,13 +70,13 @@ def host } end - def tag_process_tags!(hash) + def tag_process_tags!(app) return unless Datadog.configuration.experimental_propagate_process_tags_enabled process_tags = Core::Environment::Process.serialized return if process_tags.empty? - hash[:process_tags] = process_tags + app[:process_tags] = process_tags end end end diff --git a/sig/datadog/core/telemetry/request.rbs b/sig/datadog/core/telemetry/request.rbs index 3b2830b4a40..61baff1b40e 100644 --- a/sig/datadog/core/telemetry/request.rbs +++ b/sig/datadog/core/telemetry/request.rbs @@ -8,7 +8,7 @@ module Datadog def self.application: -> ::Hash[Symbol, untyped] def self.host: -> ::Hash[Symbol, untyped] - def self.tag_process_tags!: (Hash[Symbol, untyped] hash) -> void + def self.tag_process_tags!: (Hash[Symbol, untyped] app) -> void end end end diff --git a/spec/datadog/core/telemetry/integration/telemetry_spec.rb b/spec/datadog/core/telemetry/integration/telemetry_spec.rb index f81804e778d..be58e4124c6 100644 --- a/spec/datadog/core/telemetry/integration/telemetry_spec.rb +++ b/spec/datadog/core/telemetry/integration/telemetry_spec.rb @@ -307,31 +307,34 @@ end context 'when process tags propagation is enabled' do - it 'includes process tags in the payload when the process tags have values' do - allow(Datadog.configuration).to receive(:experimental_propagate_process_tags_enabled).and_return(true) - - component.start(false, components: Datadog.send(:components)) - component.flush - expect(sent_payloads.length).to eq 2 - - payload = sent_payloads[0] - expect(payload.fetch(:payload)).to include('process_tags' => String) - expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.workdir') - expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.basedir') - expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.type') - expect(payload.dig(:payload, 'process_tags')).to include('entrypoint.name') + let(:expected_application_hash) do + super().merge('process_tags' => String) end - it 'does not include process_tags when serialized value is empty' do + it 'includes process tags in the payload when the process tags have values' do allow(Datadog.configuration).to receive(:experimental_propagate_process_tags_enabled).and_return(true) - allow(Datadog::Core::Environment::Process).to receive(:serialized).and_return('') component.start(false, components: Datadog.send(:components)) component.flush expect(sent_payloads.length).to eq 2 payload = sent_payloads[0] - expect(payload.fetch(:payload)).not_to have_key('process_tags') + expect(payload.fetch(:payload)).to match( + 'api_version' => 'v2', + 'application' => expected_application_hash, + 'debug' => false, + 'host' => expected_host_hash, + 'payload' => Hash, + 'request_type' => 'app-started', + 'runtime_id' => String, + 'seq_id' => Integer, + 'tracer_time' => Integer, + ) + + expect(payload.dig(:payload, 'application', 'process_tags')).to include('entrypoint.workdir') + expect(payload.dig(:payload, 'application', 'process_tags')).to include('entrypoint.basedir') + expect(payload.dig(:payload, 'application', 'process_tags')).to include('entrypoint.type') + expect(payload.dig(:payload, 'application', 'process_tags')).to include('entrypoint.name') end end @@ -344,7 +347,7 @@ expect(sent_payloads.length).to eq 2 payload = sent_payloads[0] - expect(payload.fetch(:payload)).not_to have_key('process_tags') + expect(payload.dig(:payload, 'application')).not_to have_key('process_tags') end end end From 2848b63de8bf4755766834ad1fa69283d8748911 Mon Sep 17 00:00:00 2001 From: wan <26727996+wantsui@users.noreply.github.com> Date: Tue, 9 Dec 2025 14:54:21 -0500 Subject: [PATCH 4/5] Add missing definitions for steep check --- lib/datadog/core/telemetry/request.rb | 6 +++--- sig/datadog/core/configuration/settings.rbs | 4 ++++ sig/datadog/core/telemetry/request.rbs | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/datadog/core/telemetry/request.rb b/lib/datadog/core/telemetry/request.rb index 6ac7b911ec2..a093a90d4fe 100644 --- a/lib/datadog/core/telemetry/request.rb +++ b/lib/datadog/core/telemetry/request.rb @@ -55,7 +55,7 @@ def application tracer_version: tracer_version } - tag_process_tags!(app) + tag_process_tags!(app, config) app end @@ -70,8 +70,8 @@ def host } end - def tag_process_tags!(app) - return unless Datadog.configuration.experimental_propagate_process_tags_enabled + def tag_process_tags!(app, config) + return unless config.experimental_propagate_process_tags_enabled process_tags = Core::Environment::Process.serialized return if process_tags.empty? diff --git a/sig/datadog/core/configuration/settings.rbs b/sig/datadog/core/configuration/settings.rbs index 573d8ee3feb..f320a5189cf 100644 --- a/sig/datadog/core/configuration/settings.rbs +++ b/sig/datadog/core/configuration/settings.rbs @@ -132,6 +132,10 @@ module Datadog def tags: -> ::Hash[::String, ::String] + def experimental_propagate_process_tags_enabled: () -> bool + + def experimental_propagate_process_tags_enabled=: (bool value) -> bool + def logger=: (untyped logger) -> untyped def runtime_metrics: (?untyped? options) -> untyped diff --git a/sig/datadog/core/telemetry/request.rbs b/sig/datadog/core/telemetry/request.rbs index 61baff1b40e..b6575625e32 100644 --- a/sig/datadog/core/telemetry/request.rbs +++ b/sig/datadog/core/telemetry/request.rbs @@ -8,7 +8,7 @@ module Datadog def self.application: -> ::Hash[Symbol, untyped] def self.host: -> ::Hash[Symbol, untyped] - def self.tag_process_tags!: (Hash[Symbol, untyped] app) -> void + def self.tag_process_tags!: (Hash[Symbol, untyped] app, Core::Configuration::Settings config) -> void end end end From 2d0d8b1444ba2aaad37d93238836dd9356839eac Mon Sep 17 00:00:00 2001 From: wan <26727996+wantsui@users.noreply.github.com> Date: Tue, 9 Dec 2025 15:48:36 -0500 Subject: [PATCH 5/5] Add missing experimental process tags default --- spec/datadog/core/telemetry/request_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/datadog/core/telemetry/request_spec.rb b/spec/datadog/core/telemetry/request_spec.rb index 3da9dacce31..57609b20ba7 100644 --- a/spec/datadog/core/telemetry/request_spec.rb +++ b/spec/datadog/core/telemetry/request_spec.rb @@ -85,7 +85,8 @@ ci: double('ci', enabled: true), env: env, service: service_name, - version: service_version + version: service_version, + experimental_propagate_process_tags_enabled: false ) ) end