Skip to content

feat(sqlalchemy): Support span streaming#6132

Open
alexander-alderman-webb wants to merge 18 commits intomasterfrom
webb/sqlalchemy/span-first
Open

feat(sqlalchemy): Support span streaming#6132
alexander-alderman-webb wants to merge 18 commits intomasterfrom
webb/sqlalchemy/span-first

Conversation

@alexander-alderman-webb
Copy link
Copy Markdown
Contributor

@alexander-alderman-webb alexander-alderman-webb commented Apr 24, 2026

Description

Adapt add_query_source() analogously to changes to add_http_request_source() in #6084.

Add record_sql_queries_supporting_streaming() based on record_sql_queries() so that the streaming path is not triggered for other ORM integrations until they support the streaming trace lifecycle. Once the last ORM integration supports span-streaming the functions can be de-duplicated.

Set <unknown SQL query> as the name when the description was previously None.

Adapting Tests

sed commands used for converting transaction context managers:

  • sed -i '' 's/start_transaction(name="test_transaction", sampled=True)/sentry_sdk.tracing.start_span(name="custom parent")/g'
  • sed -i '' 's/start_transaction(name="test_transaction", sampled=True)/sentry_sdk.traces.start_span(name="custom parent")/g'
  • sed -i '' 's/with start_transaction(name="foo")/sentry_sdk.traces.start_span(name="custom parent")/g'
  • sed -i '' 's/start_transaction(name="foo")/sentry_sdk.traces.start_span(name="custom parent")/g'
  • sed -i '' 's/start_transaction(name="test")/sentry_sdk.traces.start_span(name="custom parent")/g'

sed commands used for converting code source attributes:

  • sed -i '' 's/CODE_LINENO/CODE_LINE_NUMBER/g'
  • sed -i '' 's/CODE_FILEPATH/CODE_FILE_PATH/g'

sed commands used for converting event capture:

  • sed -i '' 's/events = capture_events()/items = capture_items("event", "transaction", "span")/g'
  • sed -i '' 's/capture_events,/capture_items,/g'
  • sed -i '' 's/capture_events)/capture_items)/g'
  • sed -i '' '/(event,) = events/d'

sed commands used for converting op:

  • sed -i '' 's/- op/- sentry.op/g'
  • sed -i '' 's/span.get("op")/span["attributes"].get("sentry.op")/g'

sed commands used for converting description:

  • sed -i '' 's/span.get("description")/span["name"]/g'
  • sed -i '' 's/description = spans[0]["description"]/name = spans[0]["name"]/g'
  • sed -i '' 's/description/name/g'

sed commands used for converting data to attributes:

  • sed -i '' 's/data = span.get("data", {})/attributes = span["attributes"]/g'
  • sed -i '' 's/in data/in attributes/g'
  • sed -i '' 's/data.get/attributes.get/g'
  • sed -i '' 's/event["spans"]/spans/g'
  • sed -i '' 's/span["data"]/span["attributes"]/g'

sed commands used for converting timestamps:

  • sed -i '' 's/span.start_timestamp/span._start_timestamp/g'
  • sed -i '' 's/span.timestamp/span._timestamp/g'

Issues

Reminders

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 24, 2026

Codecov Results 📊

2215 passed | ⏭️ 244 skipped | Total: 2459 | Pass Rate: 90.08% | Execution Time: 5m 51s

📊 Comparison with Base Branch

Metric Change
Total Tests
Passed Tests 📈 +16
Failed Tests
Skipped Tests 📉 -16

✨ No test changes detected

All tests are passing successfully.

❌ Patch coverage is 9.84%. Project has 12704 uncovered lines.
❌ Project coverage is 41.16%. Comparing base (base) to head (head).

Files with missing lines (2)
File Patch % Lines
tracing_utils.py 76.81% ⚠️ 183 Missing and 52 partials
sqlalchemy.py 10.64% ⚠️ 84 Missing
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
- Coverage    41.19%    41.16%    -0.03%
==========================================
  Files          190       190         —
  Lines        21405     21592      +187
  Branches      7581      7210      -371
==========================================
+ Hits          8817      8888       +71
- Misses       12588     12704      +116
- Partials       479       451       -28

Generated by Codecov Action

Comment thread tests/integrations/threading/test_threading.py
Comment thread tests/conftest.py
Comment thread tests/integrations/sqlalchemy/test_sqlalchemy.py
Comment thread sentry_sdk/integrations/sqlalchemy.py
Comment thread sentry_sdk/tracing_utils.py
Comment thread tests/integrations/sqlalchemy/test_sqlalchemy.py
Comment thread sentry_sdk/integrations/asyncpg.py Outdated
Comment thread tests/integrations/sqlalchemy/test_sqlalchemy.py
@alexander-alderman-webb alexander-alderman-webb marked this pull request as ready for review April 24, 2026 10:13
@alexander-alderman-webb alexander-alderman-webb requested a review from a team as a code owner April 24, 2026 10:13
Comment thread sentry_sdk/integrations/asyncpg.py Outdated
Comment thread sentry_sdk/integrations/sqlalchemy.py
Comment thread tests/conftest.py Outdated
Comment thread tests/integrations/sqlalchemy/test_sqlalchemy.py
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 98c67f0. Configure here.

Comment thread tests/conftest.py
Comment thread sentry_sdk/tracing_utils.py
@alexander-alderman-webb alexander-alderman-webb marked this pull request as draft April 27, 2026 08:13
@alexander-alderman-webb alexander-alderman-webb marked this pull request as ready for review April 27, 2026 12:27
Comment thread tests/integrations/sqlalchemy/test_sqlalchemy.py
Copy link
Copy Markdown
Contributor

@sentrivana sentrivana left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great overall! Just not sure about a handful of attributes.

db_system = _get_db_system(conn.engine.name)
if db_system is not None:
span.set_data(SPANDATA.DB_SYSTEM, db_system)
set_on_span(SPANDATA.DB_SYSTEM, db_system)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

db.name was deprecated in favor of db.system.name, so we should use that in streaming mode

db_name = conn.engine.url.database
if db_name is not None:
span.set_data(SPANDATA.DB_NAME, db_name)
set_on_span(SPANDATA.DB_NAME, db_name)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be db.namespace in streaming mode



@contextlib.contextmanager
def record_sql_queries_supporting_streaming(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to adapt the existing record_sql_queries instead? Why a new func, if we still support both streaming and legacy mode in it?

Comment on lines +198 to +205
if params_list is not None:
data["db.params"] = params_list
if paramstyle is not None:
data["db.paramstyle"] = paramstyle
if executemany:
data["db.executemany"] = True
if record_cursor_repr and cursor is not None:
data["db.cursor"] = cursor
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're setting these as attributes couple lines later, but none of them seems to be in conventions?

Comment on lines +387 to +388
if not client.is_active():
return
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this check should apply to both streaming and non streaming modes, so I'd move it outside of the isinstance branch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants