Skip to content

Commit

Permalink
Add search metrics support
Browse files Browse the repository at this point in the history
  • Loading branch information
mkrizek authored and cutwater committed Sep 4, 2018
1 parent 511d7db commit 0623ae6
Show file tree
Hide file tree
Showing 15 changed files with 1,307 additions and 9 deletions.
37 changes: 29 additions & 8 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ So without further ado, run the following:
## Start the build process
$ make dev/up
Any missing images (i.e., postgresql, memcachd, rabbitmq) will be pulled.
Getting all the images downloaded may take a few minutes.
Any missing images (i.e. postgresql, rabbitmq, prometheus, influxdb, grafana)
will be pulled. Getting all the images downloaded may take a few minutes.
Once all the images are available, the ontainers will launch.

Aftr the above commands completes, you can take a look at the containers by
Expand All @@ -179,12 +179,13 @@ running ``docker ps`` in your second terminal session:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fc06225cdfd5 galaxy-dev:latest "/bin/sh -c /galax..." 6 hours ago Up 5 hours 0.0.0.0:8000->8000/tcp galaxy_galaxy_1
dc007355a69a elasticsearch:2.4.1 "/docker-entrypoin..." 6 hours ago Up 6 hours 9200/tcp, 9300/tcp galaxy_elastic_1
fa48c619cc3d postgres:9.5.4 "/docker-entrypoin..." 6 hours ago Up 6 hours 5432/tcp galaxy_postgres_1
b7f374cf7d56 rabbitmq:latest "docker-entrypoint..." 6 hours ago Up 6 hours 4369/tcp, 5671-5672/tcp, 25672/tcp galaxy_rabbitmq_1
9b8245eea91b memcached:latest "docker-entrypoint..." 6 hours ago Up 6 hours 11211/tcp galaxy_memcache_1
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b76488f94890 galaxy-dev:latest "/entrypoint.sh /g..." 2 minutes ago Up 2 minutes 0.0.0.0:8000->8000/tcp galaxy_galaxy_1
dfe97d19197e centos/postgresql-95-centos7 "container-entrypo..." 22 hours ago Up 2 minutes 0.0.0.0:2345->5432/tcp galaxy_postgres_1
fd3dd5f663f2 rabbitmq:latest "docker-entrypoint..." 22 hours ago Up 2 minutes 4369/tcp, 5671-5672/tcp, 25672/tcp galaxy_rabbitmq_1
9561d0cea1ec prom/prometheus:latest "/bin/prometheus -..." 2 minutes ago Up 2 minutes 0.0.0.0:9090->9090/tcp galaxy_prometheus_1
21e8b688f2ab influxdb:latest "/entrypoint.sh in..." 22 hours ago Up 2 minutes 0.0.0.0:8086->8086/tcp galaxy_influxdb_1
92186c792b4d grafana/grafana:latest "/run.sh" 2 minutes ago Up 2 minutes 0.0.0.0:3000->3000/tcp galaxy_grafana_1
Running detached
^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -323,6 +324,26 @@ OK, go for it! Your Galaxy web site is available at: `http://localhost:8000`_.
Post build setup
----------------

Metrics
^^^^^^^

From the root of the project tree, run ``make dev/setup-metrics`` to initialize
InfluxDB and import data sources and dashboards for Prometheus and InfluxDB into Grafana.

.. code-block:: console
$ make dev/setup-metrics
Log into Grafana at `http://localhost:3000`_ using the admin user with
password ``admin``. Navigate to ``Galaxy Search Metrics - InfluxDB`` and
``Galaxy Search Metrics - Prometheus`` dashboards.

Search metrics are exposed at `http://localhost:8000/api/metrics`_. From
there, the metrics are being scraped by Prometheus
(`http://localhost:9090/`_). Prometheus serves as a short-term storage.
For a long-term metrics storage, the metrics are being sent from
Prometheus to InfluxDB.

Create an admin user
^^^^^^^^^^^^^^^^^^^^

Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ celery:

.PHONY: ng_server
ng_server:
cd /galaxy/galaxyui; ng serve --host '0.0.0.0' --port '8000' --poll '5000' --watch --live-reload --progress=false ----proxy-config proxy.conf.js
cd /galaxy/galaxyui; ng serve --disable-host-check --host '0.0.0.0' --port '8000' --poll '5000' --watch --live-reload --progress=false ----proxy-config proxy.conf.js

