Improved logging mechanism (and a few minor goodies) (#54)
* Improved logging mechanism * Allow for suppression of any errors regarding failed device updates
This commit is contained in:
+26
-15
@@ -1,31 +1,42 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import logging
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if sys.version_info < (3, 5):
|
if sys.version_info < (3, 5):
|
||||||
print("To use this script you need python 3.5 or newer! got %s" % sys.version_info)
|
print("To use this script you need python 3.5 or newer! got %s" % sys.version_info)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
from logger import _LOGGER
|
import logger
|
||||||
|
logger.setup()
|
||||||
|
|
||||||
|
import logging
|
||||||
import argparse
|
import argparse
|
||||||
|
import queue
|
||||||
|
|
||||||
from workers_queue import _WORKERS_QUEUE
|
from workers_queue import _WORKERS_QUEUE
|
||||||
from config import settings
|
from config import settings
|
||||||
from mqtt import MqttClient
|
from mqtt import MqttClient
|
||||||
from workers_manager import WorkersManager
|
from workers_manager import WorkersManager
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
group = parser.add_mutually_exclusive_group()
|
group = parser.add_mutually_exclusive_group()
|
||||||
group.add_argument('-d', '--debug', action='store_true', default=False)
|
group.add_argument('-d', '--debug', action='store_true', default=False, help='Set logging to output debug information')
|
||||||
group.add_argument('-q', '--quiet', action='store_true', default=False)
|
group.add_argument('-q', '--quiet', action='store_true', default=False, help='Set logging to just output warnings and errors')
|
||||||
|
parser.add_argument('-s', '--suppress-update-failures', dest='suppress', action='store_true', default=False, help='Suppress any errors regarding failed device updates')
|
||||||
parsed = parser.parse_args()
|
parsed = parser.parse_args()
|
||||||
|
|
||||||
if parsed.debug:
|
_LOGGER = logger.get()
|
||||||
|
if parsed.quiet:
|
||||||
|
_LOGGER.setLevel(logging.WARNING)
|
||||||
|
elif parsed.debug:
|
||||||
_LOGGER.setLevel(logging.DEBUG)
|
_LOGGER.setLevel(logging.DEBUG)
|
||||||
|
logger.enable_debug_formatter()
|
||||||
else:
|
else:
|
||||||
_LOGGER.setLevel(logging.INFO)
|
_LOGGER.setLevel(logging.INFO)
|
||||||
|
logger.suppress_update_failures(parsed.suppress)
|
||||||
|
|
||||||
_LOGGER.debug('Starting')
|
_LOGGER.info('Starting')
|
||||||
|
|
||||||
mqtt = MqttClient(settings['mqtt'])
|
mqtt = MqttClient(settings['mqtt'])
|
||||||
manager = WorkersManager()
|
manager = WorkersManager()
|
||||||
@@ -33,16 +44,16 @@ manager.register_workers(settings['manager']).start(mqtt)
|
|||||||
|
|
||||||
running = True
|
running = True
|
||||||
|
|
||||||
try:
|
|
||||||
while running:
|
while running:
|
||||||
try:
|
try:
|
||||||
mqtt.publish(_WORKERS_QUEUE.get(block=True).execute())
|
mqtt.publish(_WORKERS_QUEUE.get(timeout=10).execute())
|
||||||
|
except queue.Empty: # Allow for SIGINT processing
|
||||||
|
pass
|
||||||
|
except TimeoutError:
|
||||||
|
logger.log_exception(_LOGGER, "Timeout while executing worker command", suppress=True)
|
||||||
except (KeyboardInterrupt, SystemExit):
|
except (KeyboardInterrupt, SystemExit):
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
if not parsed.quiet:
|
|
||||||
_LOGGER.exception(e)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
running = False
|
running = False
|
||||||
_LOGGER.info('Exiting allowing jobs to finish. If you need force exit use kill')
|
_LOGGER.info('Finish current jobs and shut down. If you need force exit use kill')
|
||||||
|
except Exception as e:
|
||||||
|
logger.log_exception(_LOGGER, "Fatal error while executing worker command: %s", type(e).__name__)
|
||||||
|
raise e
|
||||||
|
|||||||
@@ -1,6 +1,50 @@
|
|||||||
import logging
|
import logging
|
||||||
|
import logging.config
|
||||||
|
import yaml
|
||||||
|
|
||||||
import sys
|
APP_ROOT = 'bt-mqtt-gw'
|
||||||
|
SUPPRESSION_ENABLED = False
|
||||||
|
|
||||||
_LOGGER = logging.getLogger('bt-mqtt-gw')
|
|
||||||
_LOGGER.addHandler(logging.StreamHandler(sys.stdout))
|
def setup():
|
||||||
|
with open('logger.yaml', 'rt') as f:
|
||||||
|
config = yaml.safe_load(f.read())
|
||||||
|
logging.config.dictConfig(config)
|
||||||
|
|
||||||
|
|
||||||
|
def get(name=None):
|
||||||
|
if name:
|
||||||
|
logger_name = '{}.{}'.format(APP_ROOT, name)
|
||||||
|
else:
|
||||||
|
logger_name = APP_ROOT
|
||||||
|
return logging.getLogger(logger_name)
|
||||||
|
|
||||||
|
|
||||||
|
def enable_debug_formatter():
|
||||||
|
logging.getLogger().handlers[0].setFormatter(logging.getLogger('dummy_debug').handlers[0].formatter)
|
||||||
|
|
||||||
|
|
||||||
|
def reset():
|
||||||
|
app_level = get().getEffectiveLevel()
|
||||||
|
|
||||||
|
root = logging.getLogger()
|
||||||
|
map(root.removeHandler, root.handlers[:])
|
||||||
|
map(root.removeFilter, root.filters[:])
|
||||||
|
|
||||||
|
setup()
|
||||||
|
get().setLevel(app_level)
|
||||||
|
if app_level <= logging.DEBUG:
|
||||||
|
enable_debug_formatter()
|
||||||
|
|
||||||
|
|
||||||
|
def suppress_update_failures(suppress):
|
||||||
|
global SUPPRESSION_ENABLED
|
||||||
|
SUPPRESSION_ENABLED = suppress
|
||||||
|
|
||||||
|
|
||||||
|
def log_exception(logger, message, *args, **kwargs):
|
||||||
|
if not ('suppress' in kwargs and kwargs.pop('suppress') and SUPPRESSION_ENABLED):
|
||||||
|
if logger.isEnabledFor(logging.DEBUG):
|
||||||
|
logger.exception(message, *args, **kwargs)
|
||||||
|
elif logger.isEnabledFor(logging.WARNING):
|
||||||
|
logger.warning(message, *args, **kwargs)
|
||||||
|
|||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
version: 1
|
||||||
|
disable_existing_loggers: True
|
||||||
|
|
||||||
|
formatters:
|
||||||
|
default:
|
||||||
|
format: '%(asctime)s %(message)s'
|
||||||
|
datefmt: '%X'
|
||||||
|
minimal:
|
||||||
|
format: '%(message)s'
|
||||||
|
debug:
|
||||||
|
format: '%(asctime)s %(levelname)s %(name)s %(filename)s:%(lineno)d:%(funcName)s - %(message)s'
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
console:
|
||||||
|
class: logging.StreamHandler
|
||||||
|
formatter: default
|
||||||
|
stream: ext://sys.stdout
|
||||||
|
dummy_debug:
|
||||||
|
class: logging.NullHandler
|
||||||
|
formatter: debug
|
||||||
|
|
||||||
|
loggers:
|
||||||
|
bt-mqtt-gw:
|
||||||
|
level: INFO
|
||||||
|
dummy_debug:
|
||||||
|
handlers: [dummy_debug]
|
||||||
|
|
||||||
|
root:
|
||||||
|
handlers: [console]
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import paho.mqtt.client as mqtt
|
import paho.mqtt.client as mqtt
|
||||||
from logger import _LOGGER
|
import logger
|
||||||
|
|
||||||
LWT_ONLINE = 'online'
|
LWT_ONLINE = 'online'
|
||||||
LWT_OFFLINE = 'offline'
|
LWT_OFFLINE = 'offline'
|
||||||
|
_LOGGER = logger.get(__name__)
|
||||||
|
|
||||||
class MqttClient:
|
class MqttClient:
|
||||||
|
|
||||||
|
|||||||
@@ -9,3 +9,6 @@ class BaseWorker:
|
|||||||
|
|
||||||
def format_topic(self, *args):
|
def format_topic(self, *args):
|
||||||
return '/'.join([self.topic_prefix, *args])
|
return '/'.join([self.topic_prefix, *args])
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return self.__module__.split(".")[-1]
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import time
|
import time
|
||||||
from interruptingcow import timeout
|
|
||||||
from bluepy.btle import Scanner, DefaultDelegate
|
from bluepy.btle import Scanner, DefaultDelegate
|
||||||
from mqtt import MqttMessage
|
from mqtt import MqttMessage
|
||||||
from utils import booleanize
|
|
||||||
from workers.base import BaseWorker
|
from workers.base import BaseWorker
|
||||||
from logger import _LOGGER
|
from utils import booleanize
|
||||||
|
import logger
|
||||||
|
|
||||||
REQUIREMENTS = ['bluepy']
|
REQUIREMENTS = ['bluepy']
|
||||||
|
_LOGGER = logger.get(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ScanDelegate(DefaultDelegate):
|
class ScanDelegate(DefaultDelegate):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class LinakdeskWorker(BaseWorker):
|
|||||||
return [MqttMessage(topic=self.format_topic('height/cm'), payload=self._get_height())]
|
return [MqttMessage(topic=self.format_topic('height/cm'), payload=self._get_height())]
|
||||||
|
|
||||||
def _get_height(self):
|
def _get_height(self):
|
||||||
with timeout(20):
|
with timeout(20, exception=TimeoutError):
|
||||||
self.desk.read_dpg_data()
|
self.desk.read_dpg_data()
|
||||||
return self.desk.current_height_with_offset.cm
|
return self.desk.current_height_with_offset.cm
|
||||||
|
|
||||||
|
|||||||
+13
-5
@@ -1,29 +1,37 @@
|
|||||||
from interruptingcow import timeout
|
import logging
|
||||||
|
|
||||||
from mqtt import MqttMessage
|
from mqtt import MqttMessage
|
||||||
|
|
||||||
from workers.base import BaseWorker
|
from workers.base import BaseWorker
|
||||||
|
import logger
|
||||||
|
|
||||||
REQUIREMENTS = ['git+https://github.com/open-homeautomation/miflora.git@84f39432082796412d05b754c948499a1ad710e7#egg=miflora', 'bluepy']
|
REQUIREMENTS = ['git+https://github.com/open-homeautomation/miflora.git@84f39432082796412d05b754c948499a1ad710e7#egg=miflora', 'bluepy']
|
||||||
|
|
||||||
monitoredAttrs = ["temperature", "moisture", "light", "conductivity", "battery"]
|
monitoredAttrs = ["temperature", "moisture", "light", "conductivity", "battery"]
|
||||||
|
_LOGGER = logger.get(__name__)
|
||||||
|
|
||||||
|
|
||||||
class MifloraWorker(BaseWorker):
|
class MifloraWorker(BaseWorker):
|
||||||
def _setup(self):
|
def _setup(self):
|
||||||
from miflora.miflora_poller import MiFloraPoller
|
from miflora.miflora_poller import MiFloraPoller
|
||||||
from btlewrap.bluepy import BluepyBackend
|
from btlewrap.bluepy import BluepyBackend
|
||||||
|
|
||||||
|
_LOGGER.info("Adding %d %s devices", len(self.devices), repr(self))
|
||||||
for name, mac in self.devices.items():
|
for name, mac in self.devices.items():
|
||||||
|
_LOGGER.debug("Adding %s device '%s' (%s)", repr(self), name, mac)
|
||||||
self.devices[name] = MiFloraPoller(mac, BluepyBackend)
|
self.devices[name] = MiFloraPoller(mac, BluepyBackend)
|
||||||
|
|
||||||
def status_update(self):
|
def status_update(self):
|
||||||
|
from btlewrap.base import BluetoothBackendException
|
||||||
|
_LOGGER.info("Updating %d %s devices", len(self.devices), repr(self))
|
||||||
ret = []
|
ret = []
|
||||||
for name, poller in self.devices.items():
|
for name, poller in self.devices.items():
|
||||||
|
_LOGGER.debug("Updating %s device '%s' (%s)", repr(self), name, poller._mac)
|
||||||
try:
|
try:
|
||||||
ret += self.update_device_state(name, poller)
|
ret += self.update_device_state(name, poller)
|
||||||
except RuntimeError:
|
except BluetoothBackendException as e:
|
||||||
pass
|
logger.log_exception(_LOGGER, "Error during update of %s device '%s' (%s): %s", repr(self), name, poller._mac, type(e).__name__, suppress=True)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@timeout(8.0)
|
|
||||||
def update_device_state(self, name, poller):
|
def update_device_state(self, name, poller):
|
||||||
ret = []
|
ret = []
|
||||||
poller.clear_cache()
|
poller.clear_cache()
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ class MiscaleWorker(BaseWorker):
|
|||||||
scanner = btle.Scanner().withDelegate(scan_processor)
|
scanner = btle.Scanner().withDelegate(scan_processor)
|
||||||
scanner.scan(5, passive=True)
|
scanner.scan(5, passive=True)
|
||||||
|
|
||||||
with timeout(5):
|
with timeout(5, exception=TimeoutError):
|
||||||
while scan_processor.weight is None:
|
while scan_processor.weight is None:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
return scan_processor.weight
|
return scan_processor.weight
|
||||||
|
|||||||
@@ -1,31 +1,37 @@
|
|||||||
from interruptingcow import timeout
|
import logging
|
||||||
|
|
||||||
from mqtt import MqttMessage
|
from mqtt import MqttMessage
|
||||||
|
|
||||||
from workers.base import BaseWorker
|
from workers.base import BaseWorker
|
||||||
|
import logger
|
||||||
|
|
||||||
REQUIREMENTS = ['mithermometer==0.1.2']
|
REQUIREMENTS = ['mithermometer==0.1.2']
|
||||||
|
|
||||||
monitoredAttrs = ["temperature", "humidity", "battery"]
|
monitoredAttrs = ["temperature", "humidity", "battery"]
|
||||||
|
_LOGGER = logger.get(__name__)
|
||||||
|
|
||||||
|
|
||||||
class MithermometerWorker(BaseWorker):
|
class MithermometerWorker(BaseWorker):
|
||||||
def _setup(self):
|
def _setup(self):
|
||||||
from mithermometer.mithermometer_poller import MiThermometerPoller
|
from mithermometer.mithermometer_poller import MiThermometerPoller
|
||||||
from btlewrap.bluepy import BluepyBackend
|
from btlewrap.bluepy import BluepyBackend
|
||||||
|
|
||||||
|
_LOGGER.info("Adding %d %s devices", len(self.devices), repr(self))
|
||||||
for name, mac in self.devices.items():
|
for name, mac in self.devices.items():
|
||||||
|
_LOGGER.debug("Adding %s device '%s' (%s)", repr(self), name, mac)
|
||||||
self.devices[name] = MiThermometerPoller(mac, BluepyBackend)
|
self.devices[name] = MiThermometerPoller(mac, BluepyBackend)
|
||||||
|
|
||||||
def status_update(self):
|
def status_update(self):
|
||||||
|
from btlewrap.base import BluetoothBackendException
|
||||||
|
_LOGGER.info("Updating %d %s devices", len(self.devices), repr(self))
|
||||||
ret = []
|
ret = []
|
||||||
for name, poller in self.devices.items():
|
for name, poller in self.devices.items():
|
||||||
|
_LOGGER.debug("Updating %s device '%s' (%s)", repr(self), name, poller._mac)
|
||||||
try:
|
try:
|
||||||
ret += self.update_device_state(name, poller)
|
ret += self.update_device_state(name, poller)
|
||||||
except RuntimeError:
|
except BluetoothBackendException as e:
|
||||||
pass
|
logger.log_exception(_LOGGER, "Error during update of %s device '%s' (%s): %s", repr(self), name, poller._mac, type(e).__name__, suppress=True)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@timeout(8.0)
|
|
||||||
def update_device_state(self, name, poller):
|
def update_device_state(self, name, poller):
|
||||||
ret = []
|
ret = []
|
||||||
poller.clear_cache()
|
poller.clear_cache()
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
from mqtt import MqttMessage
|
|
||||||
from workers.base import BaseWorker
|
|
||||||
from logger import _LOGGER
|
|
||||||
import serial
|
import serial
|
||||||
|
from mqtt import MqttMessage
|
||||||
|
|
||||||
|
from workers.base import BaseWorker
|
||||||
|
import logger
|
||||||
|
|
||||||
REQUIREMENTS = ['pyserial']
|
REQUIREMENTS = ['pyserial']
|
||||||
|
_LOGGER = logger.get(__name__)
|
||||||
|
|
||||||
|
|
||||||
class MysensorsWorker(BaseWorker):
|
class MysensorsWorker(BaseWorker):
|
||||||
|
|||||||
+22
-6
@@ -1,12 +1,14 @@
|
|||||||
from builtins import staticmethod
|
from builtins import staticmethod
|
||||||
|
import logging
|
||||||
|
|
||||||
from interruptingcow import timeout
|
|
||||||
from mqtt import MqttMessage
|
from mqtt import MqttMessage
|
||||||
|
|
||||||
from workers.base import BaseWorker
|
from workers.base import BaseWorker
|
||||||
|
import logger
|
||||||
|
|
||||||
REQUIREMENTS = ['python-eq3bt']
|
REQUIREMENTS = ['python-eq3bt']
|
||||||
|
|
||||||
monitoredAttrs = ["low_battery", "valve_state", "target_temperature", "window_open", "locked"]
|
monitoredAttrs = ["low_battery", "valve_state", "target_temperature", "window_open", "locked"]
|
||||||
|
_LOGGER = logger.get(__name__)
|
||||||
|
|
||||||
STATE_AWAY = 'away'
|
STATE_AWAY = 'away'
|
||||||
STATE_ECO = 'eco'
|
STATE_ECO = 'eco'
|
||||||
@@ -15,6 +17,7 @@ STATE_MANUAL = 'manual'
|
|||||||
STATE_ON = 'on'
|
STATE_ON = 'on'
|
||||||
STATE_OFF = 'off'
|
STATE_OFF = 'off'
|
||||||
|
|
||||||
|
|
||||||
class ThermostatWorker(BaseWorker):
|
class ThermostatWorker(BaseWorker):
|
||||||
class ModesMapper():
|
class ModesMapper():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -57,7 +60,9 @@ class ThermostatWorker(BaseWorker):
|
|||||||
def _setup(self):
|
def _setup(self):
|
||||||
from eq3bt import Thermostat
|
from eq3bt import Thermostat
|
||||||
|
|
||||||
|
_LOGGER.info("Adding %d %s devices", len(self.devices), repr(self))
|
||||||
for name, mac in self.devices.items():
|
for name, mac in self.devices.items():
|
||||||
|
_LOGGER.debug("Adding %s device '%s' (%s)", repr(self), name, mac)
|
||||||
self.devices[name] = Thermostat(mac)
|
self.devices[name] = Thermostat(mac)
|
||||||
|
|
||||||
self._modes_mapper = self.ModesMapper()
|
self._modes_mapper = self.ModesMapper()
|
||||||
@@ -66,15 +71,17 @@ class ThermostatWorker(BaseWorker):
|
|||||||
from bluepy import btle
|
from bluepy import btle
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
|
_LOGGER.info("Updating %d %s devices", len(self.devices), repr(self))
|
||||||
for name, thermostat in self.devices.items():
|
for name, thermostat in self.devices.items():
|
||||||
|
_LOGGER.debug("Updating %s device '%s' (%s)", repr(self), name, thermostat._conn._mac)
|
||||||
try:
|
try:
|
||||||
ret += self.update_device_state(name, thermostat)
|
ret += self.update_device_state(name, thermostat)
|
||||||
except (RuntimeError, btle.BTLEException):
|
except btle.BTLEException as e:
|
||||||
pass
|
logger.log_exception(_LOGGER, "Error during update of %s device '%s' (%s): %s", repr(self), name, thermostat._conn._mac, type(e).__name__, suppress=True)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def on_command(self, topic, value):
|
def on_command(self, topic, value):
|
||||||
|
from bluepy import btle
|
||||||
_, device_name, method, _ = topic.split('/')
|
_, device_name, method, _ = topic.split('/')
|
||||||
|
|
||||||
thermostat = self.devices[device_name]
|
thermostat = self.devices[device_name]
|
||||||
@@ -91,10 +98,19 @@ class ThermostatWorker(BaseWorker):
|
|||||||
elif method == "target_temperature":
|
elif method == "target_temperature":
|
||||||
value = float(value)
|
value = float(value)
|
||||||
|
|
||||||
|
_LOGGER.info("Setting %s to %s on %s device '%s' (%s)", method, value, repr(self), device_name, thermostat._conn._mac)
|
||||||
|
try:
|
||||||
setattr(thermostat, method, value)
|
setattr(thermostat, method, value)
|
||||||
|
except btle.BTLEException as e:
|
||||||
|
logger.log_exception(_LOGGER, "Error setting %s to %s on %s device '%s' (%s): %s", method, value, repr(self), device_name, thermostat._conn._mac, type(e).__name__)
|
||||||
|
return []
|
||||||
|
|
||||||
|
try:
|
||||||
return self.update_device_state(device_name, thermostat)
|
return self.update_device_state(device_name, thermostat)
|
||||||
|
except btle.BTLEException as e:
|
||||||
|
logger.log_exception(_LOGGER, "Error during update of %s device '%s' (%s): %s", repr(self), device_name, thermostat._conn._mac, type(e).__name__, suppress=True)
|
||||||
|
return []
|
||||||
|
|
||||||
@timeout(8.0)
|
|
||||||
def update_device_state(self, name, thermostat):
|
def update_device_state(self, name, thermostat):
|
||||||
thermostat.update()
|
thermostat.update()
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import time
|
import time
|
||||||
from interruptingcow import timeout
|
|
||||||
from bluepy.btle import Scanner, DefaultDelegate
|
from bluepy.btle import Scanner, DefaultDelegate
|
||||||
from mqtt import MqttMessage
|
from mqtt import MqttMessage
|
||||||
|
|
||||||
from workers.base import BaseWorker
|
from workers.base import BaseWorker
|
||||||
from logger import _LOGGER
|
import logger
|
||||||
|
|
||||||
REQUIREMENTS = ['bluepy']
|
REQUIREMENTS = ['bluepy']
|
||||||
|
_LOGGER = logger.get(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ScanDelegate(DefaultDelegate):
|
class ScanDelegate(DefaultDelegate):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
+20
-15
@@ -1,5 +1,14 @@
|
|||||||
import importlib
|
import importlib
|
||||||
import threading
|
import threading
|
||||||
|
from functools import partial
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
|
from interruptingcow import timeout
|
||||||
|
from pytz import utc
|
||||||
|
|
||||||
|
from workers_queue import _WORKERS_QUEUE
|
||||||
|
import logger
|
||||||
|
|
||||||
from pip import __version__ as pip_version
|
from pip import __version__ as pip_version
|
||||||
if int(pip_version.split('.')[0]) >= 10:
|
if int(pip_version.split('.')[0]) >= 10:
|
||||||
@@ -7,12 +16,8 @@ if int(pip_version.split('.')[0]) >= 10:
|
|||||||
else:
|
else:
|
||||||
from pip import main as pip_main
|
from pip import main as pip_main
|
||||||
|
|
||||||
from apscheduler.schedulers.background import BackgroundScheduler
|
_LOGGER = logger.get(__name__)
|
||||||
from interruptingcow import timeout
|
|
||||||
from functools import partial
|
|
||||||
from logger import _LOGGER
|
|
||||||
from workers_queue import _WORKERS_QUEUE
|
|
||||||
from pytz import utc
|
|
||||||
|
|
||||||
class WorkersManager:
|
class WorkersManager:
|
||||||
class Command:
|
class Command:
|
||||||
@@ -23,10 +28,10 @@ class WorkersManager:
|
|||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
messages = []
|
messages = []
|
||||||
with timeout(35):
|
with timeout(35, exception=TimeoutError):
|
||||||
messages = self._callback(*self._args)
|
messages = self._callback(*self._args)
|
||||||
|
|
||||||
_LOGGER.debug(messages)
|
_LOGGER.debug("Command execution result: %s", messages)
|
||||||
return messages
|
return messages
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -46,7 +51,7 @@ class WorkersManager:
|
|||||||
worker_obj = klass(**worker_config['args'])
|
worker_obj = klass(**worker_config['args'])
|
||||||
|
|
||||||
if hasattr(worker_obj, 'status_update'):
|
if hasattr(worker_obj, 'status_update'):
|
||||||
_LOGGER.debug("Added: %s with %d seconds interval" % (worker_name, worker_config['update_interval']))
|
_LOGGER.debug("Added %s worker with %d seconds interval", repr(worker_obj), worker_config['update_interval'])
|
||||||
command = self.Command(worker_obj.status_update, [])
|
command = self.Command(worker_obj.status_update, [])
|
||||||
self._update_commands.append(command)
|
self._update_commands.append(command)
|
||||||
|
|
||||||
@@ -61,7 +66,7 @@ class WorkersManager:
|
|||||||
partial(self._update_interval_wrapper, command, job_id)
|
partial(self._update_interval_wrapper, command, job_id)
|
||||||
))
|
))
|
||||||
elif hasattr(worker_obj, 'run'):
|
elif hasattr(worker_obj, 'run'):
|
||||||
_LOGGER.debug("Registered: %s as daemon" % (worker_name))
|
_LOGGER.debug("Registered %s as daemon", repr(worker_obj))
|
||||||
self._daemons.append(worker_obj)
|
self._daemons.append(worker_obj)
|
||||||
else:
|
else:
|
||||||
raise "%s cannot be initialized, it has to define run or status_update method" % worker_name
|
raise "%s cannot be initialized, it has to define run or status_update method" % worker_name
|
||||||
@@ -105,21 +110,21 @@ class WorkersManager:
|
|||||||
def _pip_install_helper(package_names):
|
def _pip_install_helper(package_names):
|
||||||
for package in package_names:
|
for package in package_names:
|
||||||
pip_main(['install', '-q', package])
|
pip_main(['install', '-q', package])
|
||||||
|
logger.reset()
|
||||||
|
|
||||||
def _update_interval_wrapper(self, command, job_id, client, userdata, c):
|
def _update_interval_wrapper(self, command, job_id, client, userdata, c):
|
||||||
_LOGGER.debug("Recieved updated interval for %s with: %s", c.topic, c.payload)
|
_LOGGER.info("Recieved updated interval for %s with: %s", c.topic, c.payload)
|
||||||
try:
|
try:
|
||||||
new_interval = int(c.payload)
|
new_interval = int(c.payload)
|
||||||
self._scheduler.remove_job(job_id)
|
self._scheduler.remove_job(job_id)
|
||||||
self._scheduler.add_job(
|
self._scheduler.add_job(
|
||||||
partial(self._queue_command, command), 'interval',
|
partial(self._queue_command, command), 'interval',
|
||||||
seconds=new_interval, id=job_id
|
seconds=new_interval, id=job_id)
|
||||||
)
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
_LOGGER.info("New interval invalid, recieved: %s", c.payload)
|
logger.log_exception(_LOGGER, 'Ignoring invalid new interval: %s', c.payload)
|
||||||
|
|
||||||
def _on_command_wrapper(self, worker_obj, client, userdata, c):
|
def _on_command_wrapper(self, worker_obj, client, userdata, c):
|
||||||
_LOGGER.debug("on command wrapper for with %s: %s", c.topic, c.payload)
|
_LOGGER.debug("Received command for %s on %s: %s", repr(worker_obj), c.topic, c.payload)
|
||||||
global_topic_prefix = userdata['global_topic_prefix']
|
global_topic_prefix = userdata['global_topic_prefix']
|
||||||
topic = c.topic[len(global_topic_prefix+'/'):] if global_topic_prefix is not None else c.topic
|
topic = c.topic[len(global_topic_prefix+'/'):] if global_topic_prefix is not None else c.topic
|
||||||
self._queue_command(self.Command(worker_obj.on_command, [topic, c.payload]))
|
self._queue_command(self.Command(worker_obj.on_command, [topic, c.payload]))
|
||||||
|
|||||||
Reference in New Issue
Block a user