Source code for fastcs.tracer
from collections import defaultdict
from typing import Any
from fastcs.logging import logger
[docs]
class Tracer:
"""A mixin or standalone class for conditionally logging trace events.
This can be used for verbose logging that is disabled by default and enabled on a
per-instance basis, with filtering based on specific key-value pairs on the event.
Any instance of this class can enable tracing independently. Some key classes
inherit this class, such as ``Attributes``, and some modules have their own
``Tracer``, such as ``fastcs.launch``. When enabled, any event logged from the
object, or from another ``Tracer`` that uses the object as the ``topic``, will be
logged.
Note: The global logger level must be set to ``TRACE`` for the messages to be logged
Example usage:
.. code-block:: python
controller.ramp_rate.enable_tracing()
controller.ramp_rate.disable_tracing()
controller.connection.enable_tracing()
controller.connection.add_tracing_filter("query", "V?")
controller.connection.remove_tracing_filter("query", "V?")
controller.connection.disable_tracing()
:param name: The name of the logger. Attached to log messages as ``logger_name``.
"""
def __init__(self, name: str | None = None):
self.__tracing_enabled: bool = False
self.__tracing_filters: dict[str, list[Any]] = defaultdict(list)
self.__logger_name = name if name is not None else self.__class__.__name__
[docs]
def log_event(self, event: str, topic: "Tracer | None" = None, *args, **kwargs):
"""Log an event only if tracing is enabled and the filter matches
:param event: A message describing the event
:param topic: Another `Tracer` related to this event to enable it to be logged
:param args: Positional arguments for underlying logger
:param kwargs: Keyword arguments for underlying logger
"""
if self.__tracing_enabled or (topic is not None and topic.__tracing_enabled): # noqa: SLF001
if self.__tracing_filters:
for kwarg, values in self.__tracing_filters.items():
if kwarg in kwargs and any(kwargs[kwarg] == v for v in values):
break
else:
return
logger.trace(event, *args, logger_name=self.__logger_name, **kwargs)
[docs]
def enable_tracing(self):
"""Enable trace logging for this object"""
self.__tracing_enabled = True
[docs]
def disable_tracing(self):
"""Disable trace logging for this object"""
self.__tracing_enabled = False
[docs]
def add_tracing_filter(self, key: str, value: Any):
"""Add a filter for trace log messages from this object
To reduce trace messages further, a filter can be applied such that events must
have a key with a specific value for it to be logged.
:param key: A new or existing key to filter on
:param value: An allowed value for the event to be logged
"""
self.__tracing_filters[key].append(value)
[docs]
def remove_tracing_filter(self, key: str, value: Any):
"""Remove a specific key-value pair from the filter
:param key: An existing filter key
:param value: The allowed value to remove
"""
if (
key not in self.__tracing_filters
or value not in self.__tracing_filters[key]
):
return
self.__tracing_filters[key].remove(value)
if not self.__tracing_filters[key]:
self.__tracing_filters.pop(key)
[docs]
def clear_tracing_filters(self):
"""Clear all filters and allow all messages to be logged (if enabled)"""
self.__tracing_filters.clear()