feat(integrations): Add integration for aiomysql#4703
feat(integrations): Add integration for aiomysql#4703tonal wants to merge 11 commits intogetsentry:masterfrom
aiomysql#4703Conversation
aiomysql
|
Hey @tonal thanks for the PR, great work! Could you address the cursor comments above? |
aiomysqlaiomysql
sentry_sdk/integrations/aiomysql.py
Outdated
| """ | ||
| Adapted from module sentry_sdk.integrations.asyncpg | ||
| """ |
There was a problem hiding this comment.
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.
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨Integrations
Other
Bug Fixes 🐛Anthropic
Other
Internal Changes 🔧
Other
🤖 This preview updates automatically when you update the PR. |
sentry_sdk/integrations/aiomysql.py
Outdated
| def setup_once() -> None: | ||
| aiomysql_version = parse_version(aiomysql.__version__) | ||
| _check_minimum_version(AioMySQLIntegration, aiomysql_version) |
There was a problem hiding this comment.
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>
| if getattr(cursor, "_sentry_skip_next_execute", False): | ||
| cursor._sentry_skip_next_execute = False | ||
| return await f(*args, **kwargs) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ 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 | ||
|
|
There was a problem hiding this comment.
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)
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) |
There was a problem hiding this comment.
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)
Reviewed by Cursor Bugbot for commit 89b8669. Configure here.


Add support for aiomysql to the SDK.