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!
New Relic has for some time had instrumentation around psycopg2.register_type() specifically to unwrap the object passed in if required and avoid this issue. We include checks to make sure it is working in our test suites. If this is not doing its job, then you likely aren't initialising the New Relic agent prior to psycopg2 modules having being imported.
In future if you have issues it would be better to contact New Relic support directly rather than simply come up with a workaround. We will always address such issues if we are told about them.