← Назад к вопросам

Куда обычно пишешь логи?

2.0 Middle🔥 141 комментариев
#Другое#Основы Go

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Стратегия логирования в Go: куда и как писать логи

В Go, в отличие от некоторых других языков, нет встроенного комплексного решения для логирования, что дает разработчику гибкость, но и накладывает ответственность за выбор правильного подхода. Я, как Senior Go Developer, придерживаюсь многоуровневой стратегии, основанной на типе информации, окружении и требованиях к мониторингу.

1. Стандартные потоки вывода: stdout и stderr

Это основной и наиболее идиоматичный канал для логов приложения в Go. Современные best practices для контейнеризированных и облачных приложений диктуют отправку всех логов в стандартные потоки.

  • Для чего использовать: Все логи приложения: информационные сообщения, предупреждения, ошибки.
  • Как реализовать: Используйте встроенный пакет log. Для ротации и управления файлами в production используются не возможности самого приложения, а внешние инструменты (Docker, systemd, k8s).
package main

import (
    "log"
    "os"
)

func main() {
    // Логи в stderr (стандартное поведение пакета log)
    log.Println("Запуск приложения...")

    // Или явно настраиваем вывод
    logger := log.New(os.Stdout, "MYAPP: ", log.Ldate|log.Ltime|log.Lshortfile)
    logger.Printf("Обработка запроса ID: %d", 42)
}

Почему stdout/stderr, а не файлы напрямую? Потому что оркестраторы (Kubernetes, Docker) захватывают эти потоки, обеспечивают ротацию, агрегацию и перенаправление в централизованные системы (Loki, Elasticsearch, Cloud Logging). Ваше приложение становится проще и переносимее.

2. Структурированное логирование с использованием специализированных библиотек

Для production-систем я практически всегда использую библиотеки структурированного логирования. Они пишут в stdout, но в машиночитаемом формате (JSON), что критически важно для анализа.

  • Популярные библиотеки: Zap от Uber (высокая производительность), Slog (новый стандартный пакет с Go 1.21), zerolog, logrus.
  • Преимущества: Добавляют контекст (поля), уровни логирования (Debug, Info, Warn, Error), облегчают фильтрацию и алертинг.
// Пример с slog (стандартный пакет с Go 1.21)
package main

import (
    "log/slog"
    "os"
)

func main() {
    // Настройка JSON-вывода в stdout
    logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
    slog.SetDefault(logger) // Устанавливаем глобальный логгер

    // Лог с контекстом (полями)
    slog.Info("обработка пользователя",
        "user_id", 12345,
        "action", "payment",
        "amount", 2999.90,
    )

    slog.Warn("неоптимальный запрос к БД", "duration_ms", 1500)
    slog.Error("не удалось подключиться к внешнему API", "err", err)
}

3. Специализированные каналы для различных типов данных

Важно разделять логи (описание событий) и метрики (числовые показатели) / трейсы (распределенная отладка).

  1. Метрики (Metrics): Отправляются в системы мониторинга, такие как Prometheus, а не в логи. Используются для алертинга и построения графиков (CPU, память, latency, QPS).

    // Используется пакет github.com/prometheus/client_golang
    httpRequestsTotal.WithLabelValues("200", "/api/v1/user").Inc()
    
  2. Трассировка (Distributed Tracing): Отправляется в системы типа Jaeger или OpenTelemetry для отслеживания пути запроса через микросервисы.

    // Используется пакет go.opentelemetry.io/otel/trace
    ctx, span := tracer.Start(ctx, "handleRequest")
    defer span.End()
    
  3. Критические ошибки (Alerts): Для немедленного реагирования логи уровня ERROR и FATAL из структурированных логов настраиваются алерты в системах типа Grafana, Datadog или PagerDuty.

4. Файлы (Legacy и специфичные случаи)

Запись непосредственно в файлы используется реже, но может быть оправдана:

  • Legacy-системы, развернутые на физических серверах без оркестратора.
  • Аудит-логи со строгими требованиями к сохранности и немодифицируемости. Их часто пишут в отдельный, защищенный файл или напрямую в безопасное хранилище.
  • Логи для дебага локальной разработки.
file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
    log.Fatal(err)
}
defer file.Close()
fileLogger := log.New(file, "AUDIT: ", log.LstdFlags)
fileLogger.Println("Пользователь admin изменил права доступа")

Итоговая архитектура логирования в production

  1. Приложение генерирует структурированные (JSON) логи и направляет их в stdout/stderr.
  2. Агент (Fluentd, Promtail, Filebeat) в контейнере или на ноде собирает эти логи и отправляет в центральный агрегатор.
  3. Агрегатор (Loki, Elastic Stack, облачный logging) индексирует и хранит логи.
  4. Дашборды (Grafana, Kibana) используются для просмотра и анализа.
  5. Система алертинга мониторит логи на предмет ошибок и SLA-нарушений.
  6. Метрики и трейсы отправляются по своим каналам (Prometheus, Jaeger) и коррелируются с логами через общие идентификаторы (например, trace_id).

Таким образом, ответ на вопрос "куда писать логи" — это на stdout в структурированном виде, но с четким пониманием полного пайплайна, который превращает эти сырые данные в ценную информацию для разработчиков, DevOps и бизнеса. Выбор конкретной библиотеки (slog, zap) и бэкенда (Loki, Elastic) зависит от требований проекта к производительности, функциям и инфраструктуре.

Куда обычно пишешь логи? | PrepBro