Skip to content

Commit 2e2e5b9

Browse files
committed
Port over op/description/status extraction
1 parent 8a08fb3 commit 2e2e5b9

File tree

3 files changed

+79
-82
lines changed

3 files changed

+79
-82
lines changed

sentry_sdk/integrations/opentelemetry/potel_span_processor.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from sentry_sdk.integrations.opentelemetry.utils import (
99
is_sentry_span,
1010
convert_otel_timestamp,
11+
extract_span_data,
1112
)
1213
from sentry_sdk.integrations.opentelemetry.consts import (
1314
OTEL_SENTRY_CONTEXT,
@@ -100,7 +101,6 @@ def _collect_children(self, span):
100101

101102
# we construct the event from scratch here
102103
# and not use the current Transaction class for easier refactoring
103-
# TODO-neel-potel op, description, status logic
104104
def _root_span_to_transaction_event(self, span):
105105
# type: (ReadableSpan) -> Optional[Event]
106106
if not span.context:
@@ -114,12 +114,14 @@ def _root_span_to_transaction_event(self, span):
114114
span_id = format_span_id(span.context.span_id)
115115
parent_span_id = format_span_id(span.parent.span_id) if span.parent else None
116116

117+
(op, description, _) = extract_span_data(span)
118+
117119
trace_context = {
118120
"trace_id": trace_id,
119121
"span_id": span_id,
120122
"origin": SPAN_ORIGIN,
121-
"op": span.name, # TODO
122-
"status": "ok", # TODO
123+
"op": op,
124+
"status": "ok", # TODO-neel-potel span status mapping
123125
} # type: dict[str, Any]
124126

125127
if parent_span_id:
@@ -133,8 +135,9 @@ def _root_span_to_transaction_event(self, span):
133135

134136
event = {
135137
"type": "transaction",
136-
"transaction": span.name, # TODO
137-
"transaction_info": {"source": "custom"}, # TODO
138+
"transaction": description,
139+
# TODO-neel-potel tx source based on integration
140+
"transaction_info": {"source": "custom"},
138141
"contexts": contexts,
139142
"start_timestamp": convert_otel_timestamp(span.start_time),
140143
"timestamp": convert_otel_timestamp(span.end_time),
@@ -155,13 +158,15 @@ def _span_to_json(self, span):
155158
span_id = format_span_id(span.context.span_id)
156159
parent_span_id = format_span_id(span.parent.span_id) if span.parent else None
157160

161+
(op, description, _) = extract_span_data(span)
162+
158163
span_json = {
159164
"trace_id": trace_id,
160165
"span_id": span_id,
161166
"origin": SPAN_ORIGIN,
162-
"op": span.name, # TODO
163-
"description": span.name, # TODO
164-
"status": "ok", # TODO
167+
"op": op,
168+
"description": description,
169+
"status": "ok", # TODO-neel-potel span status mapping
165170
"start_timestamp": convert_otel_timestamp(span.start_time),
166171
"timestamp": convert_otel_timestamp(span.end_time),
167172
} # type: dict[str, Any]

sentry_sdk/integrations/opentelemetry/span_processor.py

Lines changed: 11 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@
44

55
from opentelemetry.context import get_value
66
from opentelemetry.sdk.trace import SpanProcessor, ReadableSpan as OTelSpan
7-
from opentelemetry.semconv.trace import SpanAttributes
87
from opentelemetry.trace import (
98
format_span_id,
109
format_trace_id,
1110
get_current_span,
12-
SpanKind,
1311
)
1412
from opentelemetry.trace.span import (
1513
INVALID_SPAN_ID,
@@ -23,12 +21,14 @@
2321
OTEL_SENTRY_CONTEXT,
2422
SPAN_ORIGIN,
2523
)
26-
from sentry_sdk.integrations.opentelemetry.utils import is_sentry_span
24+
from sentry_sdk.integrations.opentelemetry.utils import (
25+
is_sentry_span,
26+
extract_span_data,
27+
)
2728
from sentry_sdk.scope import add_global_event_processor
2829
from sentry_sdk.tracing import Transaction, Span as SentrySpan
2930
from sentry_sdk._types import TYPE_CHECKING
3031

31-
from urllib3.util import parse_url as urlparse
3232

3333
if TYPE_CHECKING:
3434
from typing import Any, Optional, Union
@@ -289,81 +289,19 @@ def _update_span_with_otel_data(self, sentry_span, otel_span):
289289
"""
290290
sentry_span.set_data("otel.kind", otel_span.kind)
291291

292-
op = otel_span.name
293-
description = otel_span.name
294-
295292
if otel_span.attributes is not None:
296293
for key, val in otel_span.attributes.items():
297294
sentry_span.set_data(key, val)
298295

299-
http_method = otel_span.attributes.get(SpanAttributes.HTTP_METHOD)
300-
http_method = cast("Optional[str]", http_method)
301-
302-
db_query = otel_span.attributes.get(SpanAttributes.DB_SYSTEM)
303-
304-
if http_method:
305-
op = "http"
306-
307-
if otel_span.kind == SpanKind.SERVER:
308-
op += ".server"
309-
elif otel_span.kind == SpanKind.CLIENT:
310-
op += ".client"
311-
312-
description = http_method
313-
314-
peer_name = otel_span.attributes.get(SpanAttributes.NET_PEER_NAME, None)
315-
if peer_name:
316-
description += " {}".format(peer_name)
317-
318-
target = otel_span.attributes.get(SpanAttributes.HTTP_TARGET, None)
319-
if target:
320-
description += " {}".format(target)
321-
322-
if not peer_name and not target:
323-
url = otel_span.attributes.get(SpanAttributes.HTTP_URL, None)
324-
url = cast("Optional[str]", url)
325-
if url:
326-
parsed_url = urlparse(url)
327-
url = "{}://{}{}".format(
328-
parsed_url.scheme, parsed_url.netloc, parsed_url.path
329-
)
330-
description += " {}".format(url)
331-
332-
status_code = otel_span.attributes.get(
333-
SpanAttributes.HTTP_STATUS_CODE, None
334-
)
335-
status_code = cast("Optional[int]", status_code)
336-
if status_code:
337-
sentry_span.set_http_status(status_code)
338-
339-
elif db_query:
340-
op = "db"
341-
statement = otel_span.attributes.get(SpanAttributes.DB_STATEMENT, None)
342-
statement = cast("Optional[str]", statement)
343-
if statement:
344-
description = statement
345-
296+
(op, description, status_code) = extract_span_data(otel_span)
346297
sentry_span.op = op
347298
sentry_span.description = description
299+
if status_code:
300+
sentry_span.set_http_status(status_code)
348301

349302
def _update_transaction_with_otel_data(self, sentry_span, otel_span):
350303
# type: (SentrySpan, OTelSpan) -> None
351-
if otel_span.attributes is None:
352-
return
353-
354-
http_method = otel_span.attributes.get(SpanAttributes.HTTP_METHOD)
355-
356-
if http_method:
357-
status_code = otel_span.attributes.get(SpanAttributes.HTTP_STATUS_CODE)
358-
status_code = cast("Optional[int]", status_code)
359-
if status_code:
360-
sentry_span.set_http_status(status_code)
361-
362-
op = "http"
363-
364-
if otel_span.kind == SpanKind.SERVER:
365-
op += ".server"
366-
elif otel_span.kind == SpanKind.CLIENT:
367-
op += ".client"
368-
369-
sentry_span.op = op
304+
(op, _, status_code) = extract_span_data(otel_span)
305+
sentry_span.op = op
306+
if status_code:
307+
sentry_span.set_http_status(status_code)

sentry_sdk/integrations/opentelemetry/utils.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
from typing import cast
22
from datetime import datetime, timezone
33

4+
from opentelemetry.trace import SpanKind
45
from opentelemetry.semconv.trace import SpanAttributes
56
from opentelemetry.sdk.trace import ReadableSpan
7+
from urllib3.util import parse_url as urlparse
68

79
from sentry_sdk import get_client
810
from sentry_sdk.utils import Dsn
911

1012
from sentry_sdk._types import TYPE_CHECKING
1113

1214
if TYPE_CHECKING:
13-
from typing import Optional
15+
from typing import Optional, Tuple
1416

1517

1618
def is_sentry_span(span):
@@ -49,3 +51,55 @@ def is_sentry_span(span):
4951
def convert_otel_timestamp(time):
5052
# type: (int) -> datetime
5153
return datetime.fromtimestamp(time / 1e9, timezone.utc)
54+
55+
56+
def extract_span_data(span):
57+
# type: (ReadableSpan) -> Tuple[str, str, Optional[int]]
58+
op = span.name
59+
description = span.name
60+
status_code = None
61+
62+
if span.attributes is None:
63+
return (op, description, status_code)
64+
65+
http_method = span.attributes.get(SpanAttributes.HTTP_METHOD)
66+
http_method = cast("Optional[str]", http_method)
67+
db_query = span.attributes.get(SpanAttributes.DB_SYSTEM)
68+
69+
if http_method:
70+
op = "http"
71+
if span.kind == SpanKind.SERVER:
72+
op += ".server"
73+
elif span.kind == SpanKind.CLIENT:
74+
op += ".client"
75+
76+
description = http_method
77+
78+
peer_name = span.attributes.get(SpanAttributes.NET_PEER_NAME, None)
79+
if peer_name:
80+
description += " {}".format(peer_name)
81+
82+
target = span.attributes.get(SpanAttributes.HTTP_TARGET, None)
83+
if target:
84+
description += " {}".format(target)
85+
86+
if not peer_name and not target:
87+
url = span.attributes.get(SpanAttributes.HTTP_URL, None)
88+
url = cast("Optional[str]", url)
89+
if url:
90+
parsed_url = urlparse(url)
91+
url = "{}://{}{}".format(
92+
parsed_url.scheme, parsed_url.netloc, parsed_url.path
93+
)
94+
description += " {}".format(url)
95+
96+
status_code = span.attributes.get(SpanAttributes.HTTP_STATUS_CODE)
97+
elif db_query:
98+
op = "db"
99+
statement = span.attributes.get(SpanAttributes.DB_STATEMENT, None)
100+
statement = cast("Optional[str]", statement)
101+
if statement:
102+
description = statement
103+
104+
status_code = cast("Optional[int]", status_code)
105+
return (op, description, status_code)

0 commit comments

Comments
 (0)