newrelic-python-agent
newrelic-python-agent copied to clipboard
psycopg3 support
Hey, thanks for the great monitoring integration! psycong3 was released in October 2021, do you have any plans to support it? Would be really nice to have a hook for this lib, as it brings a lot of useful features.
Hi @alexeyshockov! I'll start by saying that I am not an expert of psycopg3, or New Relic, or even Python, but we came across this problem today and also this issue that you opened.
Perhaps you've solved this already, but, if not, here's how I addressed it.
For context, startup.py
is the entry point for our web server.
startup.py
import psycopg
from newrelic_custom_instrumentation import instrument_psycopg3_async_cursor
instrument_psycopg3_async_cursor(psycopg)
# ... loads of other unrelated stuff
newrelic_custom_instrumentation.py
from newrelic.api.database_trace import (
DatabaseTrace,
enable_datastore_instance_feature,
register_database_client,
)
from newrelic.common.object_wrapper import wrap_function_wrapper
# TODO – I'm not certain we're getting everything we want out of this – I based it off database_asyncpg
class PostgresApi(object):
@staticmethod
def _instance_info(addr, connected_fut, con_params, *args, **kwargs):
if isinstance(addr, str):
host = "localhost"
port = addr
else:
host, port = addr
return host, str(port), getattr(con_params, "database", None)
@classmethod
def instance_info(cls, args, kwargs):
return cls._instance_info(*args, **kwargs)
register_database_client(
PostgresApi,
"Postgres",
quoting_style="single+dollar",
instance_info=PostgresApi.instance_info,
)
enable_datastore_instance_feature(PostgresApi)
# TODO – Similarly, there may be more things we can pass to DatabaseTrace
async def wrap_execute(wrapped, instance, args, kwargs):
query, params = args
with DatabaseTrace(
query,
database_name=instance.connection.info.dbname,
dbapi2_module=PostgresApi,
host=instance.connection.info.host,
port_path_or_id=instance.connection.info.port,
source=instance.execute,
sql_parameters=params,
):
return await wrapped(*args, **kwargs)
def instrument_psycopg3_async_cursor(module):
wrap_function_wrapper(module, "AsyncCursor.execute", wrap_execute)
As you see in my TODO comments above, I'm sure that we're missing out on more capabilities. We also have a limited use of psycopg3, hence only needing to instrument AsyncCursor.execute
. Nevertheless, hopefully this helps.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Hey @gushecht, thanks a lot for the snippet! Currently I put this on hold in my app, in favour of "good old" psycopg2. But I'm really looking forward to hear any updates from New Relic team here...
We have reviewed this ticket with the team and have created a Feature Request to get this through in our backlog. cc: @ak-war