Files
ad_toolbox/logger_interface.py
T
2026-10-10 15:25:00 +02:00

87 lines
2.7 KiB
Python

import traceback
from contextlib import contextmanager
from contextvars import ContextVar
from uuid import uuid4
_ACTIVE_LOG_GROUP = ContextVar('appdaemon_log_group', default=None)
@contextmanager
def log_group(kind, label=None, *, inherit=True):
"""Tag LoggerInterface messages in this synchronous operation with one group ID."""
parent = _ACTIVE_LOG_GROUP.get() if inherit else None
group = parent or {
'id': uuid4().hex[:12],
'kind': kind,
'label': str(label) if label is not None else '',
}
token = _ACTIVE_LOG_GROUP.set(group)
try:
yield group
finally:
_ACTIVE_LOG_GROUP.reset(token)
class LoggerInterface:
def __init__(self):
self.initialized = False
def __init__(self, ad_api, default_log='main_log', mute=False, *, ascii_encode=None):
self.initialize_logger_interface(ad_api, default_log, mute, ascii_encode=ascii_encode)
def initialize_logger_interface(self, ad_api, default_log='main_log', mute=False, *, ascii_encode=None):
self.ad_api = ad_api
self.default_log = default_log
self.mute = False
self.initialized = True
self._log_options = {} if ascii_encode is None else {'ascii_encode': ascii_encode}
def _write_log(self, message, level, log):
self.ad_api.log(self._tag_log_message(message), level=level, log=log,
**self._log_options)
def log_group(self, kind, label=None):
return log_group(kind, label)
@staticmethod
def _tag_log_message(message):
group = _ACTIVE_LOG_GROUP.get()
if group is None:
return message
marker = f"[group={group['kind']}:{group['id']}]"
if isinstance(message, str) and marker in message:
return message
return f"{message} {marker}"
def mute_logger(self, mute: bool):
if mute:
self._write_log('Muting logger', 'INFO', self.default_log)
self.mute = bool(mute)
def log_info(self, message):
assert self.initialized
if not self.mute:
self._write_log(message, 'INFO', self.default_log)
def log_warning(self, message):
assert self.initialized
self._write_log(message, 'WARNING', self.default_log)
def log_error(self, message, stop_app=False, dump_stack=False):
assert self.initialized
if dump_stack:
stack = '\n'
for line in traceback.format_stack()[:-1]:
stack += line.strip() + '\n'
else:
stack = ''
message = self._tag_log_message(message)
self._write_log(message, 'ERROR', self.default_log)
self._write_log(message + stack, 'ERROR', 'error_log')
if stop_app:
self.stop_app(self.name)