Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

Урок 3 из 25 ~18 мин +20 XP

client_golang: первый /metrics endpoint

client_golang — официальный клиент Prometheus для Go: после go get и одной строки с promhttp.Handler() ваш сервис отдаёт страницу /metrics с десятками готовых метрик. Разберём установку, минимальный сервер и что уже видно на endpoint до первой собственной метрики.

Содержание урока · 10 разделов

Порог входа в мониторинг — то, что продаёт его скептикам: пять строк, и сервис наблюдаем. Никаких агентов, брокеров и отдельных баз: библиотека ставится одной командой, регистрируется в стандартном net/http, а на /metrics уже живёт дюжина метрик, которые вам не надо писать. План урока такой: сначала установка client_golang и минимальный сервер, потом смотрим, что отдаёт endpoint из коробки, и разбираем, как promhttp устроен внутри, чтобы при проблемах знать, куда смотреть. Все примеры — обычные программы net/http, поэтому в сервис на chi или gin они переносятся без единой правки.

Установка client_golang: две команды#

Начинаем с нового модуля. Первая команда — go mod init с именем модуля, вторая — go get github.com/prometheus/client_golang/prometheus: она добавит библиотеку в go.mod и подтянет зависимости. В коде пригодятся два пакета: prometheus — сами типы метрик и реестр, prometheus/promhttp — готовый HTTP-хендлер. Требования скромные: актуальный стабильный Go, никаких переменных окружения и внешних сервисов настраивать не надо. Про версии: библиотека живёт в первой мажорной версии, API стабилен, и код из документации компилируется годами — примеры не протухнут, даже если вернётесь к ним через год. После go get загляните в go.mod: на старте это одна запись, без десятков транзитивных зависимостей — клиент собран на стандартной библиотеке.

Минимальный сервис с /metrics

GO
package main

import (
        "net/http"

        "github.com/prometheus/client_golang/prometheus/promhttp"
)

func main() {
        http.Handle("/metrics", promhttp.Handler())

        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
                w.Write([]byte("привет"))
        })

        http.ListenAndServe(":8080", nil)
}

Весь секрет — строка http.Handle с promhttp.Handler(): это обычный http.Handler из стандартной библиотеки, без адаптеров и фреймворков. Хендлер отдаёт содержимое реестра по умолчанию, где уже зарегистрированы коллекторы Go-процесса и процесса операционной системы. Запуск — go run ., после чего страница доступна на localhost:8080/metrics.

Что уже видно на /metrics без вашего кода#

Разберём инцидент, с которого начинается половина историй про внедрение мониторинга. Сервис выставил /metrics, страница открывается в браузере, всё выглядит готовым — и команда уверена, что наблюдаемость есть. Через месяц падает база, заказы встают, а дежурный узнаёт об этом от поддержки: сервер Prometheus никто не настраивал, за метриками никто не приходил, страница просто молчала в пустоту. Ошибка тонкая: живой /metrics — половина контракта, вторая половина — кто-то, кто регулярно забирает данные. Поэтому первый чек после запуска сервиса — не браузер, а настройка цели: запись job в prometheus.yml и зелёная метрика up на стороне сервера. До урока про скрейпинг достаточно curl-а: страница отвечает на localhost — кодовая половина контракта выполнена, дальше её должен кто-то читать. А теперь откройте страницу и найдите строки, начинающиеся с go_ и process_ — это работа дефолтных коллекторов, которые client_golang регистрирует автоматически. go_goroutines — текущее число горутин; семейство go_memstats_* — память из runtime: выделено, занята куча, сколько отдал сборщику; go_gc_duration_seconds — длительности сборок мусора в виде гистограммы; process_cpu_seconds_total — процессорное время процесса; process_open_fds — открытые файловые дескрипторы; process_resident_memory_bytes — резидентная память. Для половины штатных вопросов — «не текут ли горутины», «сколько ест память», «не выжрали ли дескрипторы» — этих метрик хватает без единой строчки вашего кода. Остальное — собственные метрики домена: заказы, очереди, латентность вашей бизнес-логики. Их заведём со следующего урока, а пока важно другое: endpoint живой, формат читается, и это уже работающий мониторинг.

Метрики, на которые стоит взглянуть первыми#

  • go_goroutines — число горутин прямо сейчас; медленный рост к вечеру — первый симптом утечки.
  • go_memstats_heap_inuse_bytes — занятая куча: живая память под ваши данные.
  • go_gc_duration_seconds — гистограмма длительностей сборок мусора; хвосты растут под нагрузкой.
  • process_cpu_seconds_total — суммарное процессорное время процесса; счётчик, из которого считается загрузка.
  • process_open_fds — открытые дескрипторы; если не убывает после закрытия соединений, есть куда смотреть.
  • process_resident_memory_bytes — резидентная память процесса, как её видит операционная система.

