first of all, I want to thank you and all your team for the excellent work.
I have started a project that uses sanic
I want to log any exceptions that happen in the project
exception handler:
@application.exception(ServerError)
def log_any_exception(request, exception):
...
logger.error(exception)
...
a test handler:
@application.get('/')
async def index(request):
result = 10 / 0 # division error
return await file('/'.join([application.config.TEMPLATES_DIR, 'index.html']))
after division error, log_any_exception Will not be called
but, below handler works like a charm:
@application.get('/')
async def index(request):
raise ServerError("Something bad happened", status_code=500)
return await file('/'.join([application.config.TEMPLATES_DIR, 'index.html']))
thanks
Hello,
Have you taken a look into the Exception docs?
You can pass SanicException to catch them all!
Does it help?
Else have you tried registering an exception handler for the ZeroDivisionError exception?
hi @arnulfojr, Many thanks for the prompt reply
Yes, I read the documentation carefully
You can pass SanicException to catch them all!
But did not work
And finally I solved this issue with ‌BaseException:
@application.exception(BaseException)
def log_any_exception(request, exception):
...
logger.error(exception)
...
I understand the case you want to implement, I have sandboxed the thing you're talking about, and I have some ideas I would like to suggest you.
I would recommend you to take a look into Python's Exception Hierarchy.
Now, the SanicException is extending from the Exception class.
In sanic the isinstance is used, and according to the python docs we can see that it only returns True if the exception "is an instance of the classinfo argument, or of a (direct, indirect or virtual) subclass..." which in this case the ZeroValueError is not an instance of SanicException, and therefore registering an Exception for ZeroValueError is required.
In this manner this SanicException only takes in consideration all the Sanic relevant Exceptions and subclasses of it. So a more proper way around this would be to register the exception handler to Exception instead of BaseException.
Moreover my advice would be for you to wrap your exceptions basing them from one Exception, as for example is said in this post "Defining your exceptions..." and then registering a default Exception handler for your exceptions (look below).
@app.get('/error')
async def some_error(request):
try:
number = 3 / 0
except ZeroDivisionError as e:
raise MyAppException(e) # or a subclass of it
return json(DATA, status=200)
# So then you'd register the handler
@app.exception(MyAppException)
async def handle_my_app(request, exception):
logger.error('...')
# or the "default" handler
@app.exception(Exception)
async def default_handle_exception(request, exception):
# this will catch ZeroDivisionError if no handler would be registered and no
# MyAppException would be raised
logger.error('... default handle ...')
I hope it helps :) and sorry if I made some confusion
In this manner this SanicException only takes in consideration all the Sanic relevant Exceptions and subclasses of it. So a more proper way around this would be to register the exception handler to Exception instead of BaseException.
Thanks for your suggestion
This suggestion worked for me (i.e. using @app.exception(Exception)), but the documentation is a little misleading in saying SanicException will catch them all.
I can't catch any exception in my handler.
I change sanic.error logger to:
"sanic.error": {
"level": "ERROR",
"handlers": ["main_error"],
"propagate": True,
"qualname": "sanic.error"
},
main_error is:
"main_error": {
'level': 'ERROR',
"class": "logger.MainHandler",
},
logger.MainHandler is:
class MainHandler(logging.Handler):
def emit(self, record):
trace = ''
if record.exc_info:
trace = traceback.format_exc()
...
I use @app.exception(Exception) on view and use ZeroDivisionError for exception but can't catch exception. On the other hand if i use this config for the root logger it works fine.
What do you think about it?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If this is incorrect, please respond with an update. Thank you for your contributions.
Most helpful comment
I understand the case you want to implement, I have sandboxed the thing you're talking about, and I have some ideas I would like to suggest you.
I would recommend you to take a look into Python's Exception Hierarchy.
Now, the
SanicExceptionis extending from theExceptionclass.In sanic the
isinstanceis used, and according to the python docs we can see that it only returns True if the exception "is an instance of the classinfo argument, or of a (direct, indirect or virtual) subclass..." which in this case the ZeroValueError is not an instance of SanicException, and therefore registering an Exception for ZeroValueError is required.In this manner this
SanicExceptiononly takes in consideration all the Sanic relevant Exceptions and subclasses of it. So a more proper way around this would be to register the exception handler toExceptioninstead ofBaseException.Moreover my advice would be for you to wrap your exceptions basing them from one Exception, as for example is said in this post "Defining your exceptions..." and then registering a default Exception handler for your exceptions (look below).
I hope it helps :) and sorry if I made some confusion