improved logging

This commit is contained in:
John Lancaster
2024-04-27 13:41:29 -05:00
parent 6250b6b20c
commit 68edfde755
5 changed files with 50 additions and 26 deletions

View File

@@ -1,5 +1,6 @@
import json import json
from dataclasses import dataclass from dataclasses import dataclass
from logging import Logger
from typing import List from typing import List
from appdaemon.plugins.mqtt.mqttapi import Mqtt from appdaemon.plugins.mqtt.mqttapi import Mqtt
@@ -14,10 +15,11 @@ class Button(Mqtt):
button: str | List[str] button: str | List[str]
rich: bool = False rich: bool = False
config: ButtonConfig config: ButtonConfig
logger: Logger
async def initialize(self): async def initialize(self):
self.config = ButtonConfig(**self.args) self.config = ButtonConfig(**self.args)
setup_component_logging(self) self.logger = setup_component_logging(self)
self.app: RoomController = await self.get_app(self.args['app']) self.app: RoomController = await self.get_app(self.args['app'])
self.log(f'Connected to AD app [room]{self.app.name}[/]', level='DEBUG') self.log(f'Connected to AD app [room]{self.app.name}[/]', level='DEBUG')
@@ -34,7 +36,9 @@ class Button(Mqtt):
def setup_button(self, name: str): def setup_button(self, name: str):
topic = f'zigbee2mqtt/{name}' topic = f'zigbee2mqtt/{name}'
# self.mqtt_subscribe(topic, namespace='mqtt') # self.mqtt_subscribe(topic, namespace='mqtt')
self.listen_event(self.handle_button, 'MQTT_MESSAGE', topic=topic, namespace='mqtt', button=name) self.listen_event(
self.handle_button, 'MQTT_MESSAGE', topic=topic, namespace='mqtt', button=name
)
self.log(f'MQTT topic [topic]{topic}[/] controls app [room]{self.app.name}[/]') self.log(f'MQTT topic [topic]{topic}[/] controls app [room]{self.app.name}[/]')
def handle_button(self, event_name, data, kwargs): def handle_button(self, event_name, data, kwargs):

View File

