Loggers and Logger Adapters

BurinLogger instances are what actually handle and process logging events. Each logger will have a unique name and can have its own handlers, formatters, and message style.

Loggers also exist in a hierarchy, by default loggers will propagate their logging events up through the hierarchy so handlers assigned to other loggers higher up will also receive the event. This simplifies things as handlers don’t need to be set on every single logger.

BurinLoggerAdapter instances allow you to predefine extra fields and values for a logger without needing to provide them in every logging call. This can be useful if you want to log an extra field every time. Also unlike the logging.LoggerAdapter any extra values that are passed in a call to the adapter will get merged with the defaults that were set; this mean you can also nest adapters if needed.

Note

All methods of the BurinLogger and BurinLoggerAdapter classes with an underscore_separated name also have a camelCase alias name which matches the names used in the standard logging library.

BurinLogger

Most of the methods on a logger are only called internally by other parts of Burin and do not need to be called directly. The most commonly used methods would be BurinLogger.add_handler(), BurinLogger.critical(), BurinLogger.debug(), BurinLogger.error(), BurinLogger.exception(), BurinLogger.info(), BurinLogger.log(), and BurinLogger.warning().

Here is a summary list of the methods for the BurinLogger class; below that is a full description of the class, it attributes, and methods.

BurinLogger.add_handler

Add the specified handler to this logger.

BurinLogger.call_handlers

Passes a log record to all relevant handlers.

BurinLogger.critical

Logs a message with the CRITICAL level.

BurinLogger.debug

Logs a message with the DEBUG level.

BurinLogger.error

Logs a message with the ERROR level.

BurinLogger.exception

Logs a message with the ERROR level and exception information.

BurinLogger.find_caller

Finds the logging event caller's information.

BurinLogger.get_child

Gets a child of this logger.

BurinLogger.get_children

Gets a set of loggers that are the immediate children of this logger.

BurinLogger.get_effective_level

Gets the effective log level for this logger.

BurinLogger.handle

Calls handlers for the record.

BurinLogger.has_handlers

Checks if there are any available handlers for this logger.

BurinLogger.info

Logs a message with the INFO level.

BurinLogger.is_enabled_for

Checks if the logger is enabled for the specified level.

BurinLogger.log

Logs a message with the specified level.

BurinLogger.make_record

Creates the log record and applies any extra fields to it.

BurinLogger.remove_handler

Removes the specified handler from this logger.

BurinLogger.set_level

Sets the level of this logger.

BurinLogger.warning

Logs a message with the WARNING level.

class burin.BurinLogger(name, level='NOTSET', msgStyle='%')

Loggers represent a logging channel within an application.

Note

While this is based off logging.Logger it is not a subclass of it and has a few differences and additions.

Deprecated methods like logging.Logger.warn() or logging.Logger.fatal() do not exist as methods for this class.

Other methods from logging.Logger can be called in the same way on this class without using any of the changes if desired.

This should never be instantiated directly during normal use; instead always use the get_logger() function instead to create a new instance. Calling get_logger() with the same name will always return the same logger instance.

What a logging channel encompasses is normally a specific area of the software and is up to each developer; it could be a class, module, package, process, etc.

Typically the name of the logger matches the area the logging channel represents; for example a common use case is burin.get_logger(__name__) which uses the module name for the logger.

BurinLoggers support a hierarchy similar to Python packages; so any periods ‘.’ within a name represent multiple steps. An example is the name ‘foo.bar.baz’ which shows three different loggers at different places in the hierarchy. The logger ‘foo’ is higher up the hierarchy and is a parent of ‘foo.bar’, and then ‘foo.bar’ is subsquently a parent of ‘foo.bar.baz’.

Children can propagate logging events up to parents above them in the hierarchy. This can simplify how handlers are setup as each logger doesn’t need to have its own handlers added if somewhere up the line a parent has the desired handlers already attached.

Initialization of the logger sets it up to start processing log events.

