Комментарии (3)
Ответ сгенерирован нейросетью и может содержать ошибки
Стратегия логирования в Go-приложениях
В Go-приложениях я использую многоуровневую стратегию логирования, которая зависит от среды выполнения, типа информации и требований к наблюдаемости (observability). Вот ключевые направления:
1. Стандартные потоки (stdout/stderr) для контейнеризованных приложений
Для современных микросервисных архитектур и Docker-контейнеров основной подход — запись в стандартные потоки:
package main
import (
"log"
"os"
)
func main() {
// Для информации - stdout
log.Println("Запуск сервиса пользователей v1.2.3")
// Для ошибок - stderr
log.SetOutput(os.Stderr)
log.Println("ERROR: Не удалось подключиться к БД")
}
Преимущества:
- Docker и оркестраторы (Kubernetes) автоматически собирают логи из stdout/stderr
- Централизованный сбор в системы типа ELK Stack, Loki, Datadog
- Стандартизация подхода для всех сервисов
2. Структурированное логирование (Structured Logging)
Для машинно-читаемого формата использую библиотеки с поддержкой JSON-формата:
import (
"github.com/sirupsen/logrus"
"github.com/rs/zerolog"
)
// Пример с logrus
func logWithLogrus() {
log := logrus.New()
log.SetFormatter(&logrus.JSONFormatter{})
log.WithFields(logrus.Fields{
"user_id": "12345",
"event": "login",
"ip": "192.168.1.1",
}).Info("Пользователь вошел в систему")
}
// Пример с zerolog (более производительный)
func logWithZerolog() {
log := zerolog.New(os.Stdout).With().Timestamp().Logger()
log.Info().
Str("service", "auth").
Int("duration_ms", 125).
Msg("Запрос обработан")
}
3. Многоуровневое логирование с контекстом
Для разных сред выполнения настраиваю разные уровни детализации:
// Конфигурация уровней логирования
type LogConfig struct {
Level string `env:"LOG_LEVEL" default:"info"`
Format string `env:"LOG_FORMAT" default:"json"`
AddSource bool `env:"LOG_SOURCE" default:"false"`
}
func setupLogger(cfg LogConfig) {
switch cfg.Level {
case "debug":
log.SetLevel(logrus.DebugLevel)
case "warn":
log.SetLevel(logrus.WarnLevel)
case "error":
log.SetLevel(logrus.ErrorLevel)
default:
log.SetLevel(logrus.InfoLevel)
}
if cfg.Format == "text" && cfg.AddSource {
log.SetReportCaller(true) // Добавляем информацию о месте вызова
}
}
4. Направления для разных типов логов
В зависимости от типа данных применяю различные стратегии:
-
Метрики производительности → OpenTelemetry + Prometheus
import "go.opentelemetry.io/otel" func processRequest(ctx context.Context) { tracer := otel.Tracer("auth-service") ctx, span := tracer.Start(ctx, "validate-token") defer span.End() // Логика обработки span.SetAttributes(attribute.Int("token.length", len(token))) } -
Бизнес-события (аудиты) → отдельные структурированные логи или специализированные хранилища (ClickHouse для аналитики)
-
Критические ошибки → дублирование в Sentry/Rollbar для алертинга
-
Доступ (access logs) → отдельный формат с обязательными полями (HTTP-метод, путь, статус, длительность)
5. Локальная разработка vs Продакшен
Для локальной разработки:
- Текстовый формат с цветовым выделением
- Подробный уровень debug
- Запись в файл для отладки сложных сценариев
- Pretty print для JSON-ответов
Для продакшена:
- Только JSON-формат для парсинга системами
- Уровень по умолчанию info, debug — только при проблемах
- Обязательное добавление:
timestampв UTCservice_nameиversiontrace_idдля корреляции запросовenvironment(prod/staging)
6. Продвинутые сценарии
Для enterprise-приложений добавляю:
// Распределенное логирование с трейсингом
func handlerWithContext(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
logger := log.WithContext(ctx) // Логгер наследует trace_id из контекста
logger.Info("Начало обработки запроса")
// Автоматическое логирование паник
defer func() {
if err := recover(); err != nil {
logger.WithField("panic", err).
Error("Паника восстановлена")
panic(err) // Или обработка
}
}()
}
Ключевые принципы, которых придерживаюсь:
- Never lose logs — логи никогда не должны теряться, даже при падениях
- Performance matters — асинхронная запись при высокой нагрузке через буферизацию
- Sensitive data — маскирование PII данных (пароли, токены, персональные данные)
- Rotation & retention — ротация логов по размеру/времени, политики хранения
- Correlation IDs — сквозные идентификаторы для трассировки запроса через все сервисы
Итоговый стек, который обычно применяю:
- Zerolog или logrus для структурированного логирования
- OpenTelemetry для трассировки и метрик
- Fluentd/Fluent Bit для сбора и пересылки логов в контейнеризованных средах
- Loki или ELK для хранения и поиска
- AlertManager + Sentry для реагирования на ошибки
Такой подход обеспечивает полную наблюдаемость, производительность и удобство отладки как на локальных машинах разработчиков, так и в масштабируемых продакшен-средах.