From 7e56d7ca22780159e663b88714c808fa8382c67a Mon Sep 17 00:00:00 2001 From: Victor Pellan Date: Fri, 17 Oct 2025 17:49:09 +0200 Subject: [PATCH 1/8] Add configuration for DD_TRACE_HTTP_SERVER_ERROR_STATUSES and DD_TRACE_HTTP_CLIENT_ERROR_STATUSES --- .../configuration/supported_configurations.rb | 2 + lib/datadog/tracing/configuration/ext.rb | 6 + lib/datadog/tracing/configuration/settings.rb | 35 ++++++ sig/datadog/tracing/configuration/ext.rbs | 4 + .../tracing/configuration/settings_spec.rb | 19 ++++ .../excon/configuration/settings_spec.rb | 2 +- .../faraday/configuration/settings_spec.rb | 2 +- .../grape/configuration/settings_spec.rb | 2 +- .../http/configuration/settings_spec.rb | 2 +- .../httpclient/configuration/settings_spec.rb | 2 +- .../httprb/configuration/settings_spec.rb | 2 +- .../contrib/shared_settings_examples.rb | 107 +++++++++--------- supported-configurations.json | 6 + 13 files changed, 134 insertions(+), 57 deletions(-) diff --git a/lib/datadog/core/configuration/supported_configurations.rb b/lib/datadog/core/configuration/supported_configurations.rb index a2159507761..4ba0da53977 100644 --- a/lib/datadog/core/configuration/supported_configurations.rb +++ b/lib/datadog/core/configuration/supported_configurations.rb @@ -195,8 +195,10 @@ module Configuration "DD_TRACE_HTTPRB_SERVICE_NAME" => {version: ["A"]}, "DD_TRACE_HTTP_ANALYTICS_ENABLED" => {version: ["A"]}, "DD_TRACE_HTTP_ANALYTICS_SAMPLE_RATE" => {version: ["A"]}, + "DD_TRACE_HTTP_CLIENT_ERROR_STATUSES" => {version: ["A"]}, "DD_TRACE_HTTP_ENABLED" => {version: ["A"]}, "DD_TRACE_HTTP_ERROR_STATUS_CODES" => {version: ["A"]}, + "DD_TRACE_HTTP_SERVER_ERROR_STATUSES" => {version: ["A"]}, "DD_TRACE_KAFKA_ANALYTICS_ENABLED" => {version: ["A"]}, "DD_TRACE_KAFKA_ANALYTICS_SAMPLE_RATE" => {version: ["A"]}, "DD_TRACE_KAFKA_ENABLED" => {version: ["A"]}, diff --git a/lib/datadog/tracing/configuration/ext.rb b/lib/datadog/tracing/configuration/ext.rb index b610e3ccbf9..38a324bb289 100644 --- a/lib/datadog/tracing/configuration/ext.rb +++ b/lib/datadog/tracing/configuration/ext.rb @@ -104,6 +104,12 @@ module ClientIp ENV_ENABLED = 'DD_TRACE_CLIENT_IP_ENABLED' ENV_HEADER_NAME = 'DD_TRACE_CLIENT_IP_HEADER' end + + # @public_api + module HTTPErrorStatuses + ENV_SERVER_ERROR_STATUSES = 'DD_TRACE_HTTP_SERVER_ERROR_STATUSES' + ENV_CLIENT_ERROR_STATUSES = 'DD_TRACE_HTTP_CLIENT_ERROR_STATUSES' + end end end end diff --git a/lib/datadog/tracing/configuration/settings.rb b/lib/datadog/tracing/configuration/settings.rb index 01f586913fc..c7be7bf786e 100644 --- a/lib/datadog/tracing/configuration/settings.rb +++ b/lib/datadog/tracing/configuration/settings.rb @@ -2,6 +2,8 @@ require_relative '../../tracing/configuration/ext' require_relative '../../core/environment/variable_helpers' +require_relative '../contrib/status_range_matcher' +require_relative '../contrib/status_range_env_parser' require_relative 'http' module Datadog @@ -490,6 +492,39 @@ def self.extended(base) o.env Tracing::Configuration::Ext::Distributed::ENV_X_DATADOG_TAGS_MAX_LENGTH o.default 512 end + + # HTTP error statuses configuration + # @public_api + settings :http_error_statuses do + # Defines the range of status codes to be considered errors on http.server span kinds. + # Once set, only the values within the specified range are considered errors. + # + # Format of env var: comma-separated list of values like 500,501,502 or ranges like 500-599 (e.g. `500,502,504-510`) + # + # @default `DD_TRACE_HTTP_SERVER_ERROR_STATUSES` environment variable, otherwise `500..599`. + # @return [Tracing::Contrib::StatusRangeMatcher] + option :server do |o| + o.env Tracing::Configuration::Ext::HTTPErrorStatuses::ENV_SERVER_ERROR_STATUSES + o.default 500..599 + o.setter do |v| + Tracing::Contrib::StatusRangeMatcher.new(v) if v + end + o.env_parser do |values| + Tracing::Contrib::StatusRangeEnvParser.call(values) + end + end + + option :client do |o| + o.env Tracing::Configuration::Ext::HTTPErrorStatuses::ENV_CLIENT_ERROR_STATUSES + o.default 400..499 + o.setter do |v| + Tracing::Contrib::StatusRangeMatcher.new(v) if v + end + o.env_parser do |values| + Tracing::Contrib::StatusRangeEnvParser.call(values) + end + end + end end end end diff --git a/sig/datadog/tracing/configuration/ext.rbs b/sig/datadog/tracing/configuration/ext.rbs index 574e4f833a6..df90b94aa40 100644 --- a/sig/datadog/tracing/configuration/ext.rbs +++ b/sig/datadog/tracing/configuration/ext.rbs @@ -63,6 +63,10 @@ module Datadog ENV_HEADER_NAME: "DD_TRACE_CLIENT_IP_HEADER" end + + module HTTPErrorStatuses + ENV_SERVER_ERROR_STATUSES: "DD_TRACE_HTTP_SERVER_ERROR_STATUSES" + end end end end diff --git a/spec/datadog/tracing/configuration/settings_spec.rb b/spec/datadog/tracing/configuration/settings_spec.rb index 44283faff86..bd1414ea500 100644 --- a/spec/datadog/tracing/configuration/settings_spec.rb +++ b/spec/datadog/tracing/configuration/settings_spec.rb @@ -8,6 +8,7 @@ require 'datadog/tracing/sampling/priority_sampler' require 'datadog/tracing/tracer' require 'datadog/tracing/writer' +require 'datadog/tracing/contrib/shared_settings_examples' require_relative '../../core/configuration/settings_shared_examples' RSpec.describe Datadog::Tracing::Configuration::Settings do @@ -1043,5 +1044,23 @@ def propagation_style_inject end end end + + describe '#http_error_statuses' do + describe '#server' do + it_behaves_like 'with error_status_codes setting', + env: 'DD_TRACE_HTTP_SERVER_ERROR_STATUSES', + default: 500..599, + settings_class: Datadog::Core::Configuration::Settings.new.tracing.http_error_statuses.class, + option: :server + end + + describe '#client' do + it_behaves_like 'with error_status_codes setting', + env: 'DD_TRACE_HTTP_CLIENT_ERROR_STATUSES', + default: 400..499, + settings_class: Datadog::Core::Configuration::Settings.new.tracing.http_error_statuses.class, + option: :client + end + end end end diff --git a/spec/datadog/tracing/contrib/excon/configuration/settings_spec.rb b/spec/datadog/tracing/contrib/excon/configuration/settings_spec.rb index 2959f1abd30..b6a3c36b5f7 100644 --- a/spec/datadog/tracing/contrib/excon/configuration/settings_spec.rb +++ b/spec/datadog/tracing/contrib/excon/configuration/settings_spec.rb @@ -5,5 +5,5 @@ RSpec.describe Datadog::Tracing::Contrib::Excon::Configuration::Settings do it_behaves_like 'service name setting', 'excon' it_behaves_like 'with on_error setting' - it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_EXCON_ERROR_STATUS_CODES', default: 400...600 + it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_EXCON_ERROR_STATUS_CODES', default: 400...600, settings_class: described_class, option: :error_status_codes end diff --git a/spec/datadog/tracing/contrib/faraday/configuration/settings_spec.rb b/spec/datadog/tracing/contrib/faraday/configuration/settings_spec.rb index d425c50b729..d8d1fd2d2e0 100644 --- a/spec/datadog/tracing/contrib/faraday/configuration/settings_spec.rb +++ b/spec/datadog/tracing/contrib/faraday/configuration/settings_spec.rb @@ -5,5 +5,5 @@ RSpec.describe Datadog::Tracing::Contrib::Faraday::Configuration::Settings do it_behaves_like 'service name setting', 'faraday' it_behaves_like 'with on_error setting' - it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_FARADAY_ERROR_STATUS_CODES', default: 400...600 + it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_FARADAY_ERROR_STATUS_CODES', default: 400...600, settings_class: described_class, option: :error_status_codes end diff --git a/spec/datadog/tracing/contrib/grape/configuration/settings_spec.rb b/spec/datadog/tracing/contrib/grape/configuration/settings_spec.rb index 481d619ca42..262e43467c5 100644 --- a/spec/datadog/tracing/contrib/grape/configuration/settings_spec.rb +++ b/spec/datadog/tracing/contrib/grape/configuration/settings_spec.rb @@ -3,5 +3,5 @@ RSpec.describe Datadog::Tracing::Contrib::Grape::Configuration::Settings do it_behaves_like 'with on_error setting' - it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_GRAPE_ERROR_STATUS_CODES', default: 500...600 + it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_GRAPE_ERROR_STATUS_CODES', default: 500...600, settings_class: described_class, option: :error_status_codes end diff --git a/spec/datadog/tracing/contrib/http/configuration/settings_spec.rb b/spec/datadog/tracing/contrib/http/configuration/settings_spec.rb index ade0151aa1b..8b830c2dbea 100644 --- a/spec/datadog/tracing/contrib/http/configuration/settings_spec.rb +++ b/spec/datadog/tracing/contrib/http/configuration/settings_spec.rb @@ -4,5 +4,5 @@ RSpec.describe Datadog::Tracing::Contrib::HTTP::Configuration::Settings do it_behaves_like 'service name setting', 'net/http' - it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_HTTP_ERROR_STATUS_CODES', default: 400...600 + it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_HTTP_ERROR_STATUS_CODES', default: 400...600, settings_class: described_class, option: :error_status_codes end diff --git a/spec/datadog/tracing/contrib/httpclient/configuration/settings_spec.rb b/spec/datadog/tracing/contrib/httpclient/configuration/settings_spec.rb index 5644183b640..5149b4c2c44 100644 --- a/spec/datadog/tracing/contrib/httpclient/configuration/settings_spec.rb +++ b/spec/datadog/tracing/contrib/httpclient/configuration/settings_spec.rb @@ -4,5 +4,5 @@ RSpec.describe Datadog::Tracing::Contrib::Httpclient::Configuration::Settings do it_behaves_like 'service name setting', 'httpclient' - it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_HTTPCLIENT_ERROR_STATUS_CODES', default: 400...600 + it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_HTTPCLIENT_ERROR_STATUS_CODES', default: 400...600, settings_class: described_class, option: :error_status_codes end diff --git a/spec/datadog/tracing/contrib/httprb/configuration/settings_spec.rb b/spec/datadog/tracing/contrib/httprb/configuration/settings_spec.rb index 1283619843d..53e1e101760 100644 --- a/spec/datadog/tracing/contrib/httprb/configuration/settings_spec.rb +++ b/spec/datadog/tracing/contrib/httprb/configuration/settings_spec.rb @@ -4,5 +4,5 @@ RSpec.describe Datadog::Tracing::Contrib::Httprb::Configuration::Settings do it_behaves_like 'service name setting', 'httprb' - it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_HTTPRB_ERROR_STATUS_CODES', default: 400...600 + it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_HTTPRB_ERROR_STATUS_CODES', default: 400...600, settings_class: described_class, option_path: [:error_status_codes] end diff --git a/spec/datadog/tracing/contrib/shared_settings_examples.rb b/spec/datadog/tracing/contrib/shared_settings_examples.rb index ab5509c8f5d..3314d6e9027 100644 --- a/spec/datadog/tracing/contrib/shared_settings_examples.rb +++ b/spec/datadog/tracing/contrib/shared_settings_examples.rb @@ -18,60 +18,65 @@ end end -RSpec.shared_examples_for 'with error_status_codes setting' do |env:, default:| +RSpec.shared_examples_for 'with error_status_codes setting' do |env:, default:, settings_class:, option:| + let(:result) { subject.send(option) } + context 'default without settings' do - subject { described_class.new } + subject { settings_class.new } - it { expect(subject.error_status_codes).not_to include(default.min - 1) } - it { expect(subject.error_status_codes).to include(default.min) } - it { expect(subject.error_status_codes).to include(default.max) } - it { expect(subject.error_status_codes).not_to include(default.max + 1) } + it { expect(result).not_to include(default.min - 1) } + it { expect(result).to include(default.min) } + it { expect(result).to include(default.max) } + it { expect(result).not_to include(default.max + 1) } end context 'when given error_status_codes' do + subject { settings_class.new(option_hash) } + let(:option_hash) { { option => option_value } } + context 'when given a single value' do - subject { described_class.new(error_status_codes: 500) } + let(:option_value) { 500 } - it { expect(subject.error_status_codes).not_to include 400 } - it { expect(subject.error_status_codes).not_to include 499 } - it { expect(subject.error_status_codes).to include 500 } - it { expect(subject.error_status_codes).not_to include 599 } - it { expect(subject.error_status_codes).not_to include 600 } + it { expect(result).not_to include 400 } + it { expect(result).not_to include 499 } + it { expect(result).to include 500 } + it { expect(result).not_to include 599 } + it { expect(result).not_to include 600 } end context 'when given an array of integers' do - subject { described_class.new(error_status_codes: [400, 500]) } + let(:option_value) { [400, 500] } - it { expect(subject.error_status_codes).to include 400 } - it { expect(subject.error_status_codes).not_to include 499 } - it { expect(subject.error_status_codes).to include 500 } - it { expect(subject.error_status_codes).not_to include 599 } - it { expect(subject.error_status_codes).not_to include 600 } + it { expect(result).to include 400 } + it { expect(result).not_to include 499 } + it { expect(result).to include 500 } + it { expect(result).not_to include 599 } + it { expect(result).not_to include 600 } end context 'when given a range' do - subject { described_class.new(error_status_codes: 500..600) } + let(:option_value) { 500..600 } - it { expect(subject.error_status_codes).not_to include 400 } - it { expect(subject.error_status_codes).not_to include 499 } - it { expect(subject.error_status_codes).to include 500 } - it { expect(subject.error_status_codes).to include 599 } - it { expect(subject.error_status_codes).to include 600 } + it { expect(result).not_to include 400 } + it { expect(result).not_to include 499 } + it { expect(result).to include 500 } + it { expect(result).to include 599 } + it { expect(result).to include 600 } end context 'when given an array of integer and range' do - subject { described_class.new(error_status_codes: [400, 500..600]) } + let(:option_value) { [400, 500..600] } - it { expect(subject.error_status_codes).to include 400 } - it { expect(subject.error_status_codes).not_to include 499 } - it { expect(subject.error_status_codes).to include 500 } - it { expect(subject.error_status_codes).to include 599 } - it { expect(subject.error_status_codes).to include 600 } + it { expect(result).to include 400 } + it { expect(result).not_to include 499 } + it { expect(result).to include 500 } + it { expect(result).to include 599 } + it { expect(result).to include 600 } end end context 'when configured with environment variable' do - subject { described_class.new } + subject { settings_class.new } context 'when given a single value' do around do |example| @@ -80,11 +85,11 @@ end end - it { expect(subject.error_status_codes).not_to include 400 } - it { expect(subject.error_status_codes).not_to include 499 } - it { expect(subject.error_status_codes).to include 500 } - it { expect(subject.error_status_codes).not_to include 599 } - it { expect(subject.error_status_codes).not_to include 600 } + it { expect(result).not_to include 400 } + it { expect(result).not_to include 499 } + it { expect(result).to include 500 } + it { expect(result).not_to include 599 } + it { expect(result).not_to include 600 } end context 'when given a comma separated list' do @@ -94,11 +99,11 @@ end end - it { expect(subject.error_status_codes).to include 400 } - it { expect(subject.error_status_codes).not_to include 499 } - it { expect(subject.error_status_codes).to include 500 } - it { expect(subject.error_status_codes).not_to include 599 } - it { expect(subject.error_status_codes).not_to include 600 } + it { expect(result).to include 400 } + it { expect(result).not_to include 499 } + it { expect(result).to include 500 } + it { expect(result).not_to include 599 } + it { expect(result).not_to include 600 } end context 'when given a comma separated list with space' do @@ -108,11 +113,11 @@ end end - it { expect(subject.error_status_codes).to include 400 } - it { expect(subject.error_status_codes).not_to include 499 } - it { expect(subject.error_status_codes).to include 500 } - it { expect(subject.error_status_codes).not_to include 599 } - it { expect(subject.error_status_codes).not_to include 600 } + it { expect(result).to include 400 } + it { expect(result).not_to include 499 } + it { expect(result).to include 500 } + it { expect(result).not_to include 599 } + it { expect(result).not_to include 600 } end context 'when given a comma separated list with range' do @@ -122,11 +127,11 @@ end end - it { expect(subject.error_status_codes).to include 400 } - it { expect(subject.error_status_codes).not_to include 499 } - it { expect(subject.error_status_codes).to include 500 } - it { expect(subject.error_status_codes).to include 599 } - it { expect(subject.error_status_codes).to include 600 } + it { expect(result).to include 400 } + it { expect(result).not_to include 499 } + it { expect(result).to include 500 } + it { expect(result).to include 599 } + it { expect(result).to include 600 } end end end diff --git a/supported-configurations.json b/supported-configurations.json index 25d1205804a..1adf93ef624 100644 --- a/supported-configurations.json +++ b/supported-configurations.json @@ -565,12 +565,18 @@ "DD_TRACE_HTTP_ANALYTICS_SAMPLE_RATE": { "version": ["A"] }, + "DD_TRACE_HTTP_CLIENT_ERROR_STATUSES": { + "version": ["A"] + }, "DD_TRACE_HTTP_ENABLED": { "version": ["A"] }, "DD_TRACE_HTTP_ERROR_STATUS_CODES": { "version": ["A"] }, + "DD_TRACE_HTTP_SERVER_ERROR_STATUSES": { + "version": ["A"] + }, "DD_TRACE_KAFKA_ANALYTICS_ENABLED": { "version": ["A"] }, From 793724034d934d0d244d2de7142b66a7f4bb23b0 Mon Sep 17 00:00:00 2001 From: Victor Pellan Date: Mon, 20 Oct 2025 14:36:05 +0200 Subject: [PATCH 2/8] Fallback to DD_TRACE_HTTP_SERVER_ERROR_STATUSES + DD_TRACE_HTTP_CLIENT_ERROR_STATUSES if not set instead of using default --- .../contrib/excon/configuration/settings.rb | 12 ++++-- .../contrib/faraday/configuration/settings.rb | 12 ++++-- .../contrib/grape/configuration/settings.rb | 10 +++-- .../contrib/http/configuration/settings.rb | 12 ++++-- .../httpclient/configuration/settings.rb | 12 ++++-- .../contrib/httprb/configuration/settings.rb | 12 ++++-- .../tracing/contrib/status_range_matcher.rb | 7 ++++ .../tracing/contrib/status_range_matcher.rbs | 8 +++- .../tracing/configuration/settings_spec.rb | 14 +++++-- .../grape/configuration/settings_spec.rb | 2 +- .../httprb/configuration/settings_spec.rb | 2 +- .../contrib/shared_settings_examples.rb | 40 ++++++++++++++++++- 12 files changed, 116 insertions(+), 27 deletions(-) diff --git a/lib/datadog/tracing/contrib/excon/configuration/settings.rb b/lib/datadog/tracing/contrib/excon/configuration/settings.rb index 8731d61ea24..efe06c9839b 100644 --- a/lib/datadog/tracing/contrib/excon/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/excon/configuration/settings.rb @@ -41,9 +41,15 @@ class Settings < Contrib::Configuration::Settings option :error_status_codes do |o| o.env Ext::ENV_ERROR_STATUS_CODES - o.default 400...600 - o.setter do |v| - Tracing::Contrib::StatusRangeMatcher.new(v) if v + o.setter do |value| + if value.nil? + # Fallback to global config, which is defaulted to client (400..499) + server (500..599) + client_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.client + server_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.server + client_global_error_statuses + server_global_error_statuses + else + Tracing::Contrib::StatusRangeMatcher.new(value) + end end o.env_parser do |v| Tracing::Contrib::StatusRangeEnvParser.call(v) if v diff --git a/lib/datadog/tracing/contrib/faraday/configuration/settings.rb b/lib/datadog/tracing/contrib/faraday/configuration/settings.rb index 93fc6c63879..25671987068 100644 --- a/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/faraday/configuration/settings.rb @@ -44,9 +44,15 @@ class Settings < Contrib::Configuration::Settings option :error_status_codes do |o| o.env Ext::ENV_ERROR_STATUS_CODES - o.default 400...600 - o.setter do |v| - Tracing::Contrib::StatusRangeMatcher.new(v) if v + o.setter do |value| + if value.nil? + # Fallback to global config, which is defaulted to client (400..499) + server (500..599) + client_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.client + server_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.server + client_global_error_statuses + server_global_error_statuses + else + Tracing::Contrib::StatusRangeMatcher.new(value) + end end o.env_parser do |v| Tracing::Contrib::StatusRangeEnvParser.call(v) if v diff --git a/lib/datadog/tracing/contrib/grape/configuration/settings.rb b/lib/datadog/tracing/contrib/grape/configuration/settings.rb index 8c1ad229084..cfde6cec7a0 100644 --- a/lib/datadog/tracing/contrib/grape/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/grape/configuration/settings.rb @@ -39,9 +39,13 @@ class Settings < Contrib::Configuration::Settings option :error_status_codes do |o| o.env Ext::ENV_ERROR_STATUS_CODES - o.default 500...600 - o.setter do |v| - Tracing::Contrib::StatusRangeMatcher.new(v) if v + o.setter do |value| + if value.nil? + # Fallback to global config, which is defaulted to server (500..599) + Datadog.configuration.tracing.http_error_statuses.server + else + Tracing::Contrib::StatusRangeMatcher.new(value) + end end o.env_parser do |v| Tracing::Contrib::StatusRangeEnvParser.call(v) if v diff --git a/lib/datadog/tracing/contrib/http/configuration/settings.rb b/lib/datadog/tracing/contrib/http/configuration/settings.rb index 43cc7e7a17f..5633b0cd27f 100644 --- a/lib/datadog/tracing/contrib/http/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/http/configuration/settings.rb @@ -46,9 +46,15 @@ class Settings < Contrib::Configuration::Settings option :error_status_codes do |o| o.env Ext::ENV_ERROR_STATUS_CODES - o.default 400...600 - o.setter do |v| - Tracing::Contrib::StatusRangeMatcher.new(v) if v + o.setter do |value| + if value.nil? + # Fallback to global config, which is defaulted to client (400..499) + server (500..599) + client_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.client + server_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.server + client_global_error_statuses + server_global_error_statuses + else + Tracing::Contrib::StatusRangeMatcher.new(value) + end end o.env_parser do |v| Tracing::Contrib::StatusRangeEnvParser.call(v) if v diff --git a/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb b/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb index 6f9f7060d97..7bb9ee1d6c0 100644 --- a/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb @@ -45,9 +45,15 @@ class Settings < Contrib::Configuration::Settings option :error_status_codes do |o| o.env Ext::ENV_ERROR_STATUS_CODES - o.default 400...600 - o.setter do |v| - Tracing::Contrib::StatusRangeMatcher.new(v) if v + o.setter do |value| + if value.nil? + # Fallback to global config, which is defaulted to client (400..499) + server (500..599) + client_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.client + server_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.server + client_global_error_statuses + server_global_error_statuses + else + Tracing::Contrib::StatusRangeMatcher.new(value) + end end o.env_parser do |v| Tracing::Contrib::StatusRangeEnvParser.call(v) if v diff --git a/lib/datadog/tracing/contrib/httprb/configuration/settings.rb b/lib/datadog/tracing/contrib/httprb/configuration/settings.rb index 877a2be05a5..320b4dd94ec 100644 --- a/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/httprb/configuration/settings.rb @@ -45,9 +45,15 @@ class Settings < Contrib::Configuration::Settings option :error_status_codes do |o| o.env Ext::ENV_ERROR_STATUS_CODES - o.default 400...600 - o.setter do |v| - Tracing::Contrib::StatusRangeMatcher.new(v) if v + o.setter do |value| + if value.nil? + # Fallback to global config, which is defaulted to client (400..499) + server (500..599) + client_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.client + server_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.server + client_global_error_statuses + server_global_error_statuses + else + Tracing::Contrib::StatusRangeMatcher.new(value) + end end o.env_parser do |v| Tracing::Contrib::StatusRangeEnvParser.call(v) if v diff --git a/lib/datadog/tracing/contrib/status_range_matcher.rb b/lib/datadog/tracing/contrib/status_range_matcher.rb index 94bafbba27d..d3cee9d4be2 100644 --- a/lib/datadog/tracing/contrib/status_range_matcher.rb +++ b/lib/datadog/tracing/contrib/status_range_matcher.rb @@ -5,10 +5,17 @@ module Tracing module Contrib # Useful checking whether the defined range covers status code class StatusRangeMatcher + attr_reader :ranges + def initialize(ranges) @ranges = Array(ranges) end + def +(other) + StatusRangeMatcher.new(@ranges + other.ranges) + end + alias_method :concat, :+ + def include?(status) @ranges.any? do |e| case e diff --git a/sig/datadog/tracing/contrib/status_range_matcher.rbs b/sig/datadog/tracing/contrib/status_range_matcher.rbs index a4a8f979d0c..3cc97d4848c 100644 --- a/sig/datadog/tracing/contrib/status_range_matcher.rbs +++ b/sig/datadog/tracing/contrib/status_range_matcher.rbs @@ -2,10 +2,16 @@ module Datadog module Tracing module Contrib class StatusRangeMatcher - @ranges: untyped + @ranges: Array[Integer | Range[Integer]] + + attr_reader ranges: Array[Integer | Range[Integer]] def initialize: (untyped ranges) -> void + def +: (StatusRangeMatcher other) -> StatusRangeMatcher + + alias concat + + def include?: (untyped status) -> untyped end end diff --git a/spec/datadog/tracing/configuration/settings_spec.rb b/spec/datadog/tracing/configuration/settings_spec.rb index bd1414ea500..2a5ab445d03 100644 --- a/spec/datadog/tracing/configuration/settings_spec.rb +++ b/spec/datadog/tracing/configuration/settings_spec.rb @@ -1046,20 +1046,26 @@ def propagation_style_inject end describe '#http_error_statuses' do + # We cannot use described_class (as it is Tracing::Configuration::Settings, not Core::Configuration::Settings) + # So we need to create a new `Settings` class to access the anonymous parent setting class of server and client options. + parent_setting_class = Datadog::Core::Configuration::Settings.new.tracing.http_error_statuses.class + describe '#server' do it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_HTTP_SERVER_ERROR_STATUSES', default: 500..599, - settings_class: Datadog::Core::Configuration::Settings.new.tracing.http_error_statuses.class, - option: :server + settings_class: parent_setting_class, + option: :server, + fallback_to_global: false end describe '#client' do it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_HTTP_CLIENT_ERROR_STATUSES', default: 400..499, - settings_class: Datadog::Core::Configuration::Settings.new.tracing.http_error_statuses.class, - option: :client + settings_class: parent_setting_class, + option: :client, + fallback_to_global: false end end end diff --git a/spec/datadog/tracing/contrib/grape/configuration/settings_spec.rb b/spec/datadog/tracing/contrib/grape/configuration/settings_spec.rb index 262e43467c5..12624c6109b 100644 --- a/spec/datadog/tracing/contrib/grape/configuration/settings_spec.rb +++ b/spec/datadog/tracing/contrib/grape/configuration/settings_spec.rb @@ -3,5 +3,5 @@ RSpec.describe Datadog::Tracing::Contrib::Grape::Configuration::Settings do it_behaves_like 'with on_error setting' - it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_GRAPE_ERROR_STATUS_CODES', default: 500...600, settings_class: described_class, option: :error_status_codes + it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_GRAPE_ERROR_STATUS_CODES', default: 500...600, settings_class: described_class, option: :error_status_codes, global_config: {server: 710..719} end diff --git a/spec/datadog/tracing/contrib/httprb/configuration/settings_spec.rb b/spec/datadog/tracing/contrib/httprb/configuration/settings_spec.rb index 53e1e101760..44ee3b8e103 100644 --- a/spec/datadog/tracing/contrib/httprb/configuration/settings_spec.rb +++ b/spec/datadog/tracing/contrib/httprb/configuration/settings_spec.rb @@ -4,5 +4,5 @@ RSpec.describe Datadog::Tracing::Contrib::Httprb::Configuration::Settings do it_behaves_like 'service name setting', 'httprb' - it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_HTTPRB_ERROR_STATUS_CODES', default: 400...600, settings_class: described_class, option_path: [:error_status_codes] + it_behaves_like 'with error_status_codes setting', env: 'DD_TRACE_HTTPRB_ERROR_STATUS_CODES', default: 400...600, settings_class: described_class, option: :error_status_codes end diff --git a/spec/datadog/tracing/contrib/shared_settings_examples.rb b/spec/datadog/tracing/contrib/shared_settings_examples.rb index 3314d6e9027..35d37b7e1ad 100644 --- a/spec/datadog/tracing/contrib/shared_settings_examples.rb +++ b/spec/datadog/tracing/contrib/shared_settings_examples.rb @@ -18,7 +18,7 @@ end end -RSpec.shared_examples_for 'with error_status_codes setting' do |env:, default:, settings_class:, option:| +RSpec.shared_examples_for 'with error_status_codes setting' do |env:, default:, settings_class:, option:, fallback_to_global: true, global_config: {server: 710..719, client: 700..709}| let(:result) { subject.send(option) } context 'default without settings' do @@ -30,9 +30,28 @@ it { expect(result).not_to include(default.max + 1) } end + context 'when fallback to global config', if: fallback_to_global do + before do + Datadog.configure do |c| + c.tracing.http_error_statuses.server = global_config[:server] if global_config[:server] + c.tracing.http_error_statuses.client = global_config[:client] if global_config[:client] + end + end + + # By doing this, we can omit the client config or the server config from the test (e.g. Grape only uses server config) + let(:global_error_statuses) { Array(global_config[:server]) + Array(global_config[:client]) } + + it { expect(result).not_to include default.min } + it { expect(result).not_to include global_error_statuses.min - 1 } + it { expect(result).to include global_error_statuses.min } + it { expect(result).to include global_error_statuses.max } + it { expect(result).not_to include global_error_statuses.max + 1 } + it { expect(result).not_to include default.max + 1 } + end + context 'when given error_status_codes' do subject { settings_class.new(option_hash) } - let(:option_hash) { { option => option_value } } + let(:option_hash) { {option => option_value} } context 'when given a single value' do let(:option_value) { 500 } @@ -42,6 +61,23 @@ it { expect(result).to include 500 } it { expect(result).not_to include 599 } it { expect(result).not_to include 600 } + + context 'when global config is set', if: fallback_to_global do + # global config should not be applied if config is set + before do + Datadog.configure do |c| + c.tracing.http_error_statuses.server = global_config[:server] if global_config[:server] + c.tracing.http_error_statuses.client = global_config[:client] if global_config[:client] + end + end + + # By doing this, we can omit the client config or the server config from the test (e.g. Grape only uses server config) + let(:global_error_statuses) { Array(global_config[:server]) + Array(global_config[:client]) } + + it { expect(result).to include 500 } + it { expect(result).not_to include global_error_statuses.min } + it { expect(result).not_to include global_error_statuses.max } + end end context 'when given an array of integers' do From 55f220cb3159107333ef9de3a3882f13b54a1276 Mon Sep 17 00:00:00 2001 From: Victor Pellan Date: Mon, 20 Oct 2025 18:09:00 +0200 Subject: [PATCH 3/8] Use config on ActionController --- lib/datadog/tracing/configuration/settings.rb | 7 ++ .../action_controller/instrumentation.rb | 4 +- .../tracing/contrib/action_pack/utils.rb | 5 +- .../action_controller/instrumentation_spec.rb | 76 +++++++++++++++++++ 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/lib/datadog/tracing/configuration/settings.rb b/lib/datadog/tracing/configuration/settings.rb index c7be7bf786e..543812355b8 100644 --- a/lib/datadog/tracing/configuration/settings.rb +++ b/lib/datadog/tracing/configuration/settings.rb @@ -514,6 +514,13 @@ def self.extended(base) end end + # Defines the range of status codes to be considered errors on http.client span kinds. + # Once set, only the values within the specified range are considered errors. + # + # Format of env var: comma-separated list of values like 400,401,402 or ranges like 400-499 (e.g. `400,402,404-410`) + # + # @default `DD_TRACE_HTTP_CLIENT_ERROR_STATUSES` environment variable, otherwise `400..499`. + # @return [Tracing::Contrib::StatusRangeMatcher] option :client do |o| o.env Tracing::Configuration::Ext::HTTPErrorStatuses::ENV_CLIENT_ERROR_STATUSES o.default 400..499 diff --git a/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb b/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb index 21dd6425476..5d0716e90df 100644 --- a/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +++ b/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb @@ -79,8 +79,8 @@ def finish_processing(payload) if exception.nil? # [christian] in some cases :status is not defined, # rather than firing an error, simply acknowledge we don't know it. - status = payload.fetch(:status, '?').to_s - span.status = 1 if status.start_with?('5') + status = payload[:status] + span.status = 1 if status && Datadog.configuration.tracing.http_error_statuses.server.include?(status) elsif Utils.exception_is_error?(exception) span.set_error(exception) end diff --git a/lib/datadog/tracing/contrib/action_pack/utils.rb b/lib/datadog/tracing/contrib/action_pack/utils.rb index 4c5e039055f..d3fb67adc36 100644 --- a/lib/datadog/tracing/contrib/action_pack/utils.rb +++ b/lib/datadog/tracing/contrib/action_pack/utils.rb @@ -13,8 +13,9 @@ def self.exception_is_error?(exception) # Gets the equivalent status code for the exception (not all are 5XX) # You can add custom errors via `config.action_dispatch.rescue_responses` status = ::ActionDispatch::ExceptionWrapper.status_code_for_exception(exception.class.name) - # Only 5XX exceptions are actually errors (e.g. don't flag 404s) - status.to_s.start_with?('5') + # By default, only 5XX exceptions are actually errors (e.g. don't flag 404s). + # This can be changed by setting `DD_TRACE_HTTP_SERVER_ERROR_STATUSES` environment variable. + Datadog.configuration.tracing.http_error_statuses.server.include?(status) else true end diff --git a/spec/datadog/tracing/contrib/action_pack/action_controller/instrumentation_spec.rb b/spec/datadog/tracing/contrib/action_pack/action_controller/instrumentation_spec.rb index f2d2f1bfb6a..c91277959f9 100644 --- a/spec/datadog/tracing/contrib/action_pack/action_controller/instrumentation_spec.rb +++ b/spec/datadog/tracing/contrib/action_pack/action_controller/instrumentation_spec.rb @@ -46,6 +46,42 @@ end end + context 'with a status code set in the payload' do + let(:payload) do + super().merge(status: 404) + end + + describe 'the Datadog span' do + before do + expect(Datadog.logger).to_not receive(:error) + finish_processing + end + + it do + expect(span).to_not have_error + end + end + + context 'when http_error_statuses.server is set to match the status code' do + before do + Datadog.configure do |c| + c.tracing.http_error_statuses.server = 400..599 + end + end + + describe 'the Datadog span' do + before do + expect(Datadog.logger).to_not receive(:error) + finish_processing + end + + it do + expect(span).to have_error + end + end + end + end + context 'with a 500 Server Error response' do let(:error) do raise 'Test error' @@ -71,6 +107,46 @@ end end end + + context 'with a 404 Not Found response' do + let(:error) { ::ActionController::RoutingError.new('Not Found') } + let(:payload) do + super().merge( + exception: [error.class.name, error.message], + exception_object: error + ) + end + + describe 'the Datadog span' do + before do + expect(Datadog.logger).to_not receive(:error) + finish_processing + end + + it do + expect(span).to_not have_error + end + end + + context 'when http_error_statuses.server is set to match 404' do + before do + Datadog.configure do |c| + c.tracing.http_error_statuses.server = 400..599 + end + end + + describe 'the Datadog span' do + before do + expect(Datadog.logger).to_not receive(:error) + finish_processing + end + + it do + expect(span).to have_error + end + end + end + end end end end From 1c2987713f2b8c5fc00502089df420b6b2598267 Mon Sep 17 00:00:00 2001 From: Victor Pellan Date: Tue, 21 Oct 2025 13:11:51 +0200 Subject: [PATCH 4/8] Remove hardcoded error range --- .../tracing/contrib/aws/instrumentation.rb | 2 +- .../tracing/contrib/ethon/easy_patch.rb | 2 +- .../contrib/faraday/configuration/settings.rb | 4 -- .../tracing/contrib/rails/middlewares.rb | 4 +- .../contrib/rest_client/request_patch.rb | 2 +- .../contrib/sinatra/tracer_middleware.rb | 4 +- lib/datadog/tracing/metadata/ext.rb | 1 - .../tracing/contrib/excon/middleware.rbs | 2 - .../faraday/configuration/settings.rbs | 1 - sig/datadog/tracing/metadata/ext.rbs | 1 - .../contrib/aws/instrumentation_spec.rb | 67 ++++++++++++++----- .../tracing/contrib/ethon/easy_patch_spec.rb | 12 ++++ .../contrib/rest_client/request_patch_spec.rb | 11 +++ .../tracing/contrib/sinatra/tracer_spec.rb | 11 +++ 14 files changed, 94 insertions(+), 30 deletions(-) diff --git a/lib/datadog/tracing/contrib/aws/instrumentation.rb b/lib/datadog/tracing/contrib/aws/instrumentation.rb index 4a2cf435892..c03491383a1 100644 --- a/lib/datadog/tracing/contrib/aws/instrumentation.rb +++ b/lib/datadog/tracing/contrib/aws/instrumentation.rb @@ -37,7 +37,7 @@ def annotate!(span, context) span.resource = context.safely(:resource) # Set error on the span if the Response Status Code is in error range - if Tracing::Metadata::Ext::HTTP::ERROR_RANGE.cover?(context.safely(:status_code)) + if Datadog.configuration.tracing.http_error_statuses.server.include?(context.safely(:status_code)) # At this point we do not have any additional diagnostics # besides the HTTP status code which is recorded in the span tags # later in this method. diff --git a/lib/datadog/tracing/contrib/ethon/easy_patch.rb b/lib/datadog/tracing/contrib/ethon/easy_patch.rb index 541967d91ab..f9ef781f58c 100644 --- a/lib/datadog/tracing/contrib/ethon/easy_patch.rb +++ b/lib/datadog/tracing/contrib/ethon/easy_patch.rb @@ -57,7 +57,7 @@ def complete set_span_error_message("Request has failed: #{message}") else @datadog_span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, response_code) - if Tracing::Metadata::Ext::HTTP::ERROR_RANGE.cover?(response_code) + if Datadog.configuration.tracing.http_error_statuses.server.include?(response_code) set_span_error_message("Request has failed with HTTP error: #{response_code}") end end diff --git a/lib/datadog/tracing/contrib/faraday/configuration/settings.rb b/lib/datadog/tracing/contrib/faraday/configuration/settings.rb index 25671987068..805d7a9946f 100644 --- a/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/faraday/configuration/settings.rb @@ -13,10 +13,6 @@ module Configuration # Custom settings for the Faraday integration # @public_api class Settings < Contrib::Configuration::Settings - DEFAULT_ERROR_HANDLER = lambda do |env| - Tracing::Metadata::Ext::HTTP::ERROR_RANGE.cover?(env[:status]) - end - option :enabled do |o| o.type :bool o.env Ext::ENV_ENABLED diff --git a/lib/datadog/tracing/contrib/rails/middlewares.rb b/lib/datadog/tracing/contrib/rails/middlewares.rb index 9332141dfaa..a1e8e15ad1a 100644 --- a/lib/datadog/tracing/contrib/rails/middlewares.rb +++ b/lib/datadog/tracing/contrib/rails/middlewares.rb @@ -26,8 +26,8 @@ def call(env) rescue Exception => e span = Tracing.active_span if !span.nil? && ActionPack::Utils.exception_is_error?(e) - # Only set error if it's supposed to be flagged as such - # e.g. we don't want to flag 404s. + # By default, only 5XX exceptions are actually errors (e.g. don't flag 404s). + # This can be changed by setting `DD_TRACE_HTTP_SERVER_ERROR_STATUSES` environment variable. # You can add custom errors via `config.action_dispatch.rescue_responses` span.set_error(e) diff --git a/lib/datadog/tracing/contrib/rest_client/request_patch.rb b/lib/datadog/tracing/contrib/rest_client/request_patch.rb index 03b04896604..0b387439e30 100644 --- a/lib/datadog/tracing/contrib/rest_client/request_patch.rb +++ b/lib/datadog/tracing/contrib/rest_client/request_patch.rb @@ -99,7 +99,7 @@ def datadog_trace_request(uri) end end rescue ::RestClient::ExceptionWithResponse => e - span.set_error(e) if Tracing::Metadata::Ext::HTTP::ERROR_RANGE.cover?(e.http_code) + span.set_error(e) if Datadog.configuration.tracing.http_error_statuses.server.include?(e.http_code) span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, e.http_code) raise e diff --git a/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb b/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb index 592ee31b14f..54e759a48d2 100644 --- a/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +++ b/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb @@ -70,7 +70,9 @@ def call(env) sinatra_response = ::Sinatra::Response.new([], status) # Build object to use status code helpers span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, sinatra_response.status) - span.set_error(env['sinatra.error']) if sinatra_response.server_error? + if Datadog.configuration.tracing.http_error_statuses.server.include?(sinatra_response.status) + span.set_error(env['sinatra.error']) + end end if (headers = response[1]) diff --git a/lib/datadog/tracing/metadata/ext.rb b/lib/datadog/tracing/metadata/ext.rb index dbe669c86fa..fe81f553787 100644 --- a/lib/datadog/tracing/metadata/ext.rb +++ b/lib/datadog/tracing/metadata/ext.rb @@ -94,7 +94,6 @@ module Errors # @public_api module HTTP - ERROR_RANGE = (500...600).freeze TAG_BASE_URL = 'http.base_url' TAG_METHOD = 'http.method' TAG_STATUS_CODE = 'http.status_code' diff --git a/sig/datadog/tracing/contrib/excon/middleware.rbs b/sig/datadog/tracing/contrib/excon/middleware.rbs index a088501781f..68417f257fd 100644 --- a/sig/datadog/tracing/contrib/excon/middleware.rbs +++ b/sig/datadog/tracing/contrib/excon/middleware.rbs @@ -5,8 +5,6 @@ module Datadog class Middleware < ::Excon::Middleware::Base include Contrib::HttpAnnotationHelper - DEFAULT_ERROR_HANDLER: untyped - def initialize: (untyped stack, ?::Hash[untyped, untyped] options) -> void def request_call: (untyped datum) -> untyped diff --git a/sig/datadog/tracing/contrib/faraday/configuration/settings.rbs b/sig/datadog/tracing/contrib/faraday/configuration/settings.rbs index 9689cf20b1d..54895e93a4b 100644 --- a/sig/datadog/tracing/contrib/faraday/configuration/settings.rbs +++ b/sig/datadog/tracing/contrib/faraday/configuration/settings.rbs @@ -4,7 +4,6 @@ module Datadog module Faraday module Configuration class Settings < Contrib::Configuration::Settings - DEFAULT_ERROR_HANDLER: untyped end end end diff --git a/sig/datadog/tracing/metadata/ext.rbs b/sig/datadog/tracing/metadata/ext.rbs index 4339172ed28..1a11ec4e9fc 100644 --- a/sig/datadog/tracing/metadata/ext.rbs +++ b/sig/datadog/tracing/metadata/ext.rbs @@ -45,7 +45,6 @@ module Datadog end module HTTP - ERROR_RANGE: ::Range[::Integer] TAG_BASE_URL: ::String TAG_METHOD: ::String TAG_STATUS_CODE: ::String diff --git a/spec/datadog/tracing/contrib/aws/instrumentation_spec.rb b/spec/datadog/tracing/contrib/aws/instrumentation_spec.rb index 3f74d32279f..58717810d02 100644 --- a/spec/datadog/tracing/contrib/aws/instrumentation_spec.rb +++ b/spec/datadog/tracing/contrib/aws/instrumentation_spec.rb @@ -139,23 +139,60 @@ let(:client) { ::Aws::S3::Client.new(stub_responses: true) } - before do - client.stub_responses( - :list_buckets, - status_code: 500, - body: 'test body with 500 error', - headers: {} - ) + context 'when the error status code is 500' do + before do + client.stub_responses( + :list_buckets, + status_code: 500, + body: 'test body with 500 error', + headers: {} + ) + end + + it 'generates an errored span' do + expect do + list_buckets + end.to raise_error(Aws::S3::Errors::Http500Error) + # The Http500Error instance does not contain the body of the + # response. + expect(span).to have_error + expect(span.tags['http.status_code']).to eq('500') + end end - it 'generates an errored span' do - expect do - list_buckets - end.to raise_error(Aws::S3::Errors::Http500Error) - # The Http500Error instance does not contain the body of the - # response. - expect(span).to have_error - expect(span.tags['http.status_code']).to eq('500') + context 'when the error status code is 404' do + before do + client.stub_responses( + :list_buckets, + status_code: 404, + body: 'test body with 404 error', + headers: {} + ) + end + + it ' does not generates an errored span' do + expect do + list_buckets + end.to raise_error(Aws::S3::Errors::NotFound) + expect(span).not_to have_error + expect(span.tags['http.status_code']).to eq('404') + end + + context 'when the server error statuses are configured to include 404' do + before do + Datadog.configure do |c| + c.tracing.http_error_statuses.server = 400..599 + end + end + + it 'generates an errored span' do + expect do + list_buckets + end.to raise_error(Aws::S3::Errors::NotFound) + expect(span).to have_error + expect(span.tags['http.status_code']).to eq('404') + end + end end end diff --git a/spec/datadog/tracing/contrib/ethon/easy_patch_spec.rb b/spec/datadog/tracing/contrib/ethon/easy_patch_spec.rb index 6b6c8a5d06e..6d6021cf33c 100644 --- a/spec/datadog/tracing/contrib/ethon/easy_patch_spec.rb +++ b/spec/datadog/tracing/contrib/ethon/easy_patch_spec.rb @@ -11,10 +11,12 @@ RSpec.describe Datadog::Tracing::Contrib::Ethon::EasyPatch do let(:configuration_options) { {} } let(:easy) { EthonSupport.ethon_easy_new } + let(:server_error_statuses) { nil } before do Datadog.configure do |c| c.tracing.instrument :ethon, configuration_options + c.tracing.http_error_statuses.server = server_error_statuses if server_error_statuses end end @@ -163,6 +165,7 @@ end it 'has error set' do + expect(span).to have_error expect(span).to have_error_message('Request has failed with HTTP error: 500') end end @@ -180,6 +183,15 @@ it 'has no error set' do expect(span).to_not have_error_message end + + context 'when the server error statuses are configured to include 404' do + let(:server_error_statuses) { 400..599 } + + it 'has error set' do + expect(span).to have_error + expect(span).to have_error_message('Request has failed with HTTP error: 404') + end + end end context 'request timed out' do diff --git a/spec/datadog/tracing/contrib/rest_client/request_patch_spec.rb b/spec/datadog/tracing/contrib/rest_client/request_patch_spec.rb index de5a47b40ff..644fa204daf 100644 --- a/spec/datadog/tracing/contrib/rest_client/request_patch_spec.rb +++ b/spec/datadog/tracing/contrib/rest_client/request_patch_spec.rb @@ -17,10 +17,12 @@ RSpec.describe Datadog::Tracing::Contrib::RestClient::RequestPatch do let(:configuration_options) { {} } + let(:server_error_statuses) { nil } before do Datadog.configure do |c| c.tracing.instrument :rest_client, configuration_options + c.tracing.http_error_statuses.server = server_error_statuses if server_error_statuses end WebMock.disable_net_connect!(allow: agent_url) @@ -174,6 +176,15 @@ it 'error is not set' do expect(span).to_not have_error_message end + + context 'when the server error statuses are configured to include 404' do + let(:server_error_statuses) { 400..599 } + + it 'has error set' do + expect(span).to have_error + expect(span).to have_error_message('404 Not Found') + end + end end context 'with fatal error' do diff --git a/spec/datadog/tracing/contrib/sinatra/tracer_spec.rb b/spec/datadog/tracing/contrib/sinatra/tracer_spec.rb index 38c19b0532b..adf17f5bf64 100644 --- a/spec/datadog/tracing/contrib/sinatra/tracer_spec.rb +++ b/spec/datadog/tracing/contrib/sinatra/tracer_spec.rb @@ -21,6 +21,7 @@ subject(:response) { get url } let(:configuration_options) { {} } + let(:server_error_statuses) { nil } let(:url) { '/' } let(:http_method) { 'GET' } let(:resource) { "#{http_method} #{url}" } @@ -72,6 +73,7 @@ before do Datadog.configure do |c| c.tracing.instrument :sinatra, configuration_options + c.tracing.http_error_statuses.server = server_error_statuses if server_error_statuses end end @@ -273,6 +275,15 @@ is_expected.to be_bad_request expect(span).to_not have_error end + + context 'when the server error statuses are configured to include 400' do + let(:server_error_statuses) { 400..599 } + + it 'has error set' do + is_expected.to be_bad_request + expect(span).to have_error + end + end end context 'and a request resulting in an internal error is made' do From 243d79043045776f34491d6cd836958144f8f6a1 Mon Sep 17 00:00:00 2001 From: Victor Pellan Date: Tue, 21 Oct 2025 13:33:37 +0200 Subject: [PATCH 5/8] Add rack and roda support --- .../action_controller/instrumentation.rb | 4 ++- .../tracing/contrib/rack/middlewares.rb | 4 ++- .../tracing/contrib/roda/instrumentation.rb | 4 ++- .../contrib/rack/integration_test_spec.rb | 29 +++++++++++++++++++ .../tracing/contrib/roda/shared_examples.rb | 19 ++++++++++++ 5 files changed, 57 insertions(+), 3 deletions(-) diff --git a/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb b/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb index 5d0716e90df..9ac1e9a1be1 100644 --- a/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +++ b/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb @@ -80,7 +80,9 @@ def finish_processing(payload) # [christian] in some cases :status is not defined, # rather than firing an error, simply acknowledge we don't know it. status = payload[:status] - span.status = 1 if status && Datadog.configuration.tracing.http_error_statuses.server.include?(status) + if status && Datadog.configuration.tracing.http_error_statuses.server.include?(status) + span.status = Tracing::Metadata::Ext::Errors::STATUS + end elsif Utils.exception_is_error?(exception) span.set_error(exception) end diff --git a/lib/datadog/tracing/contrib/rack/middlewares.rb b/lib/datadog/tracing/contrib/rack/middlewares.rb index 60d83a3abaf..ce64fcca231 100644 --- a/lib/datadog/tracing/contrib/rack/middlewares.rb +++ b/lib/datadog/tracing/contrib/rack/middlewares.rb @@ -227,7 +227,9 @@ def set_request_tags!(trace, request_span, env, status, headers, response, origi # detect if the status code is a 5xx and flag the request span as an error # unless it has been already set by the underlying framework - request_span.status = 1 if status.to_s.start_with?('5') && request_span.status.zero? + if request_span.status.zero? && Datadog.configuration.tracing.http_error_statuses.server.include?(status) + request_span.status = Tracing::Metadata::Ext::Errors::STATUS + end end # rubocop:enable Metrics/AbcSize # rubocop:enable Metrics/CyclomaticComplexity diff --git a/lib/datadog/tracing/contrib/roda/instrumentation.rb b/lib/datadog/tracing/contrib/roda/instrumentation.rb index 6429bbdf7c1..a7414c6cd4b 100644 --- a/lib/datadog/tracing/contrib/roda/instrumentation.rb +++ b/lib/datadog/tracing/contrib/roda/instrumentation.rb @@ -61,7 +61,9 @@ def instrument(span_name, &block) # Adds status code to the resource name once the resource comes back span.resource = "#{request_method} #{status_code}" span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, status_code) - span.status = 1 if status_code.to_s.start_with?('5') + if Datadog.configuration.tracing.http_error_statuses.server.include?(status_code) + span.status = Tracing::Metadata::Ext::Errors::STATUS + end response end end diff --git a/spec/datadog/tracing/contrib/rack/integration_test_spec.rb b/spec/datadog/tracing/contrib/rack/integration_test_spec.rb index e5e6ed4cf82..809700c0cb5 100644 --- a/spec/datadog/tracing/contrib/rack/integration_test_spec.rb +++ b/spec/datadog/tracing/contrib/rack/integration_test_spec.rb @@ -18,6 +18,7 @@ include Rack::Test::Methods let(:rack_options) { {} } + let(:server_error_statuses) { nil } let(:instrument_http) { false } let(:remote_enabled) { false } let(:apm_tracing_enabled) { true } @@ -62,6 +63,7 @@ c.tracing.instrument :rack, rack_options # Required for APM disablement tests with distributed tracing as rack can extract but not inject headers c.tracing.instrument :http if instrument_http + c.tracing.http_error_statuses.server = server_error_statuses if server_error_statuses end end end @@ -883,6 +885,33 @@ .to eq('server') end end + + context 'when the server error statuses are configured to include 400' do + let(:server_error_statuses) { 400..599 } + + describe 'GET request' do + subject(:response) { get '/failure/' } + + it do + expect(span.name).to eq('rack.request') + expect(span.type).to eq('web') + expect(span.service).to eq(Datadog.configuration.service) + expect(span.resource).to eq('GET 400') + expect(span.get_tag('http.method')).to eq('GET') + expect(span.get_tag('http.status_code')).to eq('400') + expect(span.get_tag('http.url')).to eq('/failure/') + expect(span.get_tag('http.base_url')).to eq('http://example.org') + expect(span.status).to eq(1) + expect(span).to be_root_span + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq('rack') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq('request') + expect(span.get_tag('span.kind')) + .to eq('server') + end + end + end end context 'with a route that has a server error' do diff --git a/spec/datadog/tracing/contrib/roda/shared_examples.rb b/spec/datadog/tracing/contrib/roda/shared_examples.rb index 4c85a224f7c..f7e0d1b9132 100644 --- a/spec/datadog/tracing/contrib/roda/shared_examples.rb +++ b/spec/datadog/tracing/contrib/roda/shared_examples.rb @@ -9,6 +9,7 @@ RSpec.shared_examples_for 'shared examples for roda' do |test_method| let(:configuration_options) { {} } + let(:server_error_statuses) { nil } let(:test_class) do Class.new do prepend Datadog::Tracing::Contrib::Roda::Instrumentation @@ -20,6 +21,7 @@ before do Datadog.configure do |c| c.tracing.instrument :roda, configuration_options + c.tracing.http_error_statuses.server = server_error_statuses if server_error_statuses end end @@ -102,6 +104,23 @@ expect(span.get_tag(Datadog::Tracing::Metadata::Ext::HTTP::TAG_URL)).to eq('/unsuccessful_endpoint') expect(span.get_tag(Datadog::Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE)).to eq(response_code.to_s) end + + context 'when the server error statuses are configured to include 400' do + let(:server_error_statuses) { 400..599 } + + it do + instrumented_method + expect(spans).to have(1).items + expect(span.parent_id).to be 0 + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::HTTP::TYPE_INBOUND) + expect(span.resource).to eq('GET 404') + expect(span.name).to eq('roda.request') + expect(span.status).to eq(1) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::HTTP::TAG_METHOD)).to eq('GET') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::HTTP::TAG_URL)).to eq('/unsuccessful_endpoint') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE)).to eq(response_code.to_s) + end + end end context '500' do From 35246407be9edbc407a79e2db58a5a6b948672c0 Mon Sep 17 00:00:00 2001 From: Victor Pellan Date: Tue, 21 Oct 2025 14:04:31 +0200 Subject: [PATCH 6/8] Cleaned aws test and typed status_range_matcher --- sig/datadog/tracing/contrib/status_range_matcher.rbs | 10 ++++++---- .../tracing/contrib/aws/instrumentation_spec.rb | 8 +++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sig/datadog/tracing/contrib/status_range_matcher.rbs b/sig/datadog/tracing/contrib/status_range_matcher.rbs index 3cc97d4848c..76f13780492 100644 --- a/sig/datadog/tracing/contrib/status_range_matcher.rbs +++ b/sig/datadog/tracing/contrib/status_range_matcher.rbs @@ -2,17 +2,19 @@ module Datadog module Tracing module Contrib class StatusRangeMatcher - @ranges: Array[Integer | Range[Integer]] + type range_type = Array[Integer | Range[Integer]] - attr_reader ranges: Array[Integer | Range[Integer]] + @ranges: range_type - def initialize: (untyped ranges) -> void + attr_reader ranges: range_type + + def initialize: (Integer | Range[Integer] | range_type ranges) -> void def +: (StatusRangeMatcher other) -> StatusRangeMatcher alias concat + - def include?: (untyped status) -> untyped + def include?: (Integer status) -> bool end end end diff --git a/spec/datadog/tracing/contrib/aws/instrumentation_spec.rb b/spec/datadog/tracing/contrib/aws/instrumentation_spec.rb index 58717810d02..538d461b641 100644 --- a/spec/datadog/tracing/contrib/aws/instrumentation_spec.rb +++ b/spec/datadog/tracing/contrib/aws/instrumentation_spec.rb @@ -14,10 +14,12 @@ RSpec.describe 'AWS instrumentation' do let(:configuration_options) { {} } + let(:server_error_statuses) { nil } before do Datadog.configure do |c| c.tracing.instrument :aws, configuration_options + c.tracing.http_error_statuses.server = server_error_statuses if server_error_statuses end end @@ -179,11 +181,7 @@ end context 'when the server error statuses are configured to include 404' do - before do - Datadog.configure do |c| - c.tracing.http_error_statuses.server = 400..599 - end - end + let(:server_error_statuses) { 400..599 } it 'generates an errored span' do expect do From c85b9ac2f5fb8d5801f7ac8f030181705b9a5753 Mon Sep 17 00:00:00 2001 From: Victor Pellan Date: Wed, 22 Oct 2025 11:05:11 +0200 Subject: [PATCH 7/8] Force-enable DD_TRACE_HTTP_SERVER_ERROR_STATUSES and DD_TRACE_HTTP_CLIENT_ERROR_STATUSES system-tests --- .github/forced-tests-list.cfg | 3 +++ .github/workflows/system-tests.yml | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/forced-tests-list.cfg b/.github/forced-tests-list.cfg index 8a13b700ce4..0a490762aa3 100644 --- a/.github/forced-tests-list.cfg +++ b/.github/forced-tests-list.cfg @@ -10,3 +10,6 @@ # Example : # tests/parametric/test_config_consistency.py::Test_Stable_Config_Default::test_config_precedence + +tests/test_config_consistency.py::Test_Config_HttpClientErrorStatuses_FeatureFlagCustom +tests/test_config_consistency.py::Test_Config_HttpServerErrorStatuses_FeatureFlagCustom diff --git a/.github/workflows/system-tests.yml b/.github/workflows/system-tests.yml index d9d43fce64d..788b68a3a09 100644 --- a/.github/workflows/system-tests.yml +++ b/.github/workflows/system-tests.yml @@ -108,7 +108,8 @@ jobs: TELEMETRY_APP_STARTED_PRODUCTS_DISABLED, TELEMETRY_DEPENDENCY_LOADED_TEST_FOR_DEPENDENCY_COLLECTION_DISABLED, TELEMETRY_LOG_GENERATION_DISABLED, - TELEMETRY_METRIC_GENERATION_DISABLED + TELEMETRY_METRIC_GENERATION_DISABLED, + TRACING_CONFIG_NONDEFAULT needs: - build uses: DataDog/system-tests/.github/workflows/system-tests.yml@2cbe759487228ade311550caa67a9131659a8f0b # Automated: This reference is automatically updated. From 084ca9ced9af435179e3093200fd80b5ec601077 Mon Sep 17 00:00:00 2001 From: Victor Pellan Date: Wed, 22 Oct 2025 11:34:12 +0200 Subject: [PATCH 8/8] Add DEV-3.0 comments for breaking changes --- .../contrib/action_pack/action_controller/instrumentation.rb | 2 -- lib/datadog/tracing/contrib/action_pack/utils.rb | 2 -- lib/datadog/tracing/contrib/aws/instrumentation.rb | 4 +++- lib/datadog/tracing/contrib/ethon/easy_patch.rb | 3 +++ lib/datadog/tracing/contrib/excon/configuration/settings.rb | 2 ++ lib/datadog/tracing/contrib/faraday/configuration/settings.rb | 2 ++ lib/datadog/tracing/contrib/http/configuration/settings.rb | 2 ++ .../tracing/contrib/httpclient/configuration/settings.rb | 2 ++ lib/datadog/tracing/contrib/httprb/configuration/settings.rb | 2 ++ lib/datadog/tracing/contrib/rest_client/request_patch.rb | 3 +++ 10 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb b/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb index 9ac1e9a1be1..dd60a605516 100644 --- a/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +++ b/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb @@ -77,8 +77,6 @@ def finish_processing(payload) exception = payload[:exception_object] if exception.nil? - # [christian] in some cases :status is not defined, - # rather than firing an error, simply acknowledge we don't know it. status = payload[:status] if status && Datadog.configuration.tracing.http_error_statuses.server.include?(status) span.status = Tracing::Metadata::Ext::Errors::STATUS diff --git a/lib/datadog/tracing/contrib/action_pack/utils.rb b/lib/datadog/tracing/contrib/action_pack/utils.rb index d3fb67adc36..73e5f752c2c 100644 --- a/lib/datadog/tracing/contrib/action_pack/utils.rb +++ b/lib/datadog/tracing/contrib/action_pack/utils.rb @@ -13,8 +13,6 @@ def self.exception_is_error?(exception) # Gets the equivalent status code for the exception (not all are 5XX) # You can add custom errors via `config.action_dispatch.rescue_responses` status = ::ActionDispatch::ExceptionWrapper.status_code_for_exception(exception.class.name) - # By default, only 5XX exceptions are actually errors (e.g. don't flag 404s). - # This can be changed by setting `DD_TRACE_HTTP_SERVER_ERROR_STATUSES` environment variable. Datadog.configuration.tracing.http_error_statuses.server.include?(status) else true diff --git a/lib/datadog/tracing/contrib/aws/instrumentation.rb b/lib/datadog/tracing/contrib/aws/instrumentation.rb index c03491383a1..923b1fc8f48 100644 --- a/lib/datadog/tracing/contrib/aws/instrumentation.rb +++ b/lib/datadog/tracing/contrib/aws/instrumentation.rb @@ -36,7 +36,9 @@ def annotate!(span, context) span.name = Ext::SPAN_COMMAND span.resource = context.safely(:resource) - # Set error on the span if the Response Status Code is in error range + # DEV-3.0: This was previously checking against a 500..599 range. + # To not introduce breaking change, this was changed to use `http_error_statuses.server`, + # but `aws` is a client library, this check should use `http_error_statuses.client` instead. if Datadog.configuration.tracing.http_error_statuses.server.include?(context.safely(:status_code)) # At this point we do not have any additional diagnostics # besides the HTTP status code which is recorded in the span tags diff --git a/lib/datadog/tracing/contrib/ethon/easy_patch.rb b/lib/datadog/tracing/contrib/ethon/easy_patch.rb index f9ef781f58c..db4c817ee2c 100644 --- a/lib/datadog/tracing/contrib/ethon/easy_patch.rb +++ b/lib/datadog/tracing/contrib/ethon/easy_patch.rb @@ -57,6 +57,9 @@ def complete set_span_error_message("Request has failed: #{message}") else @datadog_span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, response_code) + # DEV-3.0: This was previously checking against a 500..599 range. + # To not introduce breaking change, this was changed to use `http_error_statuses.server`, + # but `ethon` is a client library, this check should use `http_error_statuses.client` instead. if Datadog.configuration.tracing.http_error_statuses.server.include?(response_code) set_span_error_message("Request has failed with HTTP error: #{response_code}") end diff --git a/lib/datadog/tracing/contrib/excon/configuration/settings.rb b/lib/datadog/tracing/contrib/excon/configuration/settings.rb index efe06c9839b..e6b680fcbdf 100644 --- a/lib/datadog/tracing/contrib/excon/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/excon/configuration/settings.rb @@ -44,6 +44,8 @@ class Settings < Contrib::Configuration::Settings o.setter do |value| if value.nil? # Fallback to global config, which is defaulted to client (400..499) + server (500..599) + # DEV-3.0: `excon` is a client library, this should fall back to `http_error_statuses.client` only. + # We cannot change it without causing a breaking change. client_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.client server_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.server client_global_error_statuses + server_global_error_statuses diff --git a/lib/datadog/tracing/contrib/faraday/configuration/settings.rb b/lib/datadog/tracing/contrib/faraday/configuration/settings.rb index 805d7a9946f..47f6ab7e119 100644 --- a/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/faraday/configuration/settings.rb @@ -43,6 +43,8 @@ class Settings < Contrib::Configuration::Settings o.setter do |value| if value.nil? # Fallback to global config, which is defaulted to client (400..499) + server (500..599) + # DEV-3.0: `faraday` is a client library, this should fall back to `http_error_statuses.client` only. + # We cannot change it without causing a breaking change. client_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.client server_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.server client_global_error_statuses + server_global_error_statuses diff --git a/lib/datadog/tracing/contrib/http/configuration/settings.rb b/lib/datadog/tracing/contrib/http/configuration/settings.rb index 5633b0cd27f..fcfe8319211 100644 --- a/lib/datadog/tracing/contrib/http/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/http/configuration/settings.rb @@ -49,6 +49,8 @@ class Settings < Contrib::Configuration::Settings o.setter do |value| if value.nil? # Fallback to global config, which is defaulted to client (400..499) + server (500..599) + # DEV-3.0: `http` is a client library, this should fall back to `http_error_statuses.client` only. + # We cannot change it without causing a breaking change. client_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.client server_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.server client_global_error_statuses + server_global_error_statuses diff --git a/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb b/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb index 7bb9ee1d6c0..85beaa829fc 100644 --- a/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb @@ -48,6 +48,8 @@ class Settings < Contrib::Configuration::Settings o.setter do |value| if value.nil? # Fallback to global config, which is defaulted to client (400..499) + server (500..599) + # DEV-3.0: `httpclient` is a client library, this should fall back to `http_error_statuses.client` only. + # We cannot change it without causing a breaking change. client_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.client server_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.server client_global_error_statuses + server_global_error_statuses diff --git a/lib/datadog/tracing/contrib/httprb/configuration/settings.rb b/lib/datadog/tracing/contrib/httprb/configuration/settings.rb index 320b4dd94ec..a6409f59c77 100644 --- a/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/httprb/configuration/settings.rb @@ -48,6 +48,8 @@ class Settings < Contrib::Configuration::Settings o.setter do |value| if value.nil? # Fallback to global config, which is defaulted to client (400..499) + server (500..599) + # DEV-3.0: `httprb` is a client library, this should fall back to `http_error_statuses.client` only. + # We cannot change it without causing a breaking change. client_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.client server_global_error_statuses = Datadog.configuration.tracing.http_error_statuses.server client_global_error_statuses + server_global_error_statuses diff --git a/lib/datadog/tracing/contrib/rest_client/request_patch.rb b/lib/datadog/tracing/contrib/rest_client/request_patch.rb index 0b387439e30..96dcad68c67 100644 --- a/lib/datadog/tracing/contrib/rest_client/request_patch.rb +++ b/lib/datadog/tracing/contrib/rest_client/request_patch.rb @@ -99,6 +99,9 @@ def datadog_trace_request(uri) end end rescue ::RestClient::ExceptionWithResponse => e + # DEV-3.0: This was previously checking against a 500..599 range. + # To not introduce breaking change, this was changed to use `http_error_statuses.server`, + # but `rest_client` is a client library, this check should use `http_error_statuses.client` instead. span.set_error(e) if Datadog.configuration.tracing.http_error_statuses.server.include?(e.http_code) span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, e.http_code)