Skip to content

Creation Workflow

Overview

Instead of manually creating dashboards through the UI, build complete dashboard JSON structures in Python and deploy via Grafana API. This approach enables:

  • Version control for dashboard definitions
  • Repeatable dashboard creation across environments
  • Automated dashboard generation from metric inventories
  • Consistent styling and organization

Step 1: Plan Dashboard Structure

Define dashboard organization based on metrics available:

# Example structure planning
dashboard_plan = {
    "variables": ["datasource", "hostname", "time_range"],
    "rows": [
        {
            "name": "Overview",
            "panels": ["Total Events (stat)", "Current Rate (stat)", "Health (gauge)"]
        },
        {
            "name": "Detailed Metrics",
            "panels": ["Metric Timeline (timeseries)", "Distribution (histogram)"]
        }
    ]
}

Step 2: Build Dashboard JSON Structure

Create complete dashboard JSON programmatically with proper structure including:

  • Dashboard metadata (title, tags, timezone)
  • Variables for dynamic filtering (datasource, hostname)
  • Panels with queries and visualizations
  • Grid layout positioning

Step 3: Deploy via Grafana API

Deploy dashboard to Grafana:

import json, subprocess
from pathlib import Path

def deploy_dashboard(dashboard, grafana_url="http://localhost:3000"):
    password_file = Path.home() / '.secrets' / 'grafana.admin.pass'
    password = password_file.read_text().strip()

    dashboard_file = Path("/tmp/dashboard.json")
    with dashboard_file.open("w") as f:
        json.dump(dashboard, f, indent=2)

    cmd = [
        "curl", "-s", "-X", "POST",
        "-H", "Content-Type: application/json",
        "-u", f"admin:{password}",
        "-d", f"@{dashboard_file}",
        f"{grafana_url}/api/dashboards/db"
    ]

    result = subprocess.run(cmd, capture_output=True, text=True)
    response = json.loads(result.stdout)

    if response.get("status") == "success":
        print(f"✅ Dashboard deployed!")
        print(f"   URL: {grafana_url}/d/{response.get('uid')}")
        return True
    return False

Step 4: Verify Dashboard Structure

After deployment, verify the dashboard was created correctly:

def verify_dashboard(uid, grafana_url="http://localhost:3000"):
    password_file = Path.home() / '.secrets' / 'grafana.admin.pass'
    password = password_file.read_text().strip()

    cmd = ['curl', '-s', '-u', f'admin:{password}',
           f'{grafana_url}/api/dashboards/uid/{uid}']

    result = subprocess.run(cmd, capture_output=True, text=True)
    data = json.loads(result.stdout)

    dashboard = data.get('dashboard', {})
    print(f'✅ Dashboard: {dashboard.get("title")}')
    print(f'   Panels: {len(dashboard.get("panels", []))}')

Grid Layout System

Grafana uses 24-column grid with height units:

# Row spans full width
{"h": 1, "w": 24, "x": 0, "y": 0}

# Four equal panels in a row
{"h": 8, "w": 6, "x": 0, "y": 1}   # First panel
{"h": 8, "w": 6, "x": 6, "y": 1}   # Second panel
{"h": 8, "w": 6, "x": 12, "y": 1}  # Third panel
{"h": 8, "w": 6, "x": 18, "y": 1}  # Fourth panel

# Two panels: 2/3 and 1/3 width
{"h": 8, "w": 16, "x": 0, "y": 9}  # 2/3 width
{"h": 8, "w": 8, "x": 16, "y": 9}  # 1/3 width

Best Practices

  1. Plan Before Coding: Sketch dashboard layout on paper first
  2. Test Queries First: Verify queries work via API before adding to dashboard
  3. Consistent Sizing: Use standard panel heights (4 for stats, 8 for graphs)
  4. Use Variables: Enable filtering with datasource, hostname, time range variables
  5. Meaningful Thresholds: Set thresholds based on actual operational baselines
  6. Clear Titles: Panel titles should be descriptive and action-oriented
  7. Group by Function: Organize panels into rows by purpose (Overview, Details, Resources)
  8. Document Units: Always specify correct units (bytes, ops, percent, etc.)
  9. Version Control: Save dashboard creation scripts in git
  10. Verify After Deploy: Always verify panels show data after deployment