Skip to content

Commit

Permalink
Merge pull request #168 from Mirantis/app-metrics
Browse files Browse the repository at this point in the history
add metrics for users and organizations
  • Loading branch information
tomkukral authored Jan 11, 2018
2 parents affc197 + 08191ec commit 429b3df
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 1 deletion.
91 changes: 91 additions & 0 deletions kqueen/blueprints/metrics/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from collections import defaultdict
from kqueen.models import Organization
from kqueen.models import User
from prometheus_client import Gauge

import asyncio
import logging

logger = logging.getLogger(__name__)

metrics = {
'users_by_namespace': Gauge('users_by_namespace', 'Number of users in namespace', ['namespace']),
'users_by_role': Gauge('users_by_role', 'Number of users by role', ['role']),
'users_active': Gauge('users_active', 'Number of users by role'),
'organization_count': Gauge('organization_count', 'Number of organizations'),
}


class MetricUpdater:
def __init__(self):
self.data = {}

self.get_data()

def update_metrics(self):
loop = asyncio.get_event_loop()
futures = []

for metric_name, metric in metrics.items():

update_function_name = 'update_metric_{}'.format(metric_name)

logger.debug('Updating metric {metric_name}, with function {function}'.format(
metric_name=metric_name,
function=update_function_name,
))

try:
fnc = getattr(self, update_function_name)
except AttributeError:
msg = 'Missing update function {function} for metric {metric_name}'.format(
metric_name=metric_name,
function=update_function_name
)

raise Exception(msg)

# run update function
future = loop.run_in_executor(None, fnc, metric)
futures.append(future)

# run all updates
asyncio.wait(futures)

def get_data(self):
# users
cls = User
namespace = None

sum = defaultdict(lambda: defaultdict(lambda: 0))

for obj_id, obj in cls.list(namespace, True).items():
user_dict = obj.get_dict(True)

user_namespace = user_dict['organization']['namespace']
user_role = user_dict['role']
user_active = user_dict['active']

sum['namespace'][user_namespace] += 1
sum['roles'][user_role] += 1
sum['active'][user_active] += 1

self.data['users'] = sum

# organizations
objs = Organization.list(None, False)
self.data['organizations'] = len(objs)

def update_metric_users_by_namespace(self, metric):
for namespace, count in self.data['users']['namespace'].items():
metric.labels(namespace).set(count)

def update_metric_users_by_role(self, metric):
for role, count in self.data['users']['roles'].items():
metric.labels(role).set(count)

def update_metric_users_active(self, metric):
metric.set(self.data['users']['active'][True])

def update_metric_organization_count(self, metric):
metric.set(self.data['organizations'])
27 changes: 27 additions & 0 deletions kqueen/blueprints/metrics/test_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from .helpers import MetricUpdater
from prometheus_client import generate_latest

import pytest


class TestMetricUpdates:
@pytest.fixture(scope='class')
def latest(self, user):
user.save()

m = MetricUpdater()
m.update_metrics()

return generate_latest().decode('utf-8')

@pytest.mark.parametrize('metric', [
('users_by_namespace{namespace="demoorg"}'),
('users_by_role{role="superadmin"}'),
('users_active'),
('organization_count'),
])
def test_metrics_exist(user, latest, metric):

req = "{metric} ".format(metric=metric)

assert req in latest
2 changes: 1 addition & 1 deletion kqueen/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# Prometheus metrics
REQUEST_COUNT = Counter(
'request_count',
'HTPP Request Count',
'HTTP Request Count',
['method', 'endpoint', 'http_status']
)
REQUEST_LATENCY = Histogram(
Expand Down

0 comments on commit 429b3df

Please sign in to comment.