Триста горутин — это много? Проверка curl-ом за пять минут#

Ошибка интерпретации, которая ждёт на самих числах. Человек открывает /metrics, видит go_goroutines 340 и пишет в чат: «горутин триста сорок, это утечка». Число без контекста не значит ничего: под пиком триста горутин — штатная работа пула воркеров, а в другом сервисе пятьдесят — катастрофа, если обычно их двадцать. Метрика становится сигналом только в динамике и относительно базы сравнения: рост на порядок за ночь при неизменном трафике — повод смотреть; стабильные триста при живом потоке — норма. Откуда берутся горутины и как их считать — отдельная наука, у нас для неё есть урок про конкурентность, а здесь достаточно правила: сырые значения дефолтных метрик — материал для графиков, а не для вердиктов. Сравнивайте значение с собственным прошлым — вчерашним утром, прошлым пик-часом — и только потом делайте выводы. Практическая вариация для закрепления — минимальный чек-лист после установки. Первый шаг — curl с ключом silent и просмотр первых строк: должны прийти комментарии HELP и TYPE, а не HTML-страница ошибки. Второй — grep по go_goroutines: если строки нет, что-то съело хендлер — чаще всего middleware, который отдал 404, или прокси, переписавший путь. Третий — убедиться, что страница отдаётся и с внешнего адреса, если Prometheus стоит на другой машине: localhost и имя хоста — разные адреса, и новички неделями ищут «потерянные» метрики, хотя сервис просто слушал внутренний интерфейс. Четвёртый — посмотреть Content-Type: текст с версией формата подтверждает, что отвечает именно promhttp, а не случайный хендлер. Пять минут, и у сервиса есть гарантированная точка, куда можно стучаться мониторингом.

promhttp.Handler(): что происходит на каждый запрос#

Разберём хендлер по слоям, чтобы при проблемах понимать, где искать. На каждый GET /metrics promhttp собирает значения: собирает все метрики реестра через Gatherer — по умолчанию DefaultGatherer, куда попадает всё, зарегистрированное через prometheus.MustRegister. Затем сериализует в текстовый формат экспозиции и отвечает с Content-Type text/plain; более компактный protobuf включается согласованием через заголовок Accept, но для человека и curl текст — вариант по умолчанию. Сбор происходит в момент запроса, а не в фоне: значение go_goroutines на странице — это значение прямо сейчас, поэтому scrape-интервал задаёт и разрешение ваших графиков. Отсюда практика: держите /metrics на том же порту, что и сервис, но следите за весом реестра — тысяча метрик с лейблами замедлит каждый скрейп; кардинальности посвящён отдельный урок второй половины курса.

Отдельный реестр: когда нужен контроль

GO
reg := prometheus.NewRegistry()

reg.MustRegister(collectors.NewGoCollector())

http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))

// процессные метрики появятся, только если
// зарегистрировать их отдельно:
reg.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}))

NewRegistry создаёт пустой реестр вместо дефолтного, а HandlerFor связывает хендлер именно с ним. Так собирают аккуратные страницы: только свои метрики, только Go-коллектор или несколько эндпоинтов с разным содержимым. Пакет collectors входит в client_golang; тему реестров и имён до конца разберёт урок про namespace, а дефолтные метрики — урок о встроенных метриках процесса.

Вариация: /metrics на отдельном порту#

Разбор реестров подводит к полезной вариации примера: второй порт для метрик. Идея в двух ListenAndServe: основной сервер слушает внешний 8080 и про метрики не знает, а второй, поднятый в горутине на localhost:9090, отдаёт только /metrics. Выигрыш двойной: экспозиция физически недоступна из интернета, минуя любые правила прокси, и скрейп не попадает в статистику основного роутера — серии не метят сами себя. Цена тоже понятна: два порта в конфигурации, две проверки в readiness, дисциплина в файрволе. В оркестраторах чаще оставляют один порт и закрывают путь сетевыми политиками; на виртуалках и в монолитах второй порт — самый дешёвый способ изолировать экспозицию. Выбор не принципиален, пока он осознанный: случайно открытый наружу endpoint дороже любой схемы, о чём врезка ниже.

Спорное мнение: часть дефолтных метрик можно отключить#

Спорное мнение на десерт: часть go_-метрик я отключаю в крупных сервисах, и это не ересь. Каждый скрейп собирает всё, что зарегистрировано: пятьдесят серий памяти, гистограмма сборок мусора, рантайм-бухгалтерия — на ферме из двухсот подов это тысячи серий, которые никто не открывает. В зрелых сервисах я оставляю go_goroutines, пару серий памяти и процессные дескрипторы, остальное убираю отдельным реестром, как показано выше, когда появляется конкретный потребитель. Граница, где я ограничиваю сам себя: пока сервис один и команды нет — не трогайте дефолт, бесплатная видимость важнее экономии серий. Отключение — инструмент зрелого мониторинга, у которого уже есть дашборды и алерты, а не первой недели проекта. Тему больших серий по-настоящему разберёт урок про кардинальность, а сегодня достаточно правила: сначала потребитель, потом отключение.

