Monitorowanie i obserwowalność
ENMonitorowanie i obserwowalność z agentami AI polegają na tym, że Claude Code, Codex lub Cursor instrumentują serwis przez OpenTelemetry, generują konfigurację kolektora, dashboardów i alertów, a każdy element jest sprawdzany maszynowo — testami reguł promtool, walidatorami konfiguracji i zapytaniami na żywo przez serwery MCP Sentry i Grafany — więc nikt nie musi czytać wygenerowanego YAML-a linijka po linijce.
Serwis checkout sporadycznie zwraca 504. Ślady urywają się na spanie bramki, dashboard jest zielony, a alert, który powinien był zadziałać, odwołuje się do metryki, której instrumentacja przestała emitować dwa wydania temu. Agent postawi cały stos w jedno popołudnie; ta strona mówi, jak się upewnić, że to, co postawił, jest prawdą.
Strona jest dla developera, który odpowiada za serwis, i tech leada, który zatwierdza alerting. Dotyczy obserwowania twojego serwisu. Obserwowanie samych agentów — ich śladów, wywołań narzędzi, kosztów i logów audytowych — opisuje strona obserwowalność agentów.
Co daje monitoring zbudowany przez agenta
Dział zatytułowany „Co daje monitoring zbudowany przez agenta”- Bootstrap OpenTelemetry dla serwisu Node.js na aktualnych pakietach, z nazwami metryk, które te pakiety faktycznie emitują.
- Reguły alertów z testami jednostkowymi
promtool, dzięki czemu pytanie „czy alert odpali przy 10% błędów i zamilknie przy 1%?” rozstrzyga CI, a nie opinia w code review. - Polecenia walidujące każdą wygenerowaną konfigurację (Collector, Loki, Alertmanager) i prompt, który sprawdza, czy każdy panel dashboardu zwraca dane.
- Dostęp tylko do odczytu do Sentry i Grafany przez MCP, żeby agent czytał prawdziwe nazwy metryk i błędy zamiast je zgadywać.
- Plan naprawczy dla pięciu typowych sposobów, w jakie psuje się obserwowalność zbudowana przez agenta.
W jakiej kolejności budować monitoring serwisu z agentem?
Dział zatytułowany „W jakiej kolejności budować monitoring serwisu z agentem?”Kolejność nie jest przypadkowa: każda warstwa jest tyle warta, co warstwa pod nią. Alert na nieistniejącej metryce nigdy nie odpali i nic nie zgłosi, że nie odpala.
| Krok | Co generuje agent | Co dowodzi poprawności bez czytania kodu |
|---|---|---|
| 1. Instrumentacja | Bootstrap SDK OpenTelemetry | Trace ID żądania znaleziony w Tempo; lista nazw metryk z Prometheusa |
| 2. Potok | Konfiguracja Collectora, Prometheusa, Loki, Tempo i Grafany | otelcol validate, loki -verify-config=true, promtool check config |
| 3. Alerty | Reguły Prometheusa i routing Alertmanagera | promtool test rules, amtool check-config |
| 4. Dashboardy | JSON dashboardu Grafany | Zapytanie każdego panelu zwraca dane (sprawdzone przez Grafana MCP) |
| 5. Dostęp na żywo | Serwery MCP Sentry i Grafany | Tokeny tylko do odczytu; agent odpowiada na jedno pytanie incydentowe od zapytania do wniosku |
Nie pozwól agentowi przeskoczyć od razu do dashboardów. Dashboard zbudowany, zanim krok 1 został udowodniony, stoi na zgadniętych nazwach metryk.
Zinstrumentuj serwis Node.js przez OpenTelemetry
Dział zatytułowany „Zinstrumentuj serwis Node.js przez OpenTelemetry”Prompt jest ten sam we wszystkich trzech narzędziach; różni się miejsce uruchomienia i sposób zatwierdzania zmian. Prompt przypina aktualne API, bo modele uczone na starszych tutorialach sięgają po usuniętą klasę Resource i po nazwy metryk, których już nie ma.
Uruchom go z katalogu głównego repozytorium. Interaktywnie: włącz claude i wklej prompt. Do przebiegu skryptowego zapisz prompt w pliku i użyj trybu print. acceptEdits zatwierdza tylko edycje plików i odrzuca polecenia powłoki niedozwolone przez twoje reguły uprawnień, więc zezwól na trzy polecenia, których prompt potrzebuje do instalacji pakietów, uruchomienia usługi i wywołania GET /health (flagi sprawdzone w Claude Code 2.1.283):
claude -p "$(cat prompts/otel-bootstrap.md)" --permission-mode acceptEdits \ --allowedTools "Bash(npm *)" "Bash(node *)" "Bash(curl *)" --output-format jsonWynik JSON zawiera ID sesji i końcową odpowiedź, które możesz zarchiwizować razem z pull requestem.
Interaktywnie: uruchom codex w repozytorium i wklej prompt; domyślnie zatwierdzenia trafiają do ciebie. Do przebiegu bez nadzoru w jednorazowym checkoucie pozwól automatycznemu recenzentowi Codeksa odpowiadać na prośby o zatwierdzenie w sandboksie workspace-write:
codex exec --approve-for-me "$(cat prompts/otel-bootstrap.md)"--approve-for-me istnieje zarówno w codex, jak i w codex exec w codex-cli 0.157.1. Dodaj --json, żeby strumieniować zdarzenia jako JSONL do logu CI.
Otwórz panel Agent, wklej prompt i przejrzyj proponowany diff przed akceptacją. Spodziewaj się zmian w package.json, nowego src/instrumentation.ts i zmiany skryptu startowego. Poproś agenta, żeby sam uruchomił serwis i wysłał testowe żądanie; akceptacja diffu bez tego przebiegu pomija krok, który dowodzi, że instrumentacja działa.
Wynik powinien wyglądać mniej więcej tak. Wersje pakietów aktualne na 2026-09-26: @opentelemetry/sdk-node 0.222.0, @opentelemetry/resources 2.11.0, @opentelemetry/semantic-conventions 1.43.0.
// src/instrumentation.ts — compiled, then loaded with: node --require ./dist/instrumentation.js dist/server.js// (ESM service: node --experimental-loader=@opentelemetry/instrumentation/hook.mjs --import ./dist/instrumentation.js dist/server.js)import { NodeSDK } from '@opentelemetry/sdk-node';import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';import { resourceFromAttributes } from '@opentelemetry/resources';import { ATTR_DEPLOYMENT_ENVIRONMENT_NAME, ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION,} from '@opentelemetry/semantic-conventions';import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
const sdk = new NodeSDK({ resource: resourceFromAttributes({ [ATTR_SERVICE_NAME]: process.env.SERVICE_NAME ?? 'checkout', [ATTR_SERVICE_VERSION]: process.env.SERVICE_VERSION ?? '0.0.0', [ATTR_DEPLOYMENT_ENVIRONMENT_NAME]: process.env.NODE_ENV ?? 'development', }), traceExporter: new OTLPTraceExporter(), metricReader: new PeriodicExportingMetricReader({ exporter: new OTLPMetricExporter(), exportIntervalMillis: 30_000, }), instrumentations: [ getNodeAutoInstrumentations({ '@opentelemetry/instrumentation-fs': { enabled: false } }), ],});
sdk.start();process.on('SIGTERM', () => sdk.shutdown().finally(() => process.exit(0)));Eksportery same czytają OTEL_EXPORTER_OTLP_ENDPOINT ze środowiska. Zwykłe node --require ./src/instrumentation.ts nie zadziała na pliku .ts — dlatego prompt prosi o skompilowany plik. Serwis ESM ("type": "module") wymaga więcej: --require nie przechwytuje importów modułów ES, więc Express i http mogą działać, nie tworząc ani jednego spanu. Załaduj plik przez node --import ./dist/instrumentation.js i zarejestruj hook loadera @opentelemetry/instrumentation/hook.mjs zgodnie z przewodnikiem OpenTelemetry dla ESM, a potem potwierdź konfigurację, odnajdując identyfikator śladu żądania w Tempo.
Jakie nazwy metryk HTTP emituje aktualne OpenTelemetry?
Dział zatytułowany „Jakie nazwy metryk HTTP emituje aktualne OpenTelemetry?”To pułapka, która po cichu psuje alerty pisane przez agentów. Od @opentelemetry/instrumentation-http 0.222.0 (sprawdzone 2026-09-26) README pakietu mówi, że emitowane są wyłącznie stabilne konwencje semantyczne HTTP: histogram http.server.request.duration w sekundach, z atrybutami takimi jak http.route i http.response.status_code. Wersje do 0.221.0 domyślnie emitowały stare http.server.duration w milisekundach. Tutoriale sprzed 0.222.0 — a więc i modele na nich uczone — używają starej nazwy.
Po translacji z OTLP do Prometheusa nowy histogram zwykle pojawia się jako http_server_request_duration_seconds_bucket, _count i _sum, z etykietami http_route i http_response_status_code. „Zwykle” jest tu ważne: dokładne nazwy zależą od ustawień translacji w twoim Prometheusie. Stąd zasada: agent czyta nazwy metryk z działającego Prometheusa, zanim napisze pierwsze zapytanie.
# Terminal: list what Prometheus actually storescurl -s http://localhost:9090/api/v1/label/__name__/values | jq -r '.data[]' | grep '^http_server'Jeśli ta lista jest pusta, zatrzymaj się. Nic dalej nie będzie poprawne.
Postaw kolektor, Prometheusa, Loki, Tempo i Grafanę
Dział zatytułowany „Postaw kolektor, Prometheusa, Loki, Tempo i Grafanę”Poproś o plik Compose (albo wartości Helma) jednym promptem, a potem zwaliduj każdą wygenerowaną konfigurację narzędziem danego komponentu, zanim cokolwiek uruchomisz. Walidator jest szybszy niż debugowanie pętli restartów i nie wymaga czytania pliku. Zastąp LOKI_VERSION tagiem 3.x, który wdrażasz.
# Terminal: validate the configs the agent generatedotelcol validate --config=otel-collector.yaml # use your distribution's binary, e.g. otelcol-contribpromtool check config prometheus.ymldocker run --rm -v "$PWD":/config grafana/loki:LOKI_VERSION -config.file=/config/loki.yaml -verify-config=trueW Loki agenci najczęściej produkują martwą składnię. Loki 3.0 usunęło ustawienia shared_store dla shipperów TSDB i BoltDB, a structured metadata jest domyślnie włączone i wymaga, by aktywny schemat używał jednocześnie indeksu tsdb i schematu v13 (według przewodnika aktualizacji Loki 3.0 od Grafany). Wygenerowana konfiguracja z boltdb-shipper, schema: v11 albo shared_store nie przejdzie walidacji. Aktualny kształt:
# loki.yaml (Loki 3.x): TSDB index, schema v13, no shared_store anywhereschema_config: configs: - from: 2026-01-01 store: tsdb object_store: s3 schema: v13 index: prefix: index_ period: 24hstorage_config: tsdb_shipper: active_index_directory: /loki/tsdb-index cache_location: /loki/tsdb-cache aws: s3: s3://s3.eu-central-1.amazonaws.com/checkout-logs s3forcepathstyle: truecompactor: working_directory: /loki/compactorWygeneruj reguły alertów, które przetestujesz bez czytania
Dział zatytułowany „Wygeneruj reguły alertów, które przetestujesz bez czytania”Reguła alertu to mały program, a promtool test rules to jego runner testów jednostkowych. Agent pisze regułę i test razem; test podaje syntetyczne serie i sprawdza, kiedy alert odpala, a kiedy milczy. Ty przeglądasz przypadki testowe — „odpala przy 10% błędów, milczy przy 1%” — czyli dwie linijki intencji, a nie PromQL.
groups: - name: checkout-slo rules: - alert: CheckoutHighErrorRatio expr: | sum by (job) (rate(http_server_request_duration_seconds_count{job="checkout", http_response_status_code=~"5.."}[5m])) / sum by (job) (rate(http_server_request_duration_seconds_count{job="checkout"}[5m])) > 0.05 for: 5m labels: severity: critical annotations: summary: "5xx ratio above 5% on {{ $labels.job }}" runbook_url: "https://runbooks.example.com/checkout-5xx"# alerts_test.yml — run with: promtool test rules alerts_test.ymlrule_files: [alerts.yml]evaluation_interval: 1mtests: # 10% of requests fail: the alert must fire once `for: 5m` has elapsed - interval: 1m input_series: - series: 'http_server_request_duration_seconds_count{job="checkout", http_route="/pay", http_response_status_code="500"}' values: '0+10x20' - series: 'http_server_request_duration_seconds_count{job="checkout", http_route="/pay", http_response_status_code="200"}' values: '0+90x20' alert_rule_test: - eval_time: 3m alertname: CheckoutHighErrorRatio exp_alerts: [] - eval_time: 15m alertname: CheckoutHighErrorRatio exp_alerts: - exp_labels: { severity: critical, job: checkout } exp_annotations: summary: "5xx ratio above 5% on checkout" runbook_url: "https://runbooks.example.com/checkout-5xx" # 1% of requests fail: the alert must stay silent - interval: 1m input_series: - series: 'http_server_request_duration_seconds_count{job="checkout", http_route="/pay", http_response_status_code="500"}' values: '0+1x20' - series: 'http_server_request_duration_seconds_count{job="checkout", http_route="/pay", http_response_status_code="200"}' values: '0+99x20' alert_rule_test: - eval_time: 15m alertname: CheckoutHighErrorRatio exp_alerts: []Gdy agent później edytuje regułę, trzymaj plik testu poza jego zasięgiem — z tego samego powodu, dla którego chronisz każdą wyrocznię testową: agent poproszony o „przejście testu” może osłabić asercję zamiast naprawić regułę. Zobacz ochronę wyroczni testowej.
Routing Alertmanagera traktujesz tak samo: amtool check-config alertmanager.yml wyłapuje błędy składni i nieznane odbiorniki, a amtool config routes test --config.file=alertmanager.yml severity=critical service=checkout pokazuje, do którego odbiornika trafi dany zestaw etykiet.
Wepnij sprawdzenia w CI
Dział zatytułowany „Wepnij sprawdzenia w CI”Walidatory chronią cię tylko wtedy, gdy uruchamiają się przy każdej zmianie. Taki job sprawia, że „alert odpala przy 10% błędów” staje się wymaganym checkiem pull requesta:
# .github/workflows/observability.yml (excerpt)jobs: alert-tests: runs-on: ubuntu-latest permissions: contents: read steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Test alert rules run: | docker run --rm -v "$PWD/observability:/w" -w /w --entrypoint promtool \ prom/prometheus:PROMETHEUS_VERSION check rules alerts.yml docker run --rm -v "$PWD/observability:/w" -w /w --entrypoint promtool \ prom/prometheus:PROMETHEUS_VERSION test rules alerts_test.ymlZastąp PROMETHEUS_VERSION tagiem Prometheusa, którego używasz na produkcji, żeby reguły testował ten sam parser, który je ładuje. Szerszy potok opisuje strona potoki CI/CD.
Sprawdź, czy każdy panel dashboardu zwraca dane
Dział zatytułowany „Sprawdź, czy każdy panel dashboardu zwraca dane”Wygenerowany dashboard psuje się po cichu: zła nazwa metryki renderuje się jako „No data”, co wygląda jak spokojny system. Zamiast klikać po panelach, niech agent uruchomi zapytanie każdego panelu przez serwer Grafana MCP i zgłosi te, które nic nie zwracają.
Ta tabela to dowód, który dołączasz do pull requesta. Tech lead zatwierdza na podstawie „każdy panel zwraca serie” i zrzutu ekranu, a nie JSON-a.
Daj agentowi dostęp do sygnałów z produkcji przez MCP
Dział zatytułowany „Daj agentowi dostęp do sygnałów z produkcji przez MCP”Dwa oficjalne serwery MCP od dostawców pozwalają agentowi czytać to, co widzi dyżurny: Sentry (zgłoszenia błędów, zdarzenia, ślady i analiza Seer) oraz Grafana (dashboardy, Prometheus, Loki, incydenty). Popularność według dossier MCP, odczyt 2026-09-26: grafana/mcp-grafana ma około 3,5 tys. gwiazdek na GitHubie, a getsentry/sentry-mcp około 862. Sentry jest też w marketplace’ach pluginów Claude Code i Codeksa; Grafana udostępnia pluginy Claude Code (grafana-mcp, grafana-cloud-mcp). Użytkownicy Datadoga mają oficjalny zdalny serwer https://mcp.datadoghq.com/v1/mcp (US1; inne regiony zmieniają host). Pełny katalog znajdziesz na stronie serwery MCP do obserwowalności.
# Sentry: remote server with OAuth; authenticate with /mcp inside a sessionclaude mcp add --transport http sentry https://mcp.sentry.dev/mcp
# Grafana: read-only; use a Viewer-role service-account tokenclaude mcp add grafana -e GRAFANA_URL=https://grafana.example.com \ -e GRAFANA_SERVICE_ACCOUNT_TOKEN="$GRAFANA_TOKEN" -- uvx mcp-grafana --disable-writecodex mcp add sentry --url https://mcp.sentry.dev/mcpcodex mcp login sentry
codex mcp add grafana --env GRAFANA_URL=https://grafana.example.com \ --env GRAFANA_SERVICE_ACCOUNT_TOKEN="$GRAFANA_TOKEN" -- uvx mcp-grafana --disable-writeDodaj oba serwery do .cursor/mcp.json, a potem zaloguj się do Sentry, gdy Cursor o to poprosi:
{ "mcpServers": { "sentry": { "url": "https://mcp.sentry.dev/mcp" }, "grafana": { "command": "uvx", "args": ["mcp-grafana", "--disable-write"], "env": { "GRAFANA_URL": "https://grafana.example.com", "GRAFANA_SERVICE_ACCOUNT_TOKEN": "${env:GRAFANA_TOKEN}" } } }}Cursor wstawia zmienne środowiskowe w składni ${env:NAZWA}, a nie ${NAZWA}. Ta składnia pochodzi z dokumentacji MCP Cursora (SECONDARY), więc sprawdź ją w swojej wersji Cursora.
Jeśli twój zespół używa Sentry, jego skille uzupełniają serwer MCP: sentry-instrument, sentry-debug-issue i sentry-otel-exporter-setup są w getsentry/sentry-for-ai. Zainstalujesz je przez claude plugin install sentry@claude-plugins-official; w Codeksie przez /plugins → wyszukaj „sentry” (wpis jest na liście openai-curated; forma CLI codex plugin add sentry@openai-curated wymaga zalogowanego konta, bo marketplace jest udostępniany przy logowaniu; sprawdzone w codex-cli 0.157.1); w Cursorze zainstaluj wtyczkę Sentry dla Cursora (getsentry/plugin-cursor); inni agenci mogą pobrać te same skille z skills.sentry.dev. Samo repozytorium getsentry/sentry-for-ai jest źródłem skilli, a jego README każe instalować wtyczkę dla danego klienta, a nie repozytorium (sprawdzone 2026-10-02). Skill wybierz, gdy chcesz powtarzalnej procedury; serwer MCP — gdy agent potrzebuje danych na żywo.
Kto zatwierdza monitoring wygenerowany przez agenta?
Dział zatytułowany „Kto zatwierdza monitoring wygenerowany przez agenta?”Właściciel serwisu zatwierdza dowody; tech lead odpowiada za politykę alertowania. Żaden z nich nie czyta wygenerowanego YAML-a od początku do końca. Pull request, który dodaje lub zmienia monitoring, zawiera:
- Listę nazw metryk
http_server_*z działającego Prometheusa i trace ID jednego żądania znalezionego w Tempo. - Zielone wyniki
otelcol validate,promtool check config,loki -verify-config=trueiamtool check-config. - Zielone
promtool test rules, gdzie każdy alert ma jeden przypadek „musi odpalić” i jeden „musi milczeć”. - Tabelę paneli z promptu dashboardowego, bez pustych paneli.
- Potwierdzenie, że tokeny MCP są tylko do odczytu.
Tech lead przegląda przypadki testowe i progi, bo to w nich zapisana jest intencja: próg 5%, opóźnienie for: 5m i cel SLO.
Co się psuje, gdy agent buduje twoją obserwowalność?
Dział zatytułowany „Co się psuje, gdy agent buduje twoją obserwowalność?”Objaw: puste panele, alerty, które nigdy nie odpalają, zielone promtool test rules przy cichej produkcji.
Przyczyna: agent napisał z pamięci http_server_duration albo http_requests_total, a instrumentacja emituje http.server.request.duration.
Naprawa: uruchom powyższy curl z nazwami metryk i przekaż agentowi listę:
Here is the output of /api/v1/label/__name__/values filtered to http_server_*. Rewrite everyquery in observability/ to use only these names, rerun promtool test rules with series namedthe same way, and list each query you changed.Objaw: pamięć Prometheusa rośnie, zapytania zwalniają.
Przyczyna: nieograniczona etykieta, np. ID użytkownika, ID żądania albo surowa ścieżka URL zamiast http.route.
Naprawa:
Run topk(10, count by (__name__)({__name__=~".+"})) on our Prometheus through the Grafana MCP.For the top three metrics, find the label with the most distinct values. Propose a Collectorattributes processor or a relabel_config that drops or buckets it, and show the series countbefore and after on a staging Prometheus.Objaw: spany istnieją dla bramki, ale nie dla serwisów za nią.
Przyczyna: traceparent nie jest przekazywany (własny klient HTTP albo kolejka) lub sampler odrzuca spany potomne.
Naprawa:
Traces stop at our API gateway. Check that every outbound HTTP client and queue producer inthis repo propagates W3C traceparent (list any that bypass the instrumented clients), show thesampler configuration in the SDK and the Collector, then send one request with a forced-sampletraceparent and confirm through the Grafana MCP that Tempo shows the full trace.Objaw: jeden incydent budzi dyżurnego pięćdziesiąt razy.
Przyczyna: brak grupowania i inhibicji w Alertmanagerze; każdy alert objawowy idzie osobno.
Naprawa: poproś o group_by: [alertname, service], wpis inhibit_rules, dzięki któremu alert krytyczny wycisza powiązane ostrzeżenia, oraz wynik amtool config routes test pokazujący, że każda ważność trafia do właściwego odbiornika.
Objaw: Loki kończy działanie przy starcie po aktualizacji albo z wygenerowaną konfiguracją.
Przyczyna: przestarzałe shared_store, boltdb-shipper albo schemat starszy niż v13 przy włączonym structured metadata.
Naprawa: dodaj w schema_config nowy okres ze store: tsdb i schema: v13, zaczynający się w przyszłości, zostaw stary okres dla istniejących danych i ponownie uruchom -verify-config=true. Do czasu startu nowego okresu tymczasowo ustaw allow_structured_metadata: false.
Każdy taki przypadek oznacz w dzienniku incydentów klasą błędu agenta, która za nim stoi — najczęściej „wymyślone API” albo „nieaktualne dane treningowe” — żeby widzieć, jaką kontrolę dodać w następnej kolejności. Klasy definiuje taksonomia błędów.
Dokąd dalej z monitorowaniem i obserwowalnością
Dział zatytułowany „Dokąd dalej z monitorowaniem i obserwowalnością”- Reagowanie na incydenty z AI: użyj tych sygnałów i serwerów MCP, gdy alert odpali.
- Obserwowalność agentów: ten sam stos OpenTelemetry skierowany na przebiegi, wywołania narzędzi i koszty twoich agentów.
- Zakresowany triaż incydentów z AI: uruchamiaj prompt triażu pod tożsamością tylko do odczytu, gdy mitygacją kieruje wskazany człowiek.
- Stopniowe wdrażanie (progressive delivery): powyższe alerty SLO stają się wyzwalaczem wycofania wdrożenia kanarkowego.
- Optymalizacja wydajności na produkcji: zamień histogramy opóźnień w celowane poprawki.
- Wzorce monitorowania i logowania: więcej przepisów na logi, złote sygnały i alerty burn-rate.