diff --git a/borgmatic/hooks/dispatch.py b/borgmatic/hooks/dispatch.py index 4f7706fc..24793b5a 100644 --- a/borgmatic/hooks/dispatch.py +++ b/borgmatic/hooks/dispatch.py @@ -4,6 +4,7 @@ from borgmatic.hooks import ( cronhub, cronitor, healthchecks, + loki, mariadb, mongodb, mysql, @@ -11,7 +12,6 @@ from borgmatic.hooks import ( pagerduty, postgresql, sqlite, - loki, ) logger = logging.getLogger(__name__) diff --git a/borgmatic/hooks/loki.py b/borgmatic/hooks/loki.py index a26f9625..53ff2081 100644 --- a/borgmatic/hooks/loki.py +++ b/borgmatic/hooks/loki.py @@ -1,8 +1,10 @@ -import logging -import requests import json -import time +import logging import platform +import time + +import requests + from borgmatic.hooks import monitor logger = logging.getLogger(__name__) @@ -16,50 +18,54 @@ MONITOR_STATE_TO_HEALTHCHECKS = { # Threshold at which logs get flushed to loki MAX_BUFFER_LINES = 100 -class loki_log_buffer(): + +class loki_log_buffer: ''' A log buffer that allows to output the logs as loki requests in json ''' + def __init__(self, url, dry_run): self.url = url self.dry_run = dry_run self.root = {} - self.root["streams"] = [{}] - self.root["streams"][0]["stream"] = {} - self.root["streams"][0]["values"] = [] + self.root['streams'] = [{}] + self.root['streams'][0]['stream'] = {} + self.root['streams'][0]['values'] = [] def add_value(self, value): timestamp = str(time.time_ns()) - self.root["streams"][0]["values"].append((timestamp, value)) + self.root['streams'][0]['values'].append((timestamp, value)) def add_label(self, label, value): - self.root["streams"][0]["stream"][label] = value + self.root['streams'][0]['stream'][label] = value def _to_request(self): return json.dumps(self.root) def __len__(self): - return len(self.root["streams"][0]["values"]) + return len(self.root['streams'][0]['values']) def flush(self): if self.dry_run: - self.root["streams"][0]["values"] = [] + self.root['streams'][0]['values'] = [] return if len(self) == 0: return request_body = self._to_request() - self.root["streams"][0]["values"] = [] - request_header = {"Content-Type": "application/json"} + self.root['streams'][0]['values'] = [] + request_header = {'Content-Type': 'application/json'} try: - r = requests.post(self.url, headers=request_header, data=request_body, timeout=5) - r.raise_for_status() + result = requests.post(self.url, headers=request_header, data=request_body, timeout=5) + result.raise_for_status() except requests.RequestException: - logger.warn("Failed to upload logs to loki") + logger.warn('Failed to upload logs to loki') + class loki_log_handeler(logging.Handler): ''' A log handler that sends logs to loki ''' + def __init__(self, url, dry_run): super().__init__() self.buffer = loki_log_buffer(url, dry_run) @@ -79,23 +85,25 @@ class loki_log_handeler(logging.Handler): if len(self.buffer) > 0: self.buffer.flush() + def initialize_monitor(hook_config, config, config_filename, monitoring_log_level, dry_run): ''' Add a handler to the root logger to regularly send the logs to loki ''' url = hook_config.get('url') loki = loki_log_handeler(url, dry_run) - for k, v in hook_config.get('labels').items(): - if v == '__hostname': - loki.add_label(k, platform.node()) - elif v == '__config': - loki.add_label(k, config_filename.split('/')[-1]) - elif v == '__config_path': - loki.add_label(k, config_filename) + for key, value in hook_config.get('labels').items(): + if value == '__hostname': + loki.add_label(key, platform.node()) + elif value == '__config': + loki.add_label(key, config_filename.split('/')[-1]) + elif value == '__config_path': + loki.add_label(key, config_filename) else: - loki.add_label(k, v) + loki.add_label(key, value) logging.getLogger().addHandler(loki) + def ping_monitor(hook_config, config, config_filename, state, monitoring_log_level, dry_run): ''' Adds an entry to the loki logger with the current state @@ -106,6 +114,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev if state in MONITOR_STATE_TO_HEALTHCHECKS.keys(): handler.raw(f'{config_filename} {MONITOR_STATE_TO_HEALTHCHECKS[state]} backup') + def destroy_monitor(hook_config, config, config_filename, monitoring_log_level, dry_run): ''' Remove the monitor handler that was added to the root logger.