in src/smepu/core.py [0:0]
def setup_opinionated_logger(name: str, level: int = logging.INFO):
"""Configure a very opinionated logger that works on and outside SageMaker.
On SageMaker (particularly training), root logger may have no handler despite basicConfig(...). Hence, force add
stdout handler to let all log messages end up at CloudWatch.
Reason to use stdout on SageMaker: with certain container e.g., xgboost, script mode swallows stderr which means
nothing shipped to CloudWatch.
When run outside SageMaker (i.e., from your shell on your workstation), typically the root logger will be configured
to stderr, hence we don't add anymore handler to stdout (otherwise, double print log messages).
"""
fmt = "%(asctime)s [%(levelname)s] %(name)s %(message)s"
datefmt = "[%Y-%m-%d %H:%M:%S]"
logging.basicConfig(
level=level,
format=fmt,
datefmt=datefmt,
)
if not logger_has_stdeo(logging.root):
# Training: if no logging handler to stdout or stderr, setup one to stdout.
# Reason to use stdout: xgboost script mode swallows stderr.
print("0000: Root logger has no handler. Likely this is training on SageMaker.")
ch = logging.StreamHandler(sys.stdout)
ch.setFormatter(logging.Formatter(fmt, datefmt=datefmt))
logging.getLogger().addHandler(ch)
print("1000: added stdout handler to root logger")
def print_logging_setup(logger):
"""Walkthrough logger hierarchy and print details of each logger.
Print to stdout to make sure CloudWatch pick it up, regardless of how logger handler is setup.
"""
lgr = logging.getLogger(name)
while lgr is not None:
print("level: {}, name: {}, handlers: {}".format(lgr.level, lgr.name, lgr.handlers))
lgr = lgr.parent
logger = logging.getLogger(name)
logger.setLevel(level)
print_logging_setup(logger)
return logger