Konfiguracja obserwowalnośćci
Obserwowalnośćć to różnica między zgadywaniem a wiedzą o tym, co dzieje się w twoich systemach. Czy śledzisz wydajność, debugujesz problemy, czy optymalizujesz koszty, Claude Code przekształca monitorowanie z myśli końcowej w praktykę rozwoju pierwszej klasy. Ta lekcja bada, jak wykorzystać pomoc AI do kompleksowej obserwowalnośćci.
Rewolucja obserwowalnośćci
Dział zatytułowany „Rewolucja obserwowalnośćci”Scenariusz: Twoja aplikacja obsługuje miliony żądań dziennie w dziesiątkach mikroserwisów. Gdy coś pójdzie nie tak, potrzebujesz odpowiedzi w sekundach, nie godzinach. Tradycyjne podejście: grep przez logi, zgadywanie korelacji, nadzieja na najlepsze. Z Claude Code: inteligentne monitorowanie, które mówi ci co jest nie tak, zanim użytkownicy to zauważą.
Tradycyjna vs obserwowalnośćć wspomagana AI
Dział zatytułowany „Tradycyjna vs obserwowalnośćć wspomagana AI”Tydzień 1: Podstawowe logowanie- Console.log wszędzie- Brak struktury czy spójności- Logi gubione przy restarcie kontenera
Tydzień 2: Konfiguracja metryk- Ręczna instrumentacja metryk- Podstawowe wykresy CPU/pamięci- Brak niestandardowych metryk biznesowych
Tydzień 3: Kryzys debugowania- Problem produkcyjny o 3 w nocy- Grep przez gigabajty logów- Brak korelacji między usługami
Tydzień 4: Post-mortem- "Potrzebujemy lepszego monitorowania"- Zaczynamy od nowa z nowymi narzędziami
Dzień 1: Kompletna konfiguracja> Skonfiguruj OpenTelemetry z:> - Strukturalnym logowaniem> - Rozproszonymi tracingami> - Niestandardowymi metrykami> - Śledzeniem błędów
Dzień 2: Dashboardy i alerty> Stwórz dashboardy Grafana> Skonfiguruj inteligentne alerty> Ustaw wykrywanie anomalii
Godzina 3: Odpowiedź na incydent> Koreluj logi, metryki, traces> Szybko zidentyfikuj podstawową przyczynę> Automatycznie wygeneruj runbook
Ciągle: Ciągłe ulepszenia> Sugeruj nowe metryki> Optymalizuj wydajność> Redukuj koszty monitorowania
Integracja OpenTelemetry
Dział zatytułowany „Integracja OpenTelemetry”Kompletna konfiguracja OpenTelemetry
Dział zatytułowany „Kompletna konfiguracja OpenTelemetry”> Skonfiguruj OpenTelemetry dla naszej aplikacji Node.js:> - Automatyczna instrumentacja> - Niestandardowe spany i metryki> - Korelacja logów> - Export do wielu backendów> - Konfiguracja specyficzna dla środowiska
Claude generuje kompleksową konfigurację:
- Zainstaluj zależności
npm install @opentelemetry/api \ @opentelemetry/sdk-node \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/exporter-metrics-otlp-http \ @opentelemetry/exporter-trace-otlp-http \ @opentelemetry/instrumentation-http \ @opentelemetry/instrumentation-express \ @opentelemetry/instrumentation-winston
-
Stwórz konfigurację telemetrii
telemetry.js const { NodeSDK } = require('@opentelemetry/sdk-node');const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');const { Resource } = require('@opentelemetry/resources');const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-http');const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics');// Skonfiguruj atrybuty zasobówconst resource = Resource.default().merge(new Resource({[SemanticResourceAttributes.SERVICE_NAME]: process.env.SERVICE_NAME || 'myapp',[SemanticResourceAttributes.SERVICE_VERSION]: process.env.SERVICE_VERSION || '1.0.0',[SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV || 'development','team.name': 'platform','team.owner': 'engineering'}));// Skonfiguruj eksporter tracinguconst traceExporter = new OTLPTraceExporter({url: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT || 'http://localhost:4318/v1/traces',headers: {'api-key': process.env.OTEL_EXPORTER_API_KEY}});// Skonfiguruj eksporter metrykconst metricExporter = new OTLPMetricExporter({url: process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT || 'http://localhost:4318/v1/metrics',headers: {'api-key': process.env.OTEL_EXPORTER_API_KEY}});// Zainicjalizuj SDKconst sdk = new NodeSDK({resource,traceExporter,metricReader: new PeriodicExportingMetricReader({exporter: metricExporter,exportIntervalMillis: 10000}),instrumentations: [getNodeAutoInstrumentations({'@opentelemetry/instrumentation-fs': {enabled: false // Wyłącz hałaśliwą instrumentację fs}})]});// Zainicjalizuj i eksportujsdk.start().then(() => console.log('OpenTelemetry zainicjalizowane')).catch((error) => console.error('Nieudana inicjalizacja OpenTelemetry', error));module.exports = { sdk }; -
Dodaj do punktu wejścia aplikacji
// index.js - Musi być pierwszym importem!require('./telemetry');const express = require('express');const { trace, metrics } = require('@opentelemetry/api');// Pobierz tracer i meterconst tracer = trace.getTracer('myapp');const meter = metrics.getMeter('myapp');// Stwórz niestandardowe metrykiconst requestCounter = meter.createCounter('http_requests', {description: 'Liczba żądań HTTP',unit: '1'});const requestDuration = meter.createHistogram('http_request_duration', {description: 'Czas trwania żądań HTTP',unit: 'ms'});const app = express();// Middleware dla niestandardowych metrykapp.use((req, res, next) => {const start = Date.now();res.on('finish', () => {const duration = Date.now() - start;const labels = {method: req.method,route: req.route?.path || 'unknown',status_code: res.statusCode.toString()};requestCounter.add(1, labels);requestDuration.record(duration, labels);});next();}); -
Dodaj niestandardowe spany
// Przykład niestandardowej instrumentacjiasync function processOrder(orderId) {// Rozpocznij nowy spanreturn tracer.startActiveSpan('process_order', async (span) => {try {// Dodaj atrybuty spanuspan.setAttributes({'order.id': orderId,'order.processing_step': 'validation'});// Waliduj zamówienieconst order = await validateOrder(orderId);// Stwórz span potomny dla płatnościawait tracer.startActiveSpan('process_payment', async (paymentSpan) => {paymentSpan.setAttributes({'payment.amount': order.total,'payment.currency': order.currency});await processPayment(order);paymentSpan.setStatus({ code: SpanStatusCode.OK });});// Zapisz niestandardową metrykęorderProcessingCounter.add(1, {status: 'success',payment_method: order.paymentMethod});span.setStatus({ code: SpanStatusCode.OK });return order;} catch (error) {span.recordException(error);span.setStatus({code: SpanStatusCode.ERROR,message: error.message});throw error;} finally {span.end();}});}
Rozproszone tracowanie
Dział zatytułowany „Rozproszone tracowanie”> Skonfiguruj rozproszone tracowanie w naszych mikroserwisach:> - Propagacja kontekstu tracingu> - Mapowanie zależności usług> - Analiza ścieżki krytycznej> - Identyfikacja wąskich gardeł wydajności
// Propagacja kontekstu tracinguconst { propagation, trace, context } = require('@opentelemetry/api');
// Klient HTTP z propagacją tracinguasync function callDownstreamService(url, data) { const span = trace.getActiveSpan();
// Stwórz nagłówki z kontekstem tracingu const headers = {}; propagation.inject(context.active(), headers);
try { const response = await fetch(url, { method: 'POST', headers: { ...headers, 'Content-Type': 'application/json' }, body: JSON.stringify(data) });
span?.addEvent('downstream_service_called', { 'http.url': url, 'http.status_code': response.status });
return response.json(); } catch (error) { span?.recordException(error); throw error; }}
// Wyciągnij kontekst tracingu w usłudze odbierającejapp.use((req, res, next) => { // Wyciągnij kontekst tracingu z przychodzącego żądania const extractedContext = propagation.extract( context.active(), req.headers );
// Kontynuuj tracing z wyciągniętym kontekstem context.with(extractedContext, () => { next(); });});
Strukturalne logowanie
Dział zatytułowany „Strukturalne logowanie”Implementacja strukturalnych logów
Dział zatytułowany „Implementacja strukturalnych logów”> Skonfiguruj strukturalne logowanie z:> - Formatem JSON dla łatwego parsowania> - ID korelacji> - Poziomami logów i samplingiem> - Integracją z OpenTelemetry> - Maskowaniem wrażliwych danych
const winston = require('winston');const { trace, context } = require('@opentelemetry/api');
// Niestandardowy format zawierający informacje o tracinguconst traceFormat = winston.format((info) => { const span = trace.getActiveSpan(); if (span) { const spanContext = span.spanContext(); info.traceId = spanContext.traceId; info.spanId = spanContext.spanId; }
// Dodaj request ID jeśli dostępne const requestId = context.active().getValue('requestId'); if (requestId) { info.requestId = requestId; }
return info;});
// Maskowanie wrażliwych danychconst maskSensitive = winston.format((info) => { const sensitive = ['password', 'token', 'apiKey', 'pesel', 'creditCard'];
const mask = (obj) => { if (typeof obj !== 'object' || obj === null) return obj;
const masked = Array.isArray(obj) ? [] : {};
for (const [key, value] of Object.entries(obj)) { if (sensitive.some(s => key.toLowerCase().includes(s))) { masked[key] = '***REDACTED***'; } else if (typeof value === 'object' && value !== null) { masked[key] = mask(value); } else { masked[key] = value; } }
return masked; };
if (info.meta) { info.meta = mask(info.meta); }
return info;});
// Stwórz instancję loggeraconst logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), traceFormat(), maskSensitive(), winston.format.json() ), defaultMeta: { service: process.env.SERVICE_NAME || 'myapp', environment: process.env.NODE_ENV || 'development' }, transports: [ new winston.transports.Console({ format: process.env.NODE_ENV === 'development' ? winston.format.combine( winston.format.colorize(), winston.format.simple() ) : winston.format.json() }) ]});
// Dodaj sampling logów dla wysokowolumenowych logówlogger.sample = (rate = 0.1) => { return { log: (level, message, meta) => { if (Math.random() < rate) { logger.log(level, message, { ...meta, sampled: true }); } } };};
module.exports = logger;
Agregacja i analiza logów
Dział zatytułowany „Agregacja i analiza logów”// Wzorce agregacji logówclass LogAggregator { constructor() { this.buffers = new Map(); this.flushInterval = 5000; // 5 sekund
setInterval(() => this.flush(), this.flushInterval); }
aggregate(key, data) { if (!this.buffers.has(key)) { this.buffers.set(key, { count: 0, firstSeen: Date.now(), lastSeen: Date.now(), samples: [] }); }
const buffer = this.buffers.get(key); buffer.count++; buffer.lastSeen = Date.now();
// Trzymaj tylko pierwsze 5 próbek if (buffer.samples.length < 5) { buffer.samples.push(data); } }
flush() { for (const [key, buffer] of this.buffers) { if (buffer.count > 0) { logger.info('Zagregowany wpis logu', { key, count: buffer.count, duration: buffer.lastSeen - buffer.firstSeen, samples: buffer.samples }); } }
this.buffers.clear(); }}
// Użycie dla zdarzeń wysokiej częstotliwościconst aggregator = new LogAggregator();
// Zamiast logowania każdego żądaniaapp.use((req, res, next) => { aggregator.aggregate(`request:${req.method}:${req.path}`, { userAgent: req.headers['user-agent'], ip: req.ip }); next();});
Niestandardowe metryki i KPI
Dział zatytułowany „Niestandardowe metryki i KPI”Implementacja metryk biznesowych
Dział zatytułowany „Implementacja metryk biznesowych”> Zaimplementuj niestandardowe metryki biznesowe:> - Czas przetwarzania zamówień> - Przychód na minutę> - Wskaźnik porzucania koszyka> - Wskaźniki sukcesu API> - Metryki adopcji funkcji
const { metrics } = require('@opentelemetry/api');const meter = metrics.getMeter('business-metrics');
// Definicje metryk biznesowychconst orderCounter = meter.createCounter('orders_total', { description: 'Łączna liczba zamówień', unit: '1'});
const revenueCounter = meter.createCounter('revenue_total', { description: 'Łączny przychód', unit: 'PLN'});
const cartAbandonmentGauge = meter.createUpDownCounter('cart_abandonment', { description: 'Liczba porzuconych koszyków', unit: '1'});
const apiLatencyHistogram = meter.createHistogram('api_latency', { description: 'Opóźnienie endpointów API', unit: 'ms'});
const activeUsersGauge = meter.createObservableGauge('active_users', { description: 'Liczba aktywnych użytkowników'});
// Skonfiguruj callback observable gaugeactiveUsersGauge.addCallback(async (observableResult) => { const count = await getActiveUserCount(); observableResult.observe(count, { period: '5m' });});
// Pomocnicy metryk biznesowychclass BusinessMetrics { static recordOrder(order) { orderCounter.add(1, { status: order.status, payment_method: order.paymentMethod, customer_type: order.isNewCustomer ? 'new' : 'returning' });
revenueCounter.add(order.total, { currency: order.currency, region: order.region }); }
static recordCartAbandonment(cart) { cartAbandonmentGauge.add(1, { value: cart.total, items_count: cart.items.length, reason: cart.abandonmentReason || 'unknown' }); }
static recordApiCall(endpoint, method, duration, success) { apiLatencyHistogram.record(duration, { endpoint, method, success: success.toString() }); }
static async recordFeatureUsage(feature, userId) { const featureCounter = meter.createCounter(`feature_usage_${feature}`, { description: `Użycie funkcji ${feature}` });
featureCounter.add(1, { user_segment: await getUserSegment(userId), first_time: await isFirstTimeUsage(userId, feature) }); }}
module.exports = BusinessMetrics;
Metryki wydajności
Dział zatytułowany „Metryki wydajności”// Monitorowanie wydajnościconst performanceObserver = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { // Rejestruj metryki wydajności const histogram = meter.createHistogram(`performance_${entry.entryType}`, { description: `Timing wydajności dla ${entry.entryType}`, unit: 'ms' });
histogram.record(entry.duration, { name: entry.name, type: entry.entryType }); }});
performanceObserver.observe({ entryTypes: ['measure', 'navigation', 'resource']});
// Wydajność zapytań bazy danychconst dbQueryHistogram = meter.createHistogram('db_query_duration', { description: 'Czas wykonania zapytania bazy danych', unit: 'ms'});
// Owijanie zapytań bazodanowychasync function instrumentedQuery(sql, params) { const startTime = performance.now(); const labels = { operation: sql.split(' ')[0].toUpperCase(), table: extractTableName(sql) };
try { const result = await db.query(sql, params); labels.success = 'true'; return result; } catch (error) { labels.success = 'false'; labels.error_type = error.constructor.name; throw error; } finally { const duration = performance.now() - startTime; dbQueryHistogram.record(duration, labels); }}
Infrastruktura monitorowania
Dział zatytułowany „Infrastruktura monitorowania”Konfiguracja Prometheus
Dział zatytułowany „Konfiguracja Prometheus”> Skonfiguruj Prometheus do zbierania metryk:> - Konfiguracja scrapowania> - Reguły nagrywania> - Reguły alertowania> - Konfiguracja federacji
global: scrape_interval: 15s evaluation_interval: 15s external_labels: cluster: 'production' region: 'pl-central-1'
# Konfiguracja alertowaniaalerting: alertmanagers: - static_configs: - targets: - alertmanager:9093
# Pliki regułrule_files: - 'recording_rules.yml' - 'alerting_rules.yml'
# Konfiguracje scrapowaniascrape_configs: # Metryki aplikacji - job_name: 'myapp' static_configs: - targets: ['myapp:9090'] relabel_configs: - source_labels: [__address__] target_label: instance regex: '([^:]+):.*' replacement: '${1}'
# Kubernetes service discovery - job_name: 'kubernetes-pods' kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] action: replace regex: ([^:]+)(?::\d+)?;(\d+) replacement: $1:$2 target_label: __address__
# recording_rules.ymlgroups: - name: myapp_recording_rules interval: 30s rules: # Wskaźnik żądań - record: myapp:http_requests:rate5m expr: rate(http_requests_total[5m])
# Wskaźnik błędów - record: myapp:http_errors:rate5m expr: rate(http_requests_total{status=~"5.."}[5m])
# P95 opóźnienia - record: myapp:http_latency:p95 expr: histogram_quantile(0.95, rate(http_request_duration_bucket[5m]))
# Metryki biznesowe - record: myapp:orders:rate1h expr: rate(orders_total[1h])
- record: myapp:revenue:rate1h expr: rate(revenue_total[1h])
# alerting_rules.ymlgroups: - name: myapp_alerts rules: - alert: HighErrorRate expr: myapp:http_errors:rate5m > 0.05 for: 5m labels: severity: critical team: platform annotations: summary: "Wykryto wysoki wskaźnik błędów" description: "Wskaźnik błędów to {{ $value | humanizePercentage }} dla {{ $labels.instance }}"
- alert: HighLatency expr: myapp:http_latency:p95 > 1000 for: 10m labels: severity: warning annotations: summary: "Wykryto wysokie opóźnienie" description: "Opóźnienie P95 to {{ $value }}ms"
- alert: LowOrderRate expr: myapp:orders:rate1h < 10 for: 30m labels: severity: warning team: business annotations: summary: "Niski wskaźnik zamówień" description: "Wskaźnik zamówień spadł do {{ $value }} zamówień/godzinę"
Dashboardy Grafana
Dział zatytułowany „Dashboardy Grafana”> Stwórz kompleksowe dashboardy Grafana:> - Przegląd systemu> - Metryki biznesowe> - Analiza wydajności> - Śledzenie błędów> - Monitorowanie SLA
{ "dashboard": { "title": "Dashboard produkcyjny MyApp", "panels": [ { "title": "Wskaźnik żądań", "type": "graph", "targets": [ { "expr": "sum(rate(http_requests_total[5m])) by (method)", "legendFormat": "{{method}}" } ], "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 } }, { "title": "Wskaźnik błędów", "type": "graph", "targets": [ { "expr": "sum(rate(http_requests_total{status=~\"5..\"}[5m])) / sum(rate(http_requests_total[5m])) * 100", "legendFormat": "Błędy %" } ], "alert": { "conditions": [ { "evaluator": { "params": [5], "type": "gt" }, "operator": { "type": "and" }, "query": { "params": ["A", "5m", "now"] }, "reducer": { "params": [], "type": "avg" } } ] }, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 0 } }, { "title": "Percentyle czasu odpowiedzi", "type": "graph", "targets": [ { "expr": "histogram_quantile(0.99, sum(rate(http_request_duration_bucket[5m])) by (le))", "legendFormat": "p99" }, { "expr": "histogram_quantile(0.95, sum(rate(http_request_duration_bucket[5m])) by (le))", "legendFormat": "p95" }, { "expr": "histogram_quantile(0.50, sum(rate(http_request_duration_bucket[5m])) by (le))", "legendFormat": "p50" } ], "gridPos": { "h": 8, "w": 12, "x": 0, "y": 8 } }, { "title": "KPI biznesowe", "type": "stat", "targets": [ { "expr": "sum(rate(orders_total[1h])) * 3600", "legendFormat": "Zamówienia/Godzinę" }, { "expr": "sum(rate(revenue_total[1h])) * 3600", "legendFormat": "Przychód/Godzinę" }, { "expr": "sum(active_users)", "legendFormat": "Aktywni użytkownicy" } ], "gridPos": { "h": 8, "w": 12, "x": 12, "y": 8 } } ] }}
Śledzenie błędów i alertowanie
Dział zatytułowany „Śledzenie błędów i alertowanie”Kompleksowe śledzenie błędów
Dział zatytułowany „Kompleksowe śledzenie błędów”> Skonfiguruj śledzenie błędów z:> - Automatycznym przechwytywaniem błędów> - Zbieraniem stack trace> - Kontekstem użytkownika> - Śledzeniem wersji> - Grupowaniem błędów
const Sentry = require('@sentry/node');const { ProfilingIntegration } = require('@sentry/profiling-node');
// Zainicjalizuj SentrySentry.init({ dsn: process.env.SENTRY_DSN, environment: process.env.NODE_ENV, release: process.env.SERVICE_VERSION, integrations: [ new Sentry.Integrations.Http({ tracing: true }), new Sentry.Integrations.Express({ app }), new ProfilingIntegration() ], tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0, profilesSampleRate: 0.1, beforeSend(event, hint) { // Odfiltruj znane problemy if (event.exception?.values?.[0]?.type === 'NetworkError') { return null; }
// Dodaj niestandardowy kontekst event.extra = { ...event.extra, nodeVersion: process.version, memory: process.memoryUsage() };
return event; }});
// Middleware obsługi błędówapp.use((err, req, res, next) => { // Loguj do naszego loggera logger.error('Nieobsłużony błąd', { error: err.message, stack: err.stack, url: req.url, method: req.method, ip: req.ip, userAgent: req.get('user-agent') });
// Wyślij do Sentry z kontekstem Sentry.withScope((scope) => { scope.setContext('request', { url: req.url, method: req.method, headers: req.headers, query: req.query, body: req.body });
scope.setUser({ id: req.user?.id, email: req.user?.email, ip_address: req.ip });
scope.setTag('endpoint', req.route?.path || 'unknown'); scope.setLevel('error');
Sentry.captureException(err); });
// Wyślij odpowiedź błędu res.status(err.status || 500).json({ error: { message: process.env.NODE_ENV === 'production' ? 'Błąd wewnętrzny serwera' : err.message, id: res.sentry } });});
Inteligentne alertowanie
Dział zatytułowany „Inteligentne alertowanie”global: resolve_timeout: 5m slack_api_url: 'YOUR_SLACK_WEBHOOK'
route: group_by: ['alertname', 'cluster', 'service'] group_wait: 10s group_interval: 10s repeat_interval: 12h receiver: 'default' routes: - match: severity: critical receiver: pagerduty continue: true - match: team: platform receiver: platform-slack - match: team: business receiver: business-alerts
receivers: - name: 'default' slack_configs: - channel: '#alerts' title: '{{ .GroupLabels.alertname }}' text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
- name: 'pagerduty' pagerduty_configs: - service_key: 'YOUR_PAGERDUTY_KEY' description: '{{ .GroupLabels.alertname }}: {{ .CommonAnnotations.summary }}'
- name: 'platform-slack' slack_configs: - channel: '#platform-alerts' send_resolved: true title: '🚨 {{ .GroupLabels.alertname }}' text: | *Alert:* {{ .GroupLabels.alertname }} *Ważność:* {{ .CommonLabels.severity }} *Opis:* {{ .CommonAnnotations.description }} *Runbook:* <{{ .CommonAnnotations.runbook_url }}|Zobacz Runbook>
inhibit_rules: - source_match: severity: 'critical' target_match: severity: 'warning' equal: ['alertname', 'cluster', 'service']
Telemetria Claude Code
Dział zatytułowany „Telemetria Claude Code”Monitorowanie użycia Claude Code
Dział zatytułowany „Monitorowanie użycia Claude Code”> Skonfiguruj monitorowanie telemetrii Claude Code:> - Metryki użycia> - Śledzenie kosztów> - Analiza wydajności> - Metryki adopcji zespołu
# Włącz telemetrię Claude Codeexport CLAUDE_CODE_ENABLE_TELEMETRY=1export OTEL_METRICS_EXPORTER=otlpexport OTEL_LOGS_EXPORTER=otlpexport OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer your-token"
# Dodaj niestandardowe atrybuty do śledzenia zespołuexport OTEL_RESOURCE_ATTRIBUTES="department=engineering,team.id=platform,cost_center=eng-123"
// Zapytania dashboardu metryk Claude Codeconst claudeMetrics = { // Produktywność programistów linesOfCode: ` sum(rate(claude_code.lines_of_code.count[1d])) by (user_account_uuid, type) `,
// Śledzenie kosztów costPerTeam: ` sum(claude_code.cost.usage) by (department, team_id) `,
// Wskaźnik akceptacji narzędzi acceptanceRate: ` sum(rate(claude_code.code_edit_tool.decision{decision="accept"}[1h])) / sum(rate(claude_code.code_edit_tool.decision[1h])) * 100 `,
// Aktywni programiści activeDevelopers: ` count(count by (user_account_uuid)(claude_code.session.count)) `,
// Użycie języków languageDistribution: ` sum(claude_code.code_edit_tool.decision) by (language) `};
Monitorowanie wydajności
Dział zatytułowany „Monitorowanie wydajności”Application Performance Monitoring (APM)
Dział zatytułowany „Application Performance Monitoring (APM)”> Skonfiguruj kompleksowe APM:> - Śledzenie transakcji> - Analiza zapytań bazy danych> - Monitorowanie usług zewnętrznych> - Wykorzystanie zasobów
// Integracja APMconst apm = require('elastic-apm-node').start({ serviceName: process.env.SERVICE_NAME, secretToken: process.env.ELASTIC_APM_SECRET_TOKEN, serverUrl: process.env.ELASTIC_APM_SERVER_URL, environment: process.env.NODE_ENV, transactionSampleRate: 0.1, captureBody: 'errors', errorOnAbortedRequests: true, captureErrorLogStackTraces: 'always', usePathAsTransactionName: false});
// Niestandardowe śledzenie transakcjiasync function complexBusinessOperation(data) { const transaction = apm.startTransaction('process_order', 'business');
try { // Śledź operacje bazy danych const span = apm.startSpan('validate_inventory', 'db'); const inventory = await checkInventory(data.items); span.end();
// Śledź wywołania zewnętrznych API const paymentSpan = apm.startSpan('process_payment', 'external'); const payment = await processPayment(data.payment); paymentSpan.end();
// Śledź niestandardowe operacje const fulfillmentSpan = apm.startSpan('create_fulfillment', 'custom'); const order = await createFulfillmentOrder(data, payment); fulfillmentSpan.end();
transaction.result = 'success'; return order; } catch (error) { apm.captureError(error); transaction.result = 'error'; throw error; } finally { transaction.end(); }}
Monitorowanie SLO i SLA
Dział zatytułowany „Monitorowanie SLO i SLA”Monitorowanie poziomu usług
Dział zatytułowany „Monitorowanie poziomu usług”> Zaimplementuj monitorowanie SLO:> - Cele dostępności> - Cele opóźnienia> - Budżety błędów> - Alerty wskaźnika spalania
groups: - name: slo_rules interval: 30s rules: # SLO dostępności - 99.9% - record: slo:availability:ratio expr: | sum(rate(http_requests_total{status!~"5.."}[5m])) / sum(rate(http_requests_total[5m]))
# Wskaźnik spalania budżetu błędów - record: slo:error_budget:burn_rate_1h expr: | (1 - slo:availability:ratio) / (1 - 0.999) * (30 * 24) / 1
- record: slo:error_budget:burn_rate_6h expr: | (1 - slo:availability:ratio) / (1 - 0.999) * (30 * 24) / 6
# SLO opóźnienia - 95% żądań poniżej 500ms - record: slo:latency:ratio expr: | sum(rate(http_request_duration_bucket{le="0.5"}[5m])) / sum(rate(http_request_duration_count[5m]))
# Alerty multi-window multi-burn-rate - alert: ErrorBudgetBurn expr: | ( slo:error_budget:burn_rate_1h > 14.4 and slo:error_budget:burn_rate_6h > 6 ) labels: severity: critical slo: availability annotations: summary: "Budżet błędów spala się zbyt szybko" description: "Wskaźnik spalania budżetu błędów to {{ $value }} razy normalny"
Powiązane lekcje
Dział zatytułowany „Powiązane lekcje”Następne kroki
Dział zatytułowany „Następne kroki”Nauczyłeś się, jak wykorzystać Claude Code do kompleksowej obserwowalnośćci - od instrumentacji po wizualizację po alertowanie. Kluczem jest traktowanie monitorowania jako pierwszoklasowego obywatela w procesie rozwoju, nie jako myśli końcowej.
Pamiętaj: Nie możesz naprawić tego, czego nie widzisz. Używaj Claude Code do budowania obserwowalnośćci w swoje aplikacje od samego początku, tworząc systemy, które mówią ci co jest nie tak, zanim twoi użytkownicy to zauważą. Z odpowiednim monitorowaniem będziesz wdrażać z pewnością siebie i spać lepiej w nocy.