Сэмплирование логов
В сценариях с высокой пропускной способностью (логирование HTTP-запросов, обработка потоков событий) запись каждого события создаёт огромный объём данных. Функция сэмплирования DD сохраняет логи пропорционально, контролируя объём логов, но по-прежнему отражая общие тенденции.
Принцип сэмплирования
DD использует стратегию сэмплирования на основе счётчика:
┌──────────────────────────────────────────────────────────────────┐
│ Запросы 1-100 → все логируются (фаза Initial) │
│ Запрос 101 → пропущен │
│ Запрос 102 → пропущен │
│ ... │
│ Запрос 110 → логируется (1 из каждых Thereafter=10) │
│ Запрос 111 → пропущен │
│ ... │
│ (Tick истекает → счётчик сбрасывается, вход в фазу Initial) │
└──────────────────────────────────────────────────────────────────┘| Параметр | Описание | Типичное значение |
|---|---|---|
Enabled | Включить сэмплирование | true |
Initial | Первые N записей всегда логируются | 100 |
Thereafter | Логировать 1 из каждых N после Initial | 10 |
Tick | Интервал сброса счётчика (0 = без сброса) | 1s / 1m |
Быстрый старт
Включение при конфигурации
package main
import (
"log"
"time"
"github.com/cybergodev/dd"
)
func main() {
cfg := dd.DefaultConfig()
cfg.Sampling = &dd.SamplingConfig{
Enabled: true,
Initial: 100, // Первые 100 всегда логируются
Thereafter: 10, // Затем логируется 1 из каждых 10
Tick: time.Second, // Сброс счётчика каждую секунду
}
logger, err := dd.New(cfg)
if err != nil {
log.Fatal(err)
}
defer logger.Close()
// Имитация логирования с высокой нагрузкой
for i := 0; i < 1000; i++ {
logger.InfoWith("request processed",
dd.Int("seq", i),
)
}
// Фактический вывод: первые 100 + 90 из оставшихся 900 = 190 записей
}Переключение во время выполнения
// Включить сэмплирование
logger.SetSampling(&dd.SamplingConfig{
Enabled: true,
Initial: 50,
Thereafter: 20,
Tick: 0, // Без авто-сброса
})
// Отключить сэмплирование (возобновить полное логирование)
logger.SetSampling(nil)
// Запросить текущую конфигурацию сэмплирования
sc := logger.GetSampling()
if sc != nil {
fmt.Printf("Sampling: Initial=%d, Thereafter=%d\n", sc.Initial, sc.Thereafter)
}Подсказка Сэмплирование глобального Logger
Функции уровня пакета dd.SetSampling() и dd.GetSampling() работают напрямую с глобальным Logger.
Подробное описание параметров
Initial: окно полного объёма в начале
Initial гарантирует, что первые N записей после запуска или сброса Tick логируются все, обеспечивая:
- Сохранение логов инициализации на этапе запуска
- Полные записи при кратковременных всплесках трафика
- Видимость состояния на начало периода после сброса Tick
Thereafter: частота сэмплирования
| Thereafter | Эффект | Доля сохранения (после Initial) |
|---|---|---|
| 1 | Логировать каждую запись (= отключено) | 100% |
| 10 | Логировать 1 из каждых 10 | 10% |
| 100 | Логировать 1 из каждых 100 | 1% |
| 0 | Прекратить логирование после Initial | 0% |
Предупреждение Thereafter=0
Thereafter=0 означает полную остановку логирования после фазы Initial. Это полезно в некоторых сценариях (например, нужны только логи запуска), но убедитесь, что не пропустите важную информацию.
Tick: периодический сброс
// Вариант A: сброс каждую секунду (обнаружение всплесков)
Sampling: &dd.SamplingConfig{
Enabled: true, Initial: 100, Thereafter: 10,
Tick: time.Second,
}
// Вариант B: без сброса (глобальный подсчёт, долгосрочное сокращение)
Sampling: &dd.SamplingConfig{
Enabled: true, Initial: 1000, Thereafter: 100,
Tick: 0,
}После сброса Tick счётчик обнуляется и снова входит в фазу полного объёма Initial. Полезно для наблюдения за шаблонами трафика в каждом периоде.
Типичные сценарии
Сценарий 1: логирование HTTP-запросов
// Высоконагруженный API: первые 100 полностью, затем 10% сэмплирование, сброс каждую секунду
cfg.Sampling = &dd.SamplingConfig{
Enabled: true,
Initial: 100,
Thereafter: 10,
Tick: time.Second,
}Сценарий 2: логирование фоновых задач
// Пакетная обработка: первые 50 полностью, затем 1 из каждых 100, без сброса
cfg.Sampling = &dd.SamplingConfig{
Enabled: true,
Initial: 50,
Thereafter: 100,
Tick: 0,
}Сценарий 3: переключение режима отладки
// Нормальный режим: сэмплирование
logger.SetSampling(&dd.SamplingConfig{
Enabled: true, Initial: 10, Thereafter: 50,
})
// Диагностика: отключить сэмплирование, полное логирование
logger.SetSampling(nil)
// Исправлено: восстановить сэмплирование
logger.SetSampling(&dd.SamplingConfig{
Enabled: true, Initial: 10, Thereafter: 50,
})Потокобезопасность
Сэмплирование использует атомарные операции (atomic.Int64) для счётчика и мьютекс для сброса Tick. Дополнительная синхронизация не требуется при конкурентной записи логов из нескольких goroutine.
Подсказка Логи Fatal обходят сэмплирование
Даже при включённом сэмплировании логи уровня Fatal всегда записываются — Fatal должен быть зафиксирован перед выходом из программы и никогда не должен пропускаться сэмплированием.
Следующие шаги
- Производительность -- Механизмы нулевых аллокаций и пула буферов
- Конфигурация -- Полный справочник полей конфигурации
- Система Hook -- Хуки BeforeLog могут дополнить сэмплирование