Przejdź do głównej zawartości

Wzorce Monitorowania i Logowania

Twoje API zwraca losowe błędy 500. Pulpity Grafany świecą na zielono, logi błędów nie pokrywają się ze spanami, a Twój PM chce oszacowania czasu. Bolesna prawda: konfiguracja obserwowalności jest drobiazgowa, łatwo ją źle skopiować, a ten jeden ślad, którego potrzebujesz, został odrzucony przez próbkowanie godzinę temu.

Ta receptura pokazuje, jak użyć Cursor, Claude Code i Codex do wygenerowania instrumentacji i konfiguracji, która wyłapuje te awarie — oraz jak połączyć AI bezpośrednio z Grafaną i Sentry, by mogło czytać telemetrię na żywo w trakcie debugowania.

  • Gotowy do wklejenia prompt, który automatycznie instrumentuje usługę Express lub FastAPI za pomocą OpenTelemetry i eksportuje OTLP do Twojego kolektora
  • Prompty generujące reguły nagrywania Prometheus, alerty burn-rate dla SLO oraz drzewo routingu AlertManagera, które możesz przejrzeć linijka po linijce
  • Prompt do pipeline’u Logstash, który parsuje logi JSON, redaguje PII i koreluje trace_id, dzięki czemu logi linkują z powrotem do śladów
  • Konfiguracja MCP dla Grafany i Sentry, która pozwala agentowi odpytywać Twoje prawdziwe pulpity i issues, zamiast zgadywać
  • Tryby awarii, które gryzą na produkcji — eksplozje kardynalności, gubione spany, próbkowanie ukrywające ślad, którego potrzebujesz

Zanim wygenerujesz konfigurację, daj agentowi wgląd w telemetrię na żywo. Z podłączonymi serwerami MCP Grafany i Sentry model może czytać pulpity, odpytywać źródła danych i wyciągać stosy wywołań — więc jego sugestie opierają się na Twoich rzeczywistych danych, a nie na ogólnym szablonie.

Dodaj do .cursor/mcp.json. Oficjalny serwer Sentry jest zdalny (hostowany); Grafana dostarcza oficjalny binarny plik Go, który uruchamiasz lokalnie i kierujesz na swoją instancję:

{
"mcpServers": {
"sentry": { "url": "https://mcp.sentry.dev/mcp" },
"grafana": {
"command": "mcp-grafana",
"env": {
"GRAFANA_URL": "https://grafana.example.com",
"GRAFANA_API_KEY": "${GRAFANA_SERVICE_ACCOUNT_TOKEN}"
}
}
}
}

Korzyść: zamiast wklejać stos wywołań do czatu, prosisz agenta, by go pobrał.

Zinstrumentuj Usługę (Tam, Gdzie Naprawdę Zaczyna Się Większość Bugów)

Dział zatytułowany „Zinstrumentuj Usługę (Tam, Gdzie Naprawdę Zaczyna Się Większość Bugów)”

Pulpity są pochodną instrumentacji. Jeśli usługa emituje złe atrybuty lub brak kontekstu śladu, żadna liczba paneli Grafany Cię nie uratuje. To rzecz o najwyższej dźwigni, którą trzeba zrobić dobrze, i jest identyczna niezależnie od tego, którego agenta używasz — liczy się prompt.

To, co generuje agent, to standardowy bootstrap SDK — częścią wartą przejrzenia jest eksporter i zamykanie:

// tracing.js — load with: node --require ./tracing.js server.js
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-proto');
const { resourceFromAttributes } = require('@opentelemetry/resources');
const {
ATTR_SERVICE_NAME,
ATTR_SERVICE_VERSION,
} = require('@opentelemetry/semantic-conventions');
const sdk = new NodeSDK({
resource: resourceFromAttributes({
[ATTR_SERVICE_NAME]: process.env.SERVICE_NAME ?? 'api-service',
[ATTR_SERVICE_VERSION]: process.env.SERVICE_VERSION ?? '0.0.0',
'deployment.environment': process.env.ENVIRONMENT ?? 'production',
}),
// Jaeger ingests OTLP natively since v1.35 — no Jaeger exporter needed.
traceExporter: new OTLPTraceExporter({
url: process.env.OTLP_ENDPOINT ?? 'http://otel-collector:4318/v1/traces',
}),
instrumentations: [getNodeAutoInstrumentations({
'@opentelemetry/instrumentation-fs': { enabled: false },
})],
});
sdk.start();
process.on('SIGTERM', () => sdk.shutdown().finally(() => process.exit(0)));

