raven-python icon indicating copy to clipboard operation
raven-python copied to clipboard

Python 3.6/Raven 6.0.0 - Twisted transport incompatible with dsn passed to Client

Open mike-hart opened this issue 7 years ago • 4 comments

More code required below for a twisted eventloop, sorry, this is ripped from a larger project.

client = Client(dsn=some_value, transport=TwistedHTTPTransport)
client.captureMessage(message='hello')

if the DSN is a string then we get:

Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/raven/base.py", line 708, in send_remote
    failed_send)
  File "/usr/lib/python3.6/site-packages/raven/transport/twisted.py", line 45, in async_send
    headers=Headers(dict((k, [v]) for k, v in headers.items()))
  File "/usr/lib/python3.6/site-packages/twisted/web/client.py", line 1623, in request 
    parsedURI = URI.fromBytes(uri)
  File "/usr/lib/python3.6/site-packages/twisted/web/client.py", line 630, in fromBytes
    scheme, netloc, path, params, query, fragment = http.urlparse(uri)
  File "/usr/lib/python3.6/site-packages/twisted/web/http.py", line 180, in urlparse 
    raise TypeError("url must be bytes, not unicode")
TypeError: url must be bytes, not unicode

but if the DSN is bytes then we have:

Unhandled Error
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/twisted/python/usage.py", line 447, in __str__
    return self.getSynopsis() + '\n' + self.getUsage(width=None)
  File "/usr/lib/python3.6/site-packages/twisted/python/usage.py", line 483, in getUsage 
    for (cmd, short, parser, desc) in self.subCommands:
  File "/usr/lib/python3.6/site-packages/twisted/application/app.py", line 641, in subCommands
    for plug in sorted(plugins, key=attrgetter('tapname')):
  File "/usr/lib/python3.6/site-packages/twisted/plugin.py", line 213, in getPlugins
    allDropins = getCache(package)
--- <exception caught here> --- 
  File "/usr/lib/python3.6/site-packages/twisted/plugin.py", line 171, in getCache 
    provider = pluginModule.load()
  File "/usr/lib/python3.6/site-packages/twisted/python/modules.py", line 392, in load
    return self.pathEntry.pythonPath.moduleLoader(self.name)
  File "/usr/lib/python3.6/site-packages/twisted/python/reflect.py", line 301, in namedAny 
    topLevelPackage = _importAndCheckStack(trialname)
  File "/usr/lib/python3.6/site-packages/twisted/python/reflect.py", line 240, in _importAndCheckStack
    return __import__(importName)
  File "/opt/myplugin/twisted/plugins/myplugin.py", line 31, in <module>
    myplugin.utils.setup_sentry()
  File "/opt/myplugin/something/utils.py", line 47, in setup_sentry
    dsn=settings.SENTRY_DSN, transport=TwistedHTTPTransport
  File "/usr/lib/python3.6/site-packages/raven/base.py", line 167, in __init__ 
    self.set_dsn(dsn, transport)
  File "/usr/lib/python3.6/site-packages/raven/base.py", line 248, in set_dsn
    transport_registry=self._registry,
  File "/usr/lib/python3.6/site-packages/raven/conf/remote.py", line 102, in from_string
    netloc += ':%s' % url.port 
builtins.TypeError: can't concat bytes to str

mike-hart avatar Mar 14 '17 17:03 mike-hart

EDIT: works with version < 6.x

Quick workaround to this bug:

from raven.transport.twisted import TwistedHTTPTransport

class FixedTwistedHTTPTransport(TwistedHTTPTransport):
    def __init__(self, parsed_url, *args, **kwargs):
        super().__init__(parsed_url, *args, **kwargs)

        # twisted wants bytes
        if isinstance(self._url, str):
            self._url = str.encode(self._url)


client = Client(dsn=RAVEN_DSN, transport=FixedTwistedHTTPTransport)

990px avatar Mar 19 '17 08:03 990px

Unless I'm missing something very important, self._url is not something used anywhere other than the tests. This change results in a hang as the attempt to log an error results in an error which results in an attempt to log an error, which results in... etc. This causes the process to hang for an extended period at 100% CPU. The only way I found to fix this was to do the encode of the url inside the send_async method, basically copying the bulk of the implementation.

mike-hart avatar Mar 21 '17 11:03 mike-hart

You are right. I didn't notice that you are talking about 6.x version. I'm using v5.x. The only way is to overload send_async or Agent.request.

990px avatar Mar 21 '17 20:03 990px

Fix for raven==6.5.0:

    class FixTwistedHTTPTransport(TwistedHTTPTransport):
        url_encode = 'utf-8'
        def async_send(self, url, data, headers, success_cb, failure_cb):
            b_url = url.encode(url_encode)
            return super().async_send(b_url, data, headers, success_cb, failure_cb)

    client = raven.Client(dsn=dsn, transport=FixTwistedHTTPTransport)

tonal avatar Feb 26 '18 08:02 tonal