| import logging | |
| import structlog | |
| from logging.handlers import RotatingFileHandler | |
| # Configure standard logging | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", # for log aggregation, limit to message | |
| ) | |
| # Set up file handler with log rotation | |
| file_handler = RotatingFileHandler('logs/root.log', maxBytes=10*1024*1024, backupCount=3) | |
| file_handler.setLevel(logging.INFO) | |
| file_handler.setFormatter(logging.Formatter('%(message)s')) | |
| logging.getLogger().addHandler(file_handler) | |
| # rendering with structlog | |
| # from: https://www.structlog.org/en/stable/standard-library.html#rendering-within-structlog | |
| structlog.configure( | |
| processors=[ | |
| # If log level is too low, abort pipeline and throw away log entry. | |
| structlog.stdlib.filter_by_level, | |
| # Add the name of the logger to event dict. | |
| structlog.stdlib.add_logger_name, | |
| # Add log level to event dict. | |
| structlog.stdlib.add_log_level, | |
| # Perform %-style formatting. | |
| structlog.stdlib.PositionalArgumentsFormatter(), | |
| # Add a timestamp in ISO 8601 format. | |
| structlog.processors.TimeStamper(fmt="iso"), | |
| # If the "stack_info" key in the event dict is true, remove it and | |
| # render the current stack trace in the "stack" key. | |
| structlog.processors.StackInfoRenderer(), | |
| # If the "exc_info" key in the event dict is either true or a | |
| # sys.exc_info() tuple, remove "exc_info" and render the exception | |
| # with traceback into the "exception" key. | |
| structlog.processors.format_exc_info, | |
| # If some value is in bytes, decode it to a Unicode str. | |
| structlog.processors.UnicodeDecoder(), | |
| # Add callsite parameters. | |
| structlog.processors.CallsiteParameterAdder( | |
| { | |
| structlog.processors.CallsiteParameter.FILENAME, | |
| structlog.processors.CallsiteParameter.FUNC_NAME, | |
| structlog.processors.CallsiteParameter.LINENO, | |
| } | |
| ), | |
| # Render the final event dict as JSON. | |
| structlog.processors.JSONRenderer() | |
| ], | |
| # `wrapper_class` is the bound logger that you get back from | |
| # get_logger(). This one imitates the API of `logging.Logger`. | |
| wrapper_class=structlog.stdlib.BoundLogger, | |
| # `logger_factory` is used to create wrapped loggers that are used for | |
| # OUTPUT. This one returns a `logging.Logger`. The final value (a JSON | |
| # string) from the final processor (`JSONRenderer`) will be passed to | |
| # the method of the same name as that you've called on the bound logger. | |
| logger_factory=structlog.stdlib.LoggerFactory(), | |
| # Effectively freeze configuration after creating the first bound | |
| # logger. | |
| cache_logger_on_first_use=True, | |
| ) | |