WIP, not functional
This commit is contained in:
14
config/.rich_logging.yaml
Normal file
14
config/.rich_logging.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
version: 1
|
||||
disable_existing_loggers: false
|
||||
formatters:
|
||||
rich:
|
||||
style: "{"
|
||||
format: "[room]{appname}[/] {message}"
|
||||
datefmt: '%H:%M:%S.%f'
|
||||
handlers:
|
||||
rich:
|
||||
formatter: rich
|
||||
'()': 'rich.logging.RichHandler'
|
||||
markup: True
|
||||
show_path: false
|
||||
omit_repeated_times: false
|
||||
@@ -1,9 +1,13 @@
|
||||
import json
|
||||
import logging
|
||||
import logging.config
|
||||
import re
|
||||
from abc import ABC
|
||||
from dataclasses import asdict
|
||||
from importlib.resources import files
|
||||
|
||||
import yaml
|
||||
from appdaemon.adapi import ADAPI
|
||||
from rich.console import Console
|
||||
from rich.highlighter import RegexHighlighter
|
||||
from rich.theme import Theme
|
||||
@@ -42,6 +46,14 @@ class RCHighlighter(RegexHighlighter):
|
||||
]
|
||||
|
||||
|
||||
def load_rich_config():
|
||||
with files('room_control.config').joinpath('rich_logging.yaml').open('r') as f:
|
||||
RICH_CFG = yaml.safe_load(f)
|
||||
RICH_CFG['handlers']['rich']['console'] = console
|
||||
RICH_CFG['handlers']['rich']['highlighter'] = RCHighlighter()
|
||||
return RICH_CFG
|
||||
|
||||
|
||||
RICH_HANDLER_CFG = {
|
||||
'()': 'rich.logging.RichHandler',
|
||||
'markup': True,
|
||||
@@ -61,19 +73,19 @@ class ContextSettingFilter(logging.Filter, ABC):
|
||||
return record
|
||||
|
||||
|
||||
class RoomFilter(logging.Filter):
|
||||
"""Used to filter out messages that have a component field because they will have already been printed by their respective logger."""
|
||||
|
||||
def filter(self, record: logging.LogRecord) -> bool:
|
||||
return getattr(record, 'component', None) is None
|
||||
|
||||
|
||||
# @dataclass
|
||||
# class RoomControllerFilter(ContextSettingFilter):
|
||||
# room: str
|
||||
# component: Optional[str] = None
|
||||
|
||||
|
||||
class RoomFilter(logging.Filter):
|
||||
"""Used to filter out messages that have a component field because they will have already been printed by their respective logger."""
|
||||
|
||||
def filter(self, record: logging.LogRecord) -> bool:
|
||||
return not hasattr(record, 'component')
|
||||
|
||||
|
||||
# class RoomControllerFormatter(logging.Formatter):
|
||||
# def format(self, record: logging.LogRecord):
|
||||
# return super().format(record)
|
||||
@@ -87,6 +99,11 @@ class UnMarkupFilter(logging.Filter):
|
||||
return record
|
||||
|
||||
|
||||
class JSONFormatter(logging.Formatter):
|
||||
def format(self, record: logging.LogRecord) -> str:
|
||||
return json.dumps(record.__dict__)
|
||||
|
||||
|
||||
def room_logging_config(name: str):
|
||||
return {
|
||||
'version': 1,
|
||||
@@ -106,6 +123,7 @@ def room_logging_config(name: str):
|
||||
'format': '{asctime}.{msecs:03.0f} {levelname:8} {name}: {message}',
|
||||
'datefmt': '%Y-%m-%d %H:%M:%S',
|
||||
},
|
||||
'json': {'()': 'room_control.console.JSONFormatter'},
|
||||
},
|
||||
'handlers': {
|
||||
'rich_room': {
|
||||
@@ -119,7 +137,14 @@ def room_logging_config(name: str):
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
# 'class': 'logging.FileHandler',
|
||||
'filename': f'/logs/{name}.log',
|
||||
'mode': 'w',
|
||||
'maxBytes': 1000000,
|
||||
'backupCount': 3,
|
||||
},
|
||||
'json': {
|
||||
'filters': ['unmarkup'],
|
||||
'formatter': 'json',
|
||||
'filename': f'/logs/{name}.jsonl',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'maxBytes': 1000000,
|
||||
'backupCount': 3,
|
||||
},
|
||||
@@ -128,7 +153,11 @@ def room_logging_config(name: str):
|
||||
f'AppDaemon.{name}': {
|
||||
'level': 'INFO',
|
||||
'propagate': False,
|
||||
'handlers': ['rich_room', 'file'],
|
||||
'handlers': [
|
||||
'rich_room',
|
||||
'file',
|
||||
'json',
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -137,6 +166,9 @@ def room_logging_config(name: str):
|
||||
def component_logging_config(parent_room: str, component: str):
|
||||
logger_name = f'AppDaemon.{parent_room}.{component}'
|
||||
|
||||
cfg = load_rich_config()
|
||||
|
||||
|
||||
LOG_CFG = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
|
||||
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Literal, Optional
|
||||
|
||||
from appdaemon.entity import Entity
|
||||
from appdaemon.plugins.hass.hassapi import Hass
|
||||
from pydantic import BaseModel, TypeAdapter
|
||||
from pydantic import BaseModel, TypeAdapter, ValidationError
|
||||
|
||||
from .console import setup_component_logging
|
||||
|
||||
@@ -83,16 +83,18 @@ class Motion(Hass):
|
||||
)
|
||||
self.listen_state(**base_kwargs, new='off', callback=self.callback_light_off)
|
||||
|
||||
if callbacks := self.callbacks():
|
||||
for handle, entry in callbacks.items():
|
||||
self.log(
|
||||
f'Handle [yellow]{handle[:4]}[/]: {entry.function}', level='DEBUG'
|
||||
)
|
||||
for handle, cb in self.callbacks():
|
||||
self.log(f'Handle [yellow]{handle[:4]}[/]: {cb.function}', level='DEBUG')
|
||||
|
||||
def callbacks(self):
|
||||
"""Returns a dictionary of validated CallbackEntry objects that are associated with this app"""
|
||||
data = TypeAdapter(Callbacks).validate_python(self.get_callback_entries())
|
||||
return data.get(self.name, {})
|
||||
self_callbacks = self.get_callback_entries().get(self.name, {})
|
||||
for handle, cb_dict in self_callbacks.items():
|
||||
try:
|
||||
yield handle, CallbackEntry.model_validate(cb_dict)
|
||||
except ValidationError as e:
|
||||
self.logger.error('Error parsing callback dictionary')
|
||||
self.logger.error(e)
|
||||
|
||||
def listen_motion_on(self):
|
||||
"""Sets up the motion on callback to activate the room"""
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import logging.config
|
||||
from copy import deepcopy
|
||||
@@ -8,7 +9,7 @@ from appdaemon.entity import Entity
|
||||
from appdaemon.plugins.hass.hassapi import Hass
|
||||
from appdaemon.plugins.mqtt.mqttapi import Mqtt
|
||||
|
||||
from .console import console, room_logging_config
|
||||
from .console import room_logging_config
|
||||
from .model import ControllerStateConfig, RoomControllerConfig
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -95,10 +96,6 @@ class RoomController(Hass, Mqtt):
|
||||
|
||||
assert isinstance(state.time, datetime.time), f'Invalid time: {state.time}'
|
||||
|
||||
# if self.logger.isEnabledFor(logging.DEBUG):
|
||||
# # table = self._room_config.rich_table(self.name)
|
||||
# console.print(self._room_config)
|
||||
|
||||
self.states = sorted(self.states, key=lambda s: s.time, reverse=True)
|
||||
|
||||
# schedule the transitions
|
||||
@@ -209,9 +206,7 @@ class RoomController(Hass, Mqtt):
|
||||
|
||||
elif isinstance(scene_kwargs, dict):
|
||||
self.call_service('scene/apply', **scene_kwargs)
|
||||
if self.logger.isEnabledFor(logging.INFO):
|
||||
self.log('Applied scene:')
|
||||
console.print(scene_kwargs['entities'])
|
||||
self.log(f'Applied scene:\n{json.dumps(scene_kwargs, indent=2)}', level='DEBUG')
|
||||
|
||||
elif scene_kwargs is None:
|
||||
self.log('No scene, ignoring...')
|
||||
|
||||
Reference in New Issue
Block a user