Starlette: Disable error Traceback in logging

Created on 5 Apr 2020  路  4Comments  路  Source: encode/starlette

How to disable traceback logging on error?

App example:

import uvicorn
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import JSONResponse

app = Starlette(debug=False)


@app.route("/ping")
def ping(_: Request) -> JSONResponse:
    raise Exception("ERROR")


@app.exception_handler(Exception)
def exception_handler(_: Request, e: Exception):
    print(f"Unhandled exception: {e}")
    return JSONResponse({}, status_code=500)


uvicorn.run(app, host="127.0.0.1", port=8000)

When I call ping endpoint, I get the following message in the log:

INFO:     Started server process [11002]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Unhandled exception: ERROR
INFO:     127.0.0.1:53874 - "GET /ping HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/home/gleb/Projects/vertical/.venv/lib/python3.8/site-packages/uvicorn/protocols/http/httptools_impl.py", line 385, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/home/gleb/Projects/vertical/.venv/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "/home/gleb/Projects/vertical/.venv/lib/python3.8/site-packages/starlette/applications.py", line 102, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/gleb/Projects/vertical/.venv/lib/python3.8/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
  File "/home/gleb/Projects/vertical/.venv/lib/python3.8/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/home/gleb/Projects/vertical/.venv/lib/python3.8/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc from None
  File "/home/gleb/Projects/vertical/.venv/lib/python3.8/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/home/gleb/Projects/vertical/.venv/lib/python3.8/site-packages/starlette/routing.py", line 550, in __call__
    await route.handle(scope, receive, send)
  File "/home/gleb/Projects/vertical/.venv/lib/python3.8/site-packages/starlette/routing.py", line 227, in handle
    await self.app(scope, receive, send)
  File "/home/gleb/Projects/vertical/.venv/lib/python3.8/site-packages/starlette/routing.py", line 43, in app
    response = await run_in_threadpool(func, request)
  File "/home/gleb/Projects/vertical/.venv/lib/python3.8/site-packages/starlette/concurrency.py", line 34, in run_in_threadpool
    return await loop.run_in_executor(None, func, *args)
  File "/usr/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/gleb/Projects/vertical/app.py", line 11, in ping
    raise Exception("ERROR")
Exception: ERROR

Despite the fact that I handled the error, the log was still written and even with traceback.

As I went deeper, I realized that this log was written by the uvicorn.error. I can disable this logger, but I want it to write information about the server.

How do I disable this traceback and messages like Exception in ASGI application correctly?

starlette version: 0.13.2
uvicorn version: 0.11.3

Most helpful comment

I found better solution:

from starlette.middleware import base


class ExceptionHandlerMiddleware(base.BaseHTTPMiddleware):

    async def dispatch(
        self,
        request: Request,
        handler: base.RequestResponseEndpoint,
    ) -> Response:
        try:
            return await handler(request)
        except Exception as e:
            app_logger.error(f"Caught unhandled {e.__class__} exception: {e}")
            return server_error()

All 4 comments

I think your exception is getting caught by the ErrorMiddleware. Try the same with an exception that isn't excatly Exception - try using a subtype/custom exception.
(From my check using ValueError for example doesn't lead to a traceback, if handled)

@aviramha Hi! Yes, this exception caught by ErrorMiddleware. It works the way I want it to. I have a lot of exception handlers that caught Exception subclasses and they don't write a traceback.

But I should handle the Exception class: write log and return custom Response object with special content. I don't want that traceback was logged. How to hide it?

I think the desire is that only true unexepcted exceptions would reach ServerErrorMiddleware, hence it can never be suppressed.
If you really want to suppress it, which is not recommended IMO you could subclass Starlette and implement build_middleware_stack, removing the ServerErrorMiddleware or writing your own one.
(Application code shouldn't lead to any scenario where you have the base Exception type..)

I found better solution:

from starlette.middleware import base


class ExceptionHandlerMiddleware(base.BaseHTTPMiddleware):

    async def dispatch(
        self,
        request: Request,
        handler: base.RequestResponseEndpoint,
    ) -> Response:
        try:
            return await handler(request)
        except Exception as e:
            app_logger.error(f"Caught unhandled {e.__class__} exception: {e}")
            return server_error()
Was this page helpful?
0 / 5 - 0 ratings

Related issues

cw-andrews picture cw-andrews  路  4Comments

MarcDufresne picture MarcDufresne  路  6Comments

berislavlopac picture berislavlopac  路  5Comments

DrPyser picture DrPyser  路  6Comments

dgrahn picture dgrahn  路  4Comments