Zbieranie metryk
AI generuje instrumentację metryk i dashboardy
Efektywne monitorowanie i obserwowalność są kluczowe dla utrzymania niezawodnych systemów. Ta lekcja demonstruje jak możliwości AI Cursor pomagają implementować kompleksowe rozwiązania monitorowania, od podstawowych metryk po zaawansowane distributed tracing.
Nowoczesne aplikacje wymagają zaawansowanego monitorowania metryk, logów i traców. Pomoc AI czyni implementację tych złożonych systemów dostępną, pomagając budować obserwowalność klasy produkcyjnej od pierwszego dnia.
Skonfiguruj serwery MCP monitorowania:
{ "mcpServers": { "sentry": { "command": "npx", "args": ["-y", "sentry-mcp"], "env": { "SENTRY_AUTH_TOKEN": "${SENTRY_TOKEN}", "SENTRY_ORG": "your-org" } }, "grafana": { "command": "npx", "args": ["-y", "grafana-mcp"], "env": { "GRAFANA_URL": "https://grafana.company.com", "GRAFANA_API_KEY": "${GRAFANA_KEY}" } }, "sonarqube": { "command": "npx", "args": ["-y", "sonarqube-mcp-server"], "env": { "SONAR_HOST_URL": "https://sonar.company.com", "SONAR_TOKEN": "${SONAR_TOKEN}" } } }}
Zbieranie metryk
AI generuje instrumentację metryk i dashboardy
Agregacja logów
AI tworzy strukturalne logowanie i reguły parsowania
Distributed tracing
AI implementuje tracing przez mikrousługi
Reguły alertowania
AI tworzy inteligentne strategie alertowania
Instrumentacja aplikacji
// Poproś AI o instrumentację aplikacji"Dodaj metryki Prometheus do Express API:- Histogram czasu trwania żądań HTTP- Counter żądań według kodu statusu- Gauge aktywnych połączeń- Niestandardowe metryki biznesowe- Śledzenie współczynnika błędów"
// AI generuje instrumentacjęimport { register, Counter, Histogram, Gauge } from 'prom-client';import express from 'express';
// Definicja metrykconst httpRequestDuration = new Histogram({ name: 'http_request_duration_seconds', help: 'Czas trwania żądań HTTP w sekundach', labelNames: ['method', 'route', 'status_code'], buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10]});
const httpRequestTotal = new Counter({ name: 'http_requests_total', help: 'Całkowita liczba żądań HTTP', labelNames: ['method', 'route', 'status_code']});
const activeConnections = new Gauge({ name: 'active_connections', help: 'Liczba aktywnych połączeń'});
// Middleware do śledzenia metrykexport const metricsMiddleware = (req: express.Request, res: express.Response, next: express.NextFunction) => { const start = Date.now();
// Śledź aktywne połączenia activeConnections.inc();
res.on('finish', () => { const duration = (Date.now() - start) / 1000; const route = req.route?.path || 'unknown'; const labels = { method: req.method, route, status_code: res.statusCode.toString() };
httpRequestDuration.observe(labels, duration); httpRequestTotal.inc(labels); activeConnections.dec(); });
next();};
// Endpoint metrykexport const metricsEndpoint = async (req: express.Request, res: express.Response) => { res.set('Content-Type', register.contentType); res.send(await register.metrics());};
Niestandardowe metryki biznesowe
// AI implementuje metryki biznesowe"Stwórz niestandardowe metryki dla e-commerce:- Czas przetwarzania zamówień- Współczynnik sukcesu płatności- Współczynnik porzucenia koszyka- Śledzenie wyświetleń produktów- Metryki przychodów"
// AI generuje metryki biznesoweconst orderProcessingTime = new Histogram({ name: 'order_processing_duration_seconds', help: 'Czas przetwarzania zamówień', labelNames: ['payment_method', 'shipping_type'], buckets: [1, 5, 10, 30, 60, 120, 300]});
const paymentSuccessRate = new Gauge({ name: 'payment_success_rate', help: 'Procent udanych płatności', labelNames: ['payment_provider']});
const cartAbandonment = new Counter({ name: 'cart_abandonment_total', help: 'Liczba porzuconych koszyków', labelNames: ['reason']});
const revenue = new Counter({ name: 'revenue_total', help: 'Całkowity przychód', labelNames: ['currency', 'product_category']});
// Użycie w logice biznesowejexport class OrderService { async processOrder(order: Order): Promise<ProcessedOrder> { const timer = orderProcessingTime.startTimer({ payment_method: order.paymentMethod, shipping_type: order.shippingType });
try { const result = await this.processPayment(order);
if (result.success) { revenue.inc({ currency: order.currency, product_category: order.category }, order.total);
this.updatePaymentSuccessRate(order.paymentProvider, true); } else { this.updatePaymentSuccessRate(order.paymentProvider, false); }
return result; } finally { timer(); } }}
Tworzenie dashboardu Grafana
// AI tworzy dashboard Grafana"Wygeneruj dashboard Grafana dla:- Przeglądu zdrowia serwisu- Częstotliwości żądań i opóźnień- Śledzenia błędów- Metryk biznesowych- Zgodności SLA"
// AI zapewnia JSON dashboardu{ "dashboard": { "title": "Dashboard zdrowia serwisu", "panels": [ { "title": "Częstotliwość żądań", "targets": [ { "expr": "sum(rate(http_requests_total[5m])) by (service)", "legendFormat": "{{service}}" } ], "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 } }, { "title": "Opóźnienie P95", "targets": [ { "expr": "histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (service, le))", "legendFormat": "{{service}}" } ], "gridPos": { "h": 8, "w": 12, "x": 12, "y": 0 } }, { "title": "Współczynnik błędów", "targets": [ { "expr": "sum(rate(http_requests_total{status_code=~\"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" }, "type": "query" } ], "name": "Wysoki współczynnik błędów" }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 8 } } ] }}
Badanie problemów w czasie rzeczywistym z Sentry MCP
"Używając Sentry MCP, pokaż mi:- Ostatnie błędy w produkcji- Trendy błędów z ostatnich 24 godzin- Najbardziej dotkniętych użytkowników- Stack trace dla PaymentError"
// Bezpośrednie rozwiązywanie problemów"Używając Sentry MCP:- Znajdź wszystkie wystąpienia 'connection timeout'- Grupuj według serwisu- Pokaż status rozwiązania- Stwórz issue dla nierozwiązanych błędów"
Zarządzanie dashboardami z Grafana MCP
"Używając Grafana MCP:- Wyszukaj dashboardy dla 'wydajność API'- Uruchom zapytanie: rate(http_requests_total[5m])- Stwórz alert dla czasu odpowiedzi > 1s- Eksportuj JSON dashboardu do backupu"
// Optymalizacja zapytań"Używając Grafana MCP, zoptymalizuj to zapytanie PromQL:sum(rate(http_request_duration_seconds_bucket[5m])) by (le)Uczyń je bardziej efektywnym dla dużych zbiorów danych"
Jakość kodu z SonarQube MCP
"Używając SonarQube MCP:- Pobierz status quality gate dla głównej gałęzi- Wymień krytyczne hotspoty bezpieczeństwa- Pokaż trendy pokrycia kodu- Znajdź zduplikowane bloki kodu"
// Sprawdzenia przed wdrożeniem"Używając SonarQube MCP, zweryfikuj:- Brak nowych krytycznych problemów- Pokrycie kodu > 80%- Brak luk bezpieczeństwa- Wskaźnik długu technicznego < 5%"
Monitorowanie wydajności z Dynatrace MCP
"Używając Dynatrace MCP:- Pokaż aktualny feed problemów- Pobierz przepływ serwisu dla procesu checkout- Analizuj wydajność zapytań bazodanowych- Znajdź wskaźniki wycieków pamięci"
Ujednolicone workflow’y monitorowania
"Koordynuj narzędzia monitorowania:1. Gdy Sentry zgłosi skok błędów2. Sprawdź metryki Grafana dla korelacji3. Przejrzyj SonarQube pod kątem ostatnich zmian4. Analizuj Dynatrace dla głównej przyczyny"
// Bezpośrednie zapytanie z IDE"Używając Sentry MCP, znajdź wszystkie błędy:- Związane z przetwarzaniem płatności- Z ostatnich 6 godzin- Dotykające > 10 użytkownikówStwórz ticket Jira dla każdego"
// Natychmiastowy dostęp do danych// Brak przełączania kontekstu// Zautomatyzowane workflow'y
// Proces manualny:// 1. Otwórz dashboard Sentry// 2. Nawiguj do problemów// 3. Zastosuj filtry manualnie// 4. Skopiuj szczegóły błędów// 5. Przełącz się na Jira// 6. Stwórz tickety manualnie
// Czasochłonne// Przełączanie kontekstu// Podatne na błędy
// AI implementuje OpenTelemetry"Skonfiguruj OpenTelemetry z:- Automatyczną instrumentacją- Niestandardowymi spanami- Propagacją kontekstu- Wieloma eksporterami- Strategiami próbkowania"
import { NodeSDK } from '@opentelemetry/sdk-node';import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';import { Resource } from '@opentelemetry/resources';import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';import { JaegerExporter } from '@opentelemetry/exporter-jaeger';import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
// Konfiguracja SDKconst sdk = new NodeSDK({ resource: new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: 'api-service', [SemanticResourceAttributes.SERVICE_VERSION]: process.env.VERSION || '1.0.0', environment: process.env.NODE_ENV }), instrumentations: [ getNodeAutoInstrumentations({ '@opentelemetry/instrumentation-fs': { enabled: false // Wyłącz hałaśliwą instrumentację fs } }) ], traceExporter: new JaegerExporter({ endpoint: process.env.JAEGER_ENDPOINT || 'http://localhost:14268/api/traces' }), metricExporter: new PrometheusExporter({ port: 9090 })});
// Inicjalizacja SDKsdk.start();
// Niestandardowa instrumentacjaimport { trace, context, SpanStatusCode } from '@opentelemetry/api';
const tracer = trace.getTracer('api-service');
export async function processUserRequest(userId: string, request: any) { const span = tracer.startSpan('process_user_request', { attributes: { 'user.id': userId, 'request.type': request.type } });
try { // Dodaj zdarzenia span.addEvent('validation_started'); await validateRequest(request); span.addEvent('validation_completed');
// Stwórz span potomny const childSpan = tracer.startSpan('database_operation', { parent: span });
try { const result = await databaseOperation(userId, request); childSpan.setStatus({ code: SpanStatusCode.OK }); return result; } finally { childSpan.end(); } } catch (error) { span.recordException(error); span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }); throw error; } finally { span.end(); }}
// AI konfiguruje Datadog APM"Skonfiguruj Datadog APM z:- Zbieraniem śladów- Niestandardowymi tagami- Śledzeniem błędów- Monitorowaniem wydajności- Korelacją logów"
import tracer from 'dd-trace';
// Inicjalizacja traceratracer.init({ env: process.env.NODE_ENV, service: 'api-service', version: process.env.VERSION, logInjection: true, runtimeMetrics: true, profiling: true, analytics: true, tags: { team: 'platform', component: 'api' }});
// Niestandardowa instrumentacjaexport class PaymentService { async processPayment(payment: Payment) { const span = tracer.startSpan('payment.process', { resource: payment.provider, tags: { 'payment.amount': payment.amount, 'payment.currency': payment.currency, 'payment.method': payment.method } });
try { // Śledź niestandardowe metryki tracer.dogstatsd.increment('payment.attempt', 1, [ `provider:${payment.provider}`, `method:${payment.method}` ]);
const startTime = Date.now(); const result = await this.callPaymentProvider(payment);
// Śledź timing tracer.dogstatsd.histogram('payment.duration', Date.now() - startTime, [ `provider:${payment.provider}`, `success:${result.success}` ]);
if (result.success) { tracer.dogstatsd.increment('payment.success', 1, [ `provider:${payment.provider}` ]); } else { span.setTag('error', true); span.setTag('error.message', result.error); }
return result; } finally { span.finish(); } }}
// AI konfiguruje New Relic"Zaimplementuj monitorowanie New Relic:- Konfigurację APM- Niestandardowe zdarzenia- Monitorowanie przeglądarki- Monitorowanie infrastruktury- Monitorowanie syntetyczne"
import newrelic from 'newrelic';
// Niestandardowa instrumentacjaexport class OrderProcessor { async processOrder(order: Order) { // Rozpocznij transakcję return newrelic.startSegment('order:process', true, async () => { // Dodaj niestandardowe atrybuty newrelic.addCustomAttributes({ orderId: order.id, customerId: order.customerId, orderTotal: order.total, itemCount: order.items.length });
try { // Śledź niestandardowe zdarzenia newrelic.recordCustomEvent('OrderProcessing', { orderId: order.id, stage: 'started', timestamp: Date.now() });
// Przetwarzaj kroki zamówienia await this.validateOrder(order); await this.checkInventory(order); await this.processPayment(order); await this.createShipment(order);
// Zapisz sukces newrelic.recordCustomEvent('OrderProcessing', { orderId: order.id, stage: 'completed', processingTime: Date.now() - order.createdAt, success: true });
return { success: true, orderId: order.id }; } catch (error) { // Śledź błędy newrelic.noticeError(error, { orderId: order.id, stage: 'processing', customerId: order.customerId });
throw error; } }); }}
// AI tworzy strukturalne logowanie"Zaimplementuj strukturalne logowanie z:- Formatem JSON- Correlation ID- Propagacją kontekstu- Poziomami logów- Maskowaniem wrażliwych danych"
import winston from 'winston';import { v4 as uuidv4 } from 'uuid';
// Fabryka loggerówexport class LoggerFactory { static createLogger(service: string) { return winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json() ), defaultMeta: { service, environment: process.env.NODE_ENV, version: process.env.VERSION }, transports: [ new winston.transports.Console({ format: winston.format.combine( winston.format.colorize(), winston.format.simple() ) }) ] }); }}
// Middleware kontekstu żądaniaexport class RequestContext { private static storage = new AsyncLocalStorage<Context>();
static middleware() { return (req: Request, res: Response, next: NextFunction) => { const context: Context = { requestId: req.headers['x-request-id'] || uuidv4(), userId: req.user?.id, sessionId: req.session?.id, userAgent: req.headers['user-agent'], ip: req.ip };
RequestContext.storage.run(context, () => { req.context = context; next(); }); }; }
static getContext(): Context | undefined { return this.storage.getStore(); }}
// Wzbogacony logger z kontekstemexport class ContextualLogger { constructor(private logger: winston.Logger) {}
private enrichLog(level: string, message: string, meta?: any) { const context = RequestContext.getContext();
return this.logger.log({ level, message, ...context, ...this.sanitizeMeta(meta) }); }
private sanitizeMeta(meta: any): any { if (!meta) return {};
// AI implementuje maskowanie wrażliwych danych const sensitive = ['password', 'token', 'apiKey', 'secret', 'creditCard']; const sanitized = { ...meta };
for (const key of Object.keys(sanitized)) { if (sensitive.some(s => key.toLowerCase().includes(s))) { sanitized[key] = '[ZREDAGOWANO]'; } }
return sanitized; }
info(message: string, meta?: any) { this.enrichLog('info', message, meta); }
error(message: string, error?: Error, meta?: any) { this.enrichLog('error', message, { ...meta, error: { message: error?.message, stack: error?.stack, name: error?.name } }); }}
# AI tworzy konfigurację ELK"Skonfiguruj stos ELK z:- Filebeat do zbierania- Logstash do przetwarzania- Elasticsearch do przechowywania- Kibana do wizualizacji"
# filebeat.ymlfilebeat.inputs:- type: container paths: - '/var/lib/docker/containers/*/*.log' processors: - add_docker_metadata: host: "unix:///var/run/docker.sock" - decode_json_fields: fields: ["message"] target: "json" overwrite_keys: true - drop_event: when: or: - equals: json.level: "debug" - contains: json.path: "/health"
output.logstash: hosts: ["logstash:5044"] ssl.certificate_authorities: ["/etc/ca.crt"] ssl.certificate: "/etc/client.crt" ssl.key: "/etc/client.key"
# logstash.confinput { beats { port => 5044 ssl => true ssl_certificate => "/etc/logstash/server.crt" ssl_key => "/etc/logstash/server.key" }}
filter { # Parsuj timestamp date { match => [ "[json][timestamp]", "ISO8601" ] target => "@timestamp" }
# Dodaj dane GeoIP geoip { source => "[json][ip]" target => "geoip" }
# Wyodrębnij pola mutate { add_field => { "service" => "%{[json][service]}" "environment" => "%{[json][environment]}" "request_id" => "%{[json][requestId]}" } }
# Parsuj user agent useragent { source => "[json][userAgent]" target => "user_agent" }}
output { elasticsearch { hosts => ["elasticsearch:9200"] index => "logs-%{[service]}-%{+YYYY.MM.dd}" template_name => "logs" template => "/etc/logstash/templates/logs.json" }}
# AI konfiguruje stos Loki"Skonfiguruj Loki z:- Promtail do zbierania- Loki do przechowywania- Grafana do zapytań- Zapytaniami LogQL"
# promtail-config.yamlserver: http_listen_port: 9080 grpc_listen_port: 0
positions: filename: /tmp/positions.yaml
clients: - url: http://loki:3100/loki/api/v1/push
scrape_configs: - job_name: containers static_configs: - targets: - localhost labels: job: containerlogs __path__: /var/log/containers/*/*.log
pipeline_stages: - json: expressions: output: log level: level timestamp: timestamp service: service request_id: requestId
- labels: level: service: environment:
- timestamp: format: RFC3339Nano source: timestamp
- metrics: log_lines_total: type: Counter description: "Całkowite linie logów" source: level config: action: inc
http_request_duration_seconds: type: Histogram description: "Czas trwania żądania HTTP" source: duration config: buckets: [0.1, 0.5, 1, 2, 5, 10]
# loki-config.yamlauth_enabled: false
server: http_listen_port: 3100
ingester: wal: enabled: true dir: /loki/wal lifecycler: address: 127.0.0.1 ring: kvstore: store: inmemory replication_factor: 1
schema_config: configs: - from: 2024-01-01 store: boltdb-shipper object_store: filesystem schema: v11 index: prefix: index_ period: 24h
storage_config: boltdb_shipper: active_index_directory: /loki/boltdb-shipper-active cache_location: /loki/boltdb-shipper-cache shared_store: filesystem filesystem: directory: /loki/chunks
limits_config: retention_period: 30d enforce_metric_name: false reject_old_samples: true reject_old_samples_max_age: 168h
// AI implementuje distributed tracing"Stwórz distributed tracing dla mikrousług:- Propagację kontekstu trace- Integrację service mesh- Tracing zapytań bazodanowych- Tracing zewnętrznych API- Analizę wydajności"
import { Tracer, Span, SpanContext } from '@opentelemetry/api';import { W3CTraceContextPropagator } from '@opentelemetry/core';
export class TracingService { private tracer: Tracer; private propagator = new W3CTraceContextPropagator();
async handleRequest(req: Request, res: Response) { // Wyciągnij kontekst rodzica const parentContext = this.propagator.extract( context.active(), req.headers );
// Rozpocznij nowy span const span = this.tracer.startSpan('http.request', { attributes: { 'http.method': req.method, 'http.url': req.url, 'http.target': req.path, 'http.host': req.hostname, 'http.scheme': req.protocol, 'http.user_agent': req.headers['user-agent'] } }, parentContext);
// Propaguj do downstream serwisów const headers = {}; this.propagator.inject( trace.setSpan(context.active(), span), headers );
try { // Wykonaj wywołanie downstream const response = await this.callDownstreamService({ headers, ...requestData });
span.setAttributes({ 'http.status_code': response.statusCode, 'http.response_content_length': response.contentLength });
return response; } catch (error) { span.recordException(error); span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }); throw error; } finally { span.end(); } }}
// Tracing bazy danychexport class DatabaseTracer { async query(sql: string, params: any[]) { const span = tracer.startSpan('db.query', { attributes: { 'db.system': 'postgresql', 'db.statement': this.sanitizeSql(sql), 'db.operation': this.extractOperation(sql) } });
try { const result = await this.pool.query(sql, params);
span.setAttributes({ 'db.rows_affected': result.rowCount });
return result; } catch (error) { span.recordException(error); throw error; } finally { span.end(); } }
private sanitizeSql(sql: string): string { // Usuń wrażliwe dane return sql.replace(/\b\d{4,}\b/g, '?'); }}
Alerty oparte na SLO
Alertowanie oparte na celach poziomu serwisu
Wykrywanie anomalii
Wykrywanie anomalii napędzane przez ML
Alerty wielokanałowe
Integracja Slack, PagerDuty, email
Grupowanie alertów
Inteligentna korelacja alertów
# AI tworzy reguły alertów Prometheus"Wygeneruj reguły alertów dla:- Naruszeń SLO- Zużycia budżetu błędów- Wyczerpania zasobów- Incydentów bezpieczeństwa- Metryk biznesowych"
groups: - name: slo_alerts interval: 30s rules: - alert: HighErrorRate expr: | ( sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) ) > 0.05 for: 5m labels: severity: critical team: platform annotations: summary: "Wykryto wysoki współczynnik błędów" description: "Współczynnik błędów wynosi {{ $value | humanizePercentage }} przez ostatnie 5 minut" runbook_url: "https://wiki.company.com/runbooks/high-error-rate"
- alert: SLOBudgetBurn expr: | ( 1 - ( sum(rate(http_requests_total{status!~"5.."}[1h])) / sum(rate(http_requests_total[1h])) ) ) > (1 - 0.999) * 14.4 for: 5m labels: severity: warning team: platform annotations: summary: "Zbyt wysokie tempo wypalania budżetu błędów SLO" description: "Przy obecnym tempie wypalania, miesięczny budżet błędów zostanie wyczerpany w {{ $value }} godzin"
- alert: HighMemoryUsage expr: | ( container_memory_usage_bytes{pod=~"api-.*"} / container_spec_memory_limit_bytes{pod=~"api-.*"} ) > 0.9 for: 10m labels: severity: warning team: platform annotations: summary: "Pod {{ $labels.pod }} używa ponad 90% pamięci" description: "Zużycie pamięci wynosi {{ $value | humanizePercentage }}"
- name: business_alerts rules: - alert: PaymentFailureRate expr: | ( sum(rate(payment_failures_total[5m])) / sum(rate(payment_attempts_total[5m])) ) > 0.1 for: 5m labels: severity: critical team: payments annotations: summary: "Wysoki współczynnik niepowodzeń płatności" description: "Współczynnik niepowodzeń płatności wynosi {{ $value | humanizePercentage }}" impact: "Szacunkowa strata przychodów ${{ $value * 1000 | humanize }}/godzinę"
// AI tworzy system reagowania na incydenty"Zbuduj automatyzację reagowania na incydenty:- Automatyczne tworzenie incydentów- Wykonywanie runbooków- Aktualizacje strony statusu- Generowanie post-mortem- Analiza głównej przyczyny"
export class IncidentManager { async handleAlert(alert: Alert) { // Stwórz incydent const incident = await this.createIncident({ title: alert.annotations.summary, severity: alert.labels.severity, team: alert.labels.team, alertName: alert.alertname, startTime: new Date() });
// Wykonaj runbook jeśli dostępny if (alert.annotations.runbook_url) { await this.executeRunbook(alert.annotations.runbook_url, incident); }
// Powiadom zespół await this.notifyTeam(incident);
// Zaktualizuj stronę statusu await this.updateStatusPage({ component: this.getAffectedComponent(alert), status: 'degraded', message: alert.annotations.summary });
// Rozpocznij zbieranie diagnostyki await this.collectDiagnostics(incident); }
private async executeRunbook(runbookUrl: string, incident: Incident) { const runbook = await this.fetchRunbook(runbookUrl);
for (const step of runbook.steps) { try { const result = await this.executeStep(step);
await this.addIncidentNote(incident, { type: 'runbook_step', step: step.name, result: result, timestamp: new Date() });
if (result.resolved) { await this.resolveIncident(incident, { resolution: 'Automatyczne rozwiązanie runbook', steps: runbook.steps }); break; } } catch (error) { await this.addIncidentNote(incident, { type: 'runbook_error', step: step.name, error: error.message }); } } }}
// AI implementuje monitorowanie wydajności"Stwórz monitorowanie wydajności dla:- Śledzenia czasu odpowiedzi- Wydajności zapytań bazodanowych- Współczynników trafień cache- Wykorzystania zasobów- Metryk user experience"
export class PerformanceMonitor { private metrics = new MetricsCollector();
async monitorEndpoint( handler: RequestHandler ): Promise<RequestHandler> { return async (req, res, next) => { const timer = this.metrics.startTimer('http_request_duration'); const startMemory = process.memoryUsage(); const startCpu = process.cpuUsage();
// Śledź zapytania bazodanowe const queryTracker = this.trackDatabaseQueries();
try { await handler(req, res, next); } finally { const duration = timer.end(); const endMemory = process.memoryUsage(); const endCpu = process.cpuUsage();
// Zapisz metryki this.metrics.record({ endpoint: req.path, method: req.method, statusCode: res.statusCode, duration, memoryDelta: endMemory.heapUsed - startMemory.heapUsed, cpuUser: endCpu.user - startCpu.user, cpuSystem: endCpu.system - startCpu.system, dbQueries: queryTracker.getQueries(), dbDuration: queryTracker.getTotalDuration() });
// Sprawdź problemy wydajnościowe if (duration > 1000) { this.logger.warn('Wykryto wolny endpoint', { endpoint: req.path, duration, queries: queryTracker.getSlowQueries() }); } } }; }
private trackDatabaseQueries() { const queries: QueryInfo[] = [];
// Hook do database driver const originalQuery = db.query; db.query = async function(...args) { const start = Date.now(); const result = await originalQuery.apply(this, args); const duration = Date.now() - start;
queries.push({ sql: args[0], duration, rows: result.rowCount });
return result; };
return { getQueries: () => queries, getTotalDuration: () => queries.reduce((sum, q) => sum + q.duration, 0), getSlowQueries: () => queries.filter(q => q.duration > 100) }; }}
Instrumentuj wcześnie
Dodaj monitorowanie od początku, nie jako dodatek
Alertuj o objawach
Alertuj o problemach użytkowników, nie tylko metrykach technicznych
Kontekst to król
Uwzględnij odpowiedni kontekst w logach i tracach
Automatyzuj odpowiedzi
Automatyzuj typowe odpowiedzi na incydenty
Strategie migracji
Migracja starszych systemów do nowoczesnego monitorowania
Wzorce architektury
Projektowanie z myślą o obserwowalności od początku
Zaawansowane DevOps
Integracja monitorowania z CI/CD