diff --git a/emby_exporter/emby_exporter.py b/emby_exporter/emby_exporter.py index 82df331..28755ef 100755 --- a/emby_exporter/emby_exporter.py +++ b/emby_exporter/emby_exporter.py @@ -30,7 +30,126 @@ from prometheus_client import Gauge, make_wsgi_app from wsgiref.simple_server import WSGIRequestHandler, WSGIServer, make_server -__VERSION__ = '0.1' +__VERSION__ = '0.1.2' + + +class metric: + def __init__(self, name, value): + self.name = name + self.value = value + self.metric = Gauge('%s' % name.lower(), name.replace('_', ' ')) + self.metric.set(value) + + def update_value(self, value): + self.value = value + self.metric.set(value) + + +class metric_label: + def __init__(self, name, value, label=None): + self.name = name + if not label: + label = [*value.keys()][0] + self.values = dict() + self.label_values = list() + self.label_values.append(label) + self.metric = Gauge('%s' % name.lower(), name.replace('_', ' '), + [label]) + self.update_value(value) + + def update_value(self, value): + for label in value: + self.values[label] = value[label] + self.metric.labels(label).set(value[label]) + if label not in self.label_values: + self.label_values.append(label) + for label in self.label_values: + if not label in value: + self.metric.labels(label).set(0) + + +class metric_labels: + def __init__(self, name, labels, values): + self.name = name + self.values = dict() + self.labels = labels + self.metric = Gauge('%s' % name.lower(), name.replace('_', ' '), + labels) + self.update_value(values) + + def zero_missing_value(self, values, key): + if isinstance(values, dict): + for label in values: + values[label] = self.zero_missing_value(values[label], label) + else: + values = 0 + return values + + def update_old_values(self, old_values, values): + + for label in old_values: + if not label in values: + old_values[label] = self.zero_missing_value( + old_values[label], label) + else: + if isinstance(old_values[label], dict): + old_values[label] = self.update_old_values( + old_values[label], values[label]) + return old_values + + def add_new_values(self, old_values, values): + + for label in values: + if not isinstance(values[label], dict): + old_values[label] = values[label] + else: + if label in old_values: + old_values[label] = self.add_new_values( + old_values[label], values[label]) + else: + old_values[label] = values[label] + + return old_values + + def update_metrics(self, values, labels=[]): + + for label in values: + labels_tmp = list() + for i in labels: + labels_tmp.append(i) + labels_tmp.append(label) + + if not isinstance(values[label], dict): + self.metric.labels(*labels_tmp).set(values[label]) + labels_tmp.pop() + else: + self.update_metrics(values[label], labels_tmp) + + def __add_value_dict(self, d, items, value): + if len(items) > 1: + if not items[0] in d: + d[items[0]] = dict() + current = items[0] + items.pop(0) + d[current] = self.__add_value_dict(d[current], items, value) + else: + d[items[0]] = value + return d + + def update_value(self, values): + values_tmp = self.values + if isinstance(values, list): + values_new = dict() + for v in values: + v_temp = v[:len(v) - 1] + metric_value = v[len(v) - 1] + values_new = self.__add_value_dict(values_new, v_temp, + metric_value) + values = values_new + values_tmp = self.add_new_values(values_tmp, values) + values_tmp = self.update_old_values(values_tmp, values) + + self.update_metrics(values_tmp) class emby_exporter: @@ -45,35 +164,44 @@ def __init__(self, url, api_key, user_id): self.metrics = dict() self.info = None self.count_lists = ['Genres', 'ProductionYear'] + self.count_user_data = ['Played', 'IsFavorite'] self.metrics['info'] = Gauge('emby_info', 'emby info', [ 'server_name', 'version', 'local_address', 'wan_address', 'id', 'operating_system' ]) - self.metrics['size'] = Gauge('emby_library_size', 'emby library size', - ['type']) - self.metrics['devices'] = Gauge( - 'emby_devices', 'emby devices', - ['name', 'id', 'username', 'user_id', 'app_name', 'app_version']) - - self.metrics['played'] = Gauge('emby_played', 'emby played item', - ['type']) - self.metrics['favourite'] = Gauge('emby_favourite', - 'emby favourite items', ['type']) self.httpd = None + def add_update_metric(self, name, value): + if not name in self.metrics: + self.metrics[name] = metric(name, value) + self.metrics[name].update_value(value) + + def add_update_metric_label(self, name, value, label=None): + if not name in self.metrics: + self.metrics[name] = metric_label(name, value, label) + self.metrics[name].update_value(value) + + def add_update_metric_labels(self, name, labels, value): + if not name in self.metrics: + self.metrics[name] = metric_labels(name, labels, value) + self.metrics[name].update_value(value) + def count_userdata(self, data, current_data={}): - for i in data: - if i in ['Played', 'IsFavorite']: - if data[i] is True: - if not i.lower() in current_data: - current_data[i.lower()] = 1 - else: - current_data[i.lower()] += 1 + for item_type in data: + for item in data[item_type]: + for i in self.count_user_data: + if not i in current_data: + current_data[i] = dict() + if item.object_dict['UserData'][i]: + if not item_type in current_data[i]: + current_data[i][item_type] = 1 + else: + current_data[i][item_type] += 1 return current_data - def count_list(self, data, current_data={}): + def update_list(self, data, current_data={}): if isinstance(data, list): for i in data: if not i in current_data: @@ -89,29 +217,33 @@ def count_list(self, data, current_data={}): def count_stats(self, data): stats = dict() - stats['user_data'] = dict() - for m in data: + for s in self.count_lists: + stats[s] = dict() + for item_type in data: for i in self.count_lists: - if not i in stats: - stats[i] = dict() - - if i in m.object_dict: - content = m.object_dict[i] - - if i in self.count_lists: - stats[i] = self.count_list(content, stats[i]) - - stats['user_data'] = self.count_userdata( - m.object_dict['UserData'], stats['user_data']) - + if not item_type in stats[i]: + stats[i][item_type] = dict() + for m in data[item_type]: + if i in m.object_dict: + content = m.object_dict[i] + stats[i][item_type] = self.update_list( + content, stats[i][item_type]) return stats def update_stats(self, data): stats = dict() - for i in data: - stats[i] = self.count_stats(data[i]) + stats = self.count_stats(data) + for t in stats: + for i in self.count_lists: + self.metrics[i] = self.add_update_metric_labels( + 'emby_%s' % i.lower(), ['type', i.lower()], stats[i]) + + user_data = self.count_userdata(data) + for t in user_data: + self.metrics[i] = self.add_update_metric_label( + 'emby_%s' % t.lower(), user_data[t], 'type') for t in stats: for i in stats[t]: @@ -122,14 +254,6 @@ def update_stats(self, data): if 'isfavourite' in stats[t]['user_data']: self.metrics['favourite'].labels(t).set( stats[t]['user_data']['isfavourite']) - else: - options = ['type', i.lower()] - if not i in self.metrics: - self.metrics[i] = Gauge('emby_%s' % i.lower(), - 'emby %s' % i, options) - if isinstance(stats[t][i], dict): - for g in stats[t][i]: - self.metrics[i].labels(t, g).set(stats[t][i][g]) def update_metrics(self): @@ -143,18 +267,30 @@ def update_metrics(self): data = dict() data['movies'] = self.emby.movies_sync data['series'] = self.emby.series_sync - #data['episodes'] = self.emby.episodes_sync data['albums'] = self.emby.albums_sync data['artists'] = self.emby.artists_sync + #data['episodes'] = self.emby.episodes_sync #data['songs'] = self.emby.songs_sync devices = self.emby.devices_sync + device_data = list() for d in devices: - self.metrics['devices'].labels(d.name, d.id, d.last_user_name, - d.last_user_id, d.app_name, - d.app_version).set(1) + device_data.append([ + d.name, d.id, d.last_user_name, d.last_user_id, d.app_name, + d.app_version, 1 + ]) + self.add_update_metric_labels('devices', [ + 'name', 'id', 'last_user_name', 'last_user_id', 'app_name', + 'app_version' + ], device_data) + + size_tmp = dict() for i in data: - self.metrics['size'].labels(i).set(len(data[i])) + size_tmp[i] = len(data[i]) + if not 'size' in self.metrics: + self.metrics['size'] = metric_label('emby_library_size', size_tmp, + 'type') + self.metrics['size'].update_value(size_tmp) self.update_stats(data) diff --git a/setup.py b/setup.py index 0e5640c..fe6bbca 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name='emby_exporter', - version='0.1.1', + version='0.1.2', url='https://github.com/dr1s/emby_exporter.py', author='dr1s', license='MIT',