Привет всем!  Я хочу поделиться с вами тем, как легко можно написать свой экспортер для Prometheus на Golang и покажу как это можно сделать на примере небольшой программы, которая следит за тем, откуда географически установлены текущие TCP соединения. Хотелось бы сразу в самом начале очертить, так сказать, scope данной публикации и сказать про что она не рассказывает, чтобы потом не возникло вопросов: Итак, первое, что нам необходимо сделать — написать экспортер, который собственно будет собирать данные с нашего сервера и отдавать их в Prometheus. Выбор языков здесь велик: Prometheus имеет клиентские библиотеки для написания экспортеров на многих популярных языках, но я выбрал Go, во-первых, потому что так "нативнее" (раз уж сам Prometheus на нем написан), ну а во-вторых поскольку сам им пользуюсь в своей DevOps практике. Ну довольно лирики, давайте приступим к коду. Начнем писать "снизу вверх": сначала функции для определения страны по IP и самого списка удаленных IP адресов, а потом уже отправка всего этого в Prometheus. Ну тут совсем все в лоб, я не стал мудрствовать и просто воспользовался сервисом freegeoip.net, API которого к моменту написания данной статьи уже стал deprecated, и теперь они предлагают бесплатно зарегистрироваться и иметь возможность делать 10,000 запросов в месяц (что для наших целей достаточно). Тут все просто: есть endpoint вида http://api.ipstack.com/<IP>?access_key=<API_KEY>, который просто нам вернет json с нужным нам полем country_code — это все, что нам потебуется для визуализации.
Итак, напишем пакет для выдергивания страны по IP.  Обратите внимание на параметр legacy=1, мне приходится его использовать для обратной совметимости; вы, конечно, если будете использовать их API, пользуйтесь последней версией. Здесь воспользуемя пакетом github.com/shirou/gopsutil/net и отфильтруем соединения со статусом ESTABLISHED, исключив локальные IP-адреса и адреса из кастомного black-листа, который можно передать экспортеру при запуске (например, чтобы исключить все ваши собственные публичные IP адреса) Точнее, он сам все заберет. Просто будем слушать порт и отдавать на нем собранные метрики.
Используя github.com/prometheus/client_golang/prometheus создадим метрику типа Gauge. На самом деле, можно было создать и Counter, просто потом мы бы при запросах к базе использовали бы rate. Возможно, последнее с точки зрения Prometheus эффективнее, но в то время как я писал этот экспортер (полгода назад) я только начинал знакомство с Prometheus и для меня было достаточно Gauge: Собрав метрики с помощью предыдущих пунктов, обновляем наш вектор: Все это запускаем бесконечным циклом в отдельной горутине, а в основной просто биндим порт и ждем пока наши метрики заберет Prometheus: Собственно, весь код можно посмотреть в репозитории на GitHub, не хочется здесь копипастить все подряд. Но для начала, конечно же, нужно сообщить Prometheus'у, чтобы тот собирал наши метрики: (либо используя service discovery, если у вас, например, Kubernetes). Prometheus можно заставить перечитать конфиг, послав ему сигнал HUP: Сходим к нему в UI и проверим, что метрики собираются:  Отлично, теперь очередь Grafan'ы. Воспользуемся плагином grafana-worldmap-panel, который нужно предварительно установить: Далее идем к ней в UI и жмем add panel -> Worldmap Panel. Во вкладке Metrics вводим следующий запрос: И указываем legend format: {{location}}. Выглядеть все должно примерно так:    Далее переходим во вкладку Worldmap и настраиваем все как на скриншоте:   И все! Наслаждаемся нашей картой. Вот таким несложным образом можно сделать красивую карту соединений в Grafan'е.  Спасибо за внимание и жду ваших комментариев. Конечно, чтобы использовать инструмент по назначению, нужно его доделать: отфильтровывать адреса локальных подсетей и многое другое. Кстати, если кто заинтересовался и хочет развивать этот экспортер — добро пожаловать в репозиторий на GitHub! DevOps Engineer