forked from platypush/platypush
Replaced disable_logging
with a more generic logging_level
.
The `disable_logging` attribute was only available on events and responses, and it could only either entirely disable or enable logging for all the events of a certain type. The new flag allows more customization by setting the default logging level used for any message of a certain type (or `None` to disable logging). This makes it possible to e.g. set some verbose events to debug level, and the user can see them if they configure the application in debug mode. It also delegates the logging logic to the message itself, instead of having different parts of the application handling their own logic.
This commit is contained in:
parent
aa3479abeb
commit
2ee2a1d7b5
8 changed files with 180 additions and 77 deletions
|
@ -213,10 +213,9 @@ class Daemon:
|
|||
):
|
||||
self.stop_app()
|
||||
elif isinstance(msg, Response):
|
||||
logger.info('Received response: {}'.format(msg))
|
||||
msg.log()
|
||||
elif isinstance(msg, Event):
|
||||
if not msg.disable_logging:
|
||||
logger.info('Received event: {}'.format(msg))
|
||||
msg.log()
|
||||
self.event_processor.process_event(msg)
|
||||
|
||||
return _f
|
||||
|
|
|
@ -19,7 +19,7 @@ class JSONAble(ABC):
|
|||
raise NotImplementedError()
|
||||
|
||||
|
||||
class Message(object):
|
||||
class Message:
|
||||
"""
|
||||
Message generic class
|
||||
"""
|
||||
|
@ -45,9 +45,7 @@ class Message(object):
|
|||
|
||||
@staticmethod
|
||||
def parse_datetime(obj):
|
||||
if isinstance(obj, datetime.datetime) or \
|
||||
isinstance(obj, datetime.date) or \
|
||||
isinstance(obj, datetime.time):
|
||||
if isinstance(obj, (datetime.datetime, datetime.date, datetime.time)):
|
||||
return obj.isoformat()
|
||||
|
||||
def default(self, obj):
|
||||
|
@ -68,11 +66,33 @@ class Message(object):
|
|||
try:
|
||||
return super().default(obj)
|
||||
except Exception as e:
|
||||
logger.warning('Could not serialize object type {}: {}: {}'.format(
|
||||
type(obj), str(e), obj))
|
||||
logger.warning(
|
||||
'Could not serialize object type {}: {}: {}'.format(
|
||||
type(obj), str(e), obj
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, timestamp=None, *_, **__):
|
||||
def __init__(self, *_, timestamp=None, logging_level=logging.INFO, **__):
|
||||
self.timestamp = timestamp or time.time()
|
||||
self.logging_level = logging_level
|
||||
|
||||
def log(self, prefix=''):
|
||||
if self.logging_level is None:
|
||||
return # Skip logging
|
||||
|
||||
log_func = logger.info
|
||||
if self.logging_level == logging.DEBUG:
|
||||
log_func = logger.debug
|
||||
elif self.logging_level == logging.WARNING:
|
||||
log_func = logger.warning
|
||||
elif self.logging_level == logging.ERROR:
|
||||
log_func = logger.error
|
||||
elif self.logging_level == logging.FATAL:
|
||||
log_func = logger.fatal
|
||||
|
||||
if not prefix:
|
||||
prefix = f'Received {self.__class__.__name__}: '
|
||||
log_func(f'{prefix}{self}')
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
|
@ -80,12 +100,15 @@ class Message(object):
|
|||
the message into a UTF-8 JSON string
|
||||
"""
|
||||
|
||||
return json.dumps({
|
||||
return json.dumps(
|
||||
{
|
||||
attr: getattr(self, attr)
|
||||
for attr in self.__dir__()
|
||||
if (attr != '_timestamp' or not attr.startswith('_'))
|
||||
and not inspect.ismethod(getattr(self, attr))
|
||||
}, cls=self.Encoder).replace('\n', ' ')
|
||||
},
|
||||
cls=self.Encoder,
|
||||
).replace('\n', ' ')
|
||||
|
||||
def __bytes__(self):
|
||||
"""
|
||||
|
@ -105,7 +128,7 @@ class Message(object):
|
|||
|
||||
if isinstance(msg, cls):
|
||||
msg = str(msg)
|
||||
if isinstance(msg, bytes) or isinstance(msg, bytearray):
|
||||
if isinstance(msg, (bytes, bytearray)):
|
||||
msg = msg.decode('utf-8')
|
||||
if isinstance(msg, str):
|
||||
try:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import copy
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
import re
|
||||
import sys
|
||||
|
@ -11,6 +12,8 @@ from platypush.config import Config
|
|||
from platypush.message import Message
|
||||
from platypush.utils import get_event_class_by_type
|
||||
|
||||
logger = logging.getLogger('platypush')
|
||||
|
||||
|
||||
class Event(Message):
|
||||
"""Event message class"""
|
||||
|
@ -26,7 +29,7 @@ class Event(Message):
|
|||
origin=None,
|
||||
id=None,
|
||||
timestamp=None,
|
||||
disable_logging=False,
|
||||
logging_level=logging.INFO,
|
||||
disable_web_clients_notification=False,
|
||||
**kwargs
|
||||
):
|
||||
|
@ -36,15 +39,16 @@ class Event(Message):
|
|||
origin -- Origin node (default: current node) [String]
|
||||
id -- Event ID (default: auto-generated)
|
||||
kwargs -- Additional arguments for the event [kwDict]
|
||||
logging_level -- Logging level that should be applied to these
|
||||
events (default: INFO).
|
||||
"""
|
||||
|
||||
super().__init__(timestamp=timestamp)
|
||||
super().__init__(timestamp=timestamp, logging_level=logging_level)
|
||||
self.id = id if id else self._generate_id()
|
||||
self.target = target if target else Config.get('device_id')
|
||||
self.origin = origin if origin else Config.get('device_id')
|
||||
self.type = '{}.{}'.format(self.__class__.__module__, self.__class__.__name__)
|
||||
self.args = kwargs
|
||||
self.disable_logging = disable_logging
|
||||
self.disable_web_clients_notification = disable_web_clients_notification
|
||||
|
||||
for arg, value in self.args.items():
|
||||
|
@ -55,7 +59,7 @@ class Event(Message):
|
|||
'target',
|
||||
'type',
|
||||
'timestamp',
|
||||
'disable_logging',
|
||||
'logging_level',
|
||||
] and not arg.startswith('_'):
|
||||
self.__setattr__(arg, value)
|
||||
|
||||
|
@ -152,7 +156,7 @@ class Event(Message):
|
|||
result.score += 1.5
|
||||
elif re.search(condition_token, event_token):
|
||||
m = re.search('({})'.format(condition_token), event_token)
|
||||
if m.group(1):
|
||||
if m and m.group(1):
|
||||
event_tokens.pop(0)
|
||||
result.score += 1.25
|
||||
|
||||
|
@ -214,7 +218,7 @@ class EventMatchResult:
|
|||
the match is - in case of multiple event matches, the ones with the
|
||||
highest score will win"""
|
||||
|
||||
def __init__(self, is_match, score=0, parsed_args=None):
|
||||
def __init__(self, is_match, score=0.0, parsed_args=None):
|
||||
self.is_match = is_match
|
||||
self.score = score
|
||||
self.parsed_args = parsed_args or {}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import logging
|
||||
|
||||
from platypush.message.event import Event
|
||||
|
||||
|
||||
class CameraEvent(Event):
|
||||
""" Base class for camera events """
|
||||
"""Base class for camera events"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
@ -49,13 +51,13 @@ class CameraFrameCapturedEvent(CameraEvent):
|
|||
Event triggered when a camera frame has been captured
|
||||
"""
|
||||
|
||||
disable_logging = True
|
||||
|
||||
def __init__(self, filename=None, *args, **kwargs):
|
||||
super().__init__(*args, filename=filename,
|
||||
disable_logging=kwargs.pop('disable_logging')
|
||||
if 'disable_logging' in kwargs else self.disable_logging,
|
||||
**kwargs)
|
||||
super().__init__(
|
||||
*args,
|
||||
filename=filename,
|
||||
logging_level=kwargs.pop('logging_level', logging.DEBUG),
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import logging
|
||||
|
||||
from platypush.message.event import Event
|
||||
|
||||
|
||||
|
@ -5,9 +7,16 @@ class DistanceSensorEvent(Event):
|
|||
"""
|
||||
Event triggered when a new value is processed by a distance sensor.
|
||||
"""
|
||||
|
||||
def __init__(self, distance: float, unit: str = 'mm', *args, **kwargs):
|
||||
super().__init__(*args, distance=distance, unit=unit, disable_logging=True,
|
||||
disable_web_clients_notification=True, **kwargs)
|
||||
super().__init__(
|
||||
*args,
|
||||
distance=distance,
|
||||
unit=unit,
|
||||
logging_level=logging.DEBUG,
|
||||
disable_web_clients_notification=True,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import logging
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
from platypush.message.event import Event
|
||||
|
@ -12,7 +13,9 @@ class ZwaveNetworkReadyEvent(ZwaveEvent):
|
|||
"""
|
||||
Triggered when the network started on a Z-Wave adapter becomes ready.
|
||||
"""
|
||||
def __init__(self,
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
ozw_library_version: str,
|
||||
python_library_version: str,
|
||||
zwave_library: str,
|
||||
|
@ -21,8 +24,11 @@ class ZwaveNetworkReadyEvent(ZwaveEvent):
|
|||
home_id: int,
|
||||
nodes_count: int,
|
||||
device: Optional[str] = None,
|
||||
*args, **kwargs):
|
||||
super().__init__(*args,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
*args,
|
||||
device=device,
|
||||
ozw_library_version=ozw_library_version,
|
||||
python_library_version=python_library_version,
|
||||
|
@ -31,13 +37,15 @@ class ZwaveNetworkReadyEvent(ZwaveEvent):
|
|||
node_id=node_id,
|
||||
node_version=node_version,
|
||||
nodes_count=nodes_count,
|
||||
**kwargs)
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
class ZwaveNetworkStoppedEvent(ZwaveEvent):
|
||||
"""
|
||||
Triggered when a Z-Wave network is stopped.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -45,6 +53,7 @@ class ZwaveNetworkErrorEvent(ZwaveEvent):
|
|||
"""
|
||||
Triggered when an error occurs on the Z-Wave network.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -52,6 +61,7 @@ class ZwaveNetworkResetEvent(ZwaveEvent):
|
|||
"""
|
||||
Triggered when a Z-Wave network is reset.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -59,6 +69,7 @@ class ZwaveNodeEvent(ZwaveEvent):
|
|||
"""
|
||||
Generic Z-Wave node event class.
|
||||
"""
|
||||
|
||||
def __init__(self, node: Dict[str, Any], *args, **kwargs):
|
||||
super().__init__(*args, node=node, **kwargs)
|
||||
|
||||
|
@ -67,6 +78,7 @@ class ZwaveNodeAddedEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when a node is added to the network.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -74,6 +86,7 @@ class ZwaveNodeRemovedEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when a node is removed from the network.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -81,6 +94,7 @@ class ZwaveNodeRenamedEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when a node is renamed.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -88,6 +102,7 @@ class ZwaveNodeReadyEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when a node is ready.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -95,6 +110,7 @@ class ZwaveNodeAsleepEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when a node goes in sleep mode.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -102,6 +118,7 @@ class ZwaveNodeAwakeEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when a node goes back into awake mode.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -109,8 +126,11 @@ class ZwaveNodeGroupEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when a node is associated/de-associated to a group.
|
||||
"""
|
||||
|
||||
def __init__(self, group_index: Optional[int] = None, *args, **kwargs):
|
||||
kwargs['disable_logging'] = True
|
||||
# ZwaveNodeGroupEvent can be quite verbose, so we only report them if
|
||||
# debug logging is enabled
|
||||
kwargs['logging_level'] = logging.DEBUG
|
||||
super().__init__(*args, group_index=group_index, **kwargs)
|
||||
|
||||
|
||||
|
@ -118,6 +138,7 @@ class ZwaveNodeSceneEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when a scene is activated on a node.
|
||||
"""
|
||||
|
||||
def __init__(self, scene_id: int, *args, **kwargs):
|
||||
super().__init__(*args, scene_id=scene_id, **kwargs)
|
||||
|
||||
|
@ -126,6 +147,7 @@ class ZwaveNodePollingEnabledEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when the polling of a node is successfully turned on.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -133,6 +155,7 @@ class ZwaveNodePollingDisabledEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when the polling of a node is successfully turned off.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -140,6 +163,7 @@ class ZwaveButtonCreatedEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when a button is added to the network.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -147,6 +171,7 @@ class ZwaveButtonRemovedEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when a button is removed from the network.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -154,6 +179,7 @@ class ZwaveButtonOnEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when a button is pressed.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -161,6 +187,7 @@ class ZwaveButtonOffEvent(ZwaveNodeEvent):
|
|||
"""
|
||||
Triggered when a button is released.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -168,8 +195,11 @@ class ZwaveValueEvent(ZwaveEvent):
|
|||
"""
|
||||
Abstract class for Z-Wave value events.
|
||||
"""
|
||||
|
||||
def __init__(self, node: Dict[str, Any], value: Dict[str, Any], *args, **kwargs):
|
||||
kwargs['disable_logging'] = True
|
||||
# ZwaveValueEvent can be quite verbose, so we only report them if debug
|
||||
# logging is enabled
|
||||
kwargs['logging_level'] = logging.DEBUG
|
||||
super().__init__(*args, node=node, value=value, **kwargs)
|
||||
|
||||
|
||||
|
@ -177,6 +207,7 @@ class ZwaveValueAddedEvent(ZwaveValueEvent):
|
|||
"""
|
||||
Triggered when a value is added to a node on the network.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -184,6 +215,7 @@ class ZwaveValueChangedEvent(ZwaveValueEvent):
|
|||
"""
|
||||
Triggered when a value of a node on the network changes.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -191,6 +223,7 @@ class ZwaveValueRefreshedEvent(ZwaveValueEvent):
|
|||
"""
|
||||
Triggered when a value of a node on the network is refreshed.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -198,6 +231,7 @@ class ZwaveValueRemovedEvent(ZwaveValueEvent):
|
|||
"""
|
||||
Triggered when a value of a node on the network is removed.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -205,6 +239,7 @@ class ZwaveNodeQueryCompletedEvent(ZwaveEvent):
|
|||
"""
|
||||
Triggered when all the nodes on the network have been queried.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -212,16 +247,33 @@ class ZwaveCommandEvent(ZwaveEvent):
|
|||
"""
|
||||
Triggered when a command is received on the network.
|
||||
"""
|
||||
def __init__(self, state: str, state_description: str, error: Optional[str] = None,
|
||||
error_description: Optional[str] = None, node: Optional[Dict[str, Any]] = None, *args, **kwargs):
|
||||
super().__init__(*args, state=state, state_description=state_description,
|
||||
error=error, error_description=error_description, node=node, **kwargs)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
state: str,
|
||||
state_description: str,
|
||||
error: Optional[str] = None,
|
||||
error_description: Optional[str] = None,
|
||||
node: Optional[Dict[str, Any]] = None,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
*args,
|
||||
state=state,
|
||||
state_description=state_description,
|
||||
error=error,
|
||||
error_description=error_description,
|
||||
node=node,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
class ZwaveCommandWaitingEvent(ZwaveCommandEvent):
|
||||
"""
|
||||
Triggered when a command is waiting for a message to proceed.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
@ -254,6 +254,7 @@ class Request(Message):
|
|||
action
|
||||
)
|
||||
plugin = get_plugin(module_name)
|
||||
assert plugin, f'No such plugin: {module_name}'
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
msg = 'Uncaught pre-processing exception from action [{}]: {}'.format(
|
||||
|
@ -286,12 +287,8 @@ class Request(Message):
|
|||
'Response processed with errors from ' + 'action {}: {}'
|
||||
).format(action, str(response))
|
||||
)
|
||||
elif not response.disable_logging:
|
||||
logger.info(
|
||||
'Processed response from action {}: {}'.format(
|
||||
action, str(response)
|
||||
)
|
||||
)
|
||||
else:
|
||||
response.log(action)
|
||||
except (AssertionError, TimeoutError) as e:
|
||||
logger.warning(
|
||||
'%s from action [%s]: %s', e.__class__.__name__, action, str(e)
|
||||
|
|
|
@ -1,14 +1,23 @@
|
|||
import json
|
||||
import logging
|
||||
import time
|
||||
|
||||
from platypush.message import Message
|
||||
|
||||
|
||||
class Response(Message):
|
||||
""" Response message class """
|
||||
"""Response message class"""
|
||||
|
||||
def __init__(self, target=None, origin=None, id=None, output=None, errors=None,
|
||||
timestamp=None, disable_logging=False):
|
||||
def __init__(
|
||||
self,
|
||||
target=None,
|
||||
origin=None,
|
||||
id=None,
|
||||
output=None,
|
||||
errors=None,
|
||||
timestamp=None,
|
||||
logging_level=logging.INFO,
|
||||
):
|
||||
"""
|
||||
:param target: Target
|
||||
:type target: str
|
||||
|
@ -22,21 +31,20 @@ class Response(Message):
|
|||
:type timestamp: float
|
||||
"""
|
||||
|
||||
super().__init__(timestamp=timestamp)
|
||||
super().__init__(timestamp=timestamp, logging_level=logging_level)
|
||||
self.target = target
|
||||
self.output = self._parse_msg(output)
|
||||
self.errors = self._parse_msg(errors or [])
|
||||
self.origin = origin
|
||||
self.id = id
|
||||
self.disable_logging = disable_logging
|
||||
|
||||
def is_error(self):
|
||||
""" Returns True if the response has errors """
|
||||
"""Returns True if the response has errors"""
|
||||
return len(self.errors) != 0
|
||||
|
||||
@classmethod
|
||||
def _parse_msg(cls, msg):
|
||||
if isinstance(msg, bytes) or isinstance(msg, bytearray):
|
||||
if isinstance(msg, (bytes, bytearray)):
|
||||
msg = msg.decode('utf-8')
|
||||
if isinstance(msg, str):
|
||||
try:
|
||||
|
@ -54,7 +62,7 @@ class Response(Message):
|
|||
'output': msg['response']['output'],
|
||||
'errors': msg['response']['errors'],
|
||||
'timestamp': msg['_timestamp'] if '_timestamp' in msg else time.time(),
|
||||
'disable_logging': msg.get('_disable_logging', False),
|
||||
'logging_level': msg.get('_logging_level', logging.INFO),
|
||||
}
|
||||
|
||||
if 'id' in msg:
|
||||
|
@ -69,9 +77,9 @@ class Response(Message):
|
|||
Overrides the ``str()`` operator and converts
|
||||
the message into a UTF-8 JSON string
|
||||
"""
|
||||
output = self.output if self.output is not None else {
|
||||
'success': True if not self.errors else False
|
||||
}
|
||||
output = (
|
||||
self.output if self.output is not None else {'success': bool(self.errors)}
|
||||
)
|
||||
|
||||
response_dict = {
|
||||
'id': self.id,
|
||||
|
@ -85,10 +93,19 @@ class Response(Message):
|
|||
},
|
||||
}
|
||||
|
||||
if self.disable_logging:
|
||||
response_dict['_disable_logging'] = self.disable_logging
|
||||
if self.logging_level:
|
||||
response_dict['_logging_level'] = self.logging_level
|
||||
|
||||
return json.dumps(response_dict, cls=self.Encoder)
|
||||
|
||||
def log(self, action=None):
|
||||
prefix = (
|
||||
f'Processed response from action {action}: '
|
||||
if action
|
||||
else 'Received response: '
|
||||
)
|
||||
|
||||
super().log(prefix)
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
Loading…
Reference in a new issue