/void !

Grafana

3 min read

OverviewπŸ”—

Grafana is an open-source observability platform for visualizing metrics, logs, and traces from multiple data sources.

Key Features:

  • Multi-source data visualization
  • Interactive dashboards
  • Alerting and notifications
  • Support for 150+ data sources
  • Template variables for dynamic dashboards
  • Panel library and sharing

InstallationπŸ”—

DockerπŸ”—

docker run -d -p 3000:3000 --name=grafana grafana/grafana

Docker with persistent storageπŸ”—

docker run -d -p 3000:3000 \
  --name=grafana \
  -v grafana-storage:/var/lib/grafana \
  grafana/grafana

Docker ComposeπŸ”—

version: '3'
services:
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
      - GF_USERS_ALLOW_SIGN_UP=false

volumes:
  grafana-data:

Kubernetes (with Helm)πŸ”—

helm repo add grafana https://grafana.github.io/helm-charts
helm install grafana grafana/grafana

Linux (Debian/Ubuntu)πŸ”—

sudo apt-get install -y software-properties-common
sudo add-apt-repository "deb https://packages.grafana.com/oss/deb stable main"
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install grafana
sudo systemctl start grafana-server
sudo systemctl enable grafana-server

Default CredentialsπŸ”—

  • URL: http://localhost:3000
  • Username: admin
  • Password: admin (change on first login)

ConfigurationπŸ”—

Main Configuration FileπŸ”—

Location: /etc/grafana/grafana.ini (Linux) or conf/defaults.ini

[server]
http_port = 3000
domain = localhost
root_url = %(protocol)s://%(domain)s:%(http_port)s/

[database]
type = sqlite3
path = grafana.db

[security]
admin_user = admin
admin_password = admin

[users]
allow_sign_up = false
allow_org_create = false

[auth.anonymous]
enabled = false

[smtp]
enabled = true
host = smtp.gmail.com:587
user = your-email@gmail.com
password = your-password
from_address = grafana@yourdomain.com

Environment VariablesπŸ”—

# Set admin password
GF_SECURITY_ADMIN_PASSWORD=mypassword

# Disable anonymous access
GF_AUTH_ANONYMOUS_ENABLED=false

# Set SMTP
GF_SMTP_ENABLED=true
GF_SMTP_HOST=smtp.gmail.com:587
GF_SMTP_USER=email@example.com
GF_SMTP_PASSWORD=password

Data SourcesπŸ”—

Add Prometheus Data SourceπŸ”—

Via UI:

  1. Configuration β†’ Data Sources β†’ Add data source
  2. Select Prometheus
  3. URL: http://prometheus:9090
  4. Click β€œSave & Test”

Via provisioning (/etc/grafana/provisioning/datasources/prometheus.yml):

apiVersion: 1

datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true
    editable: true

Add MySQL Data SourceπŸ”—

apiVersion: 1

datasources:
  - name: MySQL
    type: mysql
    url: mysql-host:3306
    database: mydb
    user: grafana
    secureJsonData:
      password: 'password'

Add PostgreSQL Data SourceπŸ”—

apiVersion: 1

datasources:
  - name: PostgreSQL
    type: postgres
    url: postgres-host:5432
    database: mydb
    user: grafana
    secureJsonData:
      password: 'password'
    jsonData:
      sslmode: disable

Add Loki Data SourceπŸ”—

apiVersion: 1

datasources:
  - name: Loki
    type: loki
    access: proxy
    url: http://loki:3100
    jsonData:
      maxLines: 1000

Add Elasticsearch Data SourceπŸ”—

apiVersion: 1

datasources:
  - name: Elasticsearch
    type: elasticsearch
    access: proxy
    url: http://elasticsearch:9200
    database: "[logs-]YYYY.MM.DD"
    jsonData:
      esVersion: "7.10.0"
      timeField: "@timestamp"

DashboardsπŸ”—

Create Dashboard via UIπŸ”—

  1. Click β€œ+” β†’ Dashboard
  2. Click β€œAdd new panel”
  3. Configure query and visualization
  4. Click β€œApply”
  5. Click β€œSave dashboard”

Import DashboardπŸ”—

  1. Click β€œ+” β†’ Import
  2. Enter dashboard ID or JSON
  3. Select data source
  4. Click β€œImport”

Popular Dashboard IDs:

  • Node Exporter Full: 1860
  • Kubernetes Cluster Monitoring: 7249
  • Docker Dashboard: 893
  • MySQL Overview: 7362
  • NGINX: 12708

