async def notify(log_level: int = None) -> NoReturn: """Notify our users periodically of the number of red metrics.""" logging.getLogger().setLevel(log_level or logging.ERROR) sleep_duration = int(os.environ.get('NOTIFIER_SLEEP_DURATION', 60)) server_host = os.environ.get('SERVER_HOST', 'localhost') server_port = os.environ.get('SERVER_PORT', '5001') reports_url = f"http://{server_host}:{server_port}/api/v3/reports" most_recent_measurement_seen = datetime.max.isoformat() data_model = await retrieve_data_model() while True: record_health() logging.info("Determining notifications...") try: async with aiohttp.ClientSession(raise_for_status=True, trust_env=True) as session: response = await session.get(reports_url) json = await response.json() except Exception as reason: # pylint: disable=broad-except logging.error("Could not get reports from %s: %s", reports_url, reason) json = dict(reports=[]) notifications = get_notable_metrics_from_json( data_model, json, most_recent_measurement_seen) for notification in notifications: destination = str(notification["teams_webhook"]) text = build_notification_text(notification) send_notification_to_teams(destination, text) most_recent_measurement_seen = most_recent_measurement_timestamp(json) logging.info("Sleeping %.1f seconds...", sleep_duration) await asyncio.sleep(sleep_duration)
def test_unchanged_status_text(self): """Test that the text is correct.""" scale = "count" metric1 = dict(type="metric_type", name="Metric", unit="units", scale=scale, recent_measurements=[ dict(count=dict(value=0, status="near_target_met")), dict(count=dict(value=42, status="near_target_met")) ]) metric2 = dict(type="metric_type", name="Metric", unit="units", scale=scale, recent_measurements=[ dict(count=dict(value=5, status="target_met")), dict(count=dict(value=10, status="target_not_met")) ]) metric_notification_data1 = MetricNotificationData( metric1, self.data_model, "status_long_unchanged") metric_notification_data2 = MetricNotificationData( metric2, self.data_model, "status_long_unchanged") notification = Notification( self.report, [metric_notification_data1, metric_notification_data2], "destination_uuid", {}) text = build_notification_text(notification) self.assertEqual( "[Report 1](https://report1) has 2 metrics that are notable:\n\n" "* Metric has been yellow (near target met) for three weeks. Value: 42 units.\n" "* Metric has been red (target not met) for three weeks. Value: 10 units.\n", text)
def test_text(self): """Test that the text is correct.""" text = build_notification_text( dict(report_uuid="report1", report_title="Report 1", url="https://report1", metrics=[ dict(metric_type="metric_type", metric_name="Metric", metric_unit="units", old_metric_status="yellow (near target met)", old_metric_value=0, new_metric_status="red (target not met)", new_metric_value=42), dict(metric_type="metric_type", metric_name="Metric", metric_unit="units", old_metric_status="green (target met)", old_metric_value=5, new_metric_status="red (target not met)", new_metric_value=10) ])) self.assertEqual( "[Report 1](https://report1) has 2 metrics that changed status:\n\n" "* Metric status is red (target not met), was yellow (near target met). Value is 42 units, was 0 units.\n" "* Metric status is red (target not met), was green (target met). Value is 10 units, was 5 units.\n", text)
def send_notifications(self) -> int: """Send the notifications that are ready to be sent, remove them from the outbox.""" nr_sent = 0 for notification in self.notifications[:]: if notification.ready() and notification.destination["webhook"]: send_notification(str(notification.destination["webhook"]), build_notification_text(notification)) nr_sent += 1 self.notifications.remove(notification) return nr_sent
def test_unknown_text(self): """Test that the text is correct.""" metric1 = dict( type="metric_type", name="Metric", unit="units", scale="count", recent_measurements=[ dict(count=dict(value=0, status="near_target_met")), dict(count=dict(value=None, status="unknown")), ], ) metric_notification_data1 = MetricNotificationData( metric1, self.data_model, "status_changed") notification = Notification(self.report, [metric_notification_data1], "destination_uuid", {}) text = build_notification_text(notification) self.assertEqual( "[Report 1](https://report1) has 1 metric that is notable:\n\n" "* Metric status is white (unknown), was yellow (near target met). Value is ? units, was 0 units.\n", text, )