Часто задаваемые вопросы
Базовое использование
В чём разница между глобальным логгером и пользовательским логгером?
Глобальный логгер используется через пакетные функции dd.Info() и т.д., подходит для простых сценариев. Пользовательский логгер создаётся через dd.New(), поддерживает независимую конфигурацию и управление жизненным циклом.
// Глобальный логгер
dd.Info("Глобальный лог")
// Пользовательский логгер
logger, _ := dd.New(dd.JSONConfig())
logger.Info("Независимый лог")Как инициализировать глобальный логгер при запуске программы?
func init() {
err := dd.InitDefault(dd.JSONConfig())
if err != nil {
log.Fatal(err)
}
}Или через SetDefault:
logger, _ := dd.New(dd.Config{
Format: dd.FormatJSON,
Targets: []dd.OutputTarget{
dd.ConsoleOutput(),
dd.FileOutput("logs/app.json"),
},
})
dd.SetDefault(logger)Что происходит при уровне Fatal?
Fatal / Fatalf / FatalWith вызывают os.Exit(1) после вывода лога (defer-выражения не выполняются; внутренне сначала попытается Close() сбросить отложенные логи, ожидая максимум 5 секунд). Поведение выхода можно настроить через FatalHandler; если требуется очистка ресурсов, используйте ErrorWith + явный Shutdown(ctx).
Конфигурация
Как одновременно выводить в консоль и файл?
logger, _ := dd.New(dd.Config{
Targets: []dd.OutputTarget{
dd.ConsoleOutput(),
dd.FileOutput("logs/app.log"),
},
})
// Или в формате JSON
logger, _ := dd.New(dd.Config{
Format: dd.FormatJSON,
Targets: []dd.OutputTarget{
dd.ConsoleOutput(),
dd.FileOutput("logs/app.json"),
},
})Как динамически изменить уровень логирования?
_ = logger.SetLevel(dd.LevelDebug) // Изменение во время выполнения (возвращает error)
_ = dd.SetLevel(dd.LevelDebug) // Изменение уровня глобального логгераКак настроить стратегию ротации файлов?
Через конфигурацию FileWriter:
fw, _ := dd.NewFileWriter("logs/app.log",
dd.DefaultFileWriterConfig(), // 100МБ, 30 дней, 10 резервных копий
)Производительность
Влияет ли логирование на производительность программы?
DD разработан для высокой производительности:
- Низкоаллокационная оптимизация на горячих путях
- Атомарная проверка уровня, без блокировок
- Фильтрация конфиденциальных данных для больших входных данных (≥10КБ) выполняется в отдельной goroutine с защитой по таймауту; малые входные данные обрабатываются синхронно
- Опциональная буферизованная запись для уменьшения I/O
Как оптимизировать в сценариях с высокой пропускной способностью?
- Используйте
BufferedWriterдля уменьшения I/O - Проверяйте уровень перед конструированием полей
- Рассмотрите возможность включения сэмплирования логов
- Избегайте использования поля
Anyна высокочастотных путях
Подробнее в Оптимизация производительности.
Безопасность
Как работает фильтрация конфиденциальных данных?
SensitiveDataFilter использует regex-сопоставление шаблонов для автоматической замены конфиденциальных значений на [REDACTED] перед записью лога. Малые входные данные обрабатываются синхронно, большие — в отдельной goroutine с защитой по таймауту, не блокируя запись логов.
Как добавить пользовательские шаблоны конфиденциальных данных?
filter, _ := dd.NewCustomSensitiveDataFilter(
`(?i)my_secret_field\s*[:=]\s*\S+`,
)Как убедиться, что логи не были подделаны?
Используйте IntegritySigner для HMAC-подписи логов:
cfg, _ := dd.DefaultIntegrityConfigSafe()
signer, _ := dd.NewIntegritySigner(cfg)
sig := signer.Sign(logMessage)
// Проверка: signer.Verify(signedEntry)Обработка ошибок
Почему AddWriter возвращает ошибку?
Возможные причины:
ErrNilWriter-- передан nil WriterErrLoggerClosed-- логгер закрытErrMaxWritersExceeded-- превышено количество Writer
Как обработать ошибку записи?
logger.SetWriteErrorHandler(func(w io.Writer, err error) {
// Пользовательская обработка
metrics.WriteErrors.Inc()
})Тестирование
Как перехватить логи в тестах?
Используйте LoggerRecorder:
rec := dd.NewLoggerRecorder()
logger, _ := rec.NewLogger()
logger.Info("test")
if !rec.ContainsMessage("test") {
t.Error("Ожидаемый лог не найден")
}Подробнее в Тестовые утилиты.
Следующие шаги
- Быстрый старт -- руководство для начала работы
- Справочник API -- полный API
- Контрольный список для продакшена -- проверка перед развёртыванием