Проверка: содержимое дефолтного хендлера

Что отдаёт promhttp.Handler() сразу после запуска сервиса, до регистрации ваших метрик?

Проверка: Content-Type

Какой Content-Type у ответа /metrics по умолчанию?

Что вернёт несуществующий путь

Прочитайте код и выберите, что он выведет:

func main() {
        http.Handle("/metrics", promhttp.Handler())
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
                w.Write([]byte("привет"))
        })
        http.ListenAndServe(":8080", nil)
}

// запрос: GET /unknown

Соберите каркас сервиса

Восстановите путь импорта, регистрацию маршрута и создание хендлера.

package main import ( "net/http" "github.com/prometheus/client_golang//" ) func main() { http.("/metrics", promhttp.()) http.ListenAndServe(":8080", nil) }

Порядок команд в терминале

Расставьте команды от создания модуля до проверки метрик на живом сервере.

Строки

Ваша программа

Нажимайте на строки слева, чтобы собрать программу

Карточки: client_golang

Термин

client_golang

нажмите, чтобы перевернуть
Определение

Официальный клиент Prometheus для Go: типы метрик, реестры и promhttp. Ставится через go get github.com/prometheus/client_golang/prometheus.

1 / 6

Endpoint жив — теперь в него можно класть свои числа. Следующий урок — Counter: prometheus.NewCounter, MustRegister, Inc и Add на живом примере заказов, включая ловушки вроде обнуления при рестарте и паники на отрицательном Add. Позже — Gauge для текущих состояний и отдельный урок про встроенные метрики процесса, которые мелькали сегодня: горутины, память и сборки мусора разберём поимённо с советами, на что смотреть. Если сервис собран на chi, маршрут /metrics вписывается тем же http.Handle рядом с остальными — совместимость с net/http полная. Карта курса — на его странице; там же видно, где начнутся PromQL и Grafana, а пока цель одна: запустите сервис локально и убедитесь, что grep по go_goroutines что-то находит.

Песочница урока

Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.

Вывод

Запустите код, чтобы увидеть вывод.

Коротко: что запомнить

  • client_golang ставится двумя командами: go mod init и go get github.com/prometheus/client_golang/prometheus.
  • promhttp.Handler() — готовый http.Handler: вешается на /metrics и отдаёт реестр по умолчанию.
  • Из коробки идут метрики go_ и process_: горутины, память, сборки мусора, дескрипторы, процессорное время.
  • Сбор значений происходит на каждый скрейп: значения честные «прямо сейчас», интервал задаёт разрешение графиков.
  • NewRegistry и HandlerFor дают отдельный реестр, когда нужен контроль содержимого страницы.
  • /metrics не должен быть доступен из интернета: у promhttp нет авторизации.

Домашнее задание

Соберите сервис урока локально: go mod init, go get, go run. Убедитесь curl-ом, что /metrics отдаёт текст, а корень — привет; найдите на странице три метрики go_ и одну process_. Затем вынесите /metrics на отдельный порт вторым ListenAndServe в горутине и подумайте, какой вариант ближе к вашему продакшену.

Личные заметкиПусто
Хранятся только в вашем браузере (Prometheus · client_golang: первый /metrics endpoint)

Вопросы и ответы по уроку

Какая версия Go нужна для client_golang?

Актуальная стабильная: библиотека следует за релизами Go и не поддерживает старые. Требования видны в go.mod библиотеки; дополнительных инструментов ставить не нужно.

Почему на /metrics столько метрик, которых я не создавал?

client_golang автоматически регистрирует коллекторы Go-runtime и процесса: горутины, память, сборки мусора, дескрипторы, процессор. Это нормально и полезно; убрать их можно отдельным реестром или опциями коллекторов.

Как спрятать /metrics от внешних пользователей?

Внутренний интерфейс или отдельный порт, сетевые политики, reverse-proxy с запретом пути, в крайнем случае middleware с токеном. Внутри promhttp авторизации нет — открытый endpoint отдаёт устройство сервиса наружу.

Термины урока

Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.

Следующая ступень учебного пути

WebSocket25 уроков~13 чпрактика25 уроков уже доступны

WebSocket в Go: real-time чаты и уведомления

Курс WebSocket на Go: gorilla/websocket, эхо-сервер, hub-паттерн, комнаты, авторизация соединений, ping/pong, reconnect и масштабирование. 25 уроков.

  • Поднимать WS-сервер и апгрейдить HTTP-соединения
  • Писать readPump/writePump без гонок на каждое соединение
  • Строить hub: регистрацию, рассылку и комнаты
  • Авторизовывать соединения и ограничивать сообщения