Przejdź do głównej zawartości

Monitorowanie i obserwowalność z AI

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:

~/.cursor/mcp.json
{
"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

  1. 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 metryk
    const 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 metryk
    export 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 metryk
    export const metricsEndpoint = async (req: express.Request, res: express.Response) => {
    res.set('Content-Type', register.contentType);
    res.send(await register.metrics());
    };
  2. 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 biznesowe
    const 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 biznesowej
    export 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();
    }
    }
    }
  3. 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 }
    }
    ]
    }
    }
  1. 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"
  2. 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"
  3. 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%"
  4. 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"
  5. Ujednolicone workflow’y monitorowania

    "Koordynuj narzędzia monitorowania:
    1. Gdy Sentry zgłosi skok błędów
    2. Sprawdź metryki Grafana dla korelacji
    3. Przejrzyj SonarQube pod kątem ostatnich zmian
    4. 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ów
Stwórz ticket Jira dla każdego"
// Natychmiastowy dostęp do danych
// Brak przełączania kontekstu
// Zautomatyzowane workflow'y
// 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 SDK
const 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 SDK
sdk.start();
// Niestandardowa instrumentacja
import { 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 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ów
export 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 żądania
export 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 kontekstem
export 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.yml
filebeat.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.conf
input {
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 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 danych
export 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)
};
}
}
  1. Skonfiguruj zbieranie metryk Prometheus
  2. Zaimplementuj strukturalne logowanie
  3. Dodaj distributed tracing
  4. Stwórz dashboardy Grafana
  5. Skonfiguruj reguły alertowania
  1. Zidentyfikuj wolne endpointy
  2. Analizuj zapytania bazodanowe
  3. Znajdź wycieki pamięci
  4. Optymalizuj zużycie zasobów
  5. Stwórz dashboard wydajności
  1. Stwórz reguły alertów dla SLO
  2. Skonfiguruj routing alertów
  3. Zaimplementuj automatyzację runbook
  4. Zbuduj integrację strony statusu
  5. Generuj raporty post-mortem

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