@@ -6,6 +6,7 @@ from dataclasses import asdict, dataclass
from appdaemon.logging import AppNameFormatter from appdaemon.logging import AppNameFormatter
from rich.console import Console from rich.console import Console
from rich.highlighter import RegexHighlighter from rich.highlighter import RegexHighlighter
from rich.logging import RichHandler
from rich.theme import Theme from rich.theme import Theme
@@ -25,7 +26,7 @@ console = Console(
theme=Theme( theme=Theme(
{ {
'log.time': 'none', 'log.time': 'none',
'logging.level.info': 'none', # 'logging.level.info': 'none',
'room': 'italic bright_cyan', 'room': 'italic bright_cyan',
'component': 'dark_violet', 'component': 'dark_violet',
'friendly_name': 'yellow', 'friendly_name': 'yellow',
@@ -44,7 +45,7 @@ console = Console(
class ContextSettingFilter(logging.Filter): class ContextSettingFilter(logging.Filter):
def filter(self, record: logging.LogRecord): def filter(self, record: logging.LogRecord) -> logging.LogRecord:
for name, val in asdict(self).items(): for name, val in asdict(self).items():
setattr(record, name, val) setattr(record, name, val)
return record return record
@@ -56,21 +57,21 @@ class RoomControllerFilter(ContextSettingFilter):
component: str component: str
class UnMarkupFormatter(AppNameFormatter): class UnMarkupFilter(logging.Filter):
md_regex = re.compile(r'(?P<open>\[.*?\])(?P<text>.*?)(?P<close>\[\/\])') md_regex = re.compile(r'(?P<open>\[.*?\])(?P<text>.*?)(?P<close>\[\/\])')
def format(self, record: logging.LogRecord): def filter(self, record: logging.LogRecord) -> logging.LogRecord:
result = super().format(record) record.msg = self.md_regex.sub(r'\g<text>', record.msg)
return self.md_regex.sub(r'\g<text>', result) return record
def create_rich_logging_dict(parent_room: str, typ: str = None): def create_rich_logging_dict(parent_room: str, typ: str = None):
logger_name = f'room_control.{parent_room}' logger_name = f'AppDaemon.{parent_room}'
if typ is not None: if typ is not None:
logger_name += f'.{typ}' logger_name += f'.{typ}'
fmt = '[room]{room:>12}[/] [component]{component:<9}[/]{message}' fmt = '[room]{room:>10}[/] [component]{component:<9}[/] {message}'
else: else:
fmt = '[room]{room:>12}[/] {message}' fmt = '[room]{room:>10}[/] {message}'
LOG_CFG = { LOG_CFG = {
'version': 1, 'version': 1,
@@ -78,44 +79,56 @@ def create_rich_logging_dict(parent_room: str, typ: str = None):
'filters': { 'filters': {
logger_name: { logger_name: {
'()': 'console.RoomControllerFilter', '()': 'console.RoomControllerFilter',
# '.': {'room': parent_room, 'component': typ},
'room': parent_room, 'room': parent_room,
'component': typ, 'component': typ,
} },
'unmarkup': {'()': 'console.UnMarkupFilter'},
}, },
'formatters': { 'formatters': {
logger_name: { 'basic': {'style': '{', 'format': fmt, 'datefmt': '%H:%M:%S.%f'},
'err': {
'style': '{', 'style': '{',
'format': fmt, 'format': '{asctime}.{msecs:02.0f} {room} {message}',
# 'datefmt': '%Y-%m-%d %I:%M:%S %p', 'datefmt': '%I:%M:%S',
} },
}, },
'handlers': { 'handlers': {
logger_name: { logger_name: {
'filters': [logger_name], 'filters': [logger_name],
'formatter': logger_name, 'formatter': 'basic',
'()': 'rich.logging.RichHandler', '()': 'rich.logging.RichHandler',
'markup': True, 'markup': True,
'log_time_format': '%Y-%m-%d %I:%M:%S %p',
'show_path': False, 'show_path': False,
# 'show_time': False,
'omit_repeated_times': False, 'omit_repeated_times': False,
'highlighter': RCHighlighter(),
'console': console, 'console': console,
}, },
'stderr': {
'filters': [logger_name, 'unmarkup'],
'formatter': 'err',
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stderr',
},
}, },
'loggers': { 'loggers': {
logger_name: { logger_name: {
'level': 'INFO', 'level': 'INFO',
'propagate': False, 'propagate': False,
'handlers': [logger_name], 'handlers': [
logger_name,
# 'stderr'
],
} }
}, },
} }
return LOG_CFG return LOG_CFG
def setup_component_logging(self): def setup_component_logging(self) -> logging.Logger:
cfg_dict = create_rich_logging_dict(parent_room=self.args['app'], typ=type(self).__name__) """Creates a logger for a subcomponent with a RichHandler"""
typ = type(self).__name__
parent = self.args['app']
cfg_dict = create_rich_logging_dict(parent_room=parent, typ=typ)
logger_name = next(iter(cfg_dict['loggers'])) logger_name = next(iter(cfg_dict['loggers']))
try: try:
@@ -123,4 +136,4 @@ def setup_component_logging(self):
except Exception: except Exception:
console.print_exception() console.print_exception()
else: else:
self.logger = logging.getLogger(logger_name) return logging.getLogger(logger_name)

View File

@@ -1,3 +1,4 @@
from logging import Logger
from appdaemon.plugins.hass.hassapi import Hass from appdaemon.plugins.hass.hassapi import Hass
from console import setup_component_logging from console import setup_component_logging
@@ -5,8 +6,10 @@ from room_control import RoomController
class Door(Hass): class Door(Hass):
logger: Logger
async def initialize(self): async def initialize(self):
setup_component_logging(self) self.logger = setup_component_logging(self)
self.app: RoomController = await self.get_app(self.args['app']) self.app: RoomController = await self.get_app(self.args['app'])
self.log(f'Connected to AD app [room]{self.app.name}[/]', level='DEBUG') self.log(f'Connected to AD app [room]{self.app.name}[/]', level='DEBUG')

View File

@@ -1,3 +1,4 @@
from logging import Logger
import re import re
from datetime import timedelta from datetime import timedelta
from typing import Literal, Optional from typing import Literal, Optional
@@ -25,6 +26,8 @@ Callbacks = dict[str, dict[str, CallbackEntry]]
class Motion(Hass): class Motion(Hass):
logger: Logger
@property @property
def sensor(self) -> Entity: def sensor(self) -> Entity:
return self.get_entity(self.args['sensor']) return self.get_entity(self.args['sensor'])
@@ -42,7 +45,7 @@ class Motion(Hass):
return self.ref_entity.get_state() == 'on' return self.ref_entity.get_state() == 'on'
def initialize(self): def initialize(self):
setup_component_logging(self) self.logger = setup_component_logging(self)
self.app: RoomController = self.get_app(self.args['app']) self.app: RoomController = self.get_app(self.args['app'])
self.log(f'Connected to AD app [room]{self.app.name}[/]', level='DEBUG') self.log(f'Connected to AD app [room]{self.app.name}[/]', level='DEBUG')

View File

@@ -35,6 +35,7 @@ class RoomController(Hass, Mqtt):
def initialize(self): def initialize(self):
cfg_dict = create_rich_logging_dict(parent_room=self.name) cfg_dict = create_rich_logging_dict(parent_room=self.name)
logging.config.dictConfig(cfg_dict) logging.config.dictConfig(cfg_dict)
self.logger = logging.getLogger(next(iter(cfg_dict['loggers'])))
self.app_entities = self.gather_app_entities() self.app_entities = self.gather_app_entities()
# self.log(f'entities: {self.app_entities}') # self.log(f'entities: {self.app_entities}')