diff --git a/lib/sentry/client_report.ex b/lib/sentry/client_report.ex index d51133de..fe38703c 100644 --- a/lib/sentry/client_report.ex +++ b/lib/sentry/client_report.ex @@ -28,8 +28,7 @@ defmodule Sentry.ClientReport do :insufficient_data, :backpressure, :send_error, - :internal_sdk_error, - :ignored + :internal_sdk_error ] @typedoc """ diff --git a/lib/sentry/config.ex b/lib/sentry/config.ex index 60b2ac98..c133b229 100644 --- a/lib/sentry/config.ex +++ b/lib/sentry/config.ex @@ -382,8 +382,10 @@ defmodule Sentry.Config do Defaults to `[404]`, so *404 Not Found* requests are not traced. Set it to `[]` to trace them again. - Outgoing requests are not affected, and the trace is still propagated to the services - this one calls. + The transaction is dropped only once the response status is known, after the request + has been handled. The trace is still propagated as sampled, so services called while + handling the request still report their part of it. Dropped transactions are counted + in client reports with the `event_processor` reason. Outgoing requests are not affected. *Available since 14.0.0*. """ diff --git a/lib/sentry/opentelemetry/span_processor.ex b/lib/sentry/opentelemetry/span_processor.ex index 888ab31e..e8940591 100644 --- a/lib/sentry/opentelemetry/span_processor.ex +++ b/lib/sentry/opentelemetry/span_processor.ex @@ -187,13 +187,20 @@ if Sentry.OpenTelemetry.VersionChecker.tracing_compatible?() do result end - # Only incoming requests are matched. An outgoing call can become a - # transaction root of its own when it outlives the request that made it, - # and the option is not meant to drop those. - defp ignored_response_status?(%{kind: :server, attributes: attributes}) do + defp ignored_response_status?(%{kind: :server, attributes: attributes} = span_record) do case Map.get(attributes, to_string(HTTPAttributes.http_response_status_code())) do status when is_integer(status) -> - Enum.any?(Config.traces_ignore_http_status_codes(), &status_matches?(&1, status)) + ignored? = + Enum.any?(Config.traces_ignore_http_status_codes(), &status_matches?(&1, status)) + + if ignored? do + LoggerUtils.debug(fn -> + "Discarding transaction #{span_record.name} (#{span_record.span_id}): " <> + "its response status #{status} is listed in :traces_ignore_http_status_codes" + end) + end + + ignored? _other -> false @@ -206,7 +213,7 @@ if Sentry.OpenTelemetry.VersionChecker.tracing_compatible?() do defp status_matches?(code, status), do: code == status defp discard_transaction(transaction) do - ClientReport.Sender.record_discarded_events(:ignored, [transaction]) + ClientReport.Sender.record_discarded_events(:event_processor, [transaction]) true end diff --git a/test_integrations/phoenix_app/test/phoenix_app/ignored_status_traces_test.exs b/test_integrations/phoenix_app/test/phoenix_app/ignored_status_traces_test.exs index 9807ff35..db85e02f 100644 --- a/test_integrations/phoenix_app/test/phoenix_app/ignored_status_traces_test.exs +++ b/test_integrations/phoenix_app/test/phoenix_app/ignored_status_traces_test.exs @@ -1,6 +1,7 @@ defmodule PhoenixApp.IgnoredStatusTracesTest do use ExUnit.Case, async: false + import ExUnit.CaptureLog import Sentry.TestHelpers @port 4102 @@ -71,16 +72,31 @@ defmodule PhoenixApp.IgnoredStatusTracesTest do assert upstream_tx["transaction"] == "GET /upstream" end - test "a request answered with an ignored status is reported as discarded telemetry", %{ + test "a request answered with an ignored status is discarded by an event processor", %{ ref: ref, client_report_sender: sender } do put_test_config(traces_ignore_http_status_codes: [410]) + log_at_debug_level() - assert request("/responses/410") == 410 - assert reported_transactions(ref) == [] + log = + capture_log([level: :debug], fn -> + assert request("/responses/410") == 410 + assert reported_transactions(ref) == [] + end) + + assert log =~ ~r/\[debug\]\s+Discarding transaction .*response status 410/ + + assert discarded_outcomes(sender, ref, "event_processor") == %{ + "transaction" => 1, + "span" => 1 + } + end - assert discarded_outcomes(sender, ref, "ignored") == %{"transaction" => 1, "span" => 1} + defp log_at_debug_level do + previous_level = Logger.level() + Logger.configure(level: :debug) + on_exit(fn -> Logger.configure(level: previous_level) end) end defp request(path) do