-
-
Save clarksun/73024bfcbcff9e47cc79e83a2f687a76 to your computer and use it in GitHub Desktop.
Revisions
-
nkhitrov revised this gist
Jul 25, 2020 . 2 changed files with 102 additions and 96 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,97 @@ """Configure handlers and formats for application loggers.""" import logging import sys from pprint import pformat # if you dont like imports of private modules # you can move it to typing.py module from loguru import logger from loguru._defaults import LOGURU_FORMAT class InterceptHandler(logging.Handler): """ Default handler from examples in loguru documentaion. See https://loguru.readthedocs.io/en/stable/overview.html#entirely-compatible-with-standard-logging """ def emit(self, record: logging.LogRecord): # Get corresponding Loguru level if it exists try: level = logger.level(record.levelname).name except ValueError: level = record.levelno # Find caller from where originated the logged message frame, depth = logging.currentframe(), 2 while frame.f_code.co_filename == logging.__file__: frame = frame.f_back depth += 1 logger.opt(depth=depth, exception=record.exc_info).log( level, record.getMessage() ) def format_record(record: dict) -> str: """ Custom format for loguru loggers. Uses pformat for log any data like request/response body during debug. Works with logging if loguru handler it. Example: >>> payload = [{"users":[{"name": "Nick", "age": 87, "is_active": True}, {"name": "Alex", "age": 27, "is_active": True}], "count": 2}] >>> logger.bind(payload=).debug("users payload") >>> [ { 'count': 2, >>> 'users': [ {'age': 87, 'is_active': True, 'name': 'Nick'}, >>> {'age': 27, 'is_active': True, 'name': 'Alex'}]}] """ format_string = LOGURU_FORMAT if record["extra"].get("payload") is not None: record["extra"]["payload"] = pformat( record["extra"]["payload"], indent=4, compact=True, width=88 ) format_string += "\n<level>{extra[payload]}</level>" format_string += "{exception}\n" return format_string def init_logging(): """ Replaces logging handlers with a handler for using the custom handler. WARNING! if you call the init_logging in startup event function, then the first logs before the application start will be in the old format >>> app.add_event_handler("startup", init_logging) stdout: INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) INFO: Started reloader process [11528] using statreload INFO: Started server process [6036] INFO: Waiting for application startup. 2020-07-25 02:19:21.357 | INFO | uvicorn.lifespan.on:startup:34 - Application startup complete. """ # disable handlers for specific uvicorn loggers # to redirect their output to the default uvicorn logger # works with uvicorn==0.11.6 loggers = ( logging.getLogger(name) for name in logging.root.manager.loggerDict if name.startswith("uvicorn.") ) for uvicorn_logger in loggers: uvicorn_logger.handlers = [] # change handler for default uvicorn logger intercept_handler = InterceptHandler() logging.getLogger("uvicorn").handlers = [intercept_handler] # set logs output, level and format logger.configure( handlers=[{"sink": sys.stdout, "level": logging.DEBUG, "format": format_record}] ) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,104 +1,13 @@ """Gist for original issue https://github.com/tiangolo/fastapi/issues/1276#issuecomment-663748916""" from fastapi import FastAPI from starlette.requests import Request from logger import init_logging app = FastAPI(title="Test Uvicorn Handlers") init_logging() # view.py @app.get("/") def index(request: Request) -> None: logger.info("loguru info log") -
nkhitrov created this gist
Jul 24, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,109 @@ """Gist for issue https://github.com/tiangolo/fastapi/issues/1276#issuecomment-663748916""" import logging import sys from pprint import pformat from fastapi import FastAPI from loguru import logger from loguru._defaults import LOGURU_FORMAT from starlette.requests import Request # handler definition class InterceptHandler(logging.Handler): """ Default handler from examples in loguru documentaion. See https://loguru.readthedocs.io/en/stable/overview.html#entirely-compatible-with-standard-logging """ def emit(self, record: logging.LogRecord): # Get corresponding Loguru level if it exists try: level = logger.level(record.levelname).name except ValueError: level = record.levelno # Find caller from where originated the logged message frame, depth = logging.currentframe(), 2 while frame.f_code.co_filename == logging.__file__: frame = frame.f_back depth += 1 logger.opt(depth=depth, exception=record.exc_info).log( level, record.getMessage() ) def format_record(record: dict) -> str: """ Custom format for loguru loggers. Uses pformat for log any data like request/response body during debug. Works with logging if loguru handler it. Example: >>> payload = [{"users":[{"name": "Nick", "age": 87, "is_active": True}, {"name": "Alex", "age": 27, "is_active": True}], "count": 2}] >>> logger.bind(payload=).debug("users payload") >>> [ { 'count': 2, >>> 'users': [ {'age': 87, 'is_active': True, 'name': 'Nick'}, >>> {'age': 27, 'is_active': True, 'name': 'Alex'}]}] """ format_string = LOGURU_FORMAT if record["extra"].get("payload") is not None: record["extra"]["payload"] = pformat( record["extra"]["payload"], indent=4, compact=True, width=88 ) format_string += "\n<level>{extra[payload]}</level>" format_string += "{exception}\n" return format_string def init_logging(custom_handler: logging.Handler): """Replaces logging handlers with a handler for using the custom handler.""" # NOTE: # to get all loggers # >>> loggers = [logging.getLogger(name) for name in logging.root.manager.loggerDict] # disable handlers for specific uvicorn loggers # to redirect their output to the default uvicorn logger for name in ("uvicorn.error", "uvicorn.access"): logging.getLogger(name).handlers = [] # change handler for default uvicorn logger logging.getLogger("uvicorn").handlers = [custom_handler] # set logs output, level and format logger.configure( handlers=[{"sink": sys.stdout, "level": logging.DEBUG, "format": format_record}] ) ### main.py app = FastAPI(title="Logger Handler", debug=True) # WARNING! # if you call the init_logging in startup event function, # then the first logs before the application start will be in the old format # # >>> app.add_event_handler("startup", init_logging) # stdout: # INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) # INFO: Started reloader process [11528] using statreload # INFO: Started server process [6036] # INFO: Waiting for application startup. # 2020-07-25 02:19:21.357 | INFO | uvicorn.lifespan.on:startup:34 - Application startup complete. intercept_handler = InterceptHandler() init_logging(intercept_handler) # view.py @app.get("/") def index(request: Request) -> None: logger.info("loguru info log") logging.info("logging info log") logging.getLogger("fastapi").debug("fatapi info log") logger.bind(payload=dict(request.query_params)).debug("params with formating") return None