Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request failure logging in middleware cannot be hit #19

Closed
danpalmer opened this issue Nov 22, 2019 · 5 comments · Fixed by #20
Closed

Request failure logging in middleware cannot be hit #19

danpalmer opened this issue Nov 22, 2019 · 5 comments · Fixed by #20
Assignees
Labels
bug Something isn't working

Comments

@danpalmer
Copy link

danpalmer commented Nov 22, 2019

From the Django documentation...

https://docs.djangoproject.com/en/2.2/topics/http/middleware/#exception-handling

Exception handling

Django automatically converts exceptions raised by the view or by middleware into an appropriate HTTP response with an error status code. Certain exceptions are converted to 4xx status codes, while an unknown exception is converted to a 500 status code.

This conversion takes place before and after each middleware (you can think of it as the thin film in between each layer of the onion), so that every middleware can always rely on getting some kind of HTTP response back from calling its get_response callable. Middleware don’t need to worry about wrapping their call to get_response in a try/except and handling an exception that might have been raised by a later middleware or the view. Even if the very next middleware in the chain raises an Http404 exception, for example, your middleware won’t see that exception; instead it will get an HttpResponse object with a status_code of 404.

Currently the middleware in this package depends on thrown exceptions to log request failures, but this never happens.

We can reproduce this under runserver and gunicorn. It should be noted that with django-extensions and the runserver_plus command, this doesn't apply and the middleware does work.

The most obvious solution I can think of is to check the status code for an error code and mark request failure from that. This doesn't capture an exception though, and there may be a better way of doing this that will capture the exception.

@jrobichaud
Copy link
Owner

jrobichaud commented Nov 22, 2019

In case it is not an exception the request will be logged there

logger.info(
"request_finished", code=response.status_code, request=request
)

However it is logged as an info which may not be adequate. We may want to log info for 2XX/3XX, warning for 4XX, and error for 5XX, what do you think?

You can create a separate Issue for django-structlog not working when using django commands.

@danpalmer
Copy link
Author

@jrobichaud I think there may be a misunderstanding here, I'm not clear exactly what you mean by your response, but currently I don't believe it's possible to hit this condition:

traceback_object = e.__traceback__
formatted_traceback = traceback.format_tb(traceback_object)
logger.error(
"request_failed",
error_message=str(e),
error_traceback=formatted_traceback,
code=500,
request=request,
)
raise

Django catches all exceptions from get_response, so exception handling around that function call will never fire. The correct way to handle exceptions in middleware is to implement a process_exception method on the middleware. Django will then call this if there is an exception.

This is an issue because the request_failed log message contains the exception details, whereas just logging request_finished does not have that context in.

Here's an example of what we've used instead: https://gist.github.com/danpalmer/16cdd5aa2941fa9706a44bb28c54729b

@jrobichaud
Copy link
Owner

I will investigate this, thank you.

@jrobichaud
Copy link
Owner

Ok, with DEBUG = True it was actually raising an exception but not with DEBUG = False.

Your implementation works with both cases.

Do you mind if I use the gist you provided to implement it correctly?

jrobichaud added a commit that referenced this issue Nov 28, 2019
@jrobichaud
Copy link
Owner

@danpalmer can you take a quick look at #20 and tell me if it makes sense to you?

Thank you again for your help, this is really appreciated.

@jrobichaud jrobichaud self-assigned this Nov 28, 2019
@jrobichaud jrobichaud added the bug Something isn't working label Nov 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants