Files
obsidian/Работа/Замена zap на slog.md

149 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Миграция klog/zap → slog
## Контекст
`tools/klog` — тонкая обёртка над `go.uber.org/zap`, которая является точкой входа для логирования во всех сервисах.
Модуль: `gitlab.adsw.io/platform/tools/v3`, потребляется 15+ репозиториями через vendor.
## Текущий формат логов (сохраняется)
```json
{"level":"info","caller":"main.go:42","msg":"starting service","source":"accounting","date":"2026-05-08T12:34:56.789+03:00"}
{"level":"error","caller":"auth.go:28","msg":"fetching user profile","source":"accounting","date":"2026-05-08T12:34:56.789+03:00","error":"context deadline exceeded"}
```
Поля: `level` (строчными), `caller`, `msg`, `source` (при init), `date` (ISO 8601 в каждом вызове через `cookFields()`).
Формат воспроизводится через `log/slog` с кастомным JSON handler'ом + `ReplaceAttr` для приведения уровней к нижнему регистру.
## Стратегия
Публичный API `klog` **не меняется** — сервисы обновляют vendor и ничего не ломается.
Единственное breaking изменение: `SetLogger(*zap.Logger)``SetLogger(*slog.Logger)`.
Используется только в тестах через `zap.NewNop()`.
**Решение:** добавить `SetNopLogger()` — тесты меняют одну строку без импорта zap.
---
## Шаг 0 — tools (делается первым, разблокирует всё остальное)
| # | Файл | Что менять | Сложность |
|---|------|------------|-----------|
| 1 | `tools/klog/log.go` | Переписать на `log/slog` с кастомным JSON handler'ом, сохранить формат, добавить `SetNopLogger()` | Средняя |
| 2 | `tools/go.mod` | Удалить `go.uber.org/zap` из `require` | Низкая |
| 3 | `tools/vendor/` | `go mod tidy && go mod vendor` | Низкая |
После выпустить тег `v3.9.0`.
---
## Шаг 1 — тесты с `klog.SetLogger(zap.NewNop())` (критично)
Это **единственные места**, где внешний код завязан на тип `*zap.Logger`.
После обновления vendor без этих правок сервисы **не скомпилируются**.
Замена везде одинаковая: `klog.SetLogger(zap.NewNop())``klog.SetNopLogger()`
| # | Репозиторий | Файл | Сложность |
|---|-------------|------|-----------|
| 4 | `pilot` | `internal/service/agreement_link_test.go` | Низкая |
| 5 | `pilot` | `internal/service/application_test.go` | Низкая |
| 6 | `pilot` | `internal/service/distro_download_link_test.go` | Низкая |
| 7 | `pilot` | `internal/service/distro_test.go` | Низкая |
| 8 | `pilot` | `internal/service/download_history_test.go` | Низкая |
| 9 | `pilot` | `internal/service/download_link_test.go` | Низкая |
| 10 | `pilot` | `internal/service/mail_test.go` | Низкая |
| 11 | `hr` | `internal/service/department_test.go` | Низкая |
| 12 | `rubytech` | `internal/service/client_test.go` | Низкая |
| 13 | `rubytech` | `internal/service/customer_test.go` | Низкая |
| 14 | `rubytech` | `internal/service/project_test.go` | Низкая |
| 15 | `user` | `internal/private/graph/resolver_test.go` | Низкая |
| 16 | `user` | `internal/service/role_test.go` | Низкая |
| 17 | `user` | `internal/service/session_test.go` | Низкая |
| 18 | `user` | `internal/service/user_test.go` | Низкая |
---
## Шаг 2 — vendor-бамп во всех сервисах (рутина, не требует изменений кода)
Для сервисов без `SetLogger(zap.NewNop())` достаточно только обновить vendor.
Для `pilot`, `hr`, `rubytech`, `user` — сначала шаг 1, потом vendor-бамп.
```bash
go get gitlab.adsw.io/platform/tools/v3@v3.9.0
go mod vendor
```
| # | Репозиторий | Зависимость | Сложность |
|---|-------------|-------------|-----------|
| 19 | `accounting` | — | Низкая |
| 20 | `async` | — | Низкая |
| 21 | `document-generator` | — | Низкая |
| 22 | `education` | — | Низкая |
| 23 | `file-manager` | — | Низкая |
| 24 | `hr` | после п.11 | Низкая |
| 25 | `mailer` | — | Низкая |
| 26 | `partner` | — | Низкая |
| 27 | `pilot` | после пп.410 | Низкая |
| 28 | `private-api-gateway` | — | Низкая |
| 29 | `public-api-gateway` | — | Низкая |
| 30 | `rubytech` | после пп.1214 | Низкая |
| 31 | `store` | — | Низкая |
| 32 | `unisender` | — | Низкая |
| 33 | `user` | после пп.1518 | Низкая |
| 34 | `yandex` | — | Низкая |
---
## Шаг 3 — api-gateway (отдельно, не блокирует остальное)
`api-gateway` держит `*zap.Logger` как поле структуры `Application` и передаёт его
в `log.NewZapLogger()` из библиотеки `jensneuse/abstractlogger`. Это **независимо от klog**
и не блокирует миграцию остальных сервисов.
| # | Файл | Проблема | Сложность |
|---|------|----------|-----------|
| 35 | `api-gateway/pkg/application/application.go` | Поле `ZapLogger *zap.Logger``abstractlogger` требует zap. Нужно либо оставить zap только здесь, либо заменить `abstractlogger` на slog-совместимый аналог | Высокая |
| 36 | `api-gateway/cmd/http/main.go` | `klog.InitLogger()` возвращает `*zap.Logger` сейчас, после миграции вернёт `*slog.Logger` — нужно отвязать инициализацию zap от klog | Средняя |
---
## Порядок выполнения
```
Шаг 0: tools/klog/log.go → slog + SetNopLogger() → тег v3.9.0
├─► Шаг 1: исправить 15 тестовых файлов (pilot, hr, rubytech, user)
└─► Шаг 2: vendor-бамп в каждом сервисе по мере готовности (в течение месяца)
└─► Шаг 3: api-gateway — решить вопрос с abstractlogger (отдельно)
```
Шаг 0 и Шаг 1 должны быть выполнены **до** того, как любой сервис обновит vendor.
| Сервис | Готовность | Пролит |
| ------------ | :--------: | :----: |
| accounting | | |
| async | | |
| document | | |
| education | | |
| environment | | |
| file-manager | | |
| hr | + | |
| mailer | | |
| partner | | |
| pilot | + | + |
| private | | |
| public | | |
| rubytech | + | |
| store | | |
| unisender | | |
| user | | |
| yandex | + | |
| api-gateway | | |