If you attempt to register an extension with psycopg2 and happen to use the newrelic python client library you may get an error that looks like this
File "/opt/balanced/embedded/lib/python2.7/site-packages/psycopg2/_json.py", line 142, in register_default_json
loads=loads, oid=JSON_OID, array_oid=JSONARRAY_OID)
File "/opt/balanced/embedded/lib/python2.7/site-packages/psycopg2/_json.py", line 125, in register_json
register_type(JSON, not globally and conn_or_curs or None)
TypeError: argument 2 must be a connection, cursor or None
The issue you're running into is that newrelic decides to play god and replace the connection object with a proxy that it implements called ConnectionWrapper.
This is a problem because psycopg2 has some code that inspects the type of object in order to determine what how to register the extension.
Luckily SQLAlchemy checks for a handy method called _sqla_unwrap
which can be used to get the underlying connection and pass it to psycopg. I guess the engineers at newrelic didn't get around to testing this scenario and their code includes a bunch of anonymous classes so it's hard to inherit the object and patch it yourself. Here's how you can fix it yourself:
Write some code to patch the connection class
class NewRelicConnectionWrapperProxy(object):
def __init__(self, connect):
self.__connect = connect
def __call__(self, *args, **kwargs):
cxn = self.__connect(*args, **kwargs)
object.__setattr__(cxn, '_sqla_unwrap', cxn._nr_connection)
return cxn
Now, after you initialize the newrelic agent but before you initialize your database connection you can monkey patch everything:
import newrelic.agent
newrelic.agent.initialize(config_file, environment)
import psycopg2
psycopg2.connect = NewRelicConnectionWrapperProxy(psycopg2.connect)
That's all there is to it. I hope this is handy for someone.
To New Relic devs: If you fix this, please do not use anonymous classes, it's really hard to extend your code when you cannot inherit and override a class!
Thanks @GrahamDumpleton! Adding the following to my
newrelic.ini
seemed to work around this issue for me:However, I am curious if a workaround has been implemented on the newrelic agent side, so that we can work around the problem without having to disable our NR database instrumentation.