Skip to content

Instantly share code, notes, and snippets.

@Olegt0rr
Last active July 27, 2023 06:47
Show Gist options
  • Save Olegt0rr/5439c8c1f340da118b79edffa43dbc00 to your computer and use it in GitHub Desktop.
Save Olegt0rr/5439c8c1f340da118b79edffa43dbc00 to your computer and use it in GitHub Desktop.
aiohttp single log record traceback
import logging
from traceback import TracebackException
from aiohttp import web
from aiohttp.abc import StreamResponse
from aiohttp.typedefs import Handler
from aiohttp.web_exceptions import HTTPException
logger = logging.getLogger(__name__)
routes = web.RouteTableDef()
CAPTURE_LOCALS = True # get it from .env / settings
@web.middleware
async def error_middleware(request: web.Request, handler: Handler) -> StreamResponse:
"""Process all unhandled exceptions."""
try:
return await handler(request)
# upstream http-based exceptions (e.g. raised 404)
except HTTPException:
raise
# catch real exceptions
except Exception as exc:
tb = _prepare_traceback(exc)
logger.error("Handled exception! %s", tb)
return web.Response(text="Something went wrong (apology text)", status=500)
def _prepare_traceback(exc: Exception) -> str:
"""Prepare readable traceback."""
tb_exc = TracebackException.from_exception(exc, capture_locals=CAPTURE_LOCALS)
return "\n".join(tb_exc.format())
@routes.get("/")
async def bad_handler(request: web.Request):
"""Brake everything!"""
foo = "foo"
bar = {"some": "data"}
return foo / bar
if __name__ == "__main__":
app = web.Application(middlewares=[error_middleware])
app.add_routes(routes)
web.run_app(app)
@Olegt0rr
Copy link
Author

Olegt0rr commented Jun 21, 2023

В результате получаем одну запись лога, которую можно нормально читать, как локально, так и kibana

======== Running on http://0.0.0.0:8080 ========
(Press CTRL+C to quit)
Handled exception! Traceback (most recent call last):

  File "/app/draft.py", line 19, in error_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^

  File "/app/draft.py", line 43, in bad_handler
    return foo / bar
           ~~~~^~~~~

TypeError: unsupported operand type(s) for /: 'str' and 'dict'

@Olegt0rr
Copy link
Author

Кибана умеет \n переносить на новые строки

telegram-cloud-photo-size-2-5231376437360054379-y

@Olegt0rr
Copy link
Author

Olegt0rr commented Jul 27, 2023

  1. Добавил возможность печатать переменные в debug-режиме
Handled exception! Traceback (most recent call last):

  File "/app/draft.py", line 19, in error_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
    exc = TypeError("unsupported operand type(s) for /: 'str' and 'dict'")
    handler = <function bad_handler at 0x103cdeb60>
    request = <Request GET / >

  File "/app/draft.py", line 44, in bad_handler
    return foo / bar
           ~~~~^~~~~
    bar = {'some': 'data'}
    foo = 'foo'
    request = <Request GET / >

TypeError: unsupported operand type(s) for /: 'str' and 'dict'
  1. Добавил upstream для HTTP-ошибок, которые намеренно вызываем сами, например 404.
    При необходимости можно разместить в нём инструменты дебаг-логирования
try:
    ...
except HTTPException as exc:
    if logger.isEnabledFor(logging.DEBUG):
        ... # some heavy preparations
        logger.debug("Raised HTTP-exception %s: %s", type(exc).__name__, exc)
    raise

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment