Skip to content
Open
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
10 changes: 9 additions & 1 deletion lib/datadog/core/environment/process.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ module Process
# @return [String] comma-separated normalized key:value pairs
def self.serialized
return @serialized if defined?(@serialized)

@serialized = tags_array.join(',').freeze
end

# This method returns an array in the format ["k1:v1","k2:v2","k3:v3"]
# @return [Array<String>] array of normalized key:value pairs
def self.tags_array
return @tags_array if defined?(@tags_array)
tags = []

workdir = TagNormalizer.normalize_process_value(entrypoint_workdir.to_s)
Expand All @@ -27,7 +35,7 @@ def self.serialized

tags << "#{Environment::Ext::TAG_ENTRYPOINT_TYPE}:#{TagNormalizer.normalize(entrypoint_type, remove_digit_start_char: false)}"

@serialized = tags.join(',').freeze
@tags_array = tags.freeze
end

# Returns the last segment of the working directory of the process
Expand Down
5 changes: 5 additions & 0 deletions lib/datadog/core/remote/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ def payload # standard:disable Metrics/MethodLength

client_tracer[:app_version] = app_version if app_version

if Datadog.configuration.experimental_propagate_process_tags_enabled
process_tags = Core::Environment::Process.tags_array
client_tracer[:process_tags] = process_tags if process_tags.any?
end

{
client: {
state: {
Expand Down
3 changes: 3 additions & 0 deletions sig/datadog/core/environment/process.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ module Datadog
module Environment
module Process
@serialized: ::String
@tags_array: Array[::String]

def self.serialized: () -> ::String

def self.tags_array: () -> ::Array[::String]

private

def self.entrypoint_workdir: () -> ::String
Expand Down
116 changes: 110 additions & 6 deletions spec/datadog/core/environment/process_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
require 'open3'

RSpec.describe Datadog::Core::Environment::Process do
def reset_memoized_variables!
described_class.remove_instance_variable(:@serialized) if described_class.instance_variable_defined?(:@serialized)
described_class.remove_instance_variable(:@tags_array) if described_class.instance_variable_defined?(:@tags_array)
end

describe '::serialized' do
subject(:serialized) { described_class.serialized }

def reset_serialized!
described_class.remove_instance_variable(:@serialized) if described_class.instance_variable_defined?(:@serialized)
end

shared_context 'with mocked process environment' do
let(:pwd) { '/app' }

Expand All @@ -24,11 +25,11 @@ def reset_serialized!
allow(Dir).to receive(:pwd).and_return(pwd)
allow(File).to receive(:expand_path).and_call_original
allow(File).to receive(:expand_path).with('.').and_return('/app')
reset_serialized!
reset_memoized_variables!
end

after do
reset_serialized!
reset_memoized_variables!
end
end

Expand Down Expand Up @@ -147,4 +148,107 @@ def reset_serialized!
end
end
end
describe '::tags_array' do
subject(:tags_array) { described_class.tags_array }

shared_context 'with mocked process environment' do
let(:pwd) { '/app' }

around do |example|
@original_0 = $0
$0 = program_name
example.run
$0 = @original_0
end

before do
allow(Dir).to receive(:pwd).and_return(pwd)
allow(File).to receive(:expand_path).and_call_original
allow(File).to receive(:expand_path).with('.').and_return('/app')
reset_memoized_variables!
end

after do
reset_memoized_variables!
end
end

it { is_expected.to be_a_kind_of(Array) }

it 'is an array of strings' do
expect(tags_array).to all(be_a(String))
end

it 'returns the same object when called multiple times' do
# Processes are fixed so no need to recompute this on each call
first_call = described_class.tags_array
second_call = described_class.tags_array
expect(first_call).to equal(second_call)
end

context 'with /expectedbasedir/executable' do
include_context 'with mocked process environment'
let(:program_name) { '/expectedbasedir/executable' }

it 'extracts out the tag array correctly' do
expect(tags_array.length).to eq(4)
expect(described_class.tags_array).to include('entrypoint.workdir:app')
expect(described_class.tags_array).to include('entrypoint.name:executable')
expect(described_class.tags_array).to include('entrypoint.basedir:expectedbasedir')
expect(described_class.tags_array).to include('entrypoint.type:script')
end
end

context 'with irb' do
include_context 'with mocked process environment'
let(:program_name) { 'irb' }

it 'extracts out the tag array correctly' do
expect(tags_array.length).to eq(4)
expect(described_class.tags_array).to include('entrypoint.workdir:app')
expect(described_class.tags_array).to include('entrypoint.name:irb')
expect(described_class.tags_array).to include('entrypoint.basedir:app')
expect(described_class.tags_array).to include('entrypoint.type:script')
end
end

context 'with my/path/rubyapp.rb' do
include_context 'with mocked process environment'
let(:program_name) { 'my/path/rubyapp.rb' }

it 'extracts out the tag array correctly' do
expect(tags_array.length).to eq(4)
expect(described_class.tags_array).to include('entrypoint.workdir:app')
expect(described_class.tags_array).to include('entrypoint.name:rubyapp.rb')
expect(described_class.tags_array).to include('entrypoint.basedir:path')
expect(described_class.tags_array).to include('entrypoint.type:script')
end
end

context 'with my/path/foo:,bar' do
include_context 'with mocked process environment'
let(:program_name) { 'my/path/foo:,bar' }

it 'extracts out the tag array correctly' do
expect(tags_array.length).to eq(4)
expect(described_class.tags_array).to include('entrypoint.workdir:app')
expect(described_class.tags_array).to include('entrypoint.name:foo_bar')
expect(described_class.tags_array).to include('entrypoint.basedir:path')
expect(described_class.tags_array).to include('entrypoint.type:script')
end
end

context 'with bin/rails' do
include_context 'with mocked process environment'
let(:program_name) { 'bin/rails' }

it 'extracts out the tags array correctly' do
expect(tags_array.length).to eq(4)
expect(described_class.tags_array).to include('entrypoint.workdir:app')
expect(described_class.tags_array).to include('entrypoint.name:rails')
expect(described_class.tags_array).to include('entrypoint.basedir:bin')
expect(described_class.tags_array).to include('entrypoint.type:script')
end
end
end
end
35 changes: 35 additions & 0 deletions spec/datadog/core/remote/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,41 @@
end
end

context 'process_tags' do
let(:client_payload) { client.send(:payload)[:client] }

context 'when process tags propagation is enabled' do
before do
allow(Datadog.configuration).to receive(:experimental_propagate_process_tags_enabled).and_return(true)
if Datadog::Core::Environment::Process.instance_variable_defined?(:@tags_array)
Datadog::Core::Environment::Process.remove_instance_variable(:@tags_array)
end
end

it 'has process tags in the payload' do
process_tags = client_payload[:client_tracer][:process_tags]
expect(process_tags).to be_a(Array)
expect(process_tags).to include('entrypoint.workdir:app')
expect(process_tags).to include('entrypoint.name:rspec')
expect(process_tags).to include('entrypoint.basedir:bin')
expect(process_tags).to include('entrypoint.type:script')
end
end

context 'when process tags propagation is not enabled' do
# Current false by default
before do
if Datadog::Core::Environment::Process.instance_variable_defined?(:@tags_array)
Datadog::Core::Environment::Process.remove_instance_variable(:@tags_array)
end
end

it 'does not have process tags in the payload' do
expect(client_payload[:client_tracer]).not_to have_key(:process_tags)
end
end
end

context 'cached_target_files' do
it 'returns cached_target_files' do
state = repository.state
Expand Down
Loading