87 lines
2.7 KiB
Python
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)
|