graphql-python / graphene-django

Build powerful, efficient, and flexible GraphQL APIs with seamless Django integration.
http://docs.graphene-python.org/projects/django/en/latest/
MIT License
4.3k stars 768 forks source link

Graphene Django v3 swallowing all exceptions, including stack traces. #1437

Open Toruitas opened 1 year ago

Toruitas commented 1 year ago

Django 3.2.20 Graphene-Django 3.1.3 Graphene 3.3

For comparison (this version set produces exceptions in the console) Django 3.2.20 Graphene-Django 2.16.0 Graphene 2.1.9

Logging and visibility for stack traces is necessary for both development and production code in order to answer simple questions like "Where is the code that broke?" I'm migrating a project from Graphene-Django v2 to v3 and am encountering an issue regarding exception swallowing. In v2, both explicit Exceptions and unexpected Exceptions will log to the console with stack traces and also return the error message in the GraphQL response. In v3, the same exact code with no changes at all besides the version upgrade won't log anything to the console, but will return the error message in the GraphQL response. I would expect to get the exception and stack trace in the console as well.

Or is there some new option to log exceptions that is now disabled by default that I might have missed?

Thanks!

Edit: Bug still present on Graphene-Django 3.2.0

EricRobertCampbell commented 1 year ago

I was running into the same issue. There's a partial workaround (https://stackoverflow.com/questions/75166816/django-graphene-not-handling-errors/75179165#75179165) which returns the error attribute as part of the response but doesn't log it to the console.

Looks like it might also be related to https://github.com/graphql-python/graphene-django/issues/1384.

lgnashold commented 1 year ago

Also having this issue. Was not able to get the workaround above to work.

superlevure commented 9 months ago

You can use a middleware to achieve this:

import logging

logger = logging.getLogger(__name__)

class ExceptionLoggingMiddleware:
    def resolve(self, next, root, info, **args):
        try:
            return next(root, info, **args)
        except Exception as e:
            raise self._log_exception(e)

    def _log_exception(self, error: Exception) -> Exception:
        logger.exception("Exception caught in resolver.", exc_info=error)

        return error