Parameters:
  • name (str) – The name of the logger.

  • level (int | str) – The logging level for the logger. (Default = ‘NOTSET’)

  • msgStyle (str) – The style of deferred formatting to use for log messages. This determines the log record factory that is used when creating a new log record. Built in possible values are ‘%’ for %-formatting, ‘{’ for str.format() formatting, and ‘$’ for string.Template formatting. Other values can be used if custom log record factories are added using set_log_record_factory(). (Default = ‘%’)

Raises:

FactoryError – If msgStyle doesn’t match any known log record factory.

property msgStyle

Determines the log record factory to use when creating new log records.

Built in possible values are ‘%’ for %-formatting, ‘{’ for str.format() formatting, and ‘$’ for string.Template formatting. Other values can be used if custom log record factories are added using set_log_record_factory().

Note

This will raise a FactoryError if it is set to a value that doesn’t match with any log record factory.

propagate = True

Whether logging events should be propagated up the logger hierarchy.

add_handler(handler)

Add the specified handler to this logger.

Parameters:

handler (BurinHandler) – The handler to add to the logger.

call_handlers(record)

Passes a log record to all relevant handlers.

This will call all handlers on this logger and then will move through parent loggers in the hierarchy calling their handlers based on propagation checks.

Parameters:

record (BurinLogRecord) – The log record to pass to the handlers.

critical(msg, *args, **kwargs)

Logs a message with the CRITICAL level.

Additional arguments are interpreted the same way as BurinLogger.log().

Parameters:

msg (str) – The message to log.

debug(msg, *args, **kwargs)

Logs a message with the DEBUG level.

Additional arguments are interpreted the same way as BurinLogger.log().

Parameters:

msg (str) – The message to log.

error(msg, *args, **kwargs)

Logs a message with the ERROR level.

Additional arguments are interpreted the same way as BurinLogger.log().

Parameters:

msg (str) – The message to log.

exception(msg, *args, exc_info=True, **kwargs)

Logs a message with the ERROR level and exception information.

This should normally be called only within an exception handler.

Additional arguments are interpreted the same way as BurinLogger.log().

Parameters:

msg (str) – The message to log.

find_caller(stack_info=False, stacklevel=1)

Finds the logging event caller’s information.

This will traverse back through frames until it is outside of the Burin library to find the caller of the logging event.

This will get the filename, line number, function name, and optionally the stack information of the caller.

Parameters:
  • stack_info (bool) – Whether the caller’s stack information should be returned as well. (Default = False)

  • stacklevel (int) – Allows stepping further back through stack frames in case the log call was from helper/wrapper code that should be ignored as well.

Returns:

A tuple of the filename, line number, function name, and if stack_info*=**True* the stack information.

Return type:

tuple(str, int, str, str | None)

get_child(suffix)

Gets a child of this logger.

The suffix can have multiple steps down the hierarchy by including additional period separate names ‘.’; this will all be added as descendants of this logger instance.

Calling burin.get_logger('abc').get_child('def.ghi') would return the exact same logger as burin.get_logger('abc.def.ghi').

If the requested logger already exists it is simply retrieved; otherwise it will be created.

Parameters:

suffix (str) – The part of the child logger’s name below this logger.

Returns:

The child logger.

Return type:

BurinLogger

get_children()

Gets a set of loggers that are the immediate children of this logger.

Note

In Python 3.12 this method was changed on the standard logging.Logger; it is supported here for all versions of Python compatible with Burin (including versions below 3.12).

Returns:

A set of loggers that are direct children of this logger.

Return type:

set

get_effective_level()

Gets the effective log level for this logger.

This will check if a specific level is set on this logger and if not then it will check through its parents until it finds one. If no specific level is found then NOTSET is returned.

Returns:

The effective log level for this logger.

Return type:

int

handle(record)

Calls handlers for the record.

This will check if the logger is disabled or any filters before calling handlers.

Parameters:

record (BurinLogRecord) – The log record to pass to the handlers.

has_handlers()

Checks if there are any available handlers for this logger.

This will check this logger and if it doesn’t find any handlers it will move through parent loggers in the hierarchy looking for handlers based on propagation checks.

Returns:

Whether this logger has any available handlers.

Return type:

bool

info(msg, *args, **kwargs)

Logs a message with the INFO level.

Additional arguments are interpreted the same way as BurinLogger.log().

Parameters:

msg (str) – The message to log.

is_enabled_for(level)

Checks if the logger is enabled for the specified level.

Parameters:

level (int | str) – The level to check on the logger.

Returns:

If the logger is enabled for level.

Return type:

bool

log(level, msg, *args, exc_info=None, extra=None, stack_info=False, stacklevel=1, **kwargs)

Logs a message with the specified level.

Note

The arguments exc_info, extra, stack_info, and stacklevel are all keyword only arguments. These cannot be passed as positional arguments.

Any additional args and kwargs will be kept with the message and used for deferred formatting before output. Deferred formatting allows you to pass in a format string for the message and the values as additional arguments. The message then will only be formatted if it is going to be emitted by a handler.

How this formatting is done is determined by the log record factory used. This is controlled by the BurinLogger.msgStyle property of the logger. See examples below.

% style:

# Positional format args
logger.log('DEBUG', 'This is a %s event in %s', 'DEBUG', 'Burin')
# Keyword format args in a dictionary
logger.log('DEBUG', 'This is a %(lvl)s event in %(prog)s',
           { 'lvl': 'DEBUG', 'prog': 'Burin'})

{ str.format() style:

# Positional format args
logger.log('DEBUG', 'This is a {} event in {}', 'DEBUG', 'Burin')
# Format args as keyword args
logger.log('DEBUG', 'This is a {lvl} event in {prog}', lvl='DEBUG',
           prog='Burin')

$ string.Template style:

# Format args as keyword args
logger.log('DEBUG', 'This is a ${lvl} event in ${prog}',
           lvl='DEBUG', prog='Burin')
Parameters:
  • level (int | str) – The level to log the message at.

  • msg (str) – The message to log.

  • exc_info (Exception | tuple(type, Exception, traceback) | bool) – Exception information to be added to the logging message. This should be an exception instance or an exception tuple (as returned by sys.exc_info()) if possible; otherwise if it is any other value that doesn’t evaluate as False then the exception information will be fetched using sys.exc_info().

  • extra (dict{str: Any}) – A dictionary of extra attributes that are applied to the log record’s __dict__. These can be used to populate custom fields that you set in your format string for BurinFormatter. The keys in this dictionary must not interfere with the built in fields/keys in the log record.

  • stack_info (bool) – Whether to get the stack information from the logging call and add it to the log record. This allows for getting stack information for logging without an exception needing to be raised. (Default = False)

  • stacklevel (int) – If this is greater than 1 then the corresponding number of stack frames are skipped back through when getting the logging caller’s information (like filename, lineno, and funcName). This can be useful when the log call was from helper/wrapper code that doesn’t need to be included in the log record.

Raises:

KeyError – If any key in extra conflicts with a built in key of the log record.

make_record(name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None, **kwargs)

Creates the log record and applies any extra fields to it.

The type of log record that is created is determined by this logger’s BurinLogger.msgStyle value.

Parameters:
  • name (str) – The name of the logger.

  • level (int) – The level of the logging event.

  • fn (str) – The filename of the log event caller.

  • lno – The line number where the log event was called.

  • msg (str) – The log message.

  • args (tuple(Any)) – The additional positional arguments for the log event call.

  • exc_info (tuple(type, Exception, traceback)) – The exception information if this log event is from an exception handler.

  • func (str) – The name of the function where the log event was called.

  • extra (dict{str: Any}) – Extra fields to be applied to the log record.

  • sinfo (str) – The stack information for the log event call.

Returns:

The newly created log record.

Return type:

BurinLogRecord

remove_handler(handler)

Removes the specified handler from this logger.

Parameters:

handler (BurinHandler) – The handler to remove from the logger.

set_level(level)

Sets the level of this logger.

Parameters:

level (int | str) – The new level for the handler.

warning(msg, *args, **kwargs)

Logs a message with the WARNING level.

Additional arguments are interpreted the same way as BurinLogger.log().

Parameters:

msg (str) – The message to log.

BurinLoggerAdapter

Almost all of the methods of the logger adapter mirror the underlying logger or simply delegate directly to it. The only unique method to the adapter is BurinLoggerAdapter.process() which is called automatically when a log call is made. This can be overridden though to customise an adapter.

class burin.BurinLoggerAdapter(logger, extra=None)

An adapter for easily passing contextual information in logging events.

Note

This differs slightly from the standard libraries logging.LoggerAdapter. Primarily the extra dictionary that is part of this adapter is merged with any extra dictionary that is part of each logging call instead of overwriting it.

This allows for more use cases and better nesting functionality. Also the manager property and _log method are not part of this class as they were unused.

Note

Almost all of the properties and non-logging methods of this class simply delegate to the underlying logger instance.

Using an adapter can simplify logging calls where specific contextual information would repeatedly need to be added to logging calls by instead automatically adding that contextual information for every logging event.

This is supported by essentially providing an extra value once when instantiating an adapter which is then added every time a logging method is called through the adapter.

The extra mapping is added to the log record’s __dict__, so this can allow custom fields in the format string used in a BurinFormatter to be populated with these values.

Initialization requires a logger and the optional extra mapping.

Parameters:
  • logger (BurinLogger) – The logger to use when calling logging events.

  • extra (dict{str: Any}) – The mapping to be added to the log record’s __dict__.

property msgStyle

Gets or sets the BurinLogger.msgStyle of the underlying logger.

See BurinLogger.msgStyle for more information about how this is used and what it can be set to.

Note

This will raise a FactoryError if it is set to a value that doesn’t match with any log record factory.

critical(msg, *args, **kwargs)

Logs a message with the CRITICAL level.

Additional arguments are interpreted the same way as BurinLoggerAdapter.log().

Parameters:

msg (str) – The message to log.

debug(msg, *args, **kwargs)

Logs a message with the DEBUG level.

Additional arguments are interpreted the same way as BurinLoggerAdapter.log().

Parameters:

msg (str) – The message to log.

error(msg, *args, **kwargs)

Logs a message with the ERROR level.

Additional arguments are interpreted the same way as BurinLoggerAdapter.log().

Parameters:

msg (str) – The message to log.

exception(msg, *args, exc_info=True, **kwargs)

Logs a message with the ERROR level with exception info.

This should normally be called only within an exception handler.

Additional arguments are interpreted the same way as BurinLoggerAdapter.log().

Parameters:

msg (str) – The message to log.

get_effective_level()

Gets the effective log level for the underlying logger.

Returns:

The effective log level for the underlying logger.

Return type:

int

has_handlers()

Checks if there are any available handlers for the underlying logger.

Returns:

Whether the underlying logger has any available handlers.

Return type:

bool

info(msg, *args, **kwargs)

Logs a message with the INFO level.

Additional arguments are interpreted the same way as BurinLoggerAdapter.log().

Parameters:

msg (str) – The message to log.

is_enabled_for(level)

Checks if the underlying logger is enabled for the specified level.

Parameters:

level (int | str) – The level to check on the underlying logger.

Returns:

If the underlying logger is enabled for level.

Return type:

bool

log(level, msg, *args, **kwargs)

Logs a message with the specified level.

Note

Unlike BurinLogger.log() all keyword arguments (like exc_info, extra, stack_info, and stacklevel) are just handled as kwargs instead of specific arguments. This allows for more flexibility in any subclassed adapters as all of the kwargs are passed for processing as just a dictionary.

This will call BurinLoggerAdapter.process() to add the extra values of this adapter with the logging call before calling the underlying logger.

Everything is passed to the underlying logger, so for more information about how it can be used and additional arguments please see BurinLogger.log().

Parameters:
  • level (int | str) – The level to log the message at.

  • msg (str) – The message to log.

process(msg, kwargs)

Processes the log event for the adapter.

This will add the extra values passed to the adapter when it was instantiated to the log event kwargs. If another extra dictionary was passed as part of the logging event then this will merge the extra values with the ones from the log event call taking precedence.

This can be overridden to provide other types of processing or customised adapters. The log msg and all kwargs from the logging call are passed in.

Parameters:
  • msg (str) – The log message.

  • kwargs (dict{str: Any}) – All keyword arguments that were passed with the logging call.

Returns:

The log message and keyword arguments to be sent to the underlying logger after processing.

Return type:

tuple(str, dict{str: Any})

set_level(level)

Sets the level of the underlying logger.

Parameters:

level (int | str) – The new level for the handler.

warning(msg, *args, **kwargs)

Logs a message with the WARNING level.

Additional arguments are interpreted the same way as BurinLoggerAdapter.log().

Parameters:

msg (str) – The message to log.