Мониторинг Go-приложений: 3 инструмента для логирования и трейсинга

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему ваше Go-приложение молчит, и как это исправить?

Вы написали идеальный микросервис на Go. Он проходит все тесты, быстро стартует и потребляет копейки памяти. Вы выкатываете его в прод — и через час пользователи жалуются на тормоза. Вы заходите на сервер, смотрите на пустой терминал и понимаете: приложение молчит. Нет логов, нет метрик, нет понимания, что пошло не так.

Знакомая ситуация? Добро пожаловать в мир observability (наблюдаемости) Go-приложений. Без мониторинга и логирования ваш код — это чёрный ящик. Сегодня мы разберём, как превратить его в прозрачную систему, где каждая задержка и каждая ошибка видны как на ладони.

Я покажу три рабочих инструмента, реальные примеры кода на Go и дам чек-лист, который спасёт ваш продакшн. Поехали!

1. Структурированное логирование: как перестать писать в консоль и начать жить

Наивное fmt.Println("Ошибка:", err) — это прошлый век. В современном логировании Go нужен порядок: JSON-формат, уровни (debug, info, warn, error), поля для поиска. Встречайте короля — библиотеку zap от Uber.

Почему именно zap?

  • Скорость: он быстрее стандартного log в 10-100 раз на высоких нагрузках.
  • Структура: вы добавляете ключи и значения, а не лепите строки через плюс.
  • Гибкость: можно писать в файл, в stdout, в Elasticsearch — куда угодно.

Установка и базовый пример

go get -u go.uber.org/zap

Код простого логгера:

package main

import (
    "go.uber.org/zap"
)

func main() {
    logger, _ := zap.NewProduction()
    defer logger.Sync() // сбрасываем буфер перед выходом

    logger.Info("Сервис запущен",
        zap.String("env", "production"),
        zap.Int("port", 8080),
    )

    // Пример с ошибкой
    err := someFunction()
    if err != nil {
        logger.Error("Не удалось выполнить операцию",
            zap.Error(err),
            zap.String("module", "database"),
        )
    }
}

На выходе вы получаете чистый JSON:

{"level":"info","ts":1700000000.123,"msg":"Сервис запущен","env":"production","port":8080}

Теперь любой инструмент вроде Kibana или Grafana Loki сможет разобрать эти логи по полям. Хотите найти все ошибки в модуле "database" за последний час? Один клик.

Совет: не логируйте секреты и PII

Добавьте проверку: если поле содержит пароль или email — маскируйте его. Используйте zap.String("user", "***") для чувствительных данных.

2. Метрики и мониторинг: превращаем код в дашборд

Логи — это хорошо, но они говорят о прошлом. Метрики — это пульс вашего приложения в реальном времени. Для мониторинга Go приложений стандарт де-факто — Prometheus + его клиентская библиотека.

Что измерять?

  • RPS (запросов в секунду) — нагрузка на сервис.
  • Latency (p50, p95, p99) — время ответа.
  • Error rate — процент ошибок.
  • Goroutines — утечки горутин.
  • Memory / CPU — ресурсы.

Пример: добавляем метрики HTTP-сервера

package main

import (
    "net/http"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
    requestCount = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "http_requests_total",
            Help: "Total number of HTTP requests",
        },
        []string{"method", "endpoint", "status"},
    )
    requestDuration = prometheus.NewHistogramVec(
        prometheus.HistogramOpts{
            Name:    "http_request_duration_seconds",
            Help:    "Duration of HTTP requests in seconds",
            Buckets: prometheus.DefBuckets,
        },
        []string{"method", "endpoint"},
    )
)

func init() {
    prometheus.MustRegister(requestCount)
    prometheus.MustRegister(requestDuration)
}

func main() {
    // Middleware для подсчёта
    handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        timer := prometheus.NewTimer(requestDuration.WithLabelValues(r.Method, r.URL.Path))
        defer timer.ObserveDuration()

        // ваша логика
        w.WriteHeader(http.StatusOK)
        w.Write([]byte("Hello, observability!"))

        requestCount.WithLabelValues(r.Method, r.URL.Path, "200").Inc()
    })

    http.Handle("/metrics", promhttp.Handler())
    http.Handle("/", handler)

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

Теперь по адресу /metrics Prometheus будет собирать данные. Добавьте Grafana — и вы увидите живые графики. А alerts в Prometheus (например, если error rate > 5%) отправят уведомление в Telegram.

3. Трейсинг: находим иголку в стоге микросервисов

Когда у вас 10 Go-сервисов, логов и метрик уже мало. Запрос проходит через API Gateway → Auth → Core → DB. Где тормоз? Без трейсинга вы будете гадать. Трейсинг Go (распределённая трассировка) рисует карту всего пути запроса.

Инструменты: OpenTelemetry + Jaeger

OpenTelemetry — это стандарт. Он собирает spans (единицы работы) и отправляет их в Jaeger или Zipkin.

Пример: трейсинг HTTP-запроса

package main

import (
    "context"
    "log"
    "net/http"
    "time"

    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/attribute"
    "go.opentelemetry.io/otel/exporters/jaeger"
    "go.opentelemetry.io/otel/sdk/resource"
    sdktrace "go.opentelemetry.io/otel/sdk/trace"
    semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
    "go.opentelemetry.io/otel/trace"
)

func initTracer() (*sdktrace.TracerProvider, error) {
    exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint("http://localhost:14268/api/traces")))
    if err != nil {
        return nil, err
    }
    tp := sdktrace.NewTracerProvider(
        sdktrace.WithBatcher(exp),
        sdktrace.WithResource(resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String("my-go-service"),
        )),
    )
    otel.SetTracerProvider(tp)
    return tp, nil
}

func main() {
    tp, err := initTracer()
    if err != nil {
        log.Fatal(err)                

Блоги

Рекомендаций по книгам