Export DashboardπŸ”—

  1. Dashboard Settings (gear icon) β†’ JSON Model
  2. Copy JSON or click β€œSave to file”

Dashboard ProvisioningπŸ”—

Create /etc/grafana/provisioning/dashboards/dashboard.yml:

apiVersion: 1

providers:
  - name: 'Default'
    orgId: 1
    folder: ''
    type: file
    disableDeletion: false
    updateIntervalSeconds: 10
    options:
      path: /var/lib/grafana/dashboards

Place dashboard JSON files in /var/lib/grafana/dashboards/

Dashboard JSON ExampleπŸ”—

{
  "dashboard": {
    "title": "My Dashboard",
    "panels": [
      {
        "id": 1,
        "type": "graph",
        "title": "CPU Usage",
        "targets": [
          {
            "expr": "100 - (avg(rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)",
            "refId": "A"
          }
        ]
      }
    ],
    "time": {
      "from": "now-6h",
      "to": "now"
    },
    "refresh": "5s"
  }
}

Panels & VisualizationsπŸ”—

Panel TypesπŸ”—

Time Series (Graph)πŸ”—

Best for: Metrics over time

{
  "type": "timeseries",
  "targets": [
    {
      "expr": "rate(http_requests_total[5m])"
    }
  ]
}

StatπŸ”—

Best for: Single numeric value

{
  "type": "stat",
  "targets": [
    {
      "expr": "sum(up)"
    }
  ],
  "options": {
    "graphMode": "area",
    "colorMode": "value"
  }
}

GaugeπŸ”—

Best for: Percentage or threshold visualization

{
  "type": "gauge",
  "targets": [
    {
      "expr": "(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100"
    }
  ],
  "fieldConfig": {
    "defaults": {
      "max": 100,
      "min": 0,
      "thresholds": {
        "steps": [
          {"color": "green", "value": 0},
          {"color": "yellow", "value": 70},
          {"color": "red", "value": 90}
        ]
      }
    }
  }
}

Bar ChartπŸ”—

Best for: Comparing values across categories

{
  "type": "barchart",
  "targets": [
    {
      "expr": "sum(http_requests_total) by (method)"
    }
  ]
}

TableπŸ”—

Best for: Tabular data display

{
  "type": "table",
  "targets": [
    {
      "expr": "up",
      "format": "table"
    }
  ]
}

HeatmapπŸ”—

Best for: Distribution over time

{
  "type": "heatmap",
  "targets": [
    {
      "expr": "rate(http_request_duration_seconds_bucket[5m])"
    }
  ]
}

Pie ChartπŸ”—

Best for: Part-to-whole relationships

{
  "type": "piechart",
  "targets": [
    {
      "expr": "sum(http_requests_total) by (status_code)"
    }
  ]
}

Logs PanelπŸ”—

Best for: Log entries from Loki

{
  "type": "logs",
  "datasource": "Loki",
  "targets": [
    {
      "expr": "{job=\"varlogs\"}"
    }
  ]
}

Panel OptionsπŸ”—

ThresholdsπŸ”—

{
  "thresholds": {
    "mode": "absolute",
    "steps": [
      {"value": 0, "color": "green"},
      {"value": 80, "color": "yellow"},
      {"value": 100, "color": "red"}
    ]
  }
}

Value MappingsπŸ”—

{
  "mappings": [
    {
      "type": "value",
      "options": {
        "0": {"text": "Down", "color": "red"},
        "1": {"text": "Up", "color": "green"}
      }
    }
  ]
}

OverridesπŸ”—

{
  "overrides": [
    {
      "matcher": {"id": "byName", "options": "Series 1"},
      "properties": [
        {"id": "color", "value": {"mode": "fixed", "fixedColor": "blue"}}
      ]
    }
  ]
}

VariablesπŸ”—

Query VariableπŸ”—

Name: instance
Type: Query
Data source: Prometheus
Query: label_values(up, instance)
Refresh: On Dashboard Load

Usage in query:

up{instance="$instance"}

Custom VariableπŸ”—

Name: environment
Type: Custom
Values: production,staging,development

Interval VariableπŸ”—

Name: interval
Type: Interval
Values: 1m,5m,10m,30m,1h
Auto: enabled

Usage in query:

rate(http_requests_total[$interval])

Constant VariableπŸ”—

Name: threshold
Type: Constant
Value: 80

Data Source VariableπŸ”—

Name: datasource
Type: Data source
Type: Prometheus

Usage: Select data source: ${datasource}

Chained VariablesπŸ”—

