From da537773a7d733999446cf7f486100138ceecfe3 Mon Sep 17 00:00:00 2001 From: Kevin Fronczak Date: Tue, 29 Jan 2019 23:09:28 -0500 Subject: [PATCH] Add repeat log handling filter. - Added exc_info=True to some errors for traceback logging --- blinkpy/blinkpy.py | 9 +++++++-- blinkpy/camera.py | 13 +++++++++---- blinkpy/helpers/util.py | 15 +++++++++++++++ blinkpy/sync_module.py | 13 +++++++++---- tests/test_cameras.py | 6 ++++-- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/blinkpy/blinkpy.py b/blinkpy/blinkpy.py index 0cd46d7..2526c46 100644 --- a/blinkpy/blinkpy.py +++ b/blinkpy/blinkpy.py @@ -22,7 +22,7 @@ from blinkpy import api from blinkpy.sync_module import BlinkSyncModule from blinkpy.helpers.util import ( create_session, merge_dicts, BlinkURLHandler, - BlinkAuthenticationException) + BlinkAuthenticationException, RepeatLogHandler) from blinkpy.helpers.constants import ( BLINK_URL, LOGIN_URL, LOGIN_BACKUP_URL) from blinkpy.helpers.constants import __version__ @@ -63,6 +63,7 @@ class Blink(): self.cameras = CaseInsensitiveDict({}) self._login_url = LOGIN_URL self.version = __version__ + _LOGGER.addHandler(RepeatLogHandler()) @property def auth_header(self): @@ -76,6 +77,8 @@ class Blink(): Method logs in and sets auth token, urls, and ids for future requests. Essentially this is just a wrapper function for ease of use. """ + _LOGGER.handlers.pop() + _LOGGER.addHandler(RepeatLogHandler()) if self._username is None or self._password is None: if not self.login(): return @@ -126,7 +129,8 @@ class Blink(): (self.region_id, self.region), = response['region'].items() except AttributeError: _LOGGER.error("Login API endpoint failed with response %s", - response) + response, + exc_info=True) return False except KeyError: _LOGGER.warning("Could not extract region info.") @@ -136,6 +140,7 @@ class Blink(): self._host = "{}.{}".format(self.region_id, BLINK_URL) self._token = response['authtoken']['authtoken'] self.networks = response['networks'] + self._auth_header = {'Host': self._host, 'TOKEN_AUTH': self._token} self.urls = BlinkURLHandler(self.region_id) diff --git a/blinkpy/camera.py b/blinkpy/camera.py index 7991a91..f52af58 100644 --- a/blinkpy/camera.py +++ b/blinkpy/camera.py @@ -111,7 +111,7 @@ class BlinkCamera(): try: self.temperature_calibrated = resp['temp'] except KeyError: - _LOGGER.error("Could not retrieve calibrated temperature.") + _LOGGER.warning("Could not retrieve calibrated temperature.") # Check if thumbnail exists in config, if not try to # get it from the homescreen info in teh sync module @@ -172,7 +172,8 @@ class BlinkCamera(): copyfileobj(response.raw, imgfile) else: _LOGGER.error("Cannot write image to file, response %s", - response.status_code) + response.status_code, + exc_info=True) def video_to_file(self, path): """Write video to file. @@ -182,7 +183,9 @@ class BlinkCamera(): _LOGGER.debug("Writing video from %s to %s", self.name, path) response = self._cached_video if response is None: - _LOGGER.error("No saved video exist for %s.", self.name) + _LOGGER.error("No saved video exist for %s.", + self.name, + exc_info=True) return with open(path, 'wb') as vidfile: copyfileobj(response.raw, vidfile) @@ -198,5 +201,7 @@ class BlinkCamera(): return device_thumb except KeyError: pass - _LOGGER.error("Could not find thumbnail for camera %s", self.name) + _LOGGER.error("Could not find thumbnail for camera %s", + self.name, + exc_info=True) return None diff --git a/blinkpy/helpers/util.py b/blinkpy/helpers/util.py index 0023dd3..e4758ed 100644 --- a/blinkpy/helpers/util.py +++ b/blinkpy/helpers/util.py @@ -121,3 +121,18 @@ class BlinkURLHandler(): self.networks_url = "{}/networks".format(self.base_url) self.video_url = "{}/api/v2/videos".format(self.base_url) _LOGGER.debug("Setting base url to %s.", self.base_url) + + +class RepeatLogHandler(logging.StreamHandler): + """Log handler for repeat entries.""" + + def __init__(self): + """Initialize repeat log handler.""" + super().__init__() + self.log_record = set() + + def emit(self, record): + """Ensure we only log a message once.""" + if record.msg not in self.log_record: + self.log_record.add(record.msg) + super().emit(record) diff --git a/blinkpy/sync_module.py b/blinkpy/sync_module.py index bf18ceb..08e31e5 100644 --- a/blinkpy/sync_module.py +++ b/blinkpy/sync_module.py @@ -82,7 +82,7 @@ class BlinkSyncModule(): self.network_id = self.summary['network_id'] except (TypeError, KeyError): _LOGGER.error(("Could not retrieve sync module information " - "with response: %s"), response) + "with response: %s"), response, exc_info=True) return False try: @@ -91,7 +91,8 @@ class BlinkSyncModule(): self.status = self.summary['status'] except KeyError: _LOGGER.error("Could not extract some sync module info: %s", - response) + response, + exc_info=True) self.events = self.get_events() self.homescreen = api.request_homescreen(self.blink) @@ -114,7 +115,9 @@ class BlinkSyncModule(): try: return response['event'] except (TypeError, KeyError): - _LOGGER.error("Could not extract events: %s", response) + _LOGGER.error("Could not extract events: %s", + response, + exc_info=True) return False def get_camera_info(self): @@ -123,7 +126,9 @@ class BlinkSyncModule(): try: return response['devicestatus'] except (TypeError, KeyError): - _LOGGER.error("Could not extract camera info: %s", response) + _LOGGER.error("Could not extract camera info: %s", + response, + exc_info=True) return [] def refresh(self, force_cache=False): diff --git a/tests/test_cameras.py b/tests/test_cameras.py index aae0b5d..9a9a278 100644 --- a/tests/test_cameras.py +++ b/tests/test_cameras.py @@ -163,8 +163,10 @@ class TestBlinkCameraSetup(unittest.TestCase): self.assertEqual(self.camera.last_record, ['1']) self.assertEqual( logrecord.output, - ["ERROR:blinkpy.camera:Could not retrieve calibrated temperature.", - "ERROR:blinkpy.camera:Could not find thumbnail for camera new"] + [("WARNING:blinkpy.camera:Could not retrieve calibrated " + "temperature."), + ("ERROR:blinkpy.camera:Could not find thumbnail for camera new" + "\nNoneType: None")] ) def test_no_video_clips(self, mock_sess):