Логирование: доменная граница ошибок + защита секретов в логах
Приём торрента через Telegram молча падал без записи в логах. Разобрали цепочку и починили логирование/обработку ошибок по конвенции logging.md (логирует граница домена один раз, транспорты — нет). Доменная граница логирует исход: - ingest.Ingest: сбой БД → ERROR, невалидный источник → DEBUG; - команды воркера (Apply/Cancel/Retry/Refine/…) — единый чокпоинт logCmd (ERROR для инфраструктурного сбоя; DEBUG для conflict/not-ready/not-found), закрывает и Telegram-, и HTTP-путь; дублирующие ERROR-логи в tgbot сняты; - внутренний логгер tgbotapi заведён в slog: сбои long-poll getUpdates больше не уходят в stdlib log мимо структурированных логов; - тихое закрытие канала обновлений бота → ERROR. Защита секретов (инвариант «секреты не в логи»): - общий logging.SanitizeErr убирает URL из *url.Error; - закрыты утечки токена бота (getMe на старте, getFile, Send/Request) и api_key TMDB (query-параметр, попадавший в *url.Error на ERROR); - покрыто тестом internal/logging/sanitize_test.go. Ревью двумя сабагентами (fable): инфраструктурные и доменные ошибки. Отложено (не в scope этого коммита): обёртка ErrConflict в Cancel/Defer/Retry и классификация 500→409/400, обновление docs/conventions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
package tgbot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
// SetLibraryLogger направляет внутренние логи клиента tgbotapi в наш slog.
|
||||
//
|
||||
// Зачем: библиотека логирует сбои long-poll `getUpdates` через собственный
|
||||
// (stdlib `log`) логгер — МИМО slog. Из-за этого сетевые/API-ошибки поллинга не
|
||||
// попадали в структурированные JSON-логи: входящее сообщение молча не
|
||||
// подхватывалось, а в логах — пусто (см. logging.md). После вызова такие сбои
|
||||
// видны как `telegram library` (WARN).
|
||||
//
|
||||
// Токен вырезается из текста: строка ошибки транспорта — `*url.Error` с URL вида
|
||||
// `…/bot<TOKEN>/getUpdates`, писать её как есть нельзя (утечка секрета в логи).
|
||||
// Замена по подстроке страхует и от прочих мест, где токен мог бы просочиться.
|
||||
//
|
||||
// Логгер в tgbotapi — глобальный на пакет; вызывать один раз при старте.
|
||||
func SetLibraryLogger(log *slog.Logger, token string) error {
|
||||
return tgbotapi.SetLogger(libLogger{log: log, token: token})
|
||||
}
|
||||
|
||||
type libLogger struct {
|
||||
log *slog.Logger
|
||||
token string
|
||||
}
|
||||
|
||||
func (l libLogger) Println(v ...any) { l.emit(fmt.Sprintln(v...)) }
|
||||
|
||||
func (l libLogger) Printf(format string, v ...any) { l.emit(fmt.Sprintf(format, v...)) }
|
||||
|
||||
func (l libLogger) emit(msg string) {
|
||||
msg = strings.TrimSpace(msg)
|
||||
if l.token != "" {
|
||||
msg = strings.ReplaceAll(msg, l.token, "***")
|
||||
}
|
||||
// Сбои поллинга транзиентны (библиотека повторяет через 3 с) — WARN
|
||||
// («retry внешнего вызова»); устойчивый сбой станет потоком WARN — сигнал
|
||||
// разбираться, но не ERROR на каждый повтор.
|
||||
l.log.Warn("telegram library", "detail", msg)
|
||||
}
|
||||
Reference in New Issue
Block a user