diff --git a/lib/datadog/core/crashtracking/tag_builder.rb b/lib/datadog/core/crashtracking/tag_builder.rb index b4285a2f3b4..9ce1e79fcd9 100644 --- a/lib/datadog/core/crashtracking/tag_builder.rb +++ b/lib/datadog/core/crashtracking/tag_builder.rb @@ -8,14 +8,12 @@ module Datadog module Core module Crashtracking - # Builds a hash of default plus user tags to be included in a profile + # This module builds a hash of tags module TagBuilder module_function def call(settings) - # When changing or adding these, make sure they are kept in sync with - # https://docs.google.com/spreadsheets/d/1LOGMf4c4Avbtn36uZ2SWvhIGKRPLM1BoWkUP4JYj7hA/ (Datadog internal link) - tags = { + hash = { 'host' => Environment::Socket.hostname, 'language' => Environment::Identity.lang, 'process_id' => Process.pid.to_s, @@ -27,16 +25,16 @@ def call(settings) 'runtime_version' => Environment::Identity.lang_version, } - tags['env'] = settings.env if settings.env - tags['service'] = settings.service if settings.service - tags['version'] = settings.version if settings.version - tags['git.repository_url'] = Environment::Git.git_repository_url if Environment::Git.git_repository_url - tags['git.commit.sha'] = Environment::Git.git_commit_sha if Environment::Git.git_commit_sha + hash['env'] = settings.env if settings.env + hash['service'] = settings.service if settings.service + hash['version'] = settings.version if settings.version + hash['git.repository_url'] = Environment::Git.git_repository_url if Environment::Git.git_repository_url + hash['git.commit.sha'] = Environment::Git.git_commit_sha if Environment::Git.git_commit_sha - # Make sure everything is an utf-8 string, to avoid encoding issues in native code/libddprof/further downstream - settings.tags.merge(tags).map do |key, value| - [Utils.utf8_encode(key), Utils.utf8_encode(value)] - end.to_h + # Make sure everything is an utf-8 string, to avoid encoding issues in downstream + (settings.tags || {}).merge(hash).each_with_object({}) do |(key, value), h| + h[Utils.utf8_encode(key)] = Utils.utf8_encode(value) + end end end end diff --git a/spec/datadog/core/crashtracking/tag_builder_spec.rb b/spec/datadog/core/crashtracking/tag_builder_spec.rb new file mode 100644 index 00000000000..6f60b35401f --- /dev/null +++ b/spec/datadog/core/crashtracking/tag_builder_spec.rb @@ -0,0 +1,111 @@ +require 'spec_helper' +require 'datadog/core/crashtracking/tag_builder' + +RSpec.describe Datadog::Core::Crashtracking::TagBuilder do + describe '.call' do + let(:settings) { Datadog::Core::Configuration::Settings.new } + + subject(:call) { described_class.call(settings) } + + it 'returns a hash with the tags to be attached to a profile' do + expect(call).to include( + 'host' => Datadog::Core::Environment::Socket.hostname, + 'language' => 'ruby', + 'process_id' => Process.pid.to_s, + 'profiler_version' => start_with('2.'), + 'runtime' => 'ruby', + 'runtime_engine' => RUBY_ENGINE, + 'runtime-id' => Datadog::Core::Environment::Identity.id, + 'runtime_platform' => RUBY_PLATFORM, + 'runtime_version' => RUBY_VERSION, + ) + end + + describe 'unified service tagging' do + [:env, :service, :version].each do |tag| + context "when a #{tag} is defined" do + before do + settings.send("#{tag}=".to_sym, 'expected_value') + end + + it 'includes it as a tag' do + expect(call).to include(tag.to_s => 'expected_value') + end + end + + context "when #{tag} is nil" do + before do + settings.send("#{tag}=".to_sym, nil) + end + + it do + expect(call.keys).to_not include(tag.to_s) + end + end + end + end + + it 'includes the provided user tags' do + settings.tags = { 'foo' => 'bar' } + + expect(call).to include('foo' => 'bar') + end + + context 'when there is a conflict between user and metadata tags' do + it 'overrides the user-provided tags' do + settings.tags = { 'foo' => 'bar', 'language' => 'python' } + + expect(call).to include('foo' => 'bar', 'language' => 'ruby') + end + end + + context 'when user tag keys and values are not strings' do + it 'encodes them as strings' do + settings.tags = { :symbol_key => :symbol_value, nil => 'nil key', 'nil value' => nil, 12 => 34 } + + expect(call).to include('symbol_key' => 'symbol_value', '' => 'nil key', 'nil value' => '', '12' => '34') + end + end + + context 'when tagging key or value is not utf-8' do + it 'converts them to utf-8' do + settings.tags = { 'ascii-key'.encode(Encoding::ASCII) => 'ascii-value'.encode(Encoding::ASCII) } + + result = call + + result.each do |key, value| + expect([key, value]).to all(have_attributes(encoding: Encoding::UTF_8)) + end + expect(result).to include('ascii-key' => 'ascii-value') + end + end + + describe 'source code integration' do + context 'when git environment is available' do + before do + allow(Datadog::Core::Environment::Git).to receive(:git_repository_url).and_return( + 'git_repository_url' + ) + allow(Datadog::Core::Environment::Git).to receive(:git_commit_sha).and_return('git_commit_sha') + end + + it 'includes the git repository URL and commit SHA' do + expect(call).to include( + 'git.repository_url' => 'git_repository_url', 'git.commit.sha' => 'git_commit_sha' + ) + end + end + + context 'when git environment is not available' do + before do + allow(Datadog::Core::Environment::Git).to receive(:git_repository_url).and_return(nil) + allow(Datadog::Core::Environment::Git).to receive(:git_commit_sha).and_return(nil) + end + + it 'includes the git repository URL and commit SHA' do + expect(call).to_not include('git.repository_url', 'git.commit.sha') + end + end + end + end +end diff --git a/spec/datadog/core/telemetry/event_spec.rb b/spec/datadog/core/telemetry/event_spec.rb index e7cf76b8c30..b8eee1f48d8 100644 --- a/spec/datadog/core/telemetry/event_spec.rb +++ b/spec/datadog/core/telemetry/event_spec.rb @@ -44,7 +44,7 @@ def contain_configuration(*array) }, profiler: { enabled: false, - # error: anything, # FIXME: This is not deterministic + error: anything, }, }, configuration: contain_configuration(