cardinal_pythonlib.logs


Original code copyright (C) 2009-2022 Rudolf Cardinal (rudolf@pobox.com).

This file is part of cardinal_pythonlib.

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


Support functions for logging.

See https://docs.python.org/3.4/howto/logging.html#library-config

USER CODE should use the following general methods.

  1. Simple:

    import logging
    log = logging.getLogger(__name__)  # for your own logs
    logging.basicConfig()
    
  2. More complex:

    import logging
    log = logging.getLogger(__name__)
    logging.basicConfig(format=LOG_FORMAT, datefmt=LOG_DATEFMT,
                        level=loglevel)
    
  3. Using colour conveniently:

    import logging
    mylogger = logging.getLogger(__name__)
    rootlogger = logging.getLogger()
    
    from whisker.log import configure_logger_for_colour
    configure_logger_for_colour(rootlogger)
    

LIBRARY CODE should use the following general methods.

import logging
log = logging.getLogger(__name__)

# ... and if you want to suppress output unless the user configures logs:
log.addHandler(logging.NullHandler())
# ... which only needs to be done in the __init__.py for the package
#     https://stackoverflow.com/questions/12296214

# LIBRARY CODE SHOULD NOT ADD ANY OTHER HANDLERS; see above.

DO NOT call this module “logging”! Many things may get confused.

class cardinal_pythonlib.logs.BraceMessage(fmt: str, args: Tuple[Any, ...], kwargs: Dict[str, Any])[source]

Class to represent a message that includes a message including braces ({}) and a set of args/kwargs. When converted to a str, the message is realized via msg.format(*args, **kwargs).

class cardinal_pythonlib.logs.BraceStyleAdapter(logger: Logger, pass_special_logger_args: bool = True, strip_special_logger_args_from_fmt: bool = False)[source]

Wraps a logger so we can use {}-style string formatting.

Parameters:
  • logger – a logger

  • pass_special_logger_args – should we continue to pass any special arguments to the logger itself? True is standard; False probably brings a slight performance benefit, but prevents log.exception() from working properly, as the ‘exc_info’ parameter will be stripped.

  • strip_special_logger_args_from_fmt – If we’re passing special arguments to the logger, should we remove them from the argments passed to the string formatter? There is no obvious cost to saying no.

Specimen use:

import logging
from cardinal_pythonlib.logs import BraceStyleAdapter, main_only_quicksetup_rootlogger

log = BraceStyleAdapter(logging.getLogger(__name__))

main_only_quicksetup_rootlogger(level=logging.DEBUG)

log.info("Hello {}, {title} {surname}!", "world", title="Mr", surname="Smith")
# 2018-09-17 16:13:50.404 __main__:INFO: Hello world, Mr Smith!
log(level: int, msg: str, *args: Any, **kwargs: Any) None[source]

Delegate a log call to the underlying logger, after adding contextual information from this adapter instance.

process(msg: str, kwargs: Dict[str, Any]) Tuple[str, Dict[str, Any]][source]

Process the logging message and keyword arguments passed in to a logging call to insert contextual information. You can either manipulate the message itself, the keyword args or both. Return the message and kwargs modified (or not) to suit your needs.

Normally, you’ll only need to override this one method in a LoggerAdapter subclass for your specific needs.

class cardinal_pythonlib.logs.HtmlColorFormatter(append_br: bool = False, replace_nl_with_br: bool = True)[source]

Class to format Python logs in coloured HTML.

Parameters:
  • append_br – append <br> to each line?

  • replace_nl_with_br – replace \n with <br> in messages?

See https://hg.python.org/cpython/file/3.5/Lib/logging/__init__.py

format(record: LogRecord) str[source]

Internal function to format the LogRecord as HTML.

See https://docs.python.org/3.4/library/logging.html#logging.LogRecord

class cardinal_pythonlib.logs.HtmlColorHandler(logfunction: Callable[[str], None], level: int = 20)[source]

HTML handler (using HtmlColorFormatter) that sends output to a function, e.g. for display in a Qt window

Initialize the handler.

If stream is not specified, sys.stderr is used.

emit(record: LogRecord) None[source]

Internal function to process a LogRecord.

cardinal_pythonlib.logs.apply_handler_to_all_logs(handler: Handler, remove_existing: bool = False) None[source]

Applies a handler to all logs, optionally removing existing handlers.

Should ONLY be called from the if __name__ == 'main' script; see https://docs.python.org/3.4/howto/logging.html#library-config.

Generally MORE SENSIBLE just to apply a handler to the root logger.

Parameters:
  • handler – the handler to apply

  • remove_existing – remove existing handlers from logger first?

cardinal_pythonlib.logs.apply_handler_to_root_log(handler: Handler, remove_existing: bool = False) None[source]

Applies a handler to all logs, optionally removing existing handlers.

Should ONLY be called from the if __name__ == 'main' script; see https://docs.python.org/3.4/howto/logging.html#library-config.

Generally MORE SENSIBLE just to apply a handler to the root logger.

Parameters:
  • handler – the handler to apply

  • remove_existing – remove existing handlers from logger first?

cardinal_pythonlib.logs.configure_all_loggers_for_colour(remove_existing: bool = True) None[source]

Applies a preconfigured datetime/colour scheme to ALL logger.

Should ONLY be called from the if __name__ == 'main' script; see https://docs.python.org/3.4/howto/logging.html#library-config.

Generally MORE SENSIBLE just to apply a handler to the root logger.

Parameters:

