grafanalib icon indicating copy to clipboard operation
grafanalib copied to clipboard

Dashboard.to_json_data method does not return a valid json data.

Open tushushu opened this issue 2 years ago • 0 comments

Hi there~ I am trying to use Grafanalib to generate Grafana dashboards programmatically. It works great, except that I need to write a to_json function myself, since the Dashboard.to_json_data method does not return a valid json data.

  • System OS: MacOS Monterey
  • Python Version: 3.8.10
  • Grafanalib Version: 0.6.3

Below is the Python codes I wrote. If I don't use to_json function to further process the dashboard.to_json_data(), the json contains some Python objects which cannot be handled by standard Python json library.

Your feedback is appreciated, and if needed I'd like to contribute to this project. Thanks very much~

import json
from typing import List, Optional, Union

from grafanalib.core import Dashboard, GridPos, Panel, Target, TimeSeries


def gen_panel(title: str, metric: str, labels: dict) -> Panel:
    expr = metric + \
        '{' + ', '.join([f'{k}="{v}"' for k, v in labels.items()]) + '}'
    return TimeSeries(
        title=title,
        dataSource=dict(),
        targets=[
            Target(
                datasource='prometheus',
                expr=expr,
            ),
        ],
        gridPos=GridPos(h=9, w=12, x=0, y=0),
    )


def gen_dashboard(
    title: str,
    panels: List[Panel],
    description: Optional[str] = None,
    tags: Optional[List[str]] = None,
    timezone: Optional[str] = None
) -> Dashboard:
    if description is None:
        description = ""
    if tags is None:
        tags = []
    if timezone is None:
        timezone = ""
    return Dashboard(
        title=title,
        description=description,
        tags=tags,
        timezone=timezone,
        panels=panels,
    ).auto_panel_ids()


def _to_json(data: Union[dict, list], result: Union[dict, list]) -> None:
    if isinstance(data, dict):
        assert isinstance(result, dict)
        for k, v in data.items():
            if hasattr(v, "to_json_data"):
                v = v.to_json_data()
            if isinstance(v, dict):
                result[k] = dict()
                _to_json(v, result[k])
            elif isinstance(v, list):
                result[k] = list()
                _to_json(v, result[k])
            else:
                result[k] = v
    elif isinstance(data, list):
        assert isinstance(result, list)
        for v in data:
            if hasattr(v, "to_json_data"):
                v = v.to_json_data()
            if isinstance(v, dict):
                result.append(dict())
                _to_json(v, result[-1])
            elif isinstance(v, list):
                result.append(list())
                _to_json(v, result[-1])
            else:
                result.append(v)
    else:
        raise TypeError("data should be dict or list!")


def to_json(dashboard: Dashboard) -> str:
    data = dashboard.to_json_data()
    result = dict()  # type: ignore
    _to_json(data, result)
    return json.dumps(result)


if __name__ == "__main__":
    labels = {
        "env": "Env.prod",
        "job": "baz",
        "ver": "001",
        "sub_job": "zoo",
    }

    panels = [
        gen_panel(
            title="eg_foo",
            metric="foo",
            labels=labels,
        ),
        gen_panel(
            title="eg_bar",
            metric="bar",
            labels=labels,
        ),
    ]

    dashboard = gen_dashboard(
        title="dashboard_example",
        panels=panels,
    )

    print(to_json(dashboard))

tushushu avatar Aug 17 '22 13:08 tushushu