grafana的数据源不仅可以是数据库,还可以是你的应用程序

626 阅读3分钟

grafana可以非常方便地将prometheus、mysql等数据库中的数据以各种漂亮的图表形式进行展示,但是在某些情况下,grafana并不能或不方便直接从数据库中查询数据,比如,数据本身并不是以grafana可以访问到的数据库数据形式存在,或者需要对原始数据进行比较灵活、复杂的处理后才能提供给grafana进行展示等等。grafana也支持从应用程序的http接口获取展示数据,simplejson数据源就是这种类型的数据源。

1 simplejson数据源应用

1.1 安装

grafana并没有默认安装simplejson数据源,如果需要使用simplejson,需要自己安装

如果环境支持在线安装,可以通过以下方式进行安装:

$ grafana-cli plugins install grafana-simple-json-datasource

也可先下载安装包,然后手动安装:

$ mv grafana-simple-json-datasource-1.4.2.zip ./plugins-bundled
$ cd plugins-bundled
$ unzip grafana-simple-json-datasource-1.4.2.zip

安装后重启grafana

$ sudo su -
# service grafana-server restart

1.2 添加数据源

simplejson安装完后,在grafana的数据源仓库中就可以看到simplejson数据源了,我们就可以添加相应的数据源了。

如下图所示,name字段填写数据源的名字,url字段填写数据源对应的url,这个url的路径部分是simplejson数据源相关接口的路径前缀。其他的数据源信息跟普通的数据源相同。如下图所示:

b9c55849cce0fb4e05a6f2910bf9831a.png

1.3 设置panel数据源为simplejson数据源

添加了simplejson数据源,就可以在panel中使用该数据源了,如下图所示:

9d060b53dce4f18500fad5be72dfa4b0.png

上图中查询输入框中的值会作为simplejson /search接口请求body的target字段值传递给数据源后端,后端根据这个查询字符串确定返回的指标名字列表。

1.4 simplejson数据源接口

simplejson数据源由一组http接口组成:

1.4.1 GET /

该接口必须实现。健康探测接口。没有任何请求参数,返回http响应状态码200表示数据源正常。

1.4.2 POST /search

请求body内容格式:

{
    "target": "content of request, usually is a json string"
}

该接口必须实现。这个接口用来查询panel的一些选项参数,如query型变量(variable)的值,指标(metric)的名字等。请求body只有一个target字段,是一个字符串,用来传递请求的内容,比如是请求哪个变量的可能取值等,实际应用中,target往往是一个json字符串。接口返回则是一个值的list或map。因为metric、variable都是通过这个接口获取的,所以target中一般需要有一个表示查询类型的字段。

1.4.2.1 请求metric名字

请求body内容就是创建panel数据查询时查询语句输入框中的内容,如下所示:

{
    "target": "{\"type\":\"METRIC\",\"queryId1\":\"$queryId1\",\"queryId2:\"$queryId3\"}"
}

响应body可以是:

["cpu","memory"]

或者:

[ { "text" :"cpu", "value": 1}, { "text" :"memory", "value": 2} ]

表示panel可以向simplejson后端查询展示cpu、memory两个指标

1.4.2.2 请求query变量

如果我们dashboard创建了query类型的variable,且variable的数据源都是simplejson,那么grafana会向simplejson后端查询variable的可取值列表。

例如,我们创建了两个变量:

5097d176643bfdf8c659e6b8f6fada23.png

那么请求body的target字段的值就是variable变量definition(query)属性的值,格式如下:

{
    "target": "{\"type\":\"QUERY_ID1\"}"
}
{
    "target": "{\"type\":\"QUERY_ID2\", \"queryId1\": \"$queryId1\"}"
}

后端响应body格式与请求metric名字一样,是query变量的取值列表

1.4.3 POST /query

该接口必须实现。根据/search接口返回的指标列表查询这些指标的具体时间序列值。

请求body内容格式:

{
    "app": "dashboard",
    "requestId": "Q111",
    "timezone": "browser",
    "panelId": 2,
    "dashboardId": 10,
    "range": {
        "from": "2023-08-13T07:42:01.305Z",
        "to": "2023-08-13T07:47:01.305Z",
        "raw": {
            "from": "now-5m",
            "to": "now"
        }
    },
    "timeInfo": "",
    "interval": "200ms",
    "intervalMs": 200,
    "targets": [
        {
            "target": "cpu",
            "refId": "A",
            "type": "timeserie"
        },
        {
            "target": "memory",
            "refId": "B",
            "type": "timeserie"
        }
    ],
    "maxDataPoints": 1236,
    "scopedVars": {
        "__interval": {
            "text": "200ms",
            "value": "200ms"
        },
        "__interval_ms": {
            "text": "200",
            "value": 200
        }
    },
    "startTime": 1691912821305,
    "rangeRaw": {
        "from": "now-5m",
        "to": "now"
    },
  "adhocFilters": [{
    "key": "hostname",
    "operator": "=",
    "value": "example.com"
  }]
}

请求body中的target字段就是/search接口返回的metric的值

后端返回的body内容格式,如果是时间序列指标,则如下所示,是一个列表,每一个metric是一个元素,元素的datapoint字段是metric的时间序列值:

[
  {
    "target":"cpu", // metric名字
    "datapoints":[
      [80,1450754160000],  // 第一个元素是metric值,数据类型是float,第二个元素是unix时间戳,单位是毫秒
      [85,1450754220000]
    ]
  },
  {
    "target":"memory",
    "datapoints":[
      [861256321,1450754160000],
      [767469432,1450754220000]
    ]
  }
]

如果是表格形式,后端返回的body内容格式:

[
  {
    "columns":[
      {"text":"Time","type":"time"},
      {"text":"Country","type":"string"},
      {"text":"Number","type":"number"}
    ],
    "rows":[
      [1234567,"SE",123],
      [1234567,"DE",231],
      [1234567,"US",321]
    ],
    "type":"table"
  }
]

1.4.4 POST /annotations

该接口非必需。如果panel需要向simplejson数据源获取特定的事件,可以通过该接口获取

例如,我们在dashboard中创建了query annotation,数据源是simplejson:

2d2ec6752f4f26347f88aee70ef2181f.png

那么grafana会向simplejson请求annotation事件,请求body的格式:

{
  "range": {
    "from": "2016-04-15T13:44:39.070Z",
    "to": "2016-04-15T14:44:39.070Z"
  },
  "rangeRaw": {
    "from": "now-1h",
    "to": "now"
  },
  "annotation": {
    "name": "annotation_test",  // annotation的名字
    "datasource": "SimpleJsonSli",
    "iconColor": "rgba(255, 96, 96, 1)",       // annotation事件标记的颜色
    "enable": true,
    "query": "queryString"
  }
}

响应body是annotation事件的列表,格式为:

[
  {
    "annotation": "annotation_test", // annotation的名字
    "time": 1450754160000, // 必须。事件发生的时间。unix时间戳,单位为毫秒
    "title": "title", // 必须,annotation事件的标题
    "tags": ["tag1","tag2"], // 可选。annotation事件的标签
    "text": "text" // 可选。annotation事件的文本内容
  }
]

1.4.5 POST /tag-keys

该接口非必须。/query请求body中有一个adhocFilters参数,用来对数据进行过滤。过滤的key名字列表可以通过这个接口获取。

该接口无需请求参数。

响应body内容是key名字和key值数据类型的列表,格式为:

[
    {"type":"string","text":"hostname"},
    {"type":"string","text":"rack"}
]

1.4.6 POST /tag-values

该接口非必须。/query请求body中有一个adhocFilters参数,用来对数据进行过滤。过滤的key的值列表可以通过这个接口获取。

请求body内容是key的名字,格式为:

{"key": "hostname"}

响应body是key的取值列表,格式为:

[
    {'text': 'example.com'},
    {'text': 'example2.com'}
]