Przejdź do głównej zawartości

Monitorowanie i obserwowalność

Twój serwis checkout rzuca sporadycznymi błędami 504. Ślady urywają się na spanie bramki, dashboardy pokazują „wszystko na zielono”, a Twój PM chce ETA. Podejrzewasz dostawcę płatności, ale nie potrafisz tego udowodnić, bo połowa serwisów nie jest zinstrumentowana, a te które są, eksportują do instancji Jaeger, na którą nikt nie patrzy. To właśnie tę lukę asystenci AI do kodowania domykają najszybciej: zamieniają na wpół podłączony stos obserwowalności w ślady, metryki, dashboardy i alerty, które naprawdę odpowiadają na pytanie „co i dlaczego się zepsuło”.

  • Działającą konfigurację OpenTelemetry dla Node.js z aktualnym API @opentelemetry/resources 2.x (bez przestarzałej klasy Resource).
  • Trzy przepływy pracy specyficzne dla narzędzi (Cursor, Claude Code, Codex) do instrumentacji serwisu i postawienia stosu Grafany.
  • Gotowe do wklejenia prompty na dashboardy z metrykami RED, korelację sygnałów i polowanie na wąskie gardła, które działają przy minimalnej edycji.
  • Poprawne, zweryfikowane konfiguracje MCP dla Sentry i Grafany — te dwie, które naprawdę istnieją i są wydawane przez producentów.
  • Podręcznik trybów awarii dla trzech problemów z obserwowalnością, które marnują najwięcej czasu: wysokiej kardynalności, brakujących śladów i burz alertów.

Zacznij od poproszenia agenta o podłączenie OTel. Przepływ instrumentacji jest w dużej mierze identyczny we wszystkich trzech narzędziach — różnica polega na tym, jak je wywołujesz i jak każde radzi sobie z edycją wielu plików. Wskaż agentowi jawnie aktualne API 2.x; pozostawiony sam sobie sięgnie po usuniętą klasę Resource i przestarzałe SemanticResourceAttributes.

Otwórz tryb Agent (Cmd/Ctrl+I) i odwołaj się do bazy kodu, aby podchwycił Twój istniejący punkt wejścia i zależności:

@codebase Set up OpenTelemetry for our Node.js Express service.
Requirements:
- Use @opentelemetry/sdk-node with getNodeAutoInstrumentations
- Build the Resource with resourceFromAttributes() from @opentelemetry/resources
(the Resource class is removed in resources 2.x) and ATTR_SERVICE_NAME /
ATTR_SERVICE_VERSION from @opentelemetry/semantic-conventions
- OTLP/gRPC exporters for traces and metrics
- Disable the fs instrumentation (too noisy)
- Load it via node --require before app code, not inline

Przejrzyj diff w edytorze wieloplikowym, zanim go zaakceptujesz — Cursor zwykle dotknie package.json, nowego instrumentation.ts oraz Twojego skryptu startowego.

Agent powinien wyprodukować coś zbliżonego do tego. Zwróć uwagę na API 2.x — resourceFromAttributes zamiast new Resource(...) oraz stałe z prefiksem ATTR_ zamiast SemanticResourceAttributes:

// instrumentation.ts — loaded via: node --require ./instrumentation.ts app.js
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { resourceFromAttributes } from '@opentelemetry/resources';
import {
ATTR_SERVICE_NAME,
ATTR_SERVICE_VERSION,
ATTR_DEPLOYMENT_ENVIRONMENT_NAME,
} 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({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT }),
metricReader: new PeriodicExportingMetricReader({
exporter: new OTLPMetricExporter({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT }),
exportIntervalMillis: 30_000,
}),
instrumentations: [
getNodeAutoInstrumentations({
'@opentelemetry/instrumentation-fs': { enabled: false },
}),
],
});
sdk.start();

Dla spanów na poziomie biznesowym importuj API jawnie — trace i metrics pochodzą z @opentelemetry/api, którego automatyczna instrumentacja nie importuje za Ciebie:

import { trace } from '@opentelemetry/api';
export function startBusinessSpan(operation: string, attrs: Record<string, string>) {
const tracer = trace.getTracer('business-operations');
return tracer.startSpan(operation, { attributes: { 'business.operation': operation, ...attrs } });
}

Gdy spany i metryki już płyną, postaw warstwę składowania i wizualizacji. Typowy stos to OTel Collector do rozdzielania ruchu, Prometheus na metryki, Loki na logi, Tempo na ślady i Grafana na wierzchu. Poproś agenta o plik Compose, a następnie o dashboard.

Konfiguracja Loki to miejsce, gdzie agenci najczęściej emitują martwą składnię. Nalegaj na aktualny schemat TSDB — boltdb-shipper, schema: v11 oraz klucz shared_store są przestarzałe i nie wystartują na Loki 3.x:

