Instrumenting Django with Prometheus and StatsD
If you ever wondered how to monitor your Django application with Prometheus this article is for you.
Quick search on the topic will lead you to django-prometheus.
For those who don't want to use it, there is another way to export application metrics
via StatsD.
The idea is to send metrics from Django by StatsD Python library to StatsD server over UDP.
Here is an example of incrementing "hello.requests.total" metric every time "say_hello" view is run.
from statsd.defaults.django import statsd
from django.http import HttpResponse
def say_hello(request):
statsd.incr('hello.requests.total')
return HttpResponse('Hello, World!')
StatsD server aggregates measurements over time and flushes them into monitoring backend.
Here statsd_exporter comes into play.
It uses the same UDP protocol as StatsD server and exports StatsD-style metrics as Prometheus metrics,
so "hello.requests.total" becomes "hello_requests_total_counter".
All we need is to configure Django to send metrics to statsd_exporter daemon.
Let's set up "Olympus" Django project to demonstrate StatsD integration or
you can get it from github.com/marselester/django-prometheus-via-statsd.
$ virtualenv venv
$ source ./venv/bin/activate
$ pip install Django==1.11.1 statsd==3.2.1
$ django-admin.py startproject olympus .
These two lines of Django settings ./olympus/settings.py configure a default StatsD client
that is used in the "say_hello" Django view.
# statsd_exporter daemon listens to UDP at localhost:8125
STATSD_HOST = 'localhost'
STATSD_PORT = 8125
Assuming "say_hello" is available at "/hello" URL path, we can start a web server.
$ python manage.py runserver
$ curl http://localhost:8000/hello
Hello, World!
The Olympus application is ready to emit metrics. To make sure this is the case,
we can use tcpdump to capture UDP packets on loopback interface on port 8125
and print each packet in ASCII.
$ tcpdump -i lo0 udp port 8125 -A
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes
11:19:05.460810 IP localhost.57776 > localhost.8125: UDP, length 24
E..4....@................ .3hello.requests.total:1|c
As we can see, "hello.requests.total:1|c" is sent every time we hit http://localhost:8000/hello.
StatsD Exporter
Since we have StatsD metrics being sent, we can expose them for Prometheus via statsd_exporter.
Let's download the latest version and install it (the binary will be in "$GOPATH/bin/").
$ go get -u github.com/prometheus/statsd_exporter
Run statsd_exporter so it gets StatsD metrics from our Django application.
$ statsd_exporter -statsd.listen-address="localhost:8125"
By default it exposes generated Prometheus metrics at http://localhost:9102/metrics.
Check out the output, among many metrics there will be our counter from "say_hello" view.
# HELP hello_requests_total_counter Metric autogenerated by statsd_exporter.
# TYPE hello_requests_total_counter counter
hello_requests_total_counter 2
Run Everything on Kubernetes
Of course we will deploy everything on Kubernetes.
Minikube will help us here.
Minukube is an easy way to run Kubernetes locally.
When we want to build a Docker image in Minukube (so Kubernetes has an access to it),
we can configure our Docker client to communicate with the Minikube Docker daemon.
$ minikube start
Starting local Kubernetes cluster...
Kubectl is now configured to use the cluster.
$ eval $(minikube docker-env)
Django application
First, we shall deploy our Django application with statsd_exporter running in the same Kubernetes Pod.
It exposes 8000 (uWSGI) and 9102 (statsd_exporter's generated Prometheus metrics) container ports.
$ docker build -t marselester/olympus:v1.0.0 ./olympus-app/
$ kubectl apply -f ./kube/olympus-app/deployment.yml
$ kubectl apply -f ./kube/olympus-app/service.yml
Though we don't need Nginx in the demo, it's ubiquitous on production servers.
Nginx proxies HTTP requests using uWSGI protocol to "olympus-service" Kubernetes Service
we created above.
$ kubectl create configmap olympus-nginx-conf --from-file=./kube/nginx/olympus.conf
$ kubectl apply -f ./kube/nginx/deployment.yml
Prometheus
Next is Prometheus server's turn to be deployed. It is configured to scrape
own metrics from 9102 port and metrics from Pods that have "app: olympus" label.
Prometheus server listens on port 9090. On production servers you'll likely run
it behind Nginx with basic authentication and make it accessible via VPN only.
$ kubectl create configmap prometheus-server-conf --from-file=./kube/prometheus/prometheus.yml
$ kubectl apply -f ./kube/prometheus/deployment.yml
But in our case we'll use Kubernetes port forwarding to test whether Django
metrics show up in Prometheus dashboard.
$ kubectl port-forward nginx-deployment-3580857522-tn332 8080:80
$ kubectl port-forward prometheus-deployment-2456821496-8zdg8 9090
$ curl http://localhost:8080/hello
Hello, World!
"hello_requests_total_counter" should be searchable at the expression browser
http://localhost:9090/graph.
Prometheus Helm Chart
There are other ways to install Prometheus on Kubernetes:
Prometheus Operator and Helm look awesome, though I have not played with Operator yet.
Here is how you can set up Prometheus via Helm (package manager for Kubernetes).
You will need the Helm client
$ brew install kubernetes-helm
and Helm server (Tiller). The following command installs it into the Kubernetes cluster.
Now you can install Prometheus Helm package (chart).
$ helm repo update
$ helm install --name team-ops stable/prometheus
Nice, we have full-blown Prometheus "team-ops" chart release running
with alert manager and node exporter.
$ helm list
NAME REVISION UPDATED STATUS CHART NAMESPACE
team-ops 1 Thu Jun 8 21:40:29 2017 DEPLOYED prometheus-3.0.2 default
Let's add one more Prometheus to the cluster (call it "team-dev"),
but this time we want only Prometheus server with a custom prometheus.yml config.
$ helm install --name team-dev \
--set alertmanager.enabled=false \
--set kubeStateMetrics.enabled=false \
--set nodeExporter.enabled=false \
stable/prometheus
The config is stored in "team-dev-prometheus-server" ConfigMap.
Let's overwrite it with our prometheus.yml.
$ kubectl create configmap team-dev-prometheus-server \
--from-file=./kube/prometheus/prometheus.yml \
-o yaml \
--dry-run | kubectl replace -f -
To see whether "team-dev" Prometheus started, we can run a port forwarding:
$ kubectl port-forward team-dev-prometheus-server-4131857549-c98j0 9091:9090
Prometheus "team-dev" release is accessible at http://localhost:9091/graph.
I hope this helps. Cheers!
comments
Minukube & Amazon EC2 Container Registry
Minukube is an easy way to run Kubernetes locally.
When we want to build a Docker image in Minukube (so Kubernetes has an access to it),
we can configure our Docker client to communicate with the Minikube Docker daemon.
$ minikube start
Starting local Kubernetes cluster...
Kubectl is now configured to …
comments
Read More
Prometheus on Kubernetes
Prometheus is a monitoring toolkit.
Let's set it up on Kubernetes and test how it works by scraping HTTP request metrics
from hello web application
which also runs in the same cluster.
First of all, we need Kubernetes cluster running. It's easy to bootstrap one via Google Container Engine.
comments
Read More
Django REST framework: pagination on PostgreSQL triggers
Django and Django REST Framework use SQL COUNT in pagination.
As your database grows SQL COUNT becomes too slow. Fortunately the frameworks
are well designed and allow to customize a way items are count.
Let me illustrate that on a typical "books" example.
class Author(models.Model):
name = models.CharField …
comments
Read More
API based on Flask
Here I want to consider implementation of API best practices which
usually don't follow Fielding's REST strictly. Example Flask project
is on GitHub.
API Versioning
Interfaces are changed hence versioning is mandatory in order to not annoy
your users. You might need to add new resource or field to particular …
comments
Read More
Slides about SaltStack
Update I gave a talk with Simon Robson at Beercamp in Chiang Mai,
Thailand on 12 Dec 2013. We compared Salt and Ansible.
Here are my slides.
comments
Read More
Developing & Deploying Django project with SaltStack
Eventually you will need to deploy project,
but deployment was not considered in the previous post. Let's find it out.
Server configuration is different from local, thus environments will be needed
(at least production prod and development dev). Salt uses base
environment by default.
Environments are set in minion.conf …
comments
Read More
Developing Django project with SaltStack
Let's use Messaging System as an example of Django project. I want it to
run in VirtualBox which is managed by Vagrant. Infrastructure management
is provided by SaltStack.
I advise you to create separate folder for repositories (currently there
is only one) of project and clone Messaging System there.
Also …
comments
Read More
Python Developer at Uploadcare
I started to look for a full-time remote job as a Python Developer after
FanGid contract has been ended. And I found what
I was looking for -- Uploadcare, a cloud-based
file upload SaaS -- great team,
appropriate development process, adherence to quality standards.
I started to work at Uploadcare from tasks …
comments
Read More
Preparation to Python Interview
I decided to collect a little more information and experience during
preparation to Python developer interview. These are some information and
links which seemed important to me. Maybe it will be helpful.
How does it usually go?
What kind of projects did you participate in?
What did you do at …
comments
Read More
Стартап fangid.com
В середине июля 2012 г. команда стартапа fangid.com
приступила к воплощению идеи социальной концертной платформы на севере
Таиланда. Я занимался подготовительными работами (соглашениями по разработке,
первоначальной подготовкой репозитория, например, продумыванием структуры,
организацией тестов, разделением настроек), принимал участие в выработке
требований к системе и проектировании архитектуры. При конструировании системы
моими …
comments
Read More
Портфолио 2007–2011
Не стал перечислять те сайты, которые за давностью лет были переделаны либо
перестали существовать. В основном backend основан на cms myscon, которая была
переписана мною несколько раз.
2011
- электронный архив ежемесячного литературно-публицистического журнала
«Агидель» на Django. Предполагается, что ресурс будет содержать архив
журналов с 1923 года. Для удобной навигации сделал …
comments
Read More
Django TODO: тестирование во время конструирования
Тестирование, выполняемое разработчиками -- один из важнейших элементов полной
стратегии тестирования.
Тестирование может указать только на отдельные дефектные области программы --
оно не сделает программу удобнее в использовании, более быстрой, компактной,
удобочитаемой или расширяемой.
Цель тестирования противоположна целям других этапов разработки. Его целью
является нахождение ошибок. Успешным считается тест, нарушающий работу ПО …
comments
Read More
Django TODO: конструирование системы
При работе над проектом конструирование включает другие процессы, в том числе
проектирование. Формальная архитектура дает ответы только на вопросы
системного уровня, при этом значительная часть проектирования может быть
намеренно оставлена на этап конструирования. Проектирование -- это
"постепенный" процесс. Проекты приложений не возникают в умах разработчиков
сразу в готовом виде. Они развиваются …
comments
Read More
Django TODO: проектирование архитектуры системы
Следующим этапом разработки системы является проектирование архитектуры.
Архитектура должна быть продуманным концептуальным целым. Главный тезис самой
популярной книги по разработке ПО "Мифический человеко-месяц" гласит, что
основной проблемой, характерной для крупных систем, является поддержание их
концептуальной целостности. Хорошая архитектура должна соответствовать
проблеме .
Разделение системы на подсистемы на уровне архитектуры, позволяет …
comments
Read More
Django TODO: выработка требований к системе
После прочтения Макконелла захотелось спроецировать его советы на Django.
Для этого я взял за основу разработку системы Django TODO. Итак, первый этап -- выработка требований к
системе.
Требования подробно описывают, что должна делать система. Внимание к
требованиям помогает свести к минимуму изменения системы после начала
разработки. Явные требования помогают гарантировать, что …
comments
Read More
Соглашения по разработке на Python/Django
Во время разработки я часто сверяюсь с известными мне соглашениями,
стараюсь следовать рекомендациям. Цитировать их не имеет смысла -- лучше
приведу ссылки.
PEP 8 -- Style Guide for Python Code.
Code Like a Pythonista: Idiomatic Python.
В нем я нашел ответы на вопросы форматирования длинных строк:
expended_time = (self.finish_date() - self.start_date
+ datetime …
comments
Read More
Разделение настроек в Django
В Django wiki собраны
различные способы разделения настроек. Мне нравится вариант, описанный в блоге
Senko Rašić:
settings/
├── __init__.py
├── base.py
├── development.py
├── local.py
└── production.py
base.py содержит общие настройки для development.py и
production.py, например:
ADMINS = ()
MANAGERS = ADMINS
TIME_ZONE = 'Asia/Yekaterinburg'
# ...
production.py содержит настройки для …
comments
Read More
Краткий обзор инфраструктуры для разработки reusable Django приложений
Начиная впервые разрабатывать веб-приложения на новом фреймворке программист
зачастую сталкивается с некоторыми трудностями. При разработке отчуждаемых
веб-приложений на Django к этим проблемам необходимо отнести организацию
файлов в проекте, обнаружение тестов, вопросы пакетирования приложений и
организации автоматизированного тестирования. В данной статье приведены пути
решения этих проблем.
Важно знать различия между двумя …
comments
Read More
Вычислительные методы одномерной оптимизации
На третьем курсе по предмету методы оптимизации делали лабораторную работу на
тему «Вычислительные методы одномерной оптимизации».
Задача заключалась в поиске безусловного минимума функции
f(x) = pow(x, 3) – x + pow(e, -x) на начальном интервале [0, 1]
с точностью 0.00001.
Вычисления производились через:
- пассивный метод;
- равномерные блочные методы;
- метод …
comments
Read More
Определение нажатия комбинации клавиш средствами BIOS на ассемблере
По учебе понадобилось написать программу на ассемблере, которая должна
распознать нажатие «горячей» комбинации клавиш LeftCtrl+RightShift+F3 и
реагировать на него звуковым сигналом. Информации/примеров по этой теме
маловато, по этому решил опубликовать свою программку.
masm
.model small
.stack 256
.data
Msg_about db 'Распознать нажатие «горячей» комбинации клавиш', 0Ah, 0Dh …
comments
Read More
Моделирование одноканальной СМО с отказами
Дана одноканальная система массового обслуживания с отказами. В нее поступают
заявки через промежуток времени n, где n – случайная величина,
подчиненная равномерному закону распределения. Время обслуживания заявки
системой m также является случайной величиной с показательным законом
распределения. Если к моменту прихода заявки канал занят, заявка покидает
систему необслуженной.
Изначально код был …
comments
Read More