Skip to content

integration for aiomysql #4703

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

integration for aiomysql #4703

wants to merge 4 commits into from

Conversation

tonal
Copy link

@tonal tonal commented Aug 14, 2025


Thank you for contributing to sentry-python! Please add tests to validate your changes, and lint your code using tox -e linters.

Running the test suite on your PR might require maintainer approval.

@tonal tonal requested a review from a team as a code owner August 14, 2025 09:43
Comment on lines 44 to 122
aiomysql.Connection.cursor = _wrap_cursor_creation(
aiomysql.Connection.cursor
)

aiomysql.connect = _wrap_connect(aiomysql.connect)


T = TypeVar("T")


def _wrap_execute(f: Callable[..., Awaitable[T]]) -> Callable[..., Awaitable[T]]:
async def _inner(*args: Any, **kwargs: Any) -> T:
if sentry_sdk.get_client().get_integration(AioMySQLIntegration) is None:
return await f(*args, **kwargs)

conn = args[0]
query = args[1] # В aiomysql запрос передается первым аргументом
with record_sql_queries(
cursor=None,
query=query,
params_list=None,
paramstyle=None,
executemany=False,
span_origin=AioMySQLIntegration.origin,
) as span:
res = await f(*args, **kwargs)
span.set_data("db.affected_rows", res)

with capture_internal_exceptions():
add_query_source(span)

return res

return _inner


SubCursor = TypeVar("SubCursor", bound=Cursor)


@contextlib.contextmanager
def _record(
cursor: SubCursor | None,
query: str,
params_list: tuple[Any, ...] | None,
*,
executemany: bool = False,
) -> Iterator[Span]:
integration = sentry_sdk.get_client().get_integration(AioMySQLIntegration)
if integration is not None and not integration._record_params:
params_list = None

param_style = "pyformat" if params_list else None

with record_sql_queries(
cursor=cursor,
query=query,
params_list=params_list,
paramstyle=param_style,
executemany=executemany,
record_cursor_repr=cursor is not None,
span_origin=AioMySQLIntegration.origin,
) as span:
yield span


def _wrap_cursor_creation(f: Callable[..., T]) -> Callable[..., T]:
@ensure_integration_enabled(AioMySQLIntegration, f)
def _inner(*args: Any, **kwargs: Any) -> T:
query = args[0]
params_list = args[1] if len(args) > 1 else None

with _record(None, query, params_list, executemany=False) as span:
_set_db_data(span, args[0])
res = f(*args, **kwargs)
span.set_data("db.cursor", res._coro.result())

return res

return _inner

Choose a reason for hiding this comment

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

Potential bug: The wrapper for aiomysql.Connection.cursor incorrectly assumes it receives a query argument, leading to an IndexError when accessing non-existent arguments and causing a crash.
  • Description: The _wrap_cursor_creation function incorrectly wraps aiomysql.Connection.cursor. It was adapted from the asyncpg integration and assumes the method signature includes a query and parameters. However, aiomysql.Connection.cursor() does not accept a query; it only creates a cursor object. When a standard call like conn.cursor() is made, the wrapper attempts to access args[1] for query parameters. Since this argument does not exist, an IndexError is raised, causing the application to crash. The instrumentation should be applied to cursor execution methods, not the creation method.

  • Suggested fix: The wrapper logic is flawed because aiomysql.Connection.cursor() does not execute queries. The instrumentation should target the cursor's execution methods, such as cursor.execute() and cursor.executemany(), which actually receive the SQL query and parameters. Remove the wrapper for Connection.cursor() and apply it to the appropriate cursor methods instead.
    severity: 0.85, confidence: 0.9

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

Comment on lines 130 to 133
host = kwargs["host"]
port = kwargs.get("port") or 3306
user = kwargs["user"]
db = kwargs["db"]

Choose a reason for hiding this comment

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

Potential bug: The _wrap_connect function will crash with a KeyError because it directly accesses optional keyword arguments like host and user which may not be provided.
  • Description: In the _wrap_connect function, connection parameters host, user, and db are accessed directly from the kwargs dictionary using bracket notation (e.g., kwargs["host"]). The aiomysql.connect function treats these as optional parameters with default values, so they may not be present in a given call. If a developer relies on these defaults and omits the keys, a KeyError will be raised. This unhandled exception will propagate and crash the application. The inconsistent use of safe access (kwargs.get()) for the port parameter in the same function suggests this was an oversight.

  • Suggested fix: To prevent a KeyError, modify the direct kwargs access for host, user, and db to use the safe kwargs.get() method. This change allows the underlying aiomysql library to handle default values as intended when these optional parameters are not explicitly provided in the function call.
    severity: 0.78, confidence: 0.95

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

cursor[bot]

This comment was marked as outdated.


user = conn.user
if user:
span.set_data(SPANDATA.DB_USER, user)
Copy link

Choose a reason for hiding this comment

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

Bug: Unused Function in Integration Code

The _set_db_data function is defined but unused in this integration. It appears to be dead code, likely copied from the asyncpg integration without being integrated into aiomysql's logic.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant