Skip to content

feat(integrations): Add integration for aiomysql#4703

Open
tonal wants to merge 11 commits intogetsentry:masterfrom
tonal:patch-2
Open

feat(integrations): Add integration for aiomysql#4703
tonal wants to merge 11 commits intogetsentry:masterfrom
tonal:patch-2

Conversation

@tonal
Copy link
Copy Markdown

@tonal tonal commented Aug 14, 2025

Add support for aiomysql to the SDK.

@tonal tonal requested a review from a team as a code owner August 14, 2025 09:43
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

@antonpirker antonpirker added the New Integration Integrating with a new framework or library label Sep 11, 2025
@antonpirker antonpirker changed the title integration for aiomysql Feat(integrations): Add integration for aiomysql Sep 11, 2025
@antonpirker
Copy link
Copy Markdown
Contributor

Hey @tonal thanks for the PR, great work! Could you address the cursor comments above?

@antonpirker antonpirker changed the title Feat(integrations): Add integration for aiomysql feat(integrations): Add integration for aiomysql Sep 11, 2025
cursor[bot]

This comment was marked as outdated.

Comment on lines +2 to +4
"""
Adapted from module sentry_sdk.integrations.asyncpg
"""
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.

Hi @tonal ,

Thanks for the contribution, much appreciated!

Can you add unit tests for the integration as well? You can probably adapt them from the asyncpg tests.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 12, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

Integrations

  • Add integration for aiomysql by tonal in #4703
  • Instrument pyreqwest tracing by servusdei2018 in #5682

Other

  • (ai) Redact base64 data URLs in image_url content blocks by ericapisani in #5953

Bug Fixes 🐛

Anthropic

  • Capture exceptions for stream() calls by alexander-alderman-webb in #5950
  • Stop setting transaction status when child span fails by alexander-alderman-webb in #5717
  • Only finish relevant spans in .create() patches by alexander-alderman-webb in #5716

Other

  • (pydantic-ai) Use first-class hooks when available by alexander-alderman-webb in #5947
  • (wsgi) Respect HTTP_X_FORWARDED_PROTO in request.url construction by sl0thentr0py in #5963

Internal Changes 🔧

  • (ai) Remove gen_ai.tool.type span attribute by ericapisani in #5964
  • (anthropic) Separate sync and async .create() patches by alexander-alderman-webb in #5715
  • (openai) Split token counting by API for easier deprecation by ericapisani in #5930
  • (opentelemetry) Ignore mypy error by alexander-alderman-webb in #5927
  • Fix license metadata in setup.py by sl0thentr0py in #5934
  • Update validate-pr workflow by stephanie-anderson in #5931

Other

  • Handle None span context in the span processor and pin tokenizers version for anthropic tests on Python 3.8 by alexander-alderman-webb in #5967

🤖 This preview updates automatically when you update the PR.

Comment on lines +36 to +38
def setup_once() -> None:
aiomysql_version = parse_version(aiomysql.__version__)
_check_minimum_version(AioMySQLIntegration, aiomysql_version)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The AioMySQLIntegration is not registered for auto-enabling, so it will not activate by default when the aiomysql library is present, requiring manual user configuration.
Severity: MEDIUM

Suggested Fix

Add the full module path 'sentry_sdk.integrations.aiomysql.AioMySQLIntegration' to the _AUTO_ENABLING_INTEGRATIONS list in sentry_sdk/integrations/__init__.py. Also, add 'aiomysql' with its minimum supported version to the _MIN_VERSIONS dictionary in the same file to enable version checking.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: sentry_sdk/integrations/aiomysql.py#L36-L38

Potential issue: The new `AioMySQLIntegration` is not added to the
`_AUTO_ENABLING_INTEGRATIONS` list in `sentry_sdk/integrations/__init__.py`.
Consequently, the integration will not be automatically enabled when the `aiomysql`
library is detected in a user's environment. This behavior is inconsistent with other
database integrations like `asyncpg` and requires users to manually add
`AioMySQLIntegration()` to their configuration to make it work. Additionally, `aiomysql`
is missing from the `_MIN_VERSIONS` dictionary, so no version check will be performed.

Did we get this right? 👍 / 👎 to inform future reviews.

Rewrite the aiomysql integration to fix issues raised in PR getsentry#4703:

- Patch Cursor.execute and Cursor.executemany instead of Connection.query
- Make _wrap_connect async (await inside span context)
- Handle bytes/bytearray queries from executemany's internal batching
- Normalize query text using " ".join(query.split()) for performance
- Protect _sentry_skip_next_execute flag with try/finally to prevent leakage
- Remove dead _wrap_cursor and unused _record context manager

Add 17 end-to-end tests covering connect, execute, executemany, record_params,
cursor iteration, connection pools, query source, span origin, and normalization.

Update CI configuration: tox.ini envlist, GitHub Actions workflow with MySQL
service container, and test suite config.

Co-Authored-By: Qwen Code <noreply@anthropic.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Comment on lines +59 to +61
if getattr(cursor, "_sentry_skip_next_execute", False):
cursor._sentry_skip_next_execute = False
return await f(*args, **kwargs)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: When executemany is used with non-INSERT queries, the _sentry_skip_next_execute flag is reset prematurely, causing duplicate spans for subsequent operations in the loop.
Severity: MEDIUM

Suggested Fix

The _sentry_skip_next_execute flag should not be reset within _wrap_execute. Instead, it should only be set to True at the beginning of _wrap_executemany and reset to False in its finally block. This ensures all execute calls originating from a single executemany are skipped.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: sentry_sdk/integrations/aiomysql.py#L59-L61

Potential issue: When `aiomysql`'s `executemany` is used with statements other than
`INSERT` or `REPLACE` (e.g., `UPDATE`), it falls back to calling `execute` for each set
of parameters. The integration attempts to prevent duplicate spans by setting a
`_sentry_skip_next_execute` flag. However, the `_wrap_execute` function resets this flag
after the first skipped call. This causes all subsequent `execute` calls within the same
`executemany` operation to be recorded as separate, spurious spans, leading to
duplicated and incorrect transaction data. The test suite only covers the `INSERT` case,
so this bug is not caught by existing tests.

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 2 potential issues.

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 89b8669. Configure here.

SENTRY_PYTHON_TEST_MYSQL_USER: root
SENTRY_PYTHON_TEST_MYSQL_PASSWORD: root
SENTRY_PYTHON_TEST_MYSQL_DB: test

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Duplicate YAML keys cause postgres service to be silently dropped

High Severity

The Jinja template emits separate services: and env: blocks for each database (postgres, mysql). When both needs_postgres and needs_mysql are true (as in the "DBs" group), the generated YAML contains duplicate services: and env: keys at the same job level. YAML parsers silently overwrite the first occurrence with the last, so the postgres service definition and its environment variables are completely lost. This breaks all asyncpg tests in CI.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 89b8669. Configure here.

# Skip if flagged by executemany (avoids double-recording)
if getattr(cursor, "_sentry_skip_next_execute", False):
cursor._sentry_skip_next_execute = False
return await f(*args, **kwargs)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Skip flag resets after first internal execute call

Medium Severity

The _sentry_skip_next_execute flag is set to True once in _wrap_executemany, but _wrap_execute resets it to False after skipping the first internal execute call. When executemany falls back to row-by-row execution (non-INSERT queries), subsequent internal execute calls see False and record additional spans/breadcrumbs, causing double-recording. The flag needs to remain True throughout the entire executemany call — only the finally block in _wrap_executemany should reset it.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 89b8669. Configure here.

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

Labels

New Integration Integrating with a new framework or library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants