clm5/python/ctsm/ctsm_logging.py
2024-05-09 15:14:01 +08:00

102 lines
3.2 KiB
Python

"""Utilities to facilitate logging
A guide to logging in ctsm python scripts:
- At the top of each module, you should have:
logger = logging.getLogger(__name__)
- Logging should be done via that logger, NOT via logging.[whatever]
- If you want to allow the user to control logging via command-line arguments, you should:
(1) At the very start of a script / application, call setup_logging_pre_config(). (We
need to initialize logging to avoid errors from logging calls made very early in the
script.)
(2) When setting up the argument parser, call add_logging_args(parser)
(3) After parsing arguments, call process_logging_args(args)
- If you don't want to allow the user to control logging via command-line arguments, then
simply:
(1) At the very start of a script / application, call setup_logging() with the desired
arguments
- In unit tests, to avoid messages about loggers not being set up, you should call
setup_logging_for_tests (this is typically done via unit_testing.setup_for_tests)
"""
import logging
logger = logging.getLogger(__name__)
def setup_logging_pre_config():
"""Setup logging for a script / application
This function should be called at the very start of a script / application where you
intend to allow the user to control logging preferences via command-line arguments.
This sets initial options that may be changed later by process_logging_args.
"""
setup_logging(level=logging.WARNING)
def setup_logging_for_tests(enable_critical=False):
"""Setup logging as appropriate for unit tests"""
setup_logging(level=logging.CRITICAL)
if not enable_critical:
logging.disable(logging.CRITICAL)
def setup_logging(level=logging.WARNING):
"""Setup logging for a script / application
This function should be called at the very start of a script / application where you
do NOT intend to allow the user to control logging preferences via command-line
arguments, so that all of the final logging options are set here.
"""
logging.basicConfig(format="%(levelname)s: %(message)s", level=level)
def add_logging_args(parser):
"""Add common logging-related options to the argument parser"""
logging_level = parser.add_mutually_exclusive_group()
logging_level.add_argument(
"-v", "--verbose", action="store_true", help="Output extra logging info"
)
logging_level.add_argument("--silent", action="store_true", help="Only output errors")
logging_level.add_argument(
"--debug",
action="store_true",
help="Output even more logging info for debugging",
)
def process_logging_args(args):
"""Configure logging based on the logging-related args added by add_logging_args"""
root_logger = logging.getLogger()
if args.debug:
root_logger.setLevel(logging.DEBUG)
elif args.verbose:
root_logger.setLevel(logging.INFO)
elif args.silent:
root_logger.setLevel(logging.ERROR)
else:
root_logger.setLevel(logging.WARNING)
def output_to_file(file_path, message, log_to_logger=False):
"""
helper function to write to log file.
"""
with open(file_path, "a") as log_file:
log_file.write(message)
if log_to_logger:
logger.info(message)