.PHONY: waitenv
waitenv:
Expand Down Expand Up @@ -261,5 +261,9 @@ dev/lint-rule-update:
@$(DOCKER_COMPOSE) exec galaxy git config --global user.name "dev galaxy_1"
@$(DOCKER_COMPOSE) exec galaxy bash -c "cd /galaxy-lint-rules && git pull --ff-only https://github.com/ansible/galaxy-lint-rules.git master"

.PHONY: dev/setup-metrics
dev/setup-metrics:
cd scripts/metrics-setup-playbook; ansible-playbook setup.yml

%:
@:
1 change: 1 addition & 0 deletions galaxy/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,4 +270,5 @@
urlpatterns = [
url(r'^$', views.ApiRootView.as_view(), name='api_root_view'),
url(r'^v1/', include(v1_urls)),
url(r'', include('django_prometheus.urls')),
]
2 changes: 2 additions & 0 deletions galaxy/api/views/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from galaxy.api import filters
from galaxy.api import serializers
from galaxy.api.views import base_views as base
from galaxy.common import metrics
from galaxy.main import models

__all__ = [
Expand Down Expand Up @@ -79,6 +80,7 @@ def get_queryset(self):
repository__provider_namespace__namespace__active=True))

# TODO(cutwater): Use serializer to parse request arguments
@metrics.send('search')
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())

Expand Down
95 changes: 95 additions & 0 deletions galaxy/common/metrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# (c) 2012-2018, Ansible by Red Hat
#
# This file is part of Ansible Galaxy
#
# Ansible Galaxy is free software: you can redistribute it and/or modify
# it under the terms of the Apache License as published by
# the Apache Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# Ansible Galaxy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Apache License for more details.
#
# You should have received a copy of the Apache License
# along with Galaxy. If not, see <http://www.apache.org/licenses/>.

import logging
import sys

from django.conf import settings

from rest_framework.request import Request


__all__ = [
'send',
]

logger = logging.getLogger(__name__)


def send(func_name):
def decorator(function):
def wrapper(*args, **kwargs):
# call the view
result = function(*args, **kwargs)

if settings.METRICS_ENABLED:
# TODO do this async
_send(func_name, args[1])

return result
return wrapper
return decorator


def _send(func_name, request):
if not isinstance(request, Request):
raise AssertionError(
'Could not send metrics. '
'Expected rest_framework.request.Request, got %s!'
% type(request)
)

func = getattr(sys.modules[__name__], func_name, None)
if not callable(func):
raise AssertionError(
'Could not send metrics. % is not callable!' % func_name
)

try:
# FIXME POST?
func(request.GET)
except IOError as e:
logger.exception(e)


def search(data):
platforms = data.get('platforms', '').split()
cloud_platforms = data.get('cloud_platforms', '').split()
tags = data.get('tags', '').split()
keywords = data.get('keywords', '').split()

if not any((platforms, cloud_platforms, tags, keywords)):
return

search_criteria = {
'keyword': keywords,
'platform': platforms,
'cloud_platform': cloud_platforms,
'tag': tags,
}

settings.PROM_CNTR_SEARCH.labels(
keywords=','.join(keywords),
platforms=','.join(platforms),
cloud_platforms=','.join(cloud_platforms),
tags=','.join(tags)
).inc()

for criteria_type, criteria_values in search_criteria.items():
for criteria_value in criteria_values:
settings.PROM_CNTR_SEARCH_CRITERIA.labels(
ctype=criteria_type, cvalue=criteria_value).inc()
29 changes: 29 additions & 0 deletions galaxy/settings/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import os

import djcelery
import prometheus_client


djcelery.setup_loader()
Expand All @@ -43,6 +44,8 @@
# Application definition
# ---------------------------------------------------------

PROMETHEUS_EXPORT_MIGRATIONS = False