# Loki 3.x — TSDB schema (v13). shared_store is removed; do not add it.
schema_config:
configs:
- from: 2024-04-01
store: tsdb
object_store: s3
schema: v13
index:
prefix: index_
period: 24h
storage_config:
tsdb_shipper:
active_index_directory: /loki/tsdb-index
cache_location: /loki/tsdb-cache
aws:
s3: s3://endpoint/bucket
s3forcepathstyle: true
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
# storage backend comes from storage_config; no shared_store here

Krok 3: Wygeneruj reguły alertów, które reagują na właściwy sygnał

Dział zatytułowany „Krok 3: Wygeneruj reguły alertów, które reagują na właściwy sygnał”

Reguły alertów łatwo skonfigurować w subtelnie błędny sposób — nazwa metryki dryfuje, próg jest arbitralny albo reguła odwołuje się do metryki, której Twój eksporter już nie emituje. Poproś o reguły świadome SLO i przypnij metryki do tego, co kube-state-metrics faktycznie produkuje dzisiaj.

# Prometheus alert rules. Memory headroom uses kube_pod_container_resource_limits,
# not the removed cAdvisor container_spec_memory_limit_bytes metric.
groups:
- name: service_health
interval: 30s
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/ sum(rate(http_requests_total[5m])) by (service) > 0.05
for: 5m
labels: { severity: critical, team: platform }
annotations:
summary: "High error rate on {{ $labels.service }}"
runbook_url: "https://wiki.example.com/runbooks/high-error-rate"
- alert: PodMemoryUsageHigh
expr: |
sum(container_memory_working_set_bytes{pod!=""}) by (pod, container)
/ sum(kube_pod_container_resource_limits{resource="memory"}) by (pod, container) > 0.9
for: 5m
labels: { severity: warning }
annotations:
summary: "Pod {{ $labels.pod }} memory usage > 90%"

Dwa serwery MCP zamieniają Twojego agenta w asystenta dyżurnego, który potrafi odczytywać dane na żywo o błędach i z dashboardów. Oba są oficjalne od producentów — zachowaj ostrożność, bo rejestr npm ma dla obu zarówno zaślepki, jak i podróbki firm trzecich.

Kanoniczna instalacja to zdalny serwer przez HTTP z OAuth — żadnego tokenu do zarządzania, działa identycznie w Cursorze, Claude Code i Codeksie:

Okno terminala
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp

Jeśli potrzebujesz lokalnego serwera stdio (środowisko odcięte od sieci albo self-hosted Sentry), użyj oficjalnego pakietu @sentry/mcp-servera nie sentry-mcp, który jest niepowiązaną zaślepką 0.0.1. Zmienna środowiskowa to SENTRY_ACCESS_TOKEN, a instancje self-hosted przekazują --host z samą nazwą hosta:

{
"mcpServers": {
"sentry": {
"command": "npx",
"args": [
"-y",
"@sentry/mcp-server",
"--access-token=${SENTRY_ACCESS_TOKEN}",
"--host=your-org.sentry.io"
]
}
}
}

Oficjalny serwer to grafana/mcp-grafana, binarka Go dystrybuowana przez uvx (lub Docker/Helm) — a nie wrapper npm firmy trzeciej @leval/mcp-grafana. Uwierzytelniaj się tokenem konta serwisowego (GRAFANA_SERVICE_ACCOUNT_TOKEN); klucze API Grafany są przestarzałe:

{
"mcpServers": {
"grafana": {
"command": "uvx",
"args": ["mcp-grafana"],
"env": {
"GRAFANA_URL": "https://grafana.example.com",
"GRAFANA_SERVICE_ACCOUNT_TOKEN": "${GRAFANA_SERVICE_ACCOUNT_TOKEN}"
}
}
}
}

Trzy tryby awarii odpowiadają za większość zmarnowanych godzin. Przekaż agentowi objaw wraz z konkretnym zapytaniem, które powinien uruchomić.

Prometheus zwalnia do pełzania, a pamięć puchnie — zwykle przez etykietę taką jak user_id lub surowy URL wysadzający liczbę szeregów czasowych.

Analyze our Prometheus instance for high-cardinality metrics:
- Run topk(10, count by (__name__)({__name__=~".+"})) to find the worst metrics
- Identify which labels are unbounded (user IDs, request IDs, raw paths)
- Propose recording rules to pre-aggregate, and relabel_config to drop the offending labels
  • Pipeline’y CI/CD — wepnij walidację dashboardów i reguł alertów do swojego pipeline’u wdrożeniowego.
  • Reagowanie na incydenty — wykorzystaj sygnały, które właśnie zinstrumentowałeś, do szybszego postmortemu.
  • Wzorce debugowania — przepływ trace-to-logs, gdy alert w końcu zareaguje.