Database instrumentation

    The wrappers are modeled after middleware – they are callables which take another callable as one of their arguments. They call that callable to invoke the (possibly wrapped) database query, and they can do what they want around that call. They are, however, created and installed by user code, and so don’t need a separate factory like middleware do.

    Installing a wrapper is done in a context manager – so the wrappers are temporary and specific to some flow in your code.

    As mentioned above, an example of a wrapper is a query execution blocker. It could look like this:

    The parameters sent to the wrappers are:

    • sql – a str, the SQL query to be sent to the database.
    • many – a indicating whether the ultimately invoked call is execute() or executemany() (and whether params is expected to be a sequence of values, or a sequence of sequences of values).

    Using the parameters, a slightly more complex version of the blocker could include the connection name in the error message:

    For a more complete example, a query logger could look like this:

    execute_wrapper(wrapper)

    Returns a context manager which, when entered, installs a wrapper around database query executions, and when exited, removes the wrapper. The wrapper is installed on the thread-local connection object.

    is a callable taking five arguments. It is called for every query execution in the scope of the context manager, with arguments execute, sql, params, many, and context as described above. It’s expected to call execute(sql, params, many, context) and return the return value of that call.