TGViewer
Библиотека Go-разработчика | Golang Библиотека Go-разработчика | Golang @goproglib · 24.1K subscribers
Post #7324 2.99K
💡 Предложение добавить 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.

📍 Навигация: Вакансии • Задачи • Собесы

🐸 Библиотека Go-разработчика

#GoLive
  • 👍 2
  • ❤ 1
More from @goproglib
  1. Sep 28, 2026🤔 Вопрос с собеседования по Go Что выведет программа? ❤️ — 1 true / 0 false 🔥 — 1 true /…
  2. Sep 28, 2026👩‍💻 Что на самом деле происходит внутри Go map? После Go 1.24 обычный map внутри работае…
  3. Sep 26, 2026🔥 В Go 1.27 появился portable SIMD До этого SIMD-оптимизации в Go требовали архитектурног…
  4. Sep 25, 2026🤡🤡 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoGiggle
  5. Sep 25, 2026💡 Код работает. А data race уже есть В Go можно записать значение в одной горутине, прочи…
  6. Sep 23, 2026💥 TCP/IP: что происходит с данными в сети Когда Go-приложение отправляет данные по сети,…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →