💡 Предложение добавить slog.TestHandler в стандартную библиотеку Go — 22 июля 2026 г. в 10:24:00.856
💡 Предложение добавить slog.TestHandler в стандартную библиотеку Go В трекере Go появилось предложение добавить в пакет log/slog готовый хендлер, который пишет логи в testing.TB. Тогда логи приложения и логи теста окажутся в одном выводе и привяжутся к нужному тесту или подтесту. ❓ Зачем это Сопоставлять логи приложения с тестом, который их породил, приходится постоянно. Кирпичик для этого уже есть. Метод testing.TB.Output() добавили в Go 1.25 для T, B и F, а в Go 1.26 расширили на сам интерфейс TB. Но готового хендлера в slog нет, поэтому каждый проект собирает его заново. Обычно так: logger := slog.New(slog.NewTextHandler(t.Output(), nil)) Этот вариант работает, но у него два минуса. Удобства тест ориентированного хендлера приходится дописывать руками, а наивная форма имеет реальную гонку при логировании после завершения теста. ➡️ Что предлагают сделать В log/slog появится тип TestHandler, реализующий интерфейс Handler, и конструктор к нему. Чтобы не тянуть testing внутрь slog и не словить циклический импорт, вводят узкий интерфейс TestLogger. Ему удовлетворяют *testing.T, *testing.B и *testing.F. package slog // TestLogger — подмножество testing.TB, нужное хендлеру. type TestLogger interface { Output() io.Writer } // NewTestHandler возвращает Handler, который пишет записи в tb.Output(). // Вывод форматируется как у NewTextHandler. opts может быть nil. func NewTestHandler(tb TestLogger, opts *HandlerOptions) *TestHandler type TestHandler struct { tb TestLogger // куда писать // ... } func (h *TestHandler) Enabled(ctx context.Context, level Level) bool { ... } func (h *TestHandler) Handle(ctx context.Context, record Record) error { ... } func (h *TestHandler) WithAttrs(attrs []Attr) Handler { ... } func (h *TestHandler) WithGroup(name string) Handler { ... } На стороне теста всё сводится к одной строке: func TestThing(t *testing.T) { logger := slog.New(slog.NewTestHandler(t, nil)) // Логи лягут под TestThing с отступом от раннера. // Для прошедших тестов вывод скрыт, пока не передан флаг -v, // как у t.Log() и t.Logf(). doWork(logger) } Пока это обсуждение, а не принятая фича. Следить за судьбой можно в самом issue #80138.