# TODO(cutwater): Review 3rd party apps usage
INSTALLED_APPS = (
# Django apps
Expand All @@ -65,6 +68,7 @@

# 3rd part apps
'bootstrapform',
'django_prometheus',
'djcelery',
'rest_framework',
'rest_framework.authtoken',
Expand Down Expand Up @@ -288,6 +292,26 @@
If set to `None`, system temporary directory is used.
"""

# =========================================================
# Metrics Settings
# =========================================================

METRICS_ENABLED = False

PROM_CNTR_SEARCH = prometheus_client.Counter(
'search',
'',
['keywords', 'platforms', 'cloud_platforms', 'tags'],
registry=prometheus_client.REGISTRY
)

PROM_CNTR_SEARCH_CRITERIA = prometheus_client.Counter(
'search_criteria',
'',
['ctype', 'cvalue'],
registry=prometheus_client.REGISTRY
)

# =========================================================
# Logging
# =========================================================
Expand Down Expand Up @@ -368,6 +392,11 @@
'level': 'DEBUG',
'propagate': True,
},
'galaxy.common.metrics': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': True,
},
'galaxy.main': {
'handlers': ['console'],
'level': 'DEBUG',
Expand Down
9 changes: 9 additions & 0 deletions galaxy/settings/development.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@
WAIT_FOR = [
{'host': 'postgres', 'port': 5432},
{'host': 'rabbitmq', 'port': 5672},
{'host': 'influxdb', 'port': 8086},
{'host': 'grafana', 'port': 3000},
{'host': 'prometheus', 'port': 9090},
]

STATIC_ROOT = ''

# =========================================================
# Metrics Settings
# =========================================================

METRICS_ENABLED = True
7 changes: 7 additions & 0 deletions galaxy/settings/production.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
* GALAXY_RABBITMQ_USER
* GALAXY_RABBITMQ_PASSWORD
* GALAXY_ADMIN_PATH
* GALAXY_METRICS_ENABLED
"""

import os
Expand Down Expand Up @@ -203,6 +204,12 @@ def _set_logging():

LOGGING = _set_logging()

# =========================================================
# Metrics Settings
# =========================================================

METRICS_ENABLED = True

# =========================================================
# System Settings
# =========================================================
Expand Down
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ Sphinx
django-log-request-id
# format log output as json
jog

# Web analytics/metrics
prometheus_client
django-prometheus
29 changes: 29 additions & 0 deletions scripts/docker/dev/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,32 @@ services:
- RABBITMQ_DEFAULT_USER=galaxy
- RABBITMQ_DEFAULT_PASS=galaxy
- RABBITMQ_DEFAULT_VHOST=galaxy

influxdb:
image: influxdb:latest
ports:
- '8086:8086'
environment:
- INFLUXDB_REPORTING_DISABLED=true
- INFLUXDB_DB=galaxy
- INFLUXDB_ADMIN_USER=admin
- INFLUXDB_ADMIN_PASSWORD=admin
- INFLUXDB_WRITE_USER=galaxy
- INFLUXDB_WRITE_USER_PASSWORD=galaxy

grafana:
image: grafana/grafana:latest
ports:
- '3000:3000'
links:
- influxdb
- prometheus

prometheus:
image: prom/prometheus:latest
ports:
- '9090:9090'
volumes:
- './prometheus.yml:/etc/prometheus/prometheus.yml'
links:
- galaxy:galaxy.svc
11 changes: 11 additions & 0 deletions scripts/docker/dev/prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
scrape_configs:
- job_name: 'galaxy'
scrape_interval: '60s'
honor_labels: true
metrics_path: '/api/metrics'
static_configs:
- targets:
- 'galaxy.svc:8000'

remote_write:
- url: "http://influxdb:8086/api/v1/prom/write?u=galaxy&p=galaxy&db=galaxy"
44 changes: 44 additions & 0 deletions scripts/metrics-setup-playbook/influxdb_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from influxdb import InfluxDBClient


INFLUXDB_HOST = 'localhost'
INFLUXDB_PORT = 8086
INFLUXDB_USER = 'galaxy'
INFLUXDB_PASS = 'galaxy'
INFLUXDB_DB = 'galaxy'


client = InfluxDBClient(
host=INFLUXDB_HOST,
port=INFLUXDB_PORT,
username=INFLUXDB_USER,
password=INFLUXDB_PASS
)

client.create_database(INFLUXDB_DB)
client.switch_database(INFLUXDB_DB)

# Retention policies
#client.query(
# "CREATE RETENTION POLICY a_month ON %s DURATION 30d REPLICATION 1"
# % INFLUXDB_DB
#)
client.query(
"CREATE RETENTION POLICY a_year ON %s DURATION 365d REPLICATION 1 DEFAULT"
% INFLUXDB_DB
)

# Continuous queries
#client.query(
# "DROP CONTINUOUS QUERY cq_search_criteria_per_day ON %s" % INFLUXDB_DB
#)
#
#client.query(
# "CREATE CONTINUOUS QUERY cq_search_criteria_per_day ON %s "
# "RESAMPLE EVERY 30m "
# "BEGIN "
# "SELECT count(value) AS value INTO search_criteria_per_day FROM a_month.search_criteria "
# "GROUP BY time(1d), * "
# "END"
# % INFLUXDB_DB
#)
Loading

0 comments on commit 0623ae6

Please sign in to comment.