Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Configure Prometheus with alerting, recording rules, service discovery (K8s, Consul, EC2), federation, PromQL optimization, and Alertmanager.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 83% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 532% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 433% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 183% | 0% |
| case-22 | ✗→✓ | ▲ Improved | 334% | 0% |
Trigger conditions:
Complements:
observability-stack-configurator: For overall observability stack designobservability-unified-dashboard: For Grafana dashboard design with Prometheus datasourcesobservability-slo-calculator: For SLO/error budget definitions that drive alerting rulesOut of scope:
Time normalization:
NOW_ET using NIST/time.gov semantics (America/New_York, ISO-8601)NOW_ET for all access dates in citationsVerify inputs:
Validate service discovery:
kubernetes_sd_config: Verify Kubernetes API access and RBAC permissionsconsul_sd_config: Verify Consul agent accessibility and service catalogec2_sd_config: Verify AWS credentials and EC2 instance tagsfile_sd_config: Verify JSON/YAML file path and refresh intervalCheck cardinality constraints:
metric_relabel_configs to drop high-cardinality labelsSource freshness:
NOW_ET)Abort if:
Scenario: Single service with static targets or file-based service discovery, basic alerting, no recording rules.
Steps:
scrape_interval: 15s (balance between data freshness and storage)evaluation_interval: 15s (how often to evaluate alerting/recording rules)external_labels for federation or remote write (e.g., datacenter: us-east-1)job_name (logical grouping, e.g., api-service, postgres-exporter)static_configs with targets: ['localhost:9090']file_sd_configs with files: ['/etc/prometheus/targets/*.json']scrape_interval override if different from globalalerts.yml with groupsseverity: critical|warning|info)alertmanager_config with static_configs pointing to Alertmanager instancesend_resolved: true to notify when alert resolvesOutput:
prometheus.yml with global config, single scrape job, alerting rules file referencealerts.yml with 2-5 basic alertsToken budget: ≤2000 tokens
Scenario: Multiple services with Kubernetes/Consul/EC2 service discovery, recording rules for expensive queries, Alertmanager routing with grouping.
Steps:
Kubernetes Service Discovery:
kubernetes_sd_configs with role: pod (discover all pods with prometheus.io/scrape: "true" annotation)yaml relabel_configs:
action: keep regex: true
action: replace target_label: __metrics_path__ regex: (.+)
action: replace target_label: __address__ regex: (^:]+)(?::\d+)?;(\d+) replacement: $1:$2
action: replace target_label: kubernetes_namespace
action: replace target_label: kubernetes_pod_name
node, pod, service, endpoints, ingress (accessed NOW_ET: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#kubernetes_sd_config)Consul Service Discovery:
consul_sd_configs with server: 'consul.service.consul:8500'tags: ['production', 'monitoring-enabled']EC2 Service Discovery:
ec2_sd_configs with AWS region and filters__meta_ec2_tag_<tagkey>level:metric:operations (accessed NOW_ET: https://prometheus.io/docs/practices/naming/)job, instance, cluster)sum, avg, rate)yaml groups:
interval: 30s rules:
expr: sum(rate(http_requests_total5m])) by (job)
expr: histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket5m])) by (job, le))
Metric Relabeling (metric_relabel_configs):
yaml metric_relabel_configs:
action: labeldrop regex: .
action: drop regex: 'expensive_metric_.'
Target Relabeling (relabel_configs):
Multi-Window Burn Rate Alerts:
yaml groups:
rules:
expr: | ( sum(rate(http_requests_total{status=~"5.."}1h])) / sum(rate(http_requests_total1h])) ) > (14.4 0.001) for: 2m labels: severity: critical annotations: summary: "Error budget burning 14.4× faster than allowed" description: "{{ $labels.job }} has {{ $value | humanizePercentage }} error rate (SLO: 99.9%, budget exhausted in 2 days)"
Symptom-Based Alerts:
yaml
expr: histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket5m])) by (job, le)) > 0.5 for: 5m labels: severity: warning annotations: summary: "High latency on {{ $labels.job }}" description: "p95 latency is {{ $value }}s (threshold: 0.5s)"
cluster + alertname, wait 30s for batchyaml route: receiver: 'default-email' group_by: 'cluster', 'alertname'] group_wait: 30s group_interval: 5m repeat_interval: 4h routes:
severity: critical receiver: 'pagerduty'
severity: warning receiver: 'slack'
receivers:
pagerduty_configs:
slack_configs:
channel: '#alerts' title: '{{ .GroupLabels.alertname }}' text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
email_configs:
inhibit_rules:
severity: critical target_match: severity: warning equal: 'cluster', 'alertname']
Output:
prometheus.yml with Kubernetes/Consul/EC2 service discovery, relabeling configsrecording_rules.yml with 5-10 recording rules (level:metric:operations naming)alerts.yml with multi-window burn rate alerts and symptom-based alertsalertmanager.yml with routing tree, receivers, inhibition rulesToken budget: ≤6000 tokens
Scenario: Multi-datacenter federation, cardinality management, PromQL query optimization, Prometheus 3.0+ features (UTF-8, OTLP, Remote Write 2.0).
Steps:
Hierarchical Federation (Multi-DC):
NOW_ET: https://prometheus.io/docs/prometheus/latest/federation/)yaml scrape_configs:
scrape_interval: 30s honor_labels: true metrics_path: '/federate' params: 'match]':
static_configs:
Cross-Service Federation:
Query Performance Best Practices:
sum(http_requests_total) (aggregates 10k+ time series)sum(http_requests_total{job="api-service", status=~"5.."}) (aggregates 10-50 time series)api_http_requests_total) without labelsNOW_ET: https://prometheus.io/docs/prometheus/latest/querying/basics/)promql # Compute error rate using pre-recorded job-level metrics (fast) job:http_requests_total:rate5m{job="api-service", status=~"5.."} / job:http_requests_total:rate5m{job="api-service"}
Cardinality Management:
topk(10, count by (__name__)({__name__=~".+"})) to find high-cardinality metricsmetric_relabel_configs to remove high-cardinality labelsmetric_relabel_configs with action: drop to sample metricsyaml metric_relabel_configs: # Drop user_id label (high cardinality)
action: labeldrop regex: . # Keep only 5xx errors (reduce cardinality of status label)
action: keep regex: '5..'
UTF-8 Support (Prometheus 3.0+):
NOW_ET: https://prometheus.io/blog/2024/11/14/prometheus-3-0/)http_requests_total{endpoint="用户登录"} (Chinese characters now valid)OpenTelemetry OTLP Receiver (Prometheus 3.0+):
/api/v1/otlp/v1/metricsyaml otlp: protocols: http: endpoint: 0.0.0.0:9090
Remote Write 2.0 (Prometheus 3.0+):
Extract Kubernetes Annotations into Labels: yaml relabel_configs:
action: replace target_label: version
action: replace target_label: team
Drop Expensive Metrics Based on Name Pattern: yaml metric_relabel_configs:
action: drop regex: 'go_.|process_.' # Drop Go runtime metrics to save storage
Multi-Level Aggregation: yaml groups:
interval: 30s rules: # Level 1: Instance-level
expr: sum(rate(http_requests_total5m])) by (instance, job, status)
# Level 2: Job-level (aggregates Level 1)
expr: sum(instance:http_requests_total:rate5m) by (job, status)
# Level 3: Cluster-level (aggregates Level 2)
expr: sum(job:http_requests_total:rate5m) by (status)
Time-Based Routing (Mute Alerts During Maintenance): yaml route: routes:
severity: warning mute_time_intervals:
mute_time_intervals:
time_intervals:
time_intervals:
end_time: '01:00'
Grouping by Multiple Labels: yaml route: group_by: ['cluster', 'namespace', 'alertname'] group_wait: 30s group_interval: 5m repeat_interval: 12h
Output:
prometheus.yml with federation endpoints, OTLP receiver, Remote Write 2.0Token budget: ≤12000 tokens
When to use federation vs remote write:
When to create recording rules:
Alert severity assignment:
Service discovery selection:
kubernetes_sd_configs with role: pod for dynamic pod discoveryconsul_sd_configs for VM-based infrastructure with Consul service catalogec2_sd_configs for AWS instances with consistent taggingfile_sd_configs for static infrastructure or external service discoveryCardinality limits:
prometheus_tsdb_symbol_table_size_bytes >1GB or prometheus_tsdb_head_series >10MAbort conditions:
prometheus.yml schema:
yamlglobal: scrape_interval: <duration> evaluation_interval: <duration> external_labels: <label_name>: <label_value> alerting: alertmanagers: - static_configs: - targets: ['<alertmanager_host>:<port>'] rule_files: - 'alerts.yml' - 'recording_rules.yml' scrape_configs: - job_name: '<job_name>' kubernetes_sd_configs: [...] # OR consul_sd_configs, ec2_sd_configs, static_configs relabel_configs: [...] metric_relabel_configs: [...]
alerts.yml schema:
yamlgroups: - name: <group_name> rules: - alert: <alert_name> expr: <promql_expression> for: <duration> labels: severity: critical|warning|info annotations: summary: <short_description> description: <detailed_description_with_templating>
recording_rules.yml schema:
yamlgroups: - name: <group_name> interval: <duration> rules: - record: <level>:<metric>:<operations> expr: <promql_expression> labels: <label_name>: <label_value>
alertmanager.yml schema:
yamlroute: receiver: <default_receiver> group_by: [<label_name>, ...] group_wait: <duration> group_interval: <duration> repeat_interval: <duration> routes: - match: <label_name>: <label_value> receiver: <receiver_name> receivers: - name: <receiver_name> pagerduty_configs: [...] slack_configs: [...] email_configs: [...] inhibit_rules: - source_match: <label_name>: <label_value> target_match: <label_name>: <label_value> equal: [<label_name>, ...]
Required fields:
prometheus.yml: global.scrape_interval, scrape_configs[].job_namealerts.yml: alert, expr, labels.severity, annotations.summaryrecording_rules.yml: record, expralertmanager.yml: route.receiver, receivers[].nameValidation:
promtool check rules <file.yml>promtool check config prometheus.ymlamtool check-config alertmanager.ymlScenario: Scrape all pods with prometheus.io/scrape: "true" annotation, create recording rules for API latency.
prometheus.yml:
yamlglobal: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - 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.yml:
yamlgroups: - name: api_latency interval: 30s rules: - record: job:http_request_duration_seconds:p95 expr: histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (job, le)) - record: job:http_request_duration_seconds:p99 expr: histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (job, le))
Token budgets:
Safety:
promtool check rulesmetric_relabel_configs to drop secrets if accidentally exposedAuditability:
level:metric:operations conventionsummary and description with templatingDeterminism:
cluster + alertname produces predictable batchesPerformance:
Official Documentation:
NOW_ET)NOW_ET)NOW_ET)NOW_ET)NOW_ET)NOW_ET)Tooling:
promtool: Validate Prometheus configs and PromQL queriesamtool: Validate Alertmanager configs and manage silencesRelated Skills:
observability-stack-configurator: Overall observability stack designobservability-unified-dashboard: Grafana dashboard design with Prometheus datasourcesobservability-slo-calculator: SLO/error budget definitions for alerting ruleskubernetes-manifest-generator: Kubernetes deployment manifests for Prometheus + AlertmanagerOther measured skills in the registry, with their headline benchmark lift.