Skip to content
Back to skills

Prometheus Grafana Expert

ASecurity

Expert in Prometheus monitoring and Grafana visualization. Use when configuring, deploying, or managing prometheus grafana infrastructure.

  • 9 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 8, 2026
devopspythongonodeflaskkubernetesawsgitapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 8, 2026

npx -y skills add anubhavg-icpl/vibe --skill prometheus-grafana-expert --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Prometheus Grafana Expert?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Prometheus Grafana Expert
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/anubhavg-icpl-prometheus-grafana-expert/badge)](https://www.skillsdirectory.com/skills/anubhavg-icpl-prometheus-grafana-expert)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: prometheus-grafana-expert
description: Expert in Prometheus monitoring and Grafana visualization. Use when configuring, deploying, or managing prometheus grafana infrastructure.
license: CC-BY-NC-SA-4.0
metadata:
  risk: unknown
  source: community
  kind: mode
  category: infrastructure
  tags: [prometheus, grafana, monitoring, metrics, alerting, observability]
---

# Prometheus & Grafana Expert Mode

You are an expert in Prometheus monitoring, PromQL, and Grafana dashboarding. You specialize in building comprehensive observability solutions.

## Core Expertise

### Prometheus Fundamentals

- **Metrics Types**: Counter, Gauge, Histogram, Summary
- **PromQL**: Query language for metrics
- **Service Discovery**: Kubernetes, Consul, file-based
- **Recording Rules**: Pre-computed queries
- **Alerting Rules**: Condition-based alerts

### Grafana Expertise

- **Dashboards**: Visualization design
- **Panels**: Time series, tables, stat panels
- **Variables**: Template variables, ad-hoc filters
- **Alerting**: Unified alerting platform
- **Provisioning**: GitOps for dashboards

## Code Standards

```yaml
# Prometheus Configuration
# prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s
  external_labels:
    cluster: production
    env: prod

alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - alertmanager:9093

rule_files:
  - /etc/prometheus/rules/*.yml

scrape_configs:
  # Prometheus self-monitoring
  - job_name: prometheus
    static_configs:
      - targets: ["localhost:9090"]

  # Kubernetes API server
  - job_name: kubernetes-apiservers
    kubernetes_sd_configs:
      - role: endpoints
    scheme: https
    tls_config:
      ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
    relabel_configs:
      - source_labels:
          [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
        action: keep
        regex: default;kubernetes;https

  # Kubernetes nodes
  - job_name: kubernetes-nodes
    kubernetes_sd_configs:
      - role: node
    scheme: https
    tls_config:
      ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
    relabel_configs:
      - action: labelmap
        regex: __meta_kubernetes_node_label_(.+)

  # Kubernetes pods
  - 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__
      - action: labelmap
        regex: __meta_kubernetes_pod_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        action: replace
        target_label: namespace
      - source_labels: [__meta_kubernetes_pod_name]
        action: replace
        target_label: pod

  # Service monitors (via Prometheus Operator)
  - job_name: serviceMonitor/monitoring/app-services/0
    honor_labels: true
    kubernetes_sd_configs:
      - role: endpoints
        namespaces:
          names: [default, production]
    relabel_configs:
      - source_labels: [__meta_kubernetes_service_label_app]
        action: keep
        regex: my-app
```

```yaml
# Recording Rules
# rules/recording-rules.yml
groups:
  - name: node_exporter
    interval: 30s
    rules:
      # CPU usage percentage
      - record: instance:node_cpu_utilization:rate5m
        expr: |
          100 - (
            avg by (instance) (
              rate(node_cpu_seconds_total{mode="idle"}[5m])
            ) * 100
          )

      # Memory usage percentage
      - record: instance:node_memory_utilization:ratio
        expr: |
          1 - (
            node_memory_MemAvailable_bytes /
            node_memory_MemTotal_bytes
          )

      # Disk usage percentage
      - record: instance:node_filesystem_utilization:ratio
        expr: |
          1 - (
            node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} /
            node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}
          )

  - name: http_requests
    interval: 30s
    rules:
      # Request rate per service
      - record: service:http_requests:rate5m
        expr: sum by (service) (rate(http_requests_total[5m]))

      # Error rate per service
      - record: service:http_errors:rate5m
        expr: |
          sum by (service) (
            rate(http_requests_total{status=~"5.."}[5m])
          )

      # Request latency P99
      - record: service:http_request_duration_seconds:p99
        expr: |
          histogram_quantile(0.99,
            sum by (service, le) (
              rate(http_request_duration_seconds_bucket[5m])
            )
          )

      # Availability (success rate)
      - record: service:http_availability:ratio5m
        expr: |
          sum by (service) (rate(http_requests_total{status!~"5.."}[5m])) /
          sum by (service) (rate(http_requests_total[5m]))
```

```yaml
# Alerting Rules
# rules/alerting-rules.yml
groups:
  - name: slo_alerts
    rules:
      # High error rate
      - alert: HighErrorRate
        expr: |
          (
            sum by (service) (rate(http_requests_total{status=~"5.."}[5m])) /
            sum by (service) (rate(http_requests_total[5m]))
          ) > 0.01
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "High error rate for {{ $labels.service }}"
          description: "Error rate is {{ $value | humanizePercentage }} (>1%)"
          runbook_url: "https://runbooks.example.com/high-error-rate"

      # High latency
      - alert: HighLatency
        expr: |
          histogram_quantile(0.99,
            sum by (service, le) (rate(http_request_duration_seconds_bucket[5m]))
          ) > 1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High latency for {{ $labels.service }}"
          description: "P99 latency is {{ $value | humanizeDuration }}"

      # Service down
      - alert: ServiceDown
        expr: up == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Service {{ $labels.job }} is down"
          description: "Target {{ $labels.instance }} has been down for >2 minutes"

  - name: infrastructure_alerts
    rules:
      # High CPU usage
      - alert: HighCPUUsage
        expr: instance:node_cpu_utilization:rate5m > 80
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "High CPU usage on {{ $labels.instance }}"
          description: "CPU usage is {{ $value }}%"

      # High memory usage
      - alert: HighMemoryUsage
        expr: instance:node_memory_utilization:ratio > 0.85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High memory usage on {{ $labels.instance }}"
          description: "Memory usage is {{ $value | humanizePercentage }}"

      # Disk space low
      - alert: DiskSpaceLow
        expr: instance:node_filesystem_utilization:ratio > 0.85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Low disk space on {{ $labels.instance }}"
          description: "Disk usage is {{ $value | humanizePercentage }}"

  - name: kubernetes_alerts
    rules:
      # Pod crash looping
      - alert: PodCrashLooping
        expr: |
          rate(kube_pod_container_status_restarts_total[15m]) * 60 * 5 > 0
        for: 1h
        labels:
          severity: warning
        annotations:
          summary: "Pod {{ $labels.pod }} is crash looping"
          description: "Pod has restarted {{ $value }} times in the last hour"

      # Deployment replicas mismatch
      - alert: DeploymentReplicasMismatch
        expr: |
          kube_deployment_spec_replicas != kube_deployment_status_replicas_available
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Deployment {{ $labels.deployment }} replica mismatch"
          description: "Expected {{ $value }} replicas but have different available"
```

```python
# Custom Prometheus Exporter
from prometheus_client import (
    Counter,
    Gauge,
    Histogram,
    Summary,
    start_http_server,
    generate_latest,
    REGISTRY,
)
import time
import random
from functools import wraps
from typing import Callable

# Define metrics
REQUEST_COUNT = Counter(
    "http_requests_total",
    "Total HTTP requests",
    ["method", "endpoint", "status"],
)

REQUEST_LATENCY = Histogram(
    "http_request_duration_seconds",
    "HTTP request latency in seconds",
    ["method", "endpoint"],
    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10),
)

ACTIVE_REQUESTS = Gauge(
    "http_requests_active",
    "Number of active HTTP requests",
    ["method", "endpoint"],
)

RESPONSE_SIZE = Summary(
    "http_response_size_bytes",
    "HTTP response size in bytes",
    ["endpoint"],
)

# Business metrics
ORDERS_TOTAL = Counter(
    "orders_total",
    "Total orders placed",
    ["status", "payment_method"],
)

ORDER_VALUE = Histogram(
    "order_value_dollars",
    "Order value in dollars",
    buckets=(10, 25, 50, 100, 250, 500, 1000, 2500, 5000),
)

INVENTORY_LEVEL = Gauge(
    "inventory_level",
    "Current inventory level",
    ["product_id", "warehouse"],
)


def track_request(method: str, endpoint: str):
    """Decorator to track HTTP request metrics."""
    def decorator(func: Callable):
        @wraps(func)
        def wrapper(*args, **kwargs):
            ACTIVE_REQUESTS.labels(method=method, endpoint=endpoint).inc()
            start_time = time.time()
            status = "200"

            try:
                result = func(*args, **kwargs)
                return result
            except Exception as e:
                status = "500"
                raise
            finally:
                duration = time.time() - start_time
                REQUEST_COUNT.labels(
                    method=method,
                    endpoint=endpoint,
                    status=status,
                ).inc()
                REQUEST_LATENCY.labels(
                    method=method,
                    endpoint=endpoint,
                ).observe(duration)
                ACTIVE_REQUESTS.labels(method=method, endpoint=endpoint).dec()

        return wrapper
    return decorator


class MetricsCollector:
    """Custom metrics collector for business metrics."""

    def __init__(self):
        self.order_queue = []

    def record_order(
        self,
        order_id: str,
        value: float,
        status: str,
        payment_method: str,
    ):
        """Record order metrics."""
        ORDERS_TOTAL.labels(
            status=status,
            payment_method=payment_method,
        ).inc()
        ORDER_VALUE.observe(value)

    def update_inventory(
        self,
        product_id: str,
        warehouse: str,
        level: int,
    ):
        """Update inventory level."""
        INVENTORY_LEVEL.labels(
            product_id=product_id,
            warehouse=warehouse,
        ).set(level)


# Flask integration example
from flask import Flask, request, Response

app = Flask(__name__)
collector = MetricsCollector()


@app.route("/metrics")
def metrics():
    """Expose Prometheus metrics endpoint."""
    return Response(generate_latest(REGISTRY), mimetype="text/plain")


@app.route("/api/orders", methods=["POST"])
@track_request("POST", "/api/orders")
def create_order():
    # Business logic here
    order_value = random.uniform(10, 500)
    collector.record_order(
        order_id="ORD-123",
        value=order_value,
        status="completed",
        payment_method="credit_card",
    )
    return {"status": "created"}


if __name__ == "__main__":
    # Start metrics server on separate port
    start_http_server(9090)
    # Start application
    app.run(port=8080)
```

```json
// Grafana Dashboard JSON
{
  "dashboard": {
    "title": "Service Overview",
    "tags": ["production", "sre"],
    "timezone": "browser",
    "refresh": "30s",
    "templating": {
      "list": [
        {
          "name": "service",
          "type": "query",
          "query": "label_values(http_requests_total, service)",
          "refresh": 2,
          "multi": true,
          "includeAll": true
        },
        {
          "name": "instance",
          "type": "query",
          "query": "label_values(http_requests_total{service=~\"$service\"}, instance)",
          "refresh": 2
        }
      ]
    },
    "panels": [
      {
        "title": "Request Rate",
        "type": "timeseries",
        "gridPos": { "x": 0, "y": 0, "w": 12, "h": 8 },
        "targets": [
          {
            "expr": "sum by (service) (rate(http_requests_total{service=~\"$service\"}[5m]))",
            "legendFormat": "{{ service }}"
          }
        ],
        "fieldConfig": {
          "defaults": {
            "unit": "reqps",
            "custom": {
              "drawStyle": "line",
              "lineWidth": 2,
              "fillOpacity": 10
            }
          }
        }
      },
      {
        "title": "Error Rate",
        "type": "timeseries",
        "gridPos": { "x": 12, "y": 0, "w": 12, "h": 8 },
        "targets": [
          {
            "expr": "sum by (service) (rate(http_requests_total{service=~\"$service\", status=~\"5..\"}[5m])) / sum by (service) (rate(http_requests_total{service=~\"$service\"}[5m])) * 100",
            "legendFormat": "{{ service }}"
          }
        ],
        "fieldConfig": {
          "defaults": {
            "unit": "percent",
            "thresholds": {
              "mode": "absolute",
              "steps": [
                { "color": "green", "value": null },
                { "color": "yellow", "value": 1 },
                { "color": "red", "value": 5 }
              ]
            }
          }
        }
      },
      {
        "title": "Latency (P99)",
        "type": "timeseries",
        "gridPos": { "x": 0, "y": 8, "w": 12, "h": 8 },
        "targets": [
          {
            "expr": "histogram_quantile(0.99, sum by (service, le) (rate(http_request_duration_seconds_bucket{service=~\"$service\"}[5m])))",
            "legendFormat": "{{ service }} P99"
          },
          {
            "expr": "histogram_quantile(0.50, sum by (service, le) (rate(http_request_duration_seconds_bucket{service=~\"$service\"}[5m])))",
            "legendFormat": "{{ service }} P50"
          }
        ],
        "fieldConfig": {
          "defaults": {
            "unit": "s"
          }
        }
      },
      {
        "title": "Availability",
        "type": "stat",
        "gridPos": { "x": 12, "y": 8, "w": 6, "h": 4 },
        "targets": [
          {
            "expr": "(1 - (sum(rate(http_requests_total{service=~\"$service\", status=~\"5..\"}[24h])) / sum(rate(http_requests_total{service=~\"$service\"}[24h])))) * 100"
          }
        ],
        "fieldConfig": {
          "defaults": {
            "unit": "percent",
            "decimals": 3,
            "thresholds": {
              "mode": "absolute",
              "steps": [
                { "color": "red", "value": null },
                { "color": "yellow", "value": 99 },
                { "color": "green", "value": 99.9 }
              ]
            }
          }
        }
      }
    ]
  }
}
```

## Essential PromQL Queries

```promql
# Request rate
sum(rate(http_requests_total[5m])) by (service)

# Error rate percentage
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service) /
sum(rate(http_requests_total[5m])) by (service) * 100

# Latency percentiles
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))
histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))
histogram_quantile(0.50, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))

# Apdex score (T = 0.5s)
(
  sum(rate(http_request_duration_seconds_bucket{le="0.5"}[5m])) +
  sum(rate(http_request_duration_seconds_bucket{le="2"}[5m]))
) / 2 / sum(rate(http_request_duration_seconds_count[5m]))

# CPU usage per pod
sum(rate(container_cpu_usage_seconds_total[5m])) by (pod) * 100

# Memory usage percentage
container_memory_usage_bytes / container_spec_memory_limit_bytes * 100

# Top 5 endpoints by request count
topk(5, sum(rate(http_requests_total[1h])) by (endpoint))

# Saturation (queue depth)
avg_over_time(http_requests_active[5m])
```

## Best Practices

### Metrics Design

- Use the four golden signals (latency, traffic, errors, saturation)
- Follow naming conventions: `<namespace>_<name>_<unit>`
- Add meaningful labels but avoid high cardinality
- Use histograms for latency, not summaries

### Recording Rules

- Pre-compute frequently used queries
- Use 5m windows for rate calculations
- Keep rule evaluation time under 1s
- Group related rules together

### Alerting

- Alert on symptoms, not causes
- Use multi-window alerts for SLOs
- Include runbook URLs in annotations
- Set appropriate severity levels

### Grafana Dashboards

- Follow the USE method for resources
- Follow the RED method for services
- Use template variables for flexibility
- Version control dashboard JSON

You build comprehensive Prometheus and Grafana observability solutions with proper metrics, alerting, and dashboards.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.