remove_existing – remove existing handlers from logger first?

cardinal_pythonlib.logs.configure_logger_for_colour(logger: Logger, level: int = 20, remove_existing: bool = False, extranames: List[str] | None = None, with_process_id: bool = False, with_thread_id: bool = False) None[source]

Applies a preconfigured datetime/colour scheme to a logger.

Should ONLY be called from the if __name__ == 'main' script; see https://docs.python.org/3.4/howto/logging.html#library-config.

Parameters:
  • logger – logger to modify

  • level – log level to set

  • remove_existing – remove existing handlers from logger first?

  • extranames – additional names to append to the logger’s name

  • with_process_id – include the process ID in the logger’s name?

  • with_thread_id – include the thread ID in the logger’s name?

cardinal_pythonlib.logs.copy_all_logs_to_file(filename: str, fmt: str = '%(asctime)s.%(msecs)03d:%(levelname)s:%(name)s:%(message)s', datefmt: str = '%Y-%m-%d %H:%M:%S') None[source]

Copy all currently configured logs to the specified file.

Should ONLY be called from the if __name__ == 'main' script; see https://docs.python.org/3.4/howto/logging.html#library-config.

Parameters:
  • filename – file to send log output to

  • fmt – passed to the fmt= argument of logging.Formatter

  • datefmt – passed to the datefmt= argument of logging.Formatter

cardinal_pythonlib.logs.copy_root_log_to_file(filename: str, fmt: str = '%(asctime)s.%(msecs)03d:%(levelname)s:%(name)s:%(message)s', datefmt: str = '%Y-%m-%d %H:%M:%S') None[source]

Copy all currently configured logs to the specified file.

Should ONLY be called from the if __name__ == 'main' script; see https://docs.python.org/3.4/howto/logging.html#library-config.

cardinal_pythonlib.logs.get_brace_style_log_with_null_handler(name: str) BraceStyleAdapter[source]

For use by library functions. Returns a log with the specifed name that has a null handler attached, and a BraceStyleAdapter.

cardinal_pythonlib.logs.get_colour_handler(extranames: List[str] | None = None, with_process_id: bool = False, with_thread_id: bool = False, stream: TextIO | None = None) StreamHandler[source]

Gets a colour log handler using a standard format.

Parameters:
  • extranames – additional names to append to the logger’s name

  • with_process_id – include the process ID in the logger’s name?

  • with_thread_id – include the thread ID in the logger’s name?

  • streamTextIO stream to send log output to

Returns:

the logging.StreamHandler

cardinal_pythonlib.logs.get_formatter_report(f: Formatter) Dict[str, str] | None[source]

Returns information on a log formatter, as a dictionary. For debugging.

cardinal_pythonlib.logs.get_handler_report(h: Handler) Dict[str, Any][source]

Returns information on a log handler, as a dictionary. For debugging.

cardinal_pythonlib.logs.get_log_report(log: Logger | PlaceHolder) Dict[str, Any][source]

Returns information on a log, as a dictionary. For debugging.

cardinal_pythonlib.logs.get_log_with_null_handler(name: str) Logger[source]

For use by library functions. Returns a log with the specifed name that has a null handler attached, and a BraceStyleAdapter.

cardinal_pythonlib.logs.get_monochrome_handler(extranames: List[str] | None = None, with_process_id: bool = False, with_thread_id: bool = False, stream: TextIO | None = None) StreamHandler[source]

Gets a monochrome log handler using a standard format.

Parameters:
  • extranames – additional names to append to the logger’s name

  • with_process_id – include the process ID in the logger’s name?

  • with_thread_id – include the thread ID in the logger’s name?

  • streamTextIO stream to send log output to

Returns:

the logging.StreamHandler

cardinal_pythonlib.logs.main_only_quicksetup_rootlogger(level: int = 10, with_process_id: bool = False, with_thread_id: bool = False) None[source]

Quick function to set up the root logger for colour.

Should ONLY be called from the if __name__ == 'main' script; see https://docs.python.org/3.4/howto/logging.html#library-config.

Parameters:
  • level – log level to set

  • with_process_id – include the process ID in the logger’s name?

  • with_thread_id – include the thread ID in the logger’s name?

cardinal_pythonlib.logs.print_report_on_all_logs() None[source]

Use print() to report information on all logs.

cardinal_pythonlib.logs.remove_all_logger_handlers(logger: Logger) None[source]

Remove all handlers from a logger.

Parameters:

logger – logger to modify

cardinal_pythonlib.logs.reset_logformat(logger: Logger, fmt: str, datefmt: str = '%Y-%m-%d %H:%M:%S') None[source]

Create a new formatter and apply it to the logger.

logging.basicConfig() won’t reset the formatter if another module has called it, so always set the formatter like this.

Parameters:
  • logger – logger to modify

  • fmt – passed to the fmt= argument of logging.Formatter

  • datefmt – passed to the datefmt= argument of logging.Formatter

cardinal_pythonlib.logs.reset_logformat_timestamped(logger: Logger, extraname: str = '', level: int = 20) None[source]

Apply a simple time-stamped log format to an existing logger, and set its loglevel to either logging.DEBUG or logging.INFO.

Parameters:
  • logger – logger to modify

  • extraname – additional name to append to the logger’s name

  • level – log level to set

cardinal_pythonlib.logs.set_level_for_logger_and_its_handlers(log: Logger, level: int) None[source]

Set a log level for a log and all its handlers.

Parameters:
  • log – log to modify

  • level – log level to set