def setup_opinionated_logger()

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