Variable 1:
Name: region
Query: label_values(up, region)

Variable 2:
Name: instance
Query: label_values(up{region="$region"}, instance)

Multi-value VariablesπŸ”—

Enable β€œMulti-value” option to select multiple values.

Usage in query:

up{instance=~"$instance"}

TransformationsπŸ”—

Common TransformationsπŸ”—

Filter by nameπŸ”—

Filter series by name pattern.

Rename by regexπŸ”—

Regex: (.*)_total
Replace: $1

Organize fieldsπŸ”—

Reorder, hide, or rename fields.

Join by fieldπŸ”—

Combine data from multiple queries.

Add field from calculationπŸ”—

Mode: Reduce row
Calculation: Mean
Alias: average

Filter data by valueπŸ”—

Match: All conditions
Condition: temperature > 30

Group byπŸ”—

Group by: hostname
Aggregation: Mean

Transformation ExampleπŸ”—

{
  "transformations": [
    {
      "id": "filterByName",
      "options": {
        "include": {
          "pattern": "^temp.*"
        }
      }
    },
    {
      "id": "organize",
      "options": {
        "excludeByName": {},
        "indexByName": {},
        "renameByName": {
          "temp_celsius": "Temperature (Β°C)"
        }
      }
    }
  ]
}

AlertingπŸ”—

Create Alert RuleπŸ”—

Via UI:

  1. Panel β†’ Alert tab
  2. Create alert rule
  3. Define query and conditions
  4. Set evaluation interval
  5. Configure notifications

Alert Rule Example:

apiVersion: 1

groups:
  - orgId: 1
    name: my-alerts
    folder: alerts
    interval: 1m
    rules:
      - uid: alert1
        title: High CPU Usage
        condition: A
        data:
          - refId: A
            datasourceUid: prometheus-uid
            model:
              expr: 100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
              refId: A
        noDataState: NoData
        execErrState: Alerting
        for: 5m
        annotations:
          description: CPU usage is above 80%
        labels:
          severity: warning

Notification ChannelsπŸ”—

EmailπŸ”—

apiVersion: 1

notifiers:
  - name: Email
    type: email
    uid: email1
    settings:
      addresses: admin@example.com;ops@example.com

SlackπŸ”—

apiVersion: 1

contactPoints:
  - orgId: 1
    name: Slack
    receivers:
      - uid: slack1
        type: slack
        settings:
          url: https://hooks.slack.com/services/YOUR/WEBHOOK/URL
          text: |
            {{ range .Alerts }}
            Alert: {{ .Labels.alertname }}
            Status: {{ .Status }}
            {{ end }}

PagerDutyπŸ”—

apiVersion: 1

contactPoints:
  - orgId: 1
    name: PagerDuty
    receivers:
      - uid: pd1
        type: pagerduty
        settings:
          integrationKey: YOUR_INTEGRATION_KEY

WebhookπŸ”—

apiVersion: 1

contactPoints:
  - orgId: 1
    name: Webhook
    receivers:
      - uid: webhook1
        type: webhook
        settings:
          url: https://api.example.com/alerts
          httpMethod: POST

Notification PolicyπŸ”—

apiVersion: 1

policies:
  - orgId: 1
    receiver: default-email
    group_by: ['alertname', 'cluster']
    group_wait: 30s
    group_interval: 5m
    repeat_interval: 4h
    routes:
      - receiver: slack
        matchers:
          - severity = critical
      - receiver: pagerduty
        matchers:
          - severity = critical
          - team = ops

AnnotationsπŸ”—

Create AnnotationπŸ”—

{
  "dashboardId": 1,
  "panelId": 1,
  "time": 1609459200000,
  "text": "Deployment v2.0",
  "tags": ["deployment", "release"]
}

Query Annotations from PrometheusπŸ”—

Data source: Prometheus
Query: ALERTS{alertname="InstanceDown"}
Title field: alertname
Text field: summary
Tags field: severity

API ExamplesπŸ”—

AuthenticationπŸ”—

# API key (recommended)
curl -H "Authorization: Bearer YOUR_API_KEY" http://localhost:3000/api/...

# Basic auth
curl -u admin:password http://localhost:3000/api/...

Create API KeyπŸ”—

curl -X POST http://admin:admin@localhost:3000/api/auth/keys \
  -H "Content-Type: application/json" \
  -d '{
    "name": "mykey",
    "role": "Admin"
  }'

Get All DashboardsπŸ”—

curl -H "Authorization: Bearer YOUR_API_KEY" \
  http://localhost:3000/api/search?type=dash-db

