|
15 | 15 |
|
16 | 16 | from sentry_sdk.integrations._asgi_common import ( |
17 | 17 | _get_headers, |
| 18 | + _get_query, |
18 | 19 | _get_request_data, |
19 | 20 | _get_url, |
20 | 21 | ) |
|
57 | 58 |
|
58 | 59 | TRANSACTION_STYLE_VALUES = ("endpoint", "url") |
59 | 60 |
|
| 61 | +ASGI_SCOPE_PROPERTY_TO_ATTRIBUTE = { |
| 62 | + "http_version": "network.protocol.version", |
| 63 | + "method": "http.request.method", |
| 64 | + "path": "url.path", |
| 65 | + "scheme": "url.scheme", |
| 66 | + "type": "network.protocol.name", |
| 67 | +} |
| 68 | + |
60 | 69 |
|
61 | 70 | def _capture_exception(exc, mechanism_type="asgi"): |
62 | 71 | # type: (Any, str) -> None |
@@ -213,23 +222,21 @@ async def _run_app(self, scope, receive, send, asgi_version): |
213 | 222 | ) |
214 | 223 | if should_trace |
215 | 224 | else nullcontext() |
216 | | - ) as transaction: |
217 | | - if transaction is not None: |
218 | | - logger.debug( |
219 | | - "[ASGI] Started transaction: %s", transaction |
220 | | - ) |
221 | | - transaction.set_tag("asgi.type", ty) |
| 225 | + ) as span: |
| 226 | + if span is not None: |
| 227 | + logger.debug("[ASGI] Started transaction: %s", span) |
| 228 | + span.set_tag("asgi.type", ty) |
222 | 229 | try: |
223 | 230 |
|
224 | 231 | async def _sentry_wrapped_send(event): |
225 | 232 | # type: (Dict[str, Any]) -> Any |
226 | 233 | is_http_response = ( |
227 | 234 | event.get("type") == "http.response.start" |
228 | | - and transaction is not None |
| 235 | + and span is not None |
229 | 236 | and "status" in event |
230 | 237 | ) |
231 | 238 | if is_http_response: |
232 | | - transaction.set_http_status(event["status"]) |
| 239 | + span.set_http_status(event["status"]) |
233 | 240 |
|
234 | 241 | return await send(event) |
235 | 242 |
|
@@ -328,12 +335,31 @@ def _get_transaction_name_and_source(self, transaction_style, asgi_scope): |
328 | 335 |
|
329 | 336 | def _prepopulate_attributes(scope): |
330 | 337 | # type: (Any) -> dict[str, Any] |
331 | | - """Unpack asgi_scope into serializable attributes.""" |
| 338 | + """Unpack ASGI scope into serializable OTel attributes.""" |
332 | 339 | scope = scope or {} |
333 | 340 |
|
334 | 341 | attributes = {} |
335 | | - for attr in ("endpoint", "path", "root_path", "route", "scheme", "server", "type"): |
| 342 | + for attr, key in ASGI_SCOPE_PROPERTY_TO_ATTRIBUTE.items(): |
336 | 343 | if scope.get(attr): |
337 | | - attributes[f"asgi_scope.{attr}"] = scope[attr] |
| 344 | + attributes[key] = scope[attr] |
| 345 | + |
| 346 | + for attr in ("client", "server"): |
| 347 | + if scope.get(attr): |
| 348 | + try: |
| 349 | + host, port = scope[attr] |
| 350 | + attributes[f"{attr}.address"] = host |
| 351 | + attributes[f"{attr}.port"] = port |
| 352 | + except Exception: |
| 353 | + pass |
| 354 | + |
| 355 | + try: |
| 356 | + full_url = _get_url(scope) |
| 357 | + query = _get_query(scope) |
| 358 | + if query: |
| 359 | + full_url = f"{full_url}?{query}" |
| 360 | + |
| 361 | + attributes["url.full"] = full_url |
| 362 | + except Exception: |
| 363 | + pass |
338 | 364 |
|
339 | 365 | return attributes |
0 commit comments