Skip to content

Instantly share code, notes, and snippets.

@apua
Last active September 22, 2023 13:51
Show Gist options
  • Save apua/31562caa6cb58a0143d617de0018ea6a to your computer and use it in GitHub Desktop.
Save apua/31562caa6cb58a0143d617de0018ea6a to your computer and use it in GitHub Desktop.
Refer to Rust `env_logger`
import logging
import os
class ColoredFormatter(logging.Formatter):
def __init__(self, coloring=True, fmt='%(L)s{asctime} {levelname:<%(T)s} {name}%(R)s {message}',
datefmt = '%Y-%m-%dT%H:%M:%SZ', style = '{', *args, **kwargs):
if coloring:
L, R = map('\033[90m{}\033[m'.format, '[]')
T = 15
else:
L, R = '[]'
T = 5
super().__init__(fmt=fmt%locals(), datefmt=datefmt, style=style, *args, **kwargs)
self.coloring = coloring
def format(self, record):
if self.coloring:
# NOTE: Keep ASCII code be the same length (except CRITICAL) in order to format alignment.
if record.levelname == 'CRITICAL':
record.levelname = f'\033[1;4;5;7;35mCRITICAL\033[m'
elif record.levelname == 'ERROR':
record.levelname = f'\033[1;31mERROR\033[m'
elif record.levelname == 'WARNING':
record.levelname = f'\033[0;33mWARN\033[m'
elif record.levelname == 'INFO':
record.levelname = f'\033[0;32mINFO\033[m'
elif record.levelname == 'DEBUG':
record.levelname = f'\033[0;34mDEBUG\033[m'
elif record.levelname == 'TRACE':
record.levelname = f'\033[0;36mTRACE\033[m'
else:
pass
return super().format(record)
def register_trace(logging, trace_level=5):
"""
Register logging to support `TRACE` level.
"""
def trace(self, msg, *args, **kwargs):
if self.isEnabledFor(trace_level):
self._log(trace_level, msg, args, **kwargs)
logging.TRACE = trace_level
logging.addLevelName(trace_level, 'TRACE')
logging.Logger.trace = trace
def init(var_name='LOGGING'):
"""
Initialize `env_logger` including:
* registering trace level
* coloring if destination is a TTY
* reading environment variable for config
"""
register_trace(logging)
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(ColoredFormatter(
coloring = 'TERM' in os.environ and stream_handler.stream.isatty()
))
# NOTE: To keep it simple, now the config only support a level name for root logger.
logging_config = os.getenv(var_name, '').strip()
levelname = logging_config.upper()
if (level := getattr(logging, levelname, None)) is None:
logger = logging.getLogger()
logger.addHandler(stream_handler)
else:
logger = logging.getLogger()
logger.setLevel(level)
logger.addHandler(stream_handler)
if __name__ == '__main__':
init()
logger = logging.getLogger()
logger.critical('message')
logger.error('message')
logger.warning('message')
logger.info('message')
logger.debug('message')
logger.trace('message')
@apua
Copy link
Author

apua commented Sep 22, 2023

image

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