From fcd7baac71dda34dec670e701587f78142147839 Mon Sep 17 00:00:00 2001 From: Zuev Date: Sun, 22 Mar 2026 15:22:10 +0300 Subject: [PATCH] feat: Add AutoUpdateDocs agent skill and new logging documentation, updating AGENTS.md. --- .agents/skills/AutoUpdateDocs.md | 85 ++++++++++++++++ AGENTS.md | 1 + docs/LOGGING.md | 167 +++++++++++++++++++++++++++++++ 3 files changed, 253 insertions(+) create mode 100644 .agents/skills/AutoUpdateDocs.md create mode 100644 docs/LOGGING.md diff --git a/.agents/skills/AutoUpdateDocs.md b/.agents/skills/AutoUpdateDocs.md new file mode 100644 index 0000000..8910bf4 --- /dev/null +++ b/.agents/skills/AutoUpdateDocs.md @@ -0,0 +1,85 @@ +--- +name: AutoUpdateDocs +description: Автоматическое обновление документации проекта после изменений в коде +--- + +# Скилл: Автоматическое обновление документации + +## Когда активировать + +Этот скилл **ДОЛЖЕН** выполняться автоматически после любых изменений, затрагивающих: + +- **Контроллеры** (`backend/src/main/java/com/magistr/app/controller/`) → обновить `docs/API.md` +- **Модели или миграции** (`model/`, `db/migration/`) → обновить `docs/DATABASE.md` +- **Конфигурация тенантов** (`config/tenant/`) → обновить `docs/ARCHITECTURE.md` +- **Бизнес-правила или валидаторы** (`utils/`) → обновить `docs/BUSINESS_LOGIC.md` +- **Frontend** (`frontend/`) → обновить `docs/FRONTEND.md` +- **Docker/Kubernetes** (`compose.yaml`, `Dockerfile`, `../k8s/`) → обновить `docs/INFRASTRUCTURE.md` +- **Code style или структура пакетов** → обновить `docs/DEVELOPMENT.md` +- **Общая структура проекта** → обновить `docs/README.md` + +## Карта соответствия «файл → документация» + +| Изменённый файл/директория | Файл документации | +|----------------------------|-------------------| +| `controller/*Controller.java` | `docs/API.md` | +| `db/migration/V*__.sql` | `docs/DATABASE.md` | +| `model/*.java` | `docs/DATABASE.md` | +| `dto/*.java` | `docs/API.md` | +| `config/tenant/*.java` | `docs/ARCHITECTURE.md` | +| `utils/*.java` | `docs/BUSINESS_LOGIC.md` | +| `frontend/admin/js/views/*.js` | `docs/FRONTEND.md` | +| `frontend/admin/css/*.css` | `docs/FRONTEND.md` | +| `compose.yaml`, `Dockerfile` | `docs/INFRASTRUCTURE.md` | +| `application.properties` | `docs/ARCHITECTURE.md` | + +## Пошаговая инструкция + +### 1. Определить затронутые файлы документации + +После выполнения задачи пользователя — проверить по таблице выше, какие файлы документации нужно обновить. + +### 2. Прочитать текущую документацию + +Открыть соответствующий файл из `docs/` и найти секцию, которую нужно обновить. + +### 3. Внести точечные изменения + +Обновить **только затронутые секции**, не переписывая весь файл. Примеры: + +#### Новый контроллер → `docs/API.md` +Добавить новую секцию с описанием эндпоинтов: +- Метод + URL +- Тело запроса (JSON пример) +- Ответ (JSON пример) +- Валидация + +#### Новая миграция → `docs/DATABASE.md` +- Добавить новую таблицу в ER-диаграмму (Mermaid) +- Добавить описание таблицы и колонок +- Добавить запись в таблицу «Текущие миграции» + +#### Новый view → `docs/FRONTEND.md` +- Добавить в дерево файлов +- Добавить в таблицу «Разделы админ-панели» + +### 4. Обновить AGENTS.md (при необходимости) + +Если изменения затрагивают: +- Структуру директорий → обновить дерево в `AGENTS.md` +- Критические правила (Flyway, новые ограничения) → обновить секцию «Критические правила» + +### 5. Сообщить пользователю + +В конце ответа кратко упомянуть, какие файлы документации были обновлены: + +> 📝 Обновлена документация: `docs/API.md` (добавлен эндпоинт `POST /api/absences`) + +## Правила + +1. **Язык:** Вся документация на русском языке +2. **Формат:** Сохранять существующий стиль оформления файла (заголовки, таблицы, примеры кода) +3. **Не удалять:** Не удалять существующие секции без явного запроса пользователя +4. **Mermaid:** При изменении схемы БД — обязательно обновлять ER-диаграмму в `docs/DATABASE.md` +5. **Минимальные правки:** Не переписывать весь файл ради добавления одной строки — использовать точечные изменения +6. **Консистентность:** Если одно и то же понятие упоминается в нескольких файлах `docs/`, обновить все вхождения diff --git a/AGENTS.md b/AGENTS.md index 033f2d5..a6da314 100755 --- a/AGENTS.md +++ b/AGENTS.md @@ -84,3 +84,4 @@ docker compose logs -f backend | [`docs/INFRASTRUCTURE.md`](docs/INFRASTRUCTURE.md) | Docker, Kubernetes, CI/CD, мониторинг (SigNoz) | | [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) | Code Style, соглашения, пошаговое создание нового эндпоинта | | [`docs/FRONTEND.md`](docs/FRONTEND.md) | Frontend архитектура, SPA-маршрутизация, CSS, адаптивность | +| [`docs/LOGGING.md`](docs/LOGGING.md) | Логирование: SLF4J + Logback, MDC, OpenTelemetry → SigNoz | diff --git a/docs/LOGGING.md b/docs/LOGGING.md new file mode 100644 index 0000000..41ad688 --- /dev/null +++ b/docs/LOGGING.md @@ -0,0 +1,167 @@ +# 📋 Логирование + +## Стек технологий + +| Компонент | Технология | +|-----------|------------| +| Фасад | SLF4J (`org.slf4j.Logger`) | +| Реализация | Logback (поставляется с `spring-boot-starter-web`) | +| Конфигурация | Стандартная Spring Boot (без кастомного `logback.xml`) | +| Экспорт (прод) | OpenTelemetry Java Agent → OTLP → SigNoz | +| Контекст тенанта | SLF4J MDC (`tenant.id`) | + +--- + +## Архитектура + +```mermaid +graph LR + Code["Java-код
log.info(...)"] --> SLF4J["SLF4J API"] + SLF4J --> Logback["Logback"] + Logback -->|"Локальная разработка"| Console["stdout / stderr"] + Logback -->|"Продакшн"| OTelAgent["OTel Java Agent
(Logback Appender)"] + OTelAgent -->|"OTLP HTTP"| SigNoz["SigNoz"] +``` + +### Локальная разработка + +Логи выводятся в `stdout` контейнера в стандартном формате Spring Boot: + +``` +2026-03-22 12:00:00.123 INFO 1 --- [main] c.m.app.config.DataInitializer : Initializing databases for 1 tenant(s)... +``` + +Просмотр логов: + +```bash +docker compose logs -f backend +``` + +### Продакшн (Kubernetes) + +OpenTelemetry Java Agent подключается как `-javaagent` в [Dockerfile](file:///mnt/HDD/magistr/magistr/backend/Dockerfile) и автоматически перехватывает логи Logback, экспортируя их в SigNoz по OTLP. + +```dockerfile +ENTRYPOINT ["java", "-javaagent:opentelemetry-javaagent.jar", "-jar", "app.jar"] +``` + +Конфигурация агента задаётся через переменные окружения в [backend.yaml](file:///mnt/HDD/magistr/k8s/backend.yaml): + +| Переменная | Значение | Назначение | +|------------|----------|------------| +| `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://192.168.1.100:4318` | Адрес SigNoz Collector | +| `OTEL_SERVICE_NAME` | `magistr-backend` | Имя сервиса в SigNoz | +| `OTEL_RESOURCE_ATTRIBUTES` | `deployment.environment=default` | Окружение | +| `OTEL_LOGS_EXPORTER` | `otlp` | Экспорт логов через OTLP | +| `OTEL_METRICS_EXPORTER` | `otlp` | Экспорт метрик через OTLP | +| `OTEL_TRACES_EXPORTER` | `otlp` | Экспорт трейсов через OTLP | +| `OTEL_INSTRUMENTATION_LOGBACK_APPENDER_EXPERIMENTAL_CAPTURE_MDC_ATTRIBUTES` | `tenant.id` | Захват MDC-атрибута в логи | + +> [!NOTE] +> В локальной разработке OpenTelemetry Agent также встроен в Docker-образ, но без переменных `OTEL_*` он работает в режиме noop — логи идут только в stdout. + +--- + +## Мультитенантный контекст (MDC) + +Каждый HTTP-запрос обогащается tenant ID через [TenantInterceptor](file:///mnt/HDD/magistr/magistr/backend/src/main/java/com/magistr/app/config/tenant/TenantInterceptor.java): + +```java +// preHandle — при входе запроса +MDC.put("tenant.id", tenant); +Span.current().setAttribute("tenant.id", tenant); + +// afterCompletion — после завершения +MDC.remove("tenant.id"); +``` + +Это позволяет: +- Фильтровать логи по тенанту в SigNoz +- Коррелировать логи с трейсами через Span-атрибуты +- Идентифицировать, к какому университету относится каждая запись + +--- + +## Использование в коде + +### Классы с логированием + +| Класс | Уровни | Что логируется | +|-------|--------|----------------| +| `TenantInterceptor` | DEBUG, WARN | Резолвинг тенанта, неизвестный тенант (404) | +| `TenantDataSourceConfig` | INFO, WARN, ERROR | Загрузка тенантов, fallback на H2 | +| `TenantRoutingDataSource` | INFO, WARN | Добавление/удаление тенантов, тест соединения | +| `TenantConfigWatcher` | INFO, ERROR, WARN | Изменения ConfigMap, Flyway миграции | +| `ConfigMapUpdater` | INFO, WARN, ERROR | Обновление ConfigMap в K8s | +| `DataInitializer` | INFO | Инициализация БД при старте | +| `LessonsController` | INFO, DEBUG, ERROR | CRUD-операции с занятиями, валидация | + +### Паттерн использования + +```java +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MyClass { + private static final Logger log = LoggerFactory.getLogger(MyClass.class); + + public void doSomething() { + log.info("Операция выполнена: param={}", value); + log.error("Ошибка: {}", e.getMessage(), e); // со стектрейсом + } +} +``` + +### Рекомендации по уровням + +| Уровень | Когда использовать | +|---------|-------------------| +| `ERROR` | Необработанные ошибки, сбои подключения к БД, провалы миграций | +| `WARN` | Неизвестный тенант, нет конфигурации, fallback-сценарии | +| `INFO` | Успешные операции, CRUD-действия, старт/стоп компонентов | +| `DEBUG` | Детали резолвинга тенанта, ping-запросы | + +--- + +## Настройка уровня логирования + +В [application.properties](file:///mnt/HDD/magistr/magistr/backend/src/main/resources/application.properties) (по умолчанию закомментировано): + +```properties +# Включить DEBUG для всего приложения +#logging.level.root=DEBUG + +# Только для пакета приложения +logging.level.com.magistr.app=DEBUG + +# Только для конкретного класса +logging.level.com.magistr.app.config.tenant.TenantInterceptor=DEBUG +``` + +Также можно задавать через переменные окружения: + +```bash +LOGGING_LEVEL_ROOT=DEBUG +LOGGING_LEVEL_COM_MAGISTR_APP=DEBUG +``` + +--- + +## Просмотр логов + +### Локально (Docker Compose) + +```bash +# Все логи backend +docker compose logs -f backend + +# Фильтрация по ключевому слову +docker compose logs -f backend | grep "tenant" +``` + +### Продакшн (SigNoz) + +Логи доступны в веб-интерфейсе SigNoz → раздел **Logs**: +- Фильтрация по `service.name = magistr-backend` +- Фильтрация по `tenant.id` (из MDC) +- Корреляция с трейсами через общий `trace_id`