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

Bread Crumbs showing data from other uWSGI requests

Open bartek opened this issue 7 years ago • 24 comments

Hi Sentry Team,

We are running a Django application, with a uWSGI config of the following (Irrelevant data snipped):

[uwsgi]
project = gapi-layer-drf

base = /var/www
home = /opt/lib/virtualenvs/%(project)
chdir = /var/www/gapi-layer-drf/gapi

pythonpath = /var/www/gapi-layer-drf/gapi
module = gapi.wsgi

plugins-dir = /opt/uwsgi/uwsgi-2.0.13.1
plugins = python35

uid = www-data
gid = www-data

harakiri = 20
# thunder-lock is basically necessary with threading. Helps deal with the "thundering herd" problem.
thunder-lock = true

# memory-report is necessary if doing stats. Proper reporting of data.
memory-report = true
logto = /var/log/uwsgi/%(project).log
logfile-chown = www-data

master = true
processes = 5
threads = 5

# Hush uWSGI from IOError, SIGPIPE, etc.
ignore-sigpipe = true
ignore-write-errors = true
disable-write-exception = true

# Setup a socket, which is more secure and offers better performance than a network port.
socket = /tmp/%(project).sock
chmod-socket = 666
chown-socket = www-data

# Use vacuum to clean up when the service is stopped.
vacuum = true

We are using Django Rest Framework and a custom Exception Handler. Essentially, any exception is captured, transformed for the response, but also delivered to Sentry via the standard logging module. We are using Raven 5.32

The Bread Crumbs seem to work well for the most part, and the tail of the crumbs indeed shows the appropriate request that caused the exception. For example. Here's the tail end of a crumb, with the exception/time:

flightcontrolsentry

Then, above that, I have more crumbs, that are generally hidden (but not always). The primary thing to note is the substantial time difference between the previous crumbs and these ones. Essentially, they are not part of the same request-response cycle (and knowing our system, I can confirm that. We'd never hit a booking while hitting the Flight Control backend within a single request)

sentrycustomercrumb

So, quite an interesting bit for us. It's not necessarily an issue, but it might confuse our developers (or even myself in a pre-coffee state) what's going on with this request.

Anything else I can provide, please let me know. Happy to help. Thank you!

bartek avatar Nov 30 '16 02:11 bartek

That actually doesnt sound surprising to me. The uWSGI request/response cycle isnt a known quantity to Sentry, and we dont reset breadcrumbs at the start of a request IIRC. I'm not sure if our WSGI middleware does take care of this or not, but IIRC it doesn't (and should).

@mitsuhiko thoughts?

dcramer avatar Nov 30 '16 21:11 dcramer

@dcramer Running into this as well. ISTM that under normal circumstances, process_response clears the context which should clear the breadcrumbs on the current thread. However, if an exception is raised and handle_exception is called on the middleware, would the context (and thus breadcrumbs) still get cleared? Is it as simple as clearing the context there as well?

bendemaree avatar Dec 07 '16 05:12 bendemaree

@bendemaree are you running into this with django? FWIW, the ClosingIterator is responsible for clear. Not sure what process_response even was supposed to be doing. I killed that method now as it does not do anything.

Is this also happening with uwsgi or something else?

mitsuhiko avatar Dec 07 '16 23:12 mitsuhiko

Hi @mitsuhiko! No Django; running Falcon in this case, and we're running exclusively with uWSGI.

I feel a little shy asking you in particular this, but process_response would've been called if this middleware were running under Flask, right?

I'll work on coming up with a more concise example to reproduce this.

bendemaree avatar Dec 08 '16 12:12 bendemaree

@bendemaree no, that's unrelated. This is a WSGI middleware and it works the same everywhere.

mitsuhiko avatar Dec 08 '16 13:12 mitsuhiko

Not sure if this is related but something to add to the issue. I am seeing this sometimes, not with every exception:


DEBUG 2016-12-08 16:57:30,697 base 48353 139996363421440 Sending message of length 2562 to https://sentry.io/api/95888/store/
/opt/lib/virtualenvs/gapi-layer-drf/lib/python3.5/site-packages/raven/utils/compat.py:59: Warning: We detected the use of uwsgi with disabled threads.  This will cause issues with the transport you are trying to use.  Please enable threading for uwsgi.  (Enable the "enable-threads" flag).
  warn(Warning('We detected the use of uwsgi with disabled threads.  '
WARNING 2016-12-08 16:57:30,516 exception_handler 48353 139996363421440 Date fields must be formatted as YYYY-MM-DD

But as shared above, my uWSGI config has threads = 5. So perhaps this is something else?

bartek avatar Dec 09 '16 15:12 bartek

But as shared above, my uWSGI config has threads = 5. So perhaps this is something else?

fwiw enable-threads is different from threads. threads is how many uWSGI threads to run to process requests, but enable-threads is to enable the use of the GIL and allow application layer threads in Python. This is important from raven-python since we'd prefer to use a thread to send our messages and not block the running application.

mattrobenolt avatar Dec 09 '16 19:12 mattrobenolt

I tried to blast a few requests locally to it and it always gets the thread information right. There must be more to this story. Are you using eventlet or greenlet?

mitsuhiko avatar Dec 09 '16 19:12 mitsuhiko

@mattrobenolt Hm, thanks. I will adjust my uWSGI configuration to have that turned on. From your experience, does this impact Django/Flask/etc. in any way?

@mitsuhiko I am not using eventlet or greenlet. Not sure what else to provide outside of my uWSGI config, so any ideas, I'm all ears. Would be happy to share more.

bartek avatar Dec 12 '16 20:12 bartek

@bartek enable-threads should be the default same as with the holy mode. uWSGI does some weird thing to cheap in benchmarks but that causes various issues. Our docs point out to enable that I think.

mitsuhiko avatar Dec 12 '16 21:12 mitsuhiko

@mattrobenolt As a followup to your comment, I did review the uWSGI docs and identified this paragraph -- I recall seeing this when I was investigating threads

By default the Python plugin does not initialize the GIL. This means your app-generated threads will not run. If you need threads, remember to enable them with enable-threads. Running uWSGI in multithreading mode (with the threads options) will automatically enable threading support.

However, Raven does complain about the lack of enabled threads so ... confusing. Not sure which documentation to trust anymore ;)

bartek avatar Dec 13 '16 00:12 bartek

This was also reported to happen with non django (it was reported for flask).

mitsuhiko avatar Dec 13 '16 22:12 mitsuhiko

My guess currently is that this might happen if multiple clients are involved and a client's is active for the wrong thread.

mitsuhiko avatar Dec 13 '16 22:12 mitsuhiko

However, Raven does complain about the lack of enabled threads so ... confusing. Not sure which documentation to trust anymore ;)

Ah, I'll have to review. We might have to change our check. We are explicitly checking for enable-threads, but if that's true, we can check for either option.

mattrobenolt avatar Dec 13 '16 22:12 mattrobenolt

@bartek see: https://github.com/getsentry/raven-python/pull/928 I verified this is true locally.

mattrobenolt avatar Dec 13 '16 22:12 mattrobenolt

@mattrobenolt Ah great! So perhaps that was simply a red herring :)

