heros.logging ============= .. py:module:: heros.logging .. autoapi-nested-parse:: Methods and classes for logging capabilities of HEROs Attributes ---------- .. autoapisummary:: heros.logging.SPAM heros.logging._current_hero heros.logging._registered_heros heros.logging.log Classes ------- .. autoapisummary:: heros.logging.hero_logging_context heros.logging.Logger heros.logging.ColoredFormatter Functions --------- .. autoapisummary:: heros.logging.register_hero heros.logging.unregister_hero heros.logging.resolve_origin heros.logging._install_hero_record_factory heros.logging.get_logger Module Contents --------------- .. py:data:: SPAM :value: 5 .. py:data:: _current_hero :type: contextvars.ContextVar .. py:data:: _registered_heros :type: set[str] .. py:function:: register_hero(name: str) -> None Register a LocalHERO as living in this process. Records emitted from contexts without an active HERO (e.g. background threads of dependencies) are attributed to the registered HERO. .. py:function:: unregister_hero(name: str) -> None Remove a LocalHERO from the set of HEROs living in this process. .. py:function:: resolve_origin() -> str Resolve the HERO name that log records emitted now belong to. :returns: The name of the currently active HERO if set, else the name of the single HERO registered in this process, ``PID:`` if no or more than one HERO is registered .. py:class:: hero_logging_context(name: str = 'unknown', name_attr: str | None = None) Bases: :py:obj:`contextlib.ContextDecorator` Attribute all log records emitted within this context to a specific HERO. While the context is active, every log record created in it is stamped with the name of the HERO, so that records emitted by dependencies of a heroized class can be attributed to the HERO whose capability is currently executed. Can be used in three ways: - as a context manager: ```with hero_logging_context("my_hero"): ...``` - as a function or method decorator: ```@hero_logging_context("my_hero")``` uses a fixed name, while ```@hero_logging_context(name_attr="_name")``` reads the name at call time from the instance the decorated method belongs to - as a class decorator: `@hero_logging_context(name_attr="name")` wraps all plain-function methods of the class (and its base classes). :param name: name of the HERO :param name_attr: name of the attribute of the instance the decorated method belongs to. Takes precedence over `name`. .. py:attribute:: name :value: 'unknown' .. py:attribute:: name_attr :value: None .. py:attribute:: _tokens :type: list[contextvars.Token] :value: [] .. py:method:: __call__(func) .. py:method:: __enter__() .. py:method:: __exit__(*exc) .. py:function:: _install_hero_record_factory() -> None Install a log record factory that stamps every record with the origin HERO name. The factory wraps the currently installed factory (idempotently, guarded by a marker attribute) and sets `record.origin` on every created record. Since the record factory is invoked for each record at creation time, before any handler or propagation logic, this also covers third-party loggers and loggers with `propagate=False`. .. py:class:: Logger(*args, **kwargs) Bases: :py:obj:`logging.Logger` Instances of the Logger class represent a single logging channel. A "logging channel" indicates an area of an application. Exactly how an "area" is defined is up to the application developer. Since an application can have any number of areas, logging channels are identified by a unique string. Application areas can be nested (e.g. an area of "input processing" might include sub-areas "read CSV files", "read XLS files" and "read Gnumeric files"). To cater for this natural nesting, channel names are organized into a namespace hierarchy where levels are separated by periods, much like the Java or Python package namespace. So in the instance given above, channel names might be "input" for the upper level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels. There is no arbitrary limit to the depth of nesting. .. py:method:: setLevel(level, globally=False) Set logger level; optionally propagate to all existing loggers. .. py:method:: spam(msg, *args, **kwargs) Log a SPAM-level message. .. py:class:: ColoredFormatter(*args, fmt: str = '%(asctime)-15s [%(levelname)s] %(name)s@%(origin)s [%(filename)s:%(lineno)d %(funcName)s]: %(message)s', **kwargs) Bases: :py:obj:`logging.Formatter` Logging formatter that adds ANSI colors to logging output. .. py:attribute:: RESET :value: '\x1b[0m' .. py:attribute:: RED :value: '\x1b[31m' .. py:attribute:: GREEN :value: '\x1b[32m' .. py:attribute:: YELLOW :value: '\x1b[33m' .. py:attribute:: supports_color .. py:method:: format(record) Format the specified record as text. The record's attribute dictionary is used as the operand to a string formatting operation which yields the returned string. Before formatting the dictionary, a couple of preparatory steps are carried out. The message attribute of the record is computed using LogRecord.getMessage(). If the formatting string uses the time (as determined by a call to usesTime(), formatTime() is called to format the event time. If there is exception information, it is formatted using formatException() and appended to the message. .. py:method:: _supports_color() Check if the current platform supports ANSI colors. .. py:function:: get_logger(name: str = 'heros') -> logging.Logger .. py:data:: log