Skip to content

Commit

Permalink
feat(tracing): Record lost spans in client reports
Browse files Browse the repository at this point in the history
Resolves #3229
  • Loading branch information
szokeasaurusrex committed Jul 4, 2024
1 parent 854b46c commit 0ce0523
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 13 deletions.
1 change: 1 addition & 0 deletions sentry_sdk/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
"profile_chunk",
"metric_bucket",
"monitor",
"span",
]
SessionStatus = Literal["ok", "exited", "crashed", "abnormal"]

Expand Down
22 changes: 13 additions & 9 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,11 @@
from sentry_sdk.session import Session
from sentry_sdk.transport import Transport


_client_init_debug = ContextVar("client_init_debug")


SDK_INFO = {
"name": "sentry.python", # SDK name will be overridden after integrations have been loaded with sentry_sdk.integrations.setup_integrations()
"name": "sentry.python",
# SDK name will be overridden after integrations have been loaded with sentry_sdk.integrations.setup_integrations()
"version": VERSION,
"packages": [{"name": "pypi:sentry-sdk", "version": VERSION}],
}
Expand Down Expand Up @@ -453,10 +452,15 @@ def _prepare_event(
# one of the event/error processors returned None
if event_ is None:
if self.transport:
self.transport.record_lost_event(
"event_processor",
data_category=("transaction" if is_transaction else "error"),
)
if is_transaction:
self.transport.record_lost_transaction(
"event_processor", len(event.get("spans", []))
)
else:
self.transport.record_lost_event(
"event_processor",
data_category="error",
)
return None

event = event_
Expand Down Expand Up @@ -546,8 +550,8 @@ def _prepare_event(
if new_event is None:
logger.info("before send transaction dropped event")
if self.transport:
self.transport.record_lost_event(
"before_send", data_category="transaction"
self.transport.record_lost_transaction(
"before_send", len(event.get("spans", []))
)
event = new_event # type: ignore

Expand Down
5 changes: 2 additions & 3 deletions sentry_sdk/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,9 @@ class TransactionKwargs(SpanKwargs, total=False):
},
)


BAGGAGE_HEADER_NAME = "baggage"
SENTRY_TRACE_HEADER_NAME = "sentry-trace"


# Transaction source
# see https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations
TRANSACTION_SOURCE_CUSTOM = "custom"
Expand Down Expand Up @@ -856,7 +854,8 @@ def finish(self, hub=None, end_timestamp=None):
else:
reason = "sample_rate"

client.transport.record_lost_event(reason, data_category="transaction")
# No spans are discarded here because they were never recorded in the first place
client.transport.record_lost_transaction(reason, span_count=0)

return None

Expand Down
45 changes: 44 additions & 1 deletion sentry_sdk/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,22 @@ def record_lost_event(
# type: (...) -> None
"""This increments a counter for event loss by reason and
data category.
data_category="transaction" should use record_lost_transaction,
instead.
"""
return None

def record_lost_transaction(
self,
reason, # type: str
span_count, # type: int
):
# type: (...) -> None
"""This increments a counter for loss of a transaction and the transaction's spans.
The span_count should only include the number of spans contained in the transaction, EXCLUDING the transaction
itself.
"""
return None

Expand Down Expand Up @@ -229,10 +245,24 @@ def record_lost_event(
if not self.options["send_client_reports"]:
return

if data_category == "transaction":
warnings.warn(
"Use record_lost_transaction for transactions to ensure lost spans are counted.",
stacklevel=2,
)

quantity = 1
if item is not None:
data_category = item.data_category
if data_category == "attachment":

if data_category == "transaction":
# Handle transactions through record_lost_transaction.
event = item.get_event() or {}
span_count = len(event.get("spans") or [])
self.record_lost_transaction(reason, span_count)
return

elif data_category == "attachment":
# quantity of 0 is actually 1 as we do not want to count
# empty attachments as actually empty.
quantity = len(item.get_bytes()) or 1
Expand All @@ -242,6 +272,19 @@ def record_lost_event(

self._discarded_events[data_category, reason] += quantity

def record_lost_transaction(
self,
reason, # type: str
span_count, # type: int
): # type: (...) -> None
if not self.options["send_client_reports"]:
return

self._discarded_events["transaction", reason] += 1
self._discarded_events["span", reason] += (
span_count + 1
) # Also count the transaction itself

def _update_rate_limits(self, response):
# type: (urllib3.BaseHTTPResponse) -> None

Expand Down

0 comments on commit 0ce0523

Please sign in to comment.