# arch-07. Контракт наблюдаемости > Канонический контракт telemetry для всех application VM и private SigNoz. > Реализация на конкретной VM — в [`module-09-observability-vm1.md`](../VM1_app/documentation/module-09-observability-vm1.md) и [`module-09-observability-vm2.md`](../VM2_services/documentation/module-09-observability-vm2.md). > Имена сущностей — [`arch-00-glossary.md`](arch-00-glossary.md). Границы системы — [`arch-01-system-architecture.md`](arch-01-system-architecture.md). HTTP — [`arch-02-api-contracts.md`](arch-02-api-contracts.md). Compose — [`arch-03-docker-compose-blueprint.md`](arch-03-docker-compose-blueprint.md). Env — [`arch-04-settings-and-content.md`](arch-04-settings-and-content.md). Процесс — [`arch-05-agent-development-process.md`](arch-05-agent-development-process.md). Host security — [`arch-06-service-hosting-security.md`](arch-06-service-hosting-security.md). ## Назначение Документ фиксирует то, что **должно совпасть между ВМ1 и ВМ2**: схема сигналов, корреляция, redaction, sampling, Collector pipeline и удаленный backend. Локальные `service.name`, scrape targets, дашборды и алерты конкретной машины в этом файле не детализируются. Этот контракт **нельзя** независимо кастомизировать в репозитории VM. Изменение JSON-полей, labels, redaction, sampling или `service.namespace` сначала вносится сюда. ## 1. Цели и границы Наблюдаемость должна позволять: - найти пользовательский запрос по `request_id`, `trace_id` или `ux_session_id`; - восстановить путь «frontend → nginx → API → Safety → S3/Open Lines»; - измерять доступность, задержку, ошибки и насыщение каждого сервиса; - обнаруживать backlog, DLQ, circuit open, потерю telemetry и истечение TLS; - расследовать security/audit события без записи PII и секретов; - проверять SLO по данным, независимым от бизнес-логов. Telemetry не является источником бизнес-истины и не влияет на auth, safety verdict или доставку сообщений. Недоступность Collector не должна блокировать запросы. Audit в `han_app` — отдельный durable контур. ## 2. Production-like решение MVP ### 2.1. Обязательный минимум в основном Compose Каждый root Compose (ВМ1 и ВМ2) обязан содержать локальный `otel-collector`. Prometheus/Grafana/Loki/Tempo не обязаны размещаться на application VM. Операбельный вариант: 1. приложения на каждой VM экспортируют OTLP gRPC только в свой local `otel-collector:4317`; 2. Collector отправляет telemetry в self-hosted SigNoz на отдельной VM `192.168.0.5:4317`; 3. JSON stdout остаётся аварийным локальным журналом Docker с rotation; 4. пока удалённый backend недоступен в конкретном окружении, допустим архитектурный минимум из arch-03: bounded JSON stdout/platform logs и Collector `debug` exporter с sampling в acceptance; такой режим не считается полноценным production-хранением и не закрывает alerting/SLO. Требуемые возможности backend: OTLP ingest, поиск traces, PromQL-совместимые или эквивалентные metrics, поиск структурированных logs, alerting, RBAC, retention и TLS. Для текущего SigNoz plaintext OTLP разрешён только внутри доверенной приватной сети; UI — через SSH jump host. ВМ2 никогда не использует Docker hostname collector ВМ1. Каждый collector имеет собственный `otel-queue`. ### 2.2. Самостоятельно размещаемая опция Опциональный Compose profile `observability-local` может включать Prometheus, Grafana, Loki и Tempo. Он **не включается по умолчанию на малой VM**: стек требует дополнительной RAM/диска и сам становится объектом backup/monitoring. Для operable local-варианта нужны отдельный volume каждому backend, retention limits, compaction, auth через ops/VPN и отсутствие host ports. Grafana доступна только через отдельный защищённый ops route/VPN, не через публичный `/`. Рекомендуемый минимум VM при local profile: дополнительно 4 vCPU, 8 ГБ RAM и 100+ ГБ SSD сверх приложения; точный размер — после измерения ingest. Нужен ли profile на ВМ1 — TBD профильной спецификации ВМ1. ## 3. Архитектура Collector ### 3.1. Компоненты ```text backend services ─OTLP gRPC/HTTP─┐ nginx/Redis/Keycloak exporters ──┼─> otel-collector Docker JSON stdout ─filelog───────┘ ├─ OTLP remote backend (SigNoz) ├─ Prometheus endpoint (optional) └─ debug exporter (acceptance only) ``` Collector запускается одним сервисом MVP. При росте разделяется на agent/gateway: локальный agent принимает и буферизует, remote gateway выполняет policy/export. ### 3.2. Receivers - `otlp` gRPC `0.0.0.0:4317` — основной internal receiver; - `otlp` HTTP `0.0.0.0:4318` — совместимость SDK; - `prometheus` — scrape самого Collector, exporters и сервисных `/metrics`, если они не идут OTLP; - `filelog` — только если Docker logging driver предоставляет read-only каталог/volume; парсит JSON stdout без чтения secret-файлов; - `hostmetrics` — CPU, memory, filesystem, network VM/container host, если Collector получает только необходимые read-only mounts. Порты `4317`, `4318`, `8888`, `8889` используют `expose`, не `ports`. Receiver доступен только в сети `observability`. ### 3.3. Processors и порядок Во всех pipelines первым стоит защита памяти, последним — batch: 1. `memory_limiter`: check interval 1s, soft/hard limit относительно container memory; 2. `resource`: нормализует `service.namespace=han-chat`, `deployment.environment`, `service.version`; 3. `attributes`: удаляет/маскирует sensitive attributes; 4. `transform`: нормализует route/status/error semantic conventions; 5. `filter`: исключает health noise, debug events и запрещённые поля; 6. `probabilistic_sampler` или tail sampling для traces; 7. `batch`: bounded batch/timeout; 8. при remote export — `queued_retry`/sending queue и `file_storage` extension. `memory_limiter` не заменяется Docker OOM limit. При pressure Collector отбрасывает telemetry контролируемо и увеличивает `otelcol_processor_refused_*`. ### 3.4. Exporters - `otlp/remote`: endpoint из secret env/mount; для SigNoz в доверенной private network — plaintext `192.168.0.5:4317`; для любого иного remote — TLS verify; - `prometheus`: optional pull endpoint только internal; - `debug`: только `APP_ENV=test|acceptance`, verbosity normal; production debug exporter по умолчанию выключен; - `loki`/`otlphttp` — только если выбран дополнительный backend и его контракт закреплён. Секрет exporter-а не должен появляться в rendered config, логах или `/debug/configz`. Config монтируется read-only; secret подставляется env. ### 3.5. Extensions - `health_check` — internal endpoint, используется Compose; - `pprof`/`zpages` — только при явном ops profile, internal network; - `file_storage` — persistent sending queue на volume `otel-queue`; - `basicauth`/`oauth2client` — если требует remote backend. ### 3.6. Принципиальная конфигурация ```yaml receivers: otlp: protocols: grpc: {endpoint: 0.0.0.0:4317} http: {endpoint: 0.0.0.0:4318} prometheus: config: scrape_configs: - job_name: otel-collector static_configs: [{targets: ["127.0.0.1:8888"]}] processors: memory_limiter: check_interval: 1s limit_mib: 384 spike_limit_mib: 96 resource/common: attributes: - {key: service.namespace, value: han-chat, action: upsert} - {key: deployment.environment, value: "${env:APP_ENV}", action: upsert} attributes/redact: actions: - {key: http.request.header.authorization, action: delete} - {key: http.request.header.cookie, action: delete} - {key: url.query, action: delete} - {key: db.statement, action: delete} filter/noise: error_mode: ignore traces: span: - 'attributes["http.route"] == "/health/live"' batch: send_batch_size: 1024 timeout: 5s exporters: otlp/remote: endpoint: "${env:OTEL_REMOTE_ENDPOINT}" # true только для утверждённого plaintext SigNoz внутри private network; # для любого другого remote — false и проверка CA. tls: {insecure: ${env:OTEL_REMOTE_TLS_INSECURE}} headers: {authorization: "${env:OTEL_REMOTE_AUTH_HEADER}"} extensions: health_check: {endpoint: 0.0.0.0:13133} file_storage: {directory: /var/lib/otelcol/queue} service: extensions: [health_check, file_storage] pipelines: traces: receivers: [otlp] processors: [memory_limiter, resource/common, attributes/redact, filter/noise, batch] exporters: [otlp/remote] metrics: receivers: [otlp, prometheus] processors: [memory_limiter, resource/common, attributes/redact, batch] exporters: [otlp/remote] logs: receivers: [otlp] processors: [memory_limiter, resource/common, attributes/redact, filter/noise, batch] exporters: [otlp/remote] telemetry: metrics: {address: 0.0.0.0:8888} ``` Конкретная версия schema проверяется командой Collector `validate`; image закрепляется по digest. Значения memory/batch/queue — стартовые, не SLO. Для текущего SigNoz `tls.insecure` и auth header задаются профильной спецификацией VM согласно O1/O-TBD1. Scrape targets кроме самого Collector добавляет спецификация VM. ## 4. Resource attributes и корреляция Обязательные resource attributes: - `service.name` — только из реестра ниже; - `service.namespace=han-chat`; - `service.version=`; - `deployment.environment=production-like|production`; - `host.name`/`service.instance.id` без публичного IP. Реестр `service.name`: | Имя | Владелец | |---|---| | `nginx` | nginx каждой VM; различать экземпляры `host.name` / `service.instance.id` | | `api-backend` | ВМ1 | | `bitrix-local-app` | ВМ1 | | `keycloak` | ВМ1 | | `sms-service` | ВМ1, callback/internal API | | `sms-worker` | ВМ1, отправка в Direct | | `message-safety` | ВМ2 | | `bitrix-sync` | ВМ2 | | `redis` | Redis каждой VM; различать экземпляры | | `otel-collector` | collector каждой VM | Новое имя добавляется только сюда, затем в спецификацию владельца. Обязательные поля request-события: - `request_id`; - `trace_id`, `span_id`; - `ux_session_id` — nullable, только когда передан; - `service.name`; - `environment` либо canonical `deployment.environment`. `request_id` формирует/валидирует nginx; сервис возвращает его клиенту и передаёт downstream. `trace_id` берётся из active span. `ux_session_id` не является auth и не должен использоваться как metric label. ## 5. W3C propagation - принимаются только валидные `traceparent` и опциональный `tracestate`; - nginx передаёт context upstream; при edge instrumentation создаёт server span; - caller создаёт child spans для своих зависимостей (PostgreSQL, Redis, S3, Safety, Open Lines, JWKS, CRM); - internal calls передают `traceparent`, `tracestate`, `X-Request-ID`; - `baggage` по умолчанию не принимается от внешнего клиента; если включён, allow-list исключает PII; - Bitrix24/S3 могут не вернуть context: внешний client span всё равно закрывается результатом; - async outbox/inbox связывается span link с исходным trace; новый worker trace не притворяется продолжением спустя долгий срок. Frontend может отправлять валидный `traceparent`, но backend не доверяет его sampling/security атрибутам. ## 6. JSON stdout contract Одна JSON-запись на строку UTF-8: ```json { "timestamp": "2026-07-10T09:00:00.123Z", "level": "INFO", "service.name": "api-backend", "service.version": "git-abcdef0", "environment": "production-like", "module": "message_service", "event": "message.delivery.completed", "message": "Message delivery completed", "request_id": "01J...", "trace_id": "32hex", "span_id": "16hex", "ux_session_id": "uuid-or-null", "route": "/api/v1/dialogs/{dialog_id}/messages", "method": "POST", "status_code": 201, "duration_ms": 742, "dependency": "bitrix-local-app", "outcome": "success", "error_code": null } ``` Правила: - `event` — стабильная mnemonic, `message` — безопасное описание; - route — template, никогда raw URI с id/query; - stack trace допускается только в internal error log после redaction; - message text, callback body, SQL values и file content запрещены; - Docker driver ограничен `50m × 5`, но это buffer, не retention backend; - multiline stack trace сериализуется полем JSON, не отдельными строками. ## 7. Redaction и data minimization Удаляются или маскируются: - `Authorization`, Cookie, Set-Cookie, JWT, OAuth/code/refresh/access tokens; - raw OTP/mock code, Keycloak admin/client password; - phone/email/full name, device id, IP по policy (допустим HMAC/truncated); - message text, filenames с PII, document/file contents; - DSN/password, Redis URL, S3 keys; - presigned URL и любая query string; - Bitrix raw payload/download URL/application token; - `db.statement` с literals; предпочтительно operation/table, не SQL. Redaction выполняется в SDK/logger **до stdout**, затем повторяется Collector processor. Collector не может считаться единственной защитой. Автотесты отправляют canary secrets/PII и требуют отсутствие во всех трёх сигналах. ## 8. Общие правила instrumentation Детальный список инструментов конкретной VM — в профильной спецификации. Ниже правила, общие для всех сервисов. ### 8.1. FastAPI и workers - OpenTelemetry ASGI/FastAPI server spans с route template; - HTTPX client spans с sanitized host/method/status; - SQLAlchemy/asyncpg spans без параметров и raw statement; - Redis instrumentation с command name и DB index, без key/value; - boto/S3 spans: operation/bucket logical name, без object key/query; - background workers: span на claim/process/finalize, links на origin; - исключить `/health/live` из traces; readiness оставить в metrics и sampled logs. ### 8.2. PostgreSQL Собираются pool wait/checked-out, transaction duration, error class, migrations revision, managed PG provider metrics (CPU, storage, connections, locks, replication/PITR state). `user_id`, SQL text и row data не labels. ### 8.3. Redis `redis_exporter` подключается отдельным ACL user только на `INFO`, `PING`, безопасные latency/keyspace metrics. Нужны memory ratio, evictions, expirations, blocked/rejected clients, command latency, AOF status/rewrite, Pub/Sub buffers, key count/TTL агрегаты. Keys/values не экспортируются. ### 8.4. nginx JSON access log содержит `request_id`, извлечённый `trace_id`, route class, method, normalized path, status, bytes, request/upstream duration/status, TLS version, cache status. `$request` с query не используется. Collector `filelog` parser: - разбирает JSON, timestamp и severity; - переносит `service.name=nginx`; - превращает пустые/`-` в null; - route class нормализует в bounded set; - отбрасывает ACME/health success noise; - не парсит raw URI в labels. Native nginx OTEL module предпочтителен, если image/version закреплены. Без него nginx только передаёт W3C context и коррелирует access log; первый server span создаёт upstream. ### 8.5. Host/Docker CPU, load, memory/swap, disk usage/inodes/IO, network, container restarts/OOM, Docker daemon health и clock sync. Container name/version — bounded labels; container id не хранится как долгосрочный high-cardinality label. ## 9. Метрики: запрет high-cardinality Никакие UUID/user/session/dialog/task/message id не labels. Они допустимы только в sampled logs/traces при принятой retention. Allow-list labels; route template вместо raw path; status class/known code; dependency enum. Карта бизнес-метрик принадлежит спецификации VM-владельца сервиса. Сквозные SLI ниже используют сигналы обеих VM. ## 10. Сквозные dashboards в SigNoz SigNoz обязан иметь: 1. **Executive/SLO**: availability, error budget burn, p50/p95/p99, message delivery, auth, active incidents. 2. **Business flow**: guest config → OTP → bootstrap → session → dialog → safety → Open Lines → operator reply. 3. **Collector health**: accepted/sent/refused/dropped, queue, retry, exporter errors, memory/CPU — отдельно по `host.name` ВМ1 и ВМ2. Сервисные дашборды nginx/API/Safety/Keycloak/Redis/sync — в спецификациях VM. Каждая панель содержит release annotation, environment filter и links trace→logs по `trace_id`. ## 11. SLI, SLO и общие alerts Значения — начальная production-like политика до load/product review: | SLI | Initial SLO, 30 дней | |---|---| | HTTPS edge availability | 99.9% | | public config/content successful requests | 99.9% | | protected read API successful requests | 99.5% | | Keycloak login flow availability | 99.5% | | text message accepted и доставлен в Open Lines | 99.0% | | operator inbox applied без permanent loss | 99.5% | | p95 protected read API | < 750 ms | | p95 text send без внешнего rate limit | < 5 s | | telemetry Collector ingest availability | 99.0%, не входит в business availability | Файловый send измеряется отдельно: p95 не должен превышать configured safety poll budget; user-cancel, safety deny, 4xx validation и edge abuse 429 не считаются server failure. 503/504 и unexpected 5xx считаются. Paging/ticket alerts, привязанные к конкретному сервису, задаёт спецификация VM. Общие инфраструктурные paging alerts: - multi-window burn: 14.4× за 5m/1h или 6× за 30m/6h; - PostgreSQL unavailable/connection saturation >90%; - Collector exporter queue >80%, dropped/refused telemetry >0 sustained; - TLS expiry <14 дней warning, <7 дней page; - disk >85% warning, >92% page; OOM/restart loop; - managed PG backup/PITR failure. Alert содержит service, environment, symptom, dashboard, runbook, release и безопасный query; не содержит PII. ## 12. Sampling, cardinality и retention ### Traces - errors/5xx, circuit, timeout, DLQ, safety final deny и slow requests — 100%; - обычные успешные requests — 5–10%; - health/ACME success — 0%; - tail sampling предпочтителен в Collector, но head sample SDK должен оставлять достаточно данных; - sampling decision передаётся W3C. ### Metrics Cardinality budget: целевой <10 000 active series на MVP environment. CI проверяет запрещённые labels. ### Retention initial - metrics: 30 дней high resolution, 13 месяцев downsampled при доступности backend; - traces: 7 дней, errors 14 дней; - technical logs: 14 дней, security/auth logs 30 дней; - audit `han_app`: 365 дней **только как временное допущение до legal policy**; - raw Bitrix callback не хранится в telemetry; - local Docker logs: не более 250 МБ/container и 5 файлов. Legal retention/erasure имеет приоритет; изменение требует обновления policy и backup lifecycle. ## 13. Collector health и отказоустойчивость Контролируются: - `/health` extension; - process CPU/RSS/restarts; - accepted/refused/sent/failed spans, points, records; - batch send size/latency; - exporter queue capacity/size, enqueue failures, retry age; - file storage usage/corruption; - scrape failures; - config reload/validation. При remote outage queue хранится на `otel-queue` с bounded size/age. При заполнении отбрасываются сначала low-priority success traces/logs; приложение продолжает работу. Нельзя позволять queue заполнить системный диск. Telemetry outage/overflow fail-open для business и Safety readiness, но создаёт alert. ## 14. Docker Compose collector `otel-collector`: - pinned contrib image; - networks: только `observability`, а для scrape internal targets — минимально необходимая `backend`; - `expose`: 4317, 4318, 13133, 8888/8889; - без host ports; - config read-only, `otel-queue` volume rw; - non-root, read-only rootfs, tmpfs `/tmp`, drop capabilities, no-new-privileges; - перед collector запускается idempotent `otel-queue-init`: one-shot без сети и secrets, с `user: 0:0`, `cap_drop: ALL` и только `CHOWN/FOWNER`, выставляет mount root `10001:10001 0700`; collector зависит от `service_completed_successfully`; - initial limit: 0.5 CPU/512 MiB, queue disk 5–10 ГБ; уточнить load test; - healthcheck extension; - restart policy с backoff; - приложения имеют bounded non-blocking OTLP exporter queue. Новый named volume считается потенциально `root:root`; основной collector не запускается от root и volume не получает `0777`. Ownership init проверяется после первого create и повторного recreate. Доступ к Docker socket запрещён. Для container metrics используется безопасный exporter/hostmetrics, а не unrestricted socket mount. ## 15. Security - OTLP receiver internal-only; при переходе между hosts — mTLS, кроме явно зафиксированного plaintext SigNoz в private network; - remote exporter credentials least privilege; - Grafana/Prometheus/Loki/Tempo не публичны; - RBAC: viewer/operator/admin; audit доступа к logs/traces; - dashboards не показывают PII; - config/secret permissions 0400/0600; - dependency/image scan и SBOM; - защита от log injection: JSON encoding, control chars, bounded field lengths; - telemetry input не исполняет expressions из пользовательских значений; - регулярная secret-canary проверка и incident deletion procedure. ## 16. Общие runbooks ### Collector not-ready 1. `docker compose ps otel-collector` и bounded logs. 2. Проверить config validation, memory/OOM, queue volume. 3. Проверить DNS/TLS/auth remote exporter. 4. Не рестартовать бесконечно при полной queue; сначала освободить/расширить безопасно. 5. Бизнес-сервисы оставить работающими; подтвердить local JSON logs. 6. После восстановления проверить drain и gap. ### Telemetry отсутствует у одного сервиса 1. Проверить `service.name`, endpoint/protocol и сеть `observability`. 2. Проверить SDK queue/drop counters и clock. 3. Отправить synthetic request с `X-Request-ID`. 4. Найти его в stdout, Collector accepted и backend. 5. Проверить sampling/filter/redaction rules. ### Remote backend outage 1. Подтвердить exporter errors, а не application outage. 2. Оценить queue fill rate/time-to-full. 3. Ограничить debug exporter; не включать verbose. 4. При длительном outage увеличить sampling только через reviewed config. 5. После восстановления подтвердить drain и создать incident note о потере данных. ### Cardinality/ingest spike 1. Найти новое metric/log attribute по release annotation. 2. Отключить offending instrument/filter в Collector. 3. Проверить raw path/id/user/session labels. 4. Rollback instrumentation при риске стоимости/доступности. 5. Добавить CI regression test. ### Логи содержат секрет/PII 1. Ограничить доступ и остановить offending export. 2. Сохранить только incident metadata, не копировать значение. 3. Ротировать скомпрометированный secret. 4. Удалить данные по процедуре backend/provider. 5. Исправить source redaction + Collector defense; добавить canary test. Разбор высокой latency сообщения — в спецификации VM, которая владеет соответствующим hop. ## 17. Общий Definition of Done - Collector config проходит validate и запускается в root Compose каждой VM; - OTLP gRPC и HTTP принимают три сигнала; - все сервисы имеют правильные resource attributes из реестра §4; - request проходит nginx/API/Safety/Open Lines с одним `request_id` и связанным trace; - `ux_session_id` есть только где передан и не является label; - remote outage, queue full, Collector restart и backend recovery rehearsed; - local profile, если включён, имеет volumes/retention/auth и не публикует порты; - secret/PII canary отсутствует в logs/traces/metrics; - cardinality и sampling tests проходят; - SLO queries воспроизводимы и исключения документированы; - runbooks связаны с alerts; - dashboards и alerts provisioned из versioned files для SigNoz; до полного provisioning это остаётся acceptance/TBD, а не выполненный production DoD. Профильный DoD VM дополняет этот список своими сервисами и не переопределяет контракт. ## 18. Допущения, TBD и конфликты ### Решения - O1: обязательный архитектурный минимум — local Collector на каждой application VM; выбран self-hosted SigNoz на отдельной VM `192.168.0.5`, доступный по приватному OTLP gRPC. - O2: Prometheus/Grafana/Loki/Tempo — отдельный operable profile, не скрытая обязательная нагрузка основной VM. - O3: JSON stdout — аварийный локальный buffer; audit App DB — durable. - O4: telemetry fail-open для business path, но потеря telemetry alertится. - O5: ID/PII не labels; source redaction обязательна до Collector. Поля JSON, resource attributes, redaction, sampling, `service.namespace` и адрес SigNoz меняются только здесь. ### TBD - O-TBD1 закрыт: self-hosted SigNoz, `192.168.0.5:4317`, plaintext только внутри доверенной приватной сети; UI через SSH jump host. - O-TBD2: утвердить SLO/RPS/error-budget с product owner. - O-TBD3: legal retention/erasure и допустимость IP/user-agent. - O-TBD4: точные sampling и resource limits после load test. - O-TBD5: поддерживаемый nginx OTEL module и Keycloak native tracing по pinned versions. - O-TBD6: нужен ли local observability profile в первой VM — решает спецификация ВМ1. ### Обнаруженные архитектурные конфликты 1. `arch-03` разрешает stdout/platform exporter как минимум, но production-like расследования и alerts без backend ограничены. Закрыто выбором SigNoz (O1 / O-TBD1); stdout остаётся аварийным buffer. 2. `module-05` использует test-only terminal `400` и non-sticky verdict вместо canonical `403`/sticky production verdict. Dashboards обязаны маркировать сервис `stub`; production SLO Safety на нём недостоверен. Детали — спецификация ВМ2. 3. `module-07` задаёт full sync target; до code/portal cutover dashboard обязан показывать `sync_disabled`, а не синтетический CRM success. Queue/CRM SLI включаются только после module-07 preflight. Детали — спецификация ВМ2. 4. Retention, RPO/RTO и production SLO открыты в module-01/04/06/08; значения этого документа являются initial ops policy, не закрывают legal/product TBD. 5. Observability env (`OTEL_REMOTE_*`, service names, sampling/queue limits) добавлены в arch-04 и `.env.example`; sampling/queue limits уточняются после load test. ## 19. Ссылки - Профильные спецификации: [`module-09-observability-vm1.md`](../VM1_app/documentation/module-09-observability-vm1.md), [`module-09-observability-vm2.md`](../VM2_services/documentation/module-09-observability-vm2.md). - VM/Docker logging и firewall: [`../../HAN_chat/deploy/setup-vm-han-chat.sh`](../../HAN_chat/deploy/setup-vm-han-chat.sh). - Прототипный nginx stdout/access log: [`../../HAN_chat/bitrix-local-app/deploy/nginx/nginx.conf`](../../HAN_chat/bitrix-local-app/deploy/nginx/nginx.conf). - HTTP/OTLP registry: [`arch-02-api-contracts.md`](arch-02-api-contracts.md). - Compose topology: [`arch-03-docker-compose-blueprint.md`](arch-03-docker-compose-blueprint.md).