Get Dashboard by UIDπŸ”—

curl -H "Authorization: Bearer YOUR_API_KEY" \
  http://localhost:3000/api/dashboards/uid/DASHBOARD_UID

Create/Update DashboardπŸ”—

curl -X POST http://localhost:3000/api/dashboards/db \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "dashboard": {
      "title": "My Dashboard",
      "panels": []
    },
    "overwrite": true
  }'

Delete DashboardπŸ”—

curl -X DELETE http://localhost:3000/api/dashboards/uid/DASHBOARD_UID \
  -H "Authorization: Bearer YOUR_API_KEY"

Get Data SourcesπŸ”—

curl -H "Authorization: Bearer YOUR_API_KEY" \
  http://localhost:3000/api/datasources

Create Data SourceπŸ”—

curl -X POST http://localhost:3000/api/datasources \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Prometheus",
    "type": "prometheus",
    "url": "http://prometheus:9090",
    "access": "proxy",
    "isDefault": true
  }'

Query Data SourceπŸ”—

curl -X POST http://localhost:3000/api/ds/query \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "queries": [
      {
        "datasource": {"type": "prometheus"},
        "expr": "up",
        "refId": "A"
      }
    ],
    "from": "now-1h",
    "to": "now"
  }'

Create OrganizationπŸ”—

curl -X POST http://localhost:3000/api/orgs \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "New Org"}'

Create UserπŸ”—

curl -X POST http://localhost:3000/api/admin/users \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe",
    "email": "john@example.com",
    "login": "john",
    "password": "password"
  }'

Get Current UserπŸ”—

curl -H "Authorization: Bearer YOUR_API_KEY" \
  http://localhost:3000/api/user

Create SnapshotπŸ”—

curl -X POST http://localhost:3000/api/snapshots \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "dashboard": ,
    "name": "My Snapshot",
    "expires": 3600
  }'

ProvisioningπŸ”—

Directory StructureπŸ”—

/etc/grafana/provisioning/
β”œβ”€β”€ dashboards/
β”‚   β”œβ”€β”€ dashboard.yml
β”‚   └── my-dashboard.json
β”œβ”€β”€ datasources/
β”‚   └── datasource.yml
β”œβ”€β”€ notifiers/
β”‚   └── notifier.yml
└── alerting/
    β”œβ”€β”€ alert-rules.yml
    └── notification-policies.yml

Complete ExampleπŸ”—

datasources/prometheus.yml:

apiVersion: 1

datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true

dashboards/default.yml:

apiVersion: 1

providers:
  - name: 'Default'
    orgId: 1
    folder: ''
    type: file
    options:
      path: /var/lib/grafana/dashboards

Best PracticesπŸ”—

Dashboard DesignπŸ”—

  • Use consistent time ranges
  • Group related panels
  • Use appropriate visualizations
  • Add descriptions to panels
  • Use template variables for flexibility
  • Keep dashboards focused (single purpose)

PerformanceπŸ”—

  • Limit time ranges for heavy queries
  • Use recording rules in Prometheus
  • Avoid too many panels per dashboard (< 20)
  • Use appropriate refresh intervals
  • Cache query results when possible

OrganizationπŸ”—

  • Use folders to organize dashboards
  • Tag dashboards appropriately
  • Use naming conventions
  • Document complex queries
  • Version control dashboard JSON

SecurityπŸ”—

  • Use API keys instead of passwords
  • Implement role-based access control
  • Enable HTTPS
  • Regular backups
  • Update Grafana regularly

AlertingπŸ”—

  • Set appropriate thresholds
  • Avoid alert fatigue (don’t over-alert)
  • Group related alerts
  • Use meaningful alert names
  • Include context in notifications
  • Test alerts before production

Keyboard ShortcutsπŸ”—

ShortcutAction
g + hGo to home dashboard
g + pGo to profile
g + eOpen explore
sOpen search
fOpen dashboard finder
d + kToggle kiosk mode
d + eExpand all rows
d + sDashboard settings
d + vToggle in-active/active panel
Ctrl + SSave dashboard
EscExit panel edit/settings
?Show keyboard shortcuts

ResourcesπŸ”—

  • Official documentation: https://grafana.com/docs/
  • Community dashboards: https://grafana.com/grafana/dashboards/
  • Plugins: https://grafana.com/grafana/plugins/
  • Tutorials: https://grafana.com/tutorials/
  • Community forum: https://community.grafana.com/
  • GitHub: https://github.com/grafana/grafana