Pliki reguł Prometheus to obszar, gdzie pomoc AI błyszczy — składnia jest wybredna, a PromQL łatwo subtelnie zepsuć. Trzymaj prompt zdecydowany, by dostać reguły nagrywania metodą RED plus alerty burn-rate, a nie ścianę wszystkich metryk, jakie tylko można sobie wyobrazić.

Wygenerowane reguły nagrywania wyglądają tak — krótkie, łatwe do przejrzenia i będące fundamentem każdego alertu:

rules/api.yml
groups:
- name: api_recording
interval: 30s
rules:
- record: job:http_requests:rate5m
expr: sum by (job) (rate(http_requests_total[5m]))
- record: job:http_errors:ratio5m
expr: |
sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
/ sum by (job) (rate(http_requests_total[5m]))
- record: job:http_latency:p95_5m
expr: |
histogram_quantile(0.95,
sum by (job, le) (rate(http_request_duration_seconds_bucket[5m])))

Dla routingu AlertManagera przekaż agentowi swoją politykę eskalacji prostym językiem i pozwól mu wytworzyć drzewo:

Najbardziej wartościowy ruch w logowaniu to sprawienie, by logi linkowały ze śladami. Jeśli każda linia logu niesie trace_id, klikasz ze spanu w Grafanie prosto do otaczających logów. Poniższy prompt produkuje pipeline Logstash, który robi dokładnie to.

Blok korelacji śladów to część do zweryfikowania — upewnij się, że nazwy pól pasują do tego, co emituje Twój SDK OpenTelemetry:

filter {
if [message] =~ /^\{/ {
json { source => "message" target => "parsed" }
mutate {
rename => {
"[parsed][trace_id]" => "trace_id"
"[parsed][span_id]" => "span_id"
"[parsed][level]" => "log_level"
}
}
}
if [environment] == "production" and [log_level] == "DEBUG" { drop {} }
}

Domyślne próbkowanie nagłówka (head sampling) odrzuca ślady na ślepo — i tak właśnie znika ten jeden ślad, którego potrzebowałeś. Próbkowanie ogonowe (tail sampling) decyduje po zakończeniu śladu, więc możesz zachować 100% błędów i wolnych żądań, próbkując nudne rzeczy na poziomie 5%.

  1. Spany w ogóle się nie pojawiają. Najpierw sprawdź endpoint eksportera i niezgodność protokołu — OTLP/HTTP to 4318, OTLP/gRPC to 4317, a eksporter proto vs http/json musi pasować do odbiornika. Uruchom eksporter debug kolektora (verbosity: detailed), by potwierdzić, że spany docierają, zanim zaczniesz winić backend.

  2. Prometheus dostaje OOM albo scrapy są wolne. Masz eksplozję kardynalności. Odpytaj topk(20, count by (__name__)({__name__=~".+"})) oraz prometheus_tsdb_head_series, by znaleźć winowajcę, a potem usuń sprawczą etykietę regułą metric_relabel_configs. Niemal zawsze jest to etykieta dodana przez AI, której nie wyłapałeś podczas przeglądu.

  3. Alerty odpalają z opóźnieniem albo w burzach. Sprawdź ponownie for:, group_wait i repeat_interval. Alert burn-rate ze zbyt długim oknem nie zawiadomi, dopóki nie przepalisz już budżetu; group_wait: 0s na wszystkim zamienia awarię klastra w setki powiadomień.

  4. Logi nie korelują ze śladami. Nazwa pola trace_id z Twojego SDK nie pasuje do tego, czego oczekuje pipeline, albo jest zagnieżdżona. Zaloguj jedno surowe zdarzenie i potwierdź dokładną ścieżkę, zanim zaufasz blokowi rename/mutate.

  5. Ślad, którego potrzebowałeś, został odrzucony przez próbkowanie. Odrzuciło go próbkowanie nagłówka. Przenieś decyzje o błędach/opóźnieniu do próbkowania ogonowego w kolektorze (powyżej) i trzymaj błędy na 100%.