Skip to content

Оптимизация производительности

DD разработан для высокой производительности, ниже приведены рекомендации по дальнейшей оптимизации.

Низкоаллокационная оптимизация

DD минимизирует выделение памяти на горячих путях:

  • IsLevelEnabled() использует атомарные операции, без блокировок
  • Структурированные поля используют предварительно выделенные буферы
  • Избегает форматирования сообщений при несовпадении уровня логирования

Проверка уровня

На высокочастотных путях сначала проверяйте уровень, чтобы избежать ненужного конструирования полей:

go
// Рекомендуется: сначала проверить уровень
if logger.IsDebugEnabled() {
    logger.DebugWith("Подробная информация",
        dd.String("data", expensiveToString()),
        dd.Int("size", len(largeSlice)),
    )
}

// Не рекомендуется: всегда конструировать поля
logger.DebugWith("Подробная информация",
    dd.String("data", expensiveToString()),
)

Буферизованная запись

Используйте BufferedWriter для уменьшения системных вызовов I/O:

go
fw, _ := dd.NewFileWriter("logs/app.log", dd.DefaultFileWriterConfig())
bwCfg := dd.DefaultBufferedWriterConfig()
bwCfg.BufferSize = 8192
bw, _ := dd.NewBufferedWriter(fw, bwCfg)  // 8КБ буфер

logger, _ := dd.New(dd.Config{
    Targets: []dd.OutputTarget{dd.CustomOutput(bw)},
})
defer logger.Close()  // Close автоматически вызывает Flush

Размер буфера

Рекомендуется 4КБ-16КБ. Слишком маленький буфер неэффективно уменьшает системные вызовы, слишком большой увеличивает использование памяти и задержку.

Сэмплирование логов

В сценариях с высокой пропускной способностью можно включить сэмплирование логов для уменьшения дублирующихся логов:

go
logger.SetSampling(&dd.SamplingConfig{
    Enabled:    true,
    Initial:    100,    // Первые 100 записываются полностью
    Thereafter: 10,     // Затем записывается 1 из 10
    Tick:       time.Minute, // Сброс счётчика каждую минуту
})

// Динамическая регулировка во время выполнения
cfg := logger.GetSampling()

Оптимизация записи в файл

Разумная конфигурация ротации

go
fw, _ := dd.NewFileWriter("logs/app.log", dd.DefaultFileWriterConfig())
// По умолчанию: 100МБ / 30 дней / 10 резервных копий
  • Слишком маленькие файлы приводят к частой ротации, увеличивая I/O
  • Слишком много резервных копий занимает дисковое пространство
  • Настраивайте параметры в соответствии с фактическим объёмом логов

Разделение по файлам

go
// Разделение по уровням
infoWriter, _ := dd.NewFileWriter("logs/info.log", dd.DefaultFileWriterConfig())
errorWriter, _ := dd.NewFileWriter("logs/error.log", dd.DefaultFileWriterConfig())

Управление Writer

Динамическое добавление/удаление Writer

go
// Динамическое добавление во время выполнения
logger.AddWriter(newWriter)

// Удаление ненужных Writer
logger.RemoveWriter(oldWriter)

Избегание избыточного количества Writer

Каждый Writer увеличивает задержку записи. Рекомендуется не более 3-4 Writer.

Оптимизация полей

Использование типизированных полей

go
// Рекомендуется: типизированные конструкторы
dd.Int("count", 42)
dd.String("name", "test")

// Избегать: Any (требует дополнительного утверждения типа)
dd.Any("count", 42)

Избегание больших объектов

go
// Не рекомендуется: запись больших объектов
logger.InfoWith("Данные", dd.Any("payload", hugeStruct))

// Рекомендуется: записывать только ключевую информацию
logger.InfoWith("Данные",
    dd.Int("count", len(items)),
    dd.String("first", items[0].Name),
)

Закрытие и очистка

go
// Ожидание завершения фильтрующих горутин
logger.WaitForFilterGoroutines(3 * time.Second)

// Изящное завершение, ожидание сброса всех буферов
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
logger.Shutdown(ctx)

Следующие шаги