В .NET 9 появилась интересная функциональность — Log Buffering, которая позволяет буферизовать логи в памяти и выводить их только при определенных условиях. Меня заинтересовала эта идея, что я решил реализовать аналогичный механизм для Go. Так появился EmitLog — пакет для условной буферизации логов.
Проблема традиционного логирования
Представьте типичный веб-сервис с детальным логированием:
func ProcessPayment(ctx context.Context, paymentID string) error { log.Debug("Starting payment processing") log.Debug("Validating payment data") log.Debug("Checking user balance") log.Debug("Connecting to payment gateway") log.Info("Payment processed successfully") return nil }
При высокой нагрузке такой сервис генерирует огромное количество логов:
99% успешных транзакций = миллионы ненужных debug-логов
Высокие расходы на хранение в системах типа ELK, Datadog
Замедление поиска важной информации в море рутинных записей
Но если убрать debug-логи совсем, то при ошибке мы потеряем контекст происходящего.
Решение: условная буферизация
EmitLog решает эту дилемму:
Буферизует все логи запроса в памяти
Анализирует результат выполнения
Решает — сохранить логи или отбросить
// При ошибке — видим полный контекст [ERROR] Payment failed: insufficient funds [DEBUG] Starting payment processing [DEBUG] Validating payment data [DEBUG] Checking user balance [INFO] User balance: $50, required: $100 // При успехе — логи отбрасываются (или сохраняются с вероятностью 5%)
Цепочка контекста логирования
Вот как выглядит полный flow:
HTTP Request → Middleware создает BufferingWriter ↓ Создает logger с контекстом запроса ↓ Logger помещается в context.Context ↓ Handler извлекает logger: GetLoggerFromContext(ctx) ↓ Все логи пишутся в буфер в памяти ↓ [Возникла ошибка?] ↙ ↘ Да Нет ↓ ↓ Flush всех [Random < SaveRate?] логов ↙ ↘ Да Нет ↓ ↓ Сохранить Отбросить
Практическое использование
Базовая настройка
func main() { // Настраиваем zerolog log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) // Конфигурация EmitLog config := emitlog.Config{ SaveRate: 10.0, // 10% успешных запросов BufferingEnabled: true, FlushOnError: true, // Всегда при ошибках FlushOnWarn: false, // Игнорируем warnings BufferSize: 64 * 1024, // 64KB на запрос } // Применяем middleware handler := emitlog.Middleware(config, os.Stderr)(mux) http.ListenAndServe(":8080", handler) }
Использование в хендлерах
func ProcessOrderHandler(w http.ResponseWriter, r *http.Request) { // Извлекаем настроенный logger из контекста logger := emitlog.GetLoggerFromContext(r.Context()) logger.Debug().Msg("Parsing order request") var order Order if err := json.NewDecoder(r.Body).Decode(&order); err != nil { logger.Error().Err(err).Msg("Failed to parse order") http.Error(w, "Bad request", 400) return // Все debug-логи будут выведены! } logger.Debug(). Str("order_id", order.ID). Float64("amount", order.Amount). Msg("Processing order") if err := processPayment(order); err != nil { logger.Error().Err(err).Msg("Payment failed") http.Error(w, "Payment failed", 500) return // Видим полный контекст ошибки } logger.Info().Msg("Order processed successfully") w.WriteHeader(200) // При успехе логи сохранятся только с вероятностью SaveRate }
Преимущества подхода
1. Снижение объема логов
Традиционное логирование:
1M запросов/день × 10 логов/запрос = 10M записей
При SaveRate = 5%: 50K записей + логи всех ошибок
Экономия: 95%+ на хранении
2. Полный контекст при ошибках
Когда что-то идет не так, вы видите всю историю запроса:
Все debug-сообщения
Промежуточные состояния
Точную последовательность операций
3. Производительность
Снижение I/O: меньше записей на диск/сеть
Батчинг: при сбросе логи пишутся одним блоком
4. Гибкая конфигурация
// Development config.BufferingEnabled = false // Видим все сразу config.SaveRate = 100.0 // Сохраняем все // Staging config.SaveRate = 50.0 // Половину для анализа config.FlushOnWarn = true // Warnings тоже важны // Production config.SaveRate = 5.0 // Только 5% успешных config.BufferSize = 128 * 1024 // Больше буфер
Когда использовать EmitLog
✅ Идеально подходит для:
Высоконагруженных API с детальным логированием
Микросервисов с дорогой инфраструктурой логирования
Систем, где ошибки требуют полного контекста для отладки
❌ Не подходит для:
Критичных аудит-логов (compliance)
Реального времени мониторинга
Маленьких приложений с небольшим объемом логов
Заключение
Код проекта доступен на GitHub
Буду рад фидбеку и предложениям по развитию проекта!
мой телерамм для связи https://t.me/atsaregorodtsev
