src.co_tools.get_logger

  1import logging
  2import os
  3
  4LOGGER_DIR_PATH = "../results/co_logs"  # path to log directory
  5co_computation_id = os.environ.get("CO_COMPUTATION_ID")
  6aws_batch_job_id = os.getenv("AWS_BATCH_JOB_ID")
  7# name for the log file in ../results/co_logs
  8LOGGER_FILE_NAME = co_computation_id if co_computation_id else aws_batch_job_id
  9ENV_LEVEL = os.environ.get("CO_LOG_LEVEL")
 10DEFAULT_LEVEL = "WARNING" if not ENV_LEVEL else ENV_LEVEL.upper()
 11
 12"""
 13Benefit to this logger is that it adds to each log entry a timestamp,
 14project name, name of .py file, line number and the log level.
 15[%(asctime)s - %(name)s - %(filename)s:%(lineno)s - %(levelname)s] %(message)s"
 16How to use:
 17import the logger -> from get_logger import LOGGER
 18LOGGER.{mode}("string to log")
 19How to modify log level:
 20set the environment variable CO_LOG_LEVEL in the run script
 21ex. export CO_LOG_LEVEL="INFO"
 22"""
 23
 24
 25def get_logger_for_string(*, logger_name: str, level: str):
 26    """
 27    :description: A mapping function from strings to logging levels.
 28    :param logger_name: Name of the logger handle e.g. `stream_handle`.
 29    :param level: The string describing the logging level to set.
 30    :return: in [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR].
 31    DEBUG: Detailed information, typically of interest only when diagnosing
 32    problems.
 33    INFO: Confirmation that things are working as expected.
 34    WARNING: An indication that something unexpected happened, or indicative of
 35    some problem in the near future (e.g. 'disk space low'). The software is
 36    still working as expected.
 37    ERROR: Due to a more serious problem, the software has not been able to
 38    perform some function.
 39    CRITICAL: A serious error, indicating that the program itself may be unable
 40    to continue running.
 41    The default level is WARNING, which means that only events of this level
 42    and above will be tracked, unless the logging package is configured to
 43    do otherwise.
 44    """
 45    if level == "DEBUG":
 46        return logging.DEBUG
 47    elif level == "INFO":
 48        return logging.INFO
 49    elif level == "WARNING":
 50        return logging.WARNING
 51    elif level == "ERROR":
 52        return logging.ERROR
 53    elif level == "CRITICAL":
 54        return logging.CRITICAL
 55    else:
 56        raise Exception(
 57            f"{logger_name} logging level is not one of [DEBUG, INFO, "
 58            + "WARNING, ERROR, CRITICAL]"
 59        )
 60
 61
 62def generate_logger(
 63    *,
 64    name: str = LOGGER_FILE_NAME,
 65    logging_level: str = DEFAULT_LEVEL,
 66    format_string: str = (
 67        "[%(asctime)s - %(name)s - %(filename)s:%(lineno)s - %(levelname)s] "
 68        + "%(message)s"
 69    ),
 70):
 71    """
 72    :description: Creates a logger as desired for the global namespace without
 73    polluting the global namespace.
 74    :param name: The name of the logger.
 75    :param logging_level: The logging level to record to the logging file.
 76    :param format_string: A string to be passed to Python's logger generator
 77    facility to format logging output.
 78    :returns: A usable and proper Python logger.
 79    """
 80
 81    logging_level = get_logger_for_string(logger_name=name, level=logging_level)
 82
 83    logger = logging.getLogger(name)
 84    logger.setLevel(logging_level)
 85
 86    # create console handler with a higher log level
 87
 88    os.makedirs(LOGGER_DIR_PATH, exist_ok=True)
 89
 90    file_handle = logging.FileHandler(f"{LOGGER_DIR_PATH}/{name}.log")
 91    file_handle.setLevel(logging_level)
 92    console_handler = logging.StreamHandler()
 93    console_handler.setLevel(logging.ERROR)
 94    # create formatter and add it to the handlers
 95    log_format = logging.Formatter(format_string, "%Y-%m-%d %H:%M:%S")
 96    file_handle.setFormatter(log_format)
 97
 98    logger.addHandler(file_handle)
 99    logger.addHandler(console_handler)
100
101    return logger
102
103
104LOGGER = None
105
106if not LOGGER:
107    LOGGER = generate_logger()
DEFAULT_LEVEL = 'DEBUG'