My guess currently is that this might happen if multiple clients are involved and a client's is active for the wrong thread.

@mitsuhiko When you say client, you are specifically speaking of any arbitrary client making the HTTP request, correct? We do have many requests occurring at once, but they shouldn't be stepping over each others toes in any way, since they all have explicit requests and actions. Hmm.

bartek avatar Dec 14 '16 01:12 bartek

When you say client, you are specifically speaking of any arbitrary client making the HTTP request, correct?

No, we mean instances of the Raven client.

mattrobenolt avatar Dec 14 '16 18:12 mattrobenolt

We're getting the same issue with Django + gunicorn. Breadcrumbs work as expected when using the debug server.

gunicorn config for testing:

import os
# assumes gunicorn conf is located 1 directory inside root. change appropriately (app_root/configs/)
config_dir = os.path.dirname(os.path.realpath(__file__))
chdir = os.path.dirname(config_dir)
bind = '127.0.0.1:8000'
timeout = 120

antdking avatar Jul 20 '17 15:07 antdking

Same problem here with Django and --enable-threads. The rest of our setup is a pretty vanilla Django one. How can I help debug this?

jonashaag avatar Sep 21 '17 08:09 jonashaag

Apologies if this is not relevant, but for me this issue seems to go away when I remove the following lines of code:

https://github.com/getsentry/raven-python/blob/master/raven/context.py#L129-L135

jan11011977 avatar Oct 03 '17 09:10 jan11011977

Hey, would be good to get an update on this. We've just started trialling Sentry, and this is causing breadcrumbs to be pretty useless.

We're Python 3, Django, gunicorn running worker processes, installed just with the app in INSTALLED_APPS (i.e. we aren't using the WSGI middleware). Happy to provide more info to debug this.

danpalmer avatar Feb 01 '18 09:02 danpalmer

@danpalmer gunicorn is a different issue. If you are using gunicorn i don't think breadcrumbs work properly yet unless something patches threading.local. Not sure if gunicorn does that.

mitsuhiko avatar Apr 02 '18 18:04 mitsuhiko

I'm also seeing what seem to be breadcrumbs from irrelevant requests on uWSGI (only noticed it now even if we've been using Sentry for a while 😅 ).

Since our uwsgi.ini looks like follows (plus some irrelevant stanzas), each worker should only be dealing with a single request at a time. We do have some "worker" threads that shoot stuff into metrics services and so on, but those shouldn't matter...

[uwsgi]
die-on-term
enable-threads
master
need-app
strict
thunder-lock
wsgi = roi.wsgi
http = :8000
processes = 16
cheaper = 4
max-requests = 1000
offload-threads = 4
reload-on-rss = 1000

akx avatar Oct 08 '18 12:10 akx

Hmm, if it helps, it looks like these leaky breadcrumbs maybe don't occur for exceptions, only for logging output. Our logging config is (non-Raven/Sentry things cropped out)

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'root': {
        'level': 'INFO',
        'handlers': ['sentry'],
    },
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        },
    },
    'handlers': {
        'sentry': {
            'level': 'WARNING',
            'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler',
            'filters': ['require_debug_false'],
        },
    },
    'loggers': {
        'raven': {
            'level': 'WARNING',
            'handlers': ['console'],
            'propagate': False,
        },
        'sentry.errors': {
            'level': 'DEBUG',
            'handlers': ['console'],
            'propagate': False,
        },
    }
}

akx avatar Oct 09 '18 07:10 akx