Benefit to this logger is that it adds to each log entry a timestamp, project name, name of .py file, line number and the log level. [%(asctime)s - %(name)s - %(filename)s:%(lineno)s - %(levelname)s] %(message)s" How to use: import the logger -> from get_logger import LOGGER LOGGER.{mode}("string to log") How to modify log level: set the environment variable CO_LOG_LEVEL in the run script ex. export CO_LOG_LEVEL="INFO"

def get_logger_for_string(*, logger_name: str, level: str):
26def get_logger_for_string(*, logger_name: str, level: str):
27    """
28    :description: A mapping function from strings to logging levels.
29    :param logger_name: Name of the logger handle e.g. `stream_handle`.
30    :param level: The string describing the logging level to set.
31    :return: in [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR].
32    DEBUG: Detailed information, typically of interest only when diagnosing
33    problems.
34    INFO: Confirmation that things are working as expected.
35    WARNING: An indication that something unexpected happened, or indicative of
36    some problem in the near future (e.g. 'disk space low'). The software is
37    still working as expected.
38    ERROR: Due to a more serious problem, the software has not been able to
39    perform some function.
40    CRITICAL: A serious error, indicating that the program itself may be unable
41    to continue running.
42    The default level is WARNING, which means that only events of this level
43    and above will be tracked, unless the logging package is configured to
44    do otherwise.
45    """
46    if level == "DEBUG":
47        return logging.DEBUG
48    elif level == "INFO":
49        return logging.INFO
50    elif level == "WARNING":
51        return logging.WARNING
52    elif level == "ERROR":
53        return logging.ERROR
54    elif level == "CRITICAL":
55        return logging.CRITICAL
56    else:
57        raise Exception(
58            f"{logger_name} logging level is not one of [DEBUG, INFO, "
59            + "WARNING, ERROR, CRITICAL]"
60        )

:description: A mapping function from strings to logging levels.

Parameters
  • logger_name: Name of the logger handle e.g. stream_handle.
  • level: The string describing the logging level to set.
Returns

in [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR]. DEBUG: Detailed information, typically of interest only when diagnosing problems. INFO: Confirmation that things are working as expected. WARNING: An indication that something unexpected happened, or indicative of some problem in the near future (e.g. 'disk space low'). The software is still working as expected. ERROR: Due to a more serious problem, the software has not been able to perform some function. CRITICAL: A serious error, indicating that the program itself may be unable to continue running. The default level is WARNING, which means that only events of this level and above will be tracked, unless the logging package is configured to do otherwise.

def generate_logger( *, name: str = None, logging_level: str = 'DEBUG', format_string: str = '[%(asctime)s - %(name)s - %(filename)s:%(lineno)s - %(levelname)s] %(message)s'):
 63def generate_logger(
 64    *,
 65    name: str = LOGGER_FILE_NAME,
 66    logging_level: str = DEFAULT_LEVEL,
 67    format_string: str = (
 68        "[%(asctime)s - %(name)s - %(filename)s:%(lineno)s - %(levelname)s] "
 69        + "%(message)s"
 70    ),
 71):
 72    """
 73    :description: Creates a logger as desired for the global namespace without
 74    polluting the global namespace.
 75    :param name: The name of the logger.
 76    :param logging_level: The logging level to record to the logging file.
 77    :param format_string: A string to be passed to Python's logger generator
 78    facility to format logging output.
 79    :returns: A usable and proper Python logger.
 80    """
 81
 82    logging_level = get_logger_for_string(logger_name=name, level=logging_level)
 83
 84    logger = logging.getLogger(name)
 85    logger.setLevel(logging_level)
 86
 87    # create console handler with a higher log level
 88
 89    os.makedirs(LOGGER_DIR_PATH, exist_ok=True)
 90
 91    file_handle = logging.FileHandler(f"{LOGGER_DIR_PATH}/{name}.log")
 92    file_handle.setLevel(logging_level)
 93    console_handler = logging.StreamHandler()
 94    console_handler.setLevel(logging.ERROR)
 95    # create formatter and add it to the handlers
 96    log_format = logging.Formatter(format_string, "%Y-%m-%d %H:%M:%S")
 97    file_handle.setFormatter(log_format)
 98
 99    logger.addHandler(file_handle)
100    logger.addHandler(console_handler)
101
102    return logger

:description: Creates a logger as desired for the global namespace without polluting the global namespace.

Parameters
  • name: The name of the logger.
  • logging_level: The logging level to record to the logging file.
  • format_string: A string to be passed to Python's logger generator facility to format logging output. :returns: A usable and proper Python logger.