summaryrefslogtreecommitdiffstats
path: root/src/web/api/formatters
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 11:19:16 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-07-24 09:53:24 +0000
commitb5f8ee61a7f7e9bd291dd26b0585d03eb686c941 (patch)
treed4d31289c39fc00da064a825df13a0b98ce95b10 /src/web/api/formatters
parentAdding upstream version 1.44.3. (diff)
downloadnetdata-upstream.tar.xz
netdata-upstream.zip
Adding upstream version 1.46.3.upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/web/api/formatters/README.md82
-rw-r--r--src/web/api/formatters/charts2json.c (renamed from web/api/formatters/charts2json.c)4
-rw-r--r--src/web/api/formatters/charts2json.h (renamed from web/api/formatters/charts2json.h)0
-rw-r--r--src/web/api/formatters/csv/README.md148
-rw-r--r--src/web/api/formatters/csv/csv.c (renamed from web/api/formatters/csv/csv.c)0
-rw-r--r--src/web/api/formatters/csv/csv.h (renamed from web/api/formatters/csv/csv.h)0
-rw-r--r--src/web/api/formatters/json/README.md160
-rw-r--r--src/web/api/formatters/json/json.c (renamed from web/api/formatters/json/json.c)0
-rw-r--r--src/web/api/formatters/json/json.h (renamed from web/api/formatters/json/json.h)0
-rw-r--r--src/web/api/formatters/json_wrapper.c (renamed from web/api/formatters/json_wrapper.c)24
-rw-r--r--src/web/api/formatters/json_wrapper.h (renamed from web/api/formatters/json_wrapper.h)0
-rw-r--r--src/web/api/formatters/rrd2json.c (renamed from web/api/formatters/rrd2json.c)0
-rw-r--r--src/web/api/formatters/rrd2json.h (renamed from web/api/formatters/rrd2json.h)0
-rw-r--r--src/web/api/formatters/rrdset2json.c (renamed from web/api/formatters/rrdset2json.c)4
-rw-r--r--src/web/api/formatters/rrdset2json.h (renamed from web/api/formatters/rrdset2json.h)0
-rw-r--r--src/web/api/formatters/ssv/README.md63
-rw-r--r--src/web/api/formatters/ssv/ssv.c (renamed from web/api/formatters/ssv/ssv.c)0
-rw-r--r--src/web/api/formatters/ssv/ssv.h (renamed from web/api/formatters/ssv/ssv.h)0
-rw-r--r--src/web/api/formatters/value/README.md28
-rw-r--r--src/web/api/formatters/value/value.c153
-rw-r--r--src/web/api/formatters/value/value.h (renamed from web/api/formatters/value/value.h)0
21 files changed, 650 insertions, 16 deletions
diff --git a/src/web/api/formatters/README.md b/src/web/api/formatters/README.md
new file mode 100644
index 000000000..6347f5fb4
--- /dev/null
+++ b/src/web/api/formatters/README.md
@@ -0,0 +1,82 @@
+<!--
+title: "Query formatting"
+custom_edit_url: https://github.com/netdata/netdata/edit/master/src/web/api/formatters/README.md
+sidebar_label: "Query formatting"
+learn_status: "Published"
+learn_topic_type: "References"
+learn_rel_path: "Developers/Web/Api/Formatters"
+-->
+
+# Query formatting
+
+API data queries need to be formatted before returned to the caller.
+Using API parameters, the caller may define the format he/she wishes to get back.
+
+The following formats are supported:
+
+| format|module|content type|description|
+|:----:|:----:|:----------:|:----------|
+| `array`|[ssv](/src/web/api/formatters/ssv/README.md)|application/json|a JSON array|
+| `csv`|[csv](/src/web/api/formatters/csv/README.md)|text/plain|a text table, comma separated, with a header line (dimension names) and `\r\n` at the end of the lines|
+| `csvjsonarray`|[csv](/src/web/api/formatters/csv/README.md)|application/json|a JSON array, with each row as another array (the first row has the dimension names)|
+| `datasource`|[json](/src/web/api/formatters/json/README.md)|application/json|a Google Visualization Provider `datasource` javascript callback|
+| `datatable`|[json](/src/web/api/formatters/json/README.md)|application/json|a Google `datatable`|
+| `html`|[csv](/src/web/api/formatters/csv/README.md)|text/html|an html table|
+| `json`|[json](/src/web/api/formatters/json/README.md)|application/json|a JSON object|
+| `jsonp`|[json](/src/web/api/formatters/json/README.md)|application/json|a JSONP javascript callback|
+| `markdown`|[csv](/src/web/api/formatters/csv/README.md)|text/plain|a markdown table|
+| `ssv`|[ssv](/src/web/api/formatters/ssv/README.md)|text/plain|a space separated list of values|
+| `ssvcomma`|[ssv](/src/web/api/formatters/ssv/README.md)|text/plain|a comma separated list of values|
+| `tsv`|[csv](/src/web/api/formatters/csv/README.md)|text/plain|a TAB delimited `csv` (MS Excel flavor)|
+
+For examples of each format, check the relative module documentation.
+
+## Metadata with the `jsonwrap` option
+
+All data queries can be encapsulated to JSON object having metadata about the query and the results.
+
+This is done by adding the `options=jsonwrap` to the API URL (if there are other `options` append
+`,jsonwrap` to the existing ones).
+
+This is such an object:
+
+```bash
+# curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=system.cpu&after=-3600&points=6&group=average&format=csv&options=nonzero,jsonwrap'
+{
+ "api": 1,
+ "id": "system.cpu",
+ "name": "system.cpu",
+ "view_update_every": 600,
+ "update_every": 1,
+ "first_entry": 1540387074,
+ "last_entry": 1540647070,
+ "before": 1540647000,
+ "after": 1540644000,
+ "dimension_names": ["steal", "softirq", "user", "system", "iowait"],
+ "dimension_ids": ["steal", "softirq", "user", "system", "iowait"],
+ "latest_values": [0, 0.2493766, 1.745636, 0.4987531, 0],
+ "view_latest_values": [0.0158314, 0.0516506, 0.866549, 0.7196127, 0.0050002],
+ "dimensions": 5,
+ "points": 6,
+ "format": "csv",
+ "result": "time,steal,softirq,user,system,iowait\n2018-10-27 13:30:00,0.0158314,0.0516506,0.866549,0.7196127,0.0050002\n2018-10-27 13:20:00,0.0149856,0.0529183,0.8673155,0.7121144,0.0049979\n2018-10-27 13:10:00,0.0137501,0.053315,0.8578097,0.7197613,0.0054209\n2018-10-27 13:00:00,0.0154252,0.0554688,0.899432,0.7200638,0.0067252\n2018-10-27 12:50:00,0.0145866,0.0495922,0.8404341,0.7011141,0.0041688\n2018-10-27 12:40:00,0.0162366,0.0595954,0.8827475,0.7020573,0.0041636\n",
+ "min": 0,
+ "max": 0
+}
+```
+
+## Downloading data query result files
+
+Following the [Google Visualization Provider guidelines](https://developers.google.com/chart/interactive/docs/dev/implementing_data_source),
+Netdata supports parsing `tqx` options.
+
+Using these options, any Netdata data query can instruct the web browser to download
+the result and save it under a given filename.
+
+For example, to download a CSV file with CPU utilization of the last hour,
+[click here](https://registry.my-netdata.io/api/v1/data?chart=system.cpu&after=-3600&format=csv&options=nonzero&tqx=outFileName:system+cpu+utilization+of+the+last_hour.csv).
+
+This is done by appending `&tqx=outFileName:FILENAME` to any data query.
+The output will be in the format given with `&format=`.
+
+
diff --git a/web/api/formatters/charts2json.c b/src/web/api/formatters/charts2json.c
index cab4debae..0b45d77c4 100644
--- a/web/api/formatters/charts2json.c
+++ b/src/web/api/formatters/charts2json.c
@@ -31,7 +31,7 @@ const char* get_release_channel() {
}
}
if (use_stable == -1)
- use_stable = strchr(program_version, '-') ? 0 : 1;
+ use_stable = strchr(NETDATA_VERSION, '-') ? 0 : 1;
}
return (use_stable)?"stable":"nightly";
}
@@ -96,7 +96,7 @@ void charts2json(RRDHOST *host, BUFFER *wb) {
buffer_json_object_close(wb);
}
}
- rrd_unlock();
+ rrd_rdunlock();
}
buffer_json_array_close(wb);
diff --git a/web/api/formatters/charts2json.h b/src/web/api/formatters/charts2json.h
index 7b07af5a0..7b07af5a0 100644
--- a/web/api/formatters/charts2json.h
+++ b/src/web/api/formatters/charts2json.h
diff --git a/src/web/api/formatters/csv/README.md b/src/web/api/formatters/csv/README.md
new file mode 100644
index 000000000..e60aab57b
--- /dev/null
+++ b/src/web/api/formatters/csv/README.md
@@ -0,0 +1,148 @@
+<!--
+title: "CSV formatter"
+custom_edit_url: https://github.com/netdata/netdata/edit/master/src/web/api/formatters/csv/README.md
+sidebar_label: "CSV formatter"
+learn_status: "Published"
+learn_topic_type: "References"
+learn_rel_path: "Developers/Web/Api/Formatters"
+-->
+
+# CSV formatter
+
+The CSV formatter presents [results of database queries](/src/web/api/queries/README.md) in the following formats:
+
+| format|content type|description|
+| :----:|:----------:|:----------|
+| `csv`|text/plain|a text table, comma separated, with a header line (dimension names) and `\r\n` at the end of the lines|
+| `csvjsonarray`|application/json|a JSON array, with each row as another array (the first row has the dimension names)|
+| `tsv`|text/plain|like `csv` but TAB is used instead of comma to separate values (MS Excel flavor)|
+| `html`|text/html|an html table|
+| `markdown`|text/plain|markdown table|
+
+In all formats the date and time is the first column.
+
+The CSV formatter respects the following API `&options=`:
+
+| option|supported|description|
+|:----:|:-------:|:----------|
+| `nonzero`|yes|to return only the dimensions that have at least a non-zero value|
+| `flip`|yes|to return the rows older to newer (the default is newer to older)|
+| `seconds`|yes|to return the date and time in unix timestamp|
+| `ms`|yes|to return the date and time in unit timestamp as milliseconds|
+| `percent`|yes|to replace all values with their percentage over the row total|
+| `abs`|yes|to turn all values positive|
+| `null2zero`|yes|to replace gaps with zeros (the default prints the string `null`|
+
+## Examples
+
+Get the system total bandwidth for all physical network interfaces, over the last hour,
+in 6 rows (one for every 10 minutes), in `csv` format:
+
+Netdata always returns bandwidth in `kilobits`.
+
+```bash
+# curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=system.net&format=csv&after=-3600&group=sum&points=6&options=abs'
+time,received,sent
+2018-10-26 23:50:00,90214.67847,215137.79762
+2018-10-26 23:40:00,90126.32286,238587.57522
+2018-10-26 23:30:00,86061.22688,213389.23526
+2018-10-26 23:20:00,85590.75164,206129.01608
+2018-10-26 23:10:00,83163.30691,194311.77384
+2018-10-26 23:00:00,85167.29657,197538.07773
+```
+
+---
+
+Get the max RAM used by the SQL server and any cron jobs, over the last hour, in 2 rows (one for every 30
+minutes), in `tsv` format, and format the date and time as unix timestamp:
+
+Netdata always returns memory in `MB`.
+
+```bash
+# curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=apps.mem&format=tsv&after=-3600&group=max&points=2&options=nonzero,seconds&dimensions=sql,cron'
+time sql cron
+1540598400 61.95703 0.25
+1540596600 61.95703 0.25
+```
+
+---
+
+Get an HTML table of the last 4 values (4 seconds) of system CPU utilization:
+
+Netdata always returns CPU utilization as `%`.
+
+```bash
+# curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=system.cpu&format=html&after=-4&options=nonzero'
+<html>
+<center>
+<table border="0" cellpadding="5" cellspacing="5">
+<tr><td>time</td><td>softirq</td><td>user</td><td>system</td></tr>
+<tr><td>2018-10-27 00:16:07</td><td>0.25</td><td>1</td><td>0.75</td></tr>
+<tr><td>2018-10-27 00:16:06</td><td>0</td><td>1.0025063</td><td>0.5012531</td></tr>
+<tr><td>2018-10-27 00:16:05</td><td>0</td><td>1</td><td>0.75</td></tr>
+<tr><td>2018-10-27 00:16:04</td><td>0</td><td>1.0025063</td><td>0.7518797</td></tr>
+</table>
+</center>
+</html>
+```
+
+This is how it looks when rendered by a web browser:
+
+![image](https://user-images.githubusercontent.com/2662304/47597887-bafbf480-d99c-11e8-864a-d880bb8d2e5b.png)
+
+---
+
+Get a JSON array with the average bandwidth rate of the mysql server, over the last hour, in 6 values
+(one every 10 minutes), and return the date and time in milliseconds:
+
+Netdata always returns bandwidth rates in `kilobits/s`.
+
+```bash
+# curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=mysql_local.net&format=csvjsonarray&after=-3600&points=6&group=average&options=abs,ms'
+[
+["time","in","out"],
+[1540599600000,0.7499986,120.2810185],
+[1540599000000,0.7500019,120.2815509],
+[1540598400000,0.7499999,120.2812319],
+[1540597800000,0.7500044,120.2819634],
+[1540597200000,0.7499968,120.2807337],
+[1540596600000,0.7499988,120.2810527]
+]
+```
+
+---
+
+Get the number of processes started per minute, for the last 10 minutes, in `markdown` format:
+
+```bash
+# curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=system.forks&format=markdown&after=-600&points=10&group=sum'
+time | started
+:---: |:---:
+2018-10-27 03:52:00| 245.1706149
+2018-10-27 03:51:00| 152.6654636
+2018-10-27 03:50:00| 163.1755789
+2018-10-27 03:49:00| 176.1574766
+2018-10-27 03:48:00| 178.0137076
+2018-10-27 03:47:00| 183.8306543
+2018-10-27 03:46:00| 264.1635621
+2018-10-27 03:45:00| 205.001551
+2018-10-27 03:44:00| 7026.9852167
+2018-10-27 03:43:00| 205.9904794
+```
+
+And this is how it looks when formatted:
+
+| time | started |
+|:--:|:-----:|
+| 2018-10-27 03:52:00 | 245.1706149 |
+| 2018-10-27 03:51:00 | 152.6654636 |
+| 2018-10-27 03:50:00 | 163.1755789 |
+| 2018-10-27 03:49:00 | 176.1574766 |
+| 2018-10-27 03:48:00 | 178.0137076 |
+| 2018-10-27 03:47:00 | 183.8306543 |
+| 2018-10-27 03:46:00 | 264.1635621 |
+| 2018-10-27 03:45:00 | 205.001551 |
+| 2018-10-27 03:44:00 | 7026.9852167 |
+| 2018-10-27 03:43:00 | 205.9904794 |
+
+
diff --git a/web/api/formatters/csv/csv.c b/src/web/api/formatters/csv/csv.c
index d81ddb34e..d81ddb34e 100644
--- a/web/api/formatters/csv/csv.c
+++ b/src/web/api/formatters/csv/csv.c
diff --git a/web/api/formatters/csv/csv.h b/src/web/api/formatters/csv/csv.h
index 666d4c660..666d4c660 100644
--- a/web/api/formatters/csv/csv.h
+++ b/src/web/api/formatters/csv/csv.h
diff --git a/src/web/api/formatters/json/README.md b/src/web/api/formatters/json/README.md
new file mode 100644
index 000000000..4137b0372
--- /dev/null
+++ b/src/web/api/formatters/json/README.md
@@ -0,0 +1,160 @@
+<!--
+title: "JSON formatter"
+custom_edit_url: https://github.com/netdata/netdata/edit/master/src/web/api/formatters/json/README.md
+sidebar_label: "JSON formatter"
+learn_status: "Published"
+learn_topic_type: "References"
+learn_rel_path: "Developers/Web/Api/Formatters"
+-->
+
+# JSON formatter
+
+The CSV formatter presents [results of database queries](/src/web/api/queries/README.md) in the following formats:
+
+| format | content type | description|
+|:----:|:----------:|:----------|
+| `json` | application/json | return the query result as a json object|
+| `jsonp` | application/json | return the query result as a JSONP javascript callback|
+| `datatable` | application/json | return the query result as a Google `datatable`|
+| `datasource` | application/json | return the query result as a Google Visualization Provider `datasource` javascript callback|
+
+The CSV formatter respects the following API `&options=`:
+
+| option | supported | description|
+|:----:|:-------:|:----------|
+| `google_json` | yes | enable the Google flavor of JSON (using double quotes for strings and `Date()` function for dates|
+| `objectrows` | yes | return each row as an object, instead of an array|
+| `nonzero` | yes | to return only the dimensions that have at least a non-zero value|
+| `flip` | yes | to return the rows older to newer (the default is newer to older)|
+| `seconds` | yes | to return the date and time in unix timestamp|
+| `ms` | yes | to return the date and time in unit timestamp as milliseconds|
+| `percent` | yes | to replace all values with their percentage over the row total|
+| `abs` | yes | to turn all values positive|
+| `null2zero` | yes | to replace gaps with zeros (the default prints the string `null`|
+
+## Examples
+
+To show the differences between each format, in the following examples we query the same
+chart (having just one dimension called `active`), changing only the query `format` and its `options`.
+
+> Using `format=json` and `options=`
+
+```bash
+# curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=nginx_local.connections&after=-3600&points=6&group=average&format=json&options='
+{
+ "labels": ["time", "active"],
+ "data":
+ [
+ [ 1540644600, 224.2516667],
+ [ 1540644000, 229.29],
+ [ 1540643400, 222.41],
+ [ 1540642800, 226.6816667],
+ [ 1540642200, 246.4083333],
+ [ 1540641600, 241.0966667]
+ ]
+}
+```
+
+> Using `format=json` and `options=objectrows`
+
+```bash
+# curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=nginx_local.connections&after=-3600&points=6&group=average&format=json&options=objectrows'
+{
+ "labels": ["time", "active"],
+ "data":
+ [
+ { "time": 1540644600, "active": 224.2516667},
+ { "time": 1540644000, "active": 229.29},
+ { "time": 1540643400, "active": 222.41},
+ { "time": 1540642800, "active": 226.6816667},
+ { "time": 1540642200, "active": 246.4083333},
+ { "time": 1540641600, "active": 241.0966667}
+ ]
+}
+```
+
+> Using `format=json` and `options=objectrows,google_json`
+
+```bash
+# curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=nginx_local.connections&after=-3600&points=6&group=average&formatjson&options=objectrows,google_json'
+{
+ "labels": ["time", "active"],
+ "data":
+ [
+ { "time": new Date(2018,9,27,12,50,0), "active": 224.2516667},
+ { "time": new Date(2018,9,27,12,40,0), "active": 229.29},
+ { "time": new Date(2018,9,27,12,30,0), "active": 222.41},
+ { "time": new Date(2018,9,27,12,20,0), "active": 226.6816667},
+ { "time": new Date(2018,9,27,12,10,0), "active": 246.4083333},
+ { "time": new Date(2018,9,27,12,0,0), "active": 241.0966667}
+ ]
+}
+```
+
+> Using `format=jsonp` and `options=`
+
+```bash
+curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=nginx_local.connections&after=-3600&points=6&group=average&formjsonp&options='
+callback({
+ "labels": ["time", "active"],
+ "data":
+ [
+ [ 1540645200, 235.885],
+ [ 1540644600, 224.2516667],
+ [ 1540644000, 229.29],
+ [ 1540643400, 222.41],
+ [ 1540642800, 226.6816667],
+ [ 1540642200, 246.4083333]
+ ]
+});
+```
+
+> Using `format=datatable` and `options=`
+
+```bash
+curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=nginx_local.connections&after=-3600&points=6&group=average&formdatatable&options='
+{
+ "cols":
+ [
+ {"id":"","label":"time","pattern":"","type":"datetime"},
+ {"id":"","label":"","pattern":"","type":"string","p":{"role":"annotation"}},
+ {"id":"","label":"","pattern":"","type":"string","p":{"role":"annotationText"}},
+ {"id":"","label":"active","pattern":"","type":"number"}
+ ],
+ "rows":
+ [
+ {"c":[{"v":"Date(2018,9,27,13,0,0)"},{"v":null},{"v":null},{"v":235.885}]},
+ {"c":[{"v":"Date(2018,9,27,12,50,0)"},{"v":null},{"v":null},{"v":224.2516667}]},
+ {"c":[{"v":"Date(2018,9,27,12,40,0)"},{"v":null},{"v":null},{"v":229.29}]},
+ {"c":[{"v":"Date(2018,9,27,12,30,0)"},{"v":null},{"v":null},{"v":222.41}]},
+ {"c":[{"v":"Date(2018,9,27,12,20,0)"},{"v":null},{"v":null},{"v":226.6816667}]},
+ {"c":[{"v":"Date(2018,9,27,12,10,0)"},{"v":null},{"v":null},{"v":246.4083333}]}
+ ]
+}
+```
+
+> Using `format=datasource` and `options=`
+
+```bash
+curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=nginx_local.connections&after=-3600&points=6&group=average&format=datasource&options='
+google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'ok',sig:'1540645368',table:{
+ "cols":
+ [
+ {"id":"","label":"time","pattern":"","type":"datetime"},
+ {"id":"","label":"","pattern":"","type":"string","p":{"role":"annotation"}},
+ {"id":"","label":"","pattern":"","type":"string","p":{"role":"annotationText"}},
+ {"id":"","label":"active","pattern":"","type":"number"}
+ ],
+ "rows":
+ [
+ {"c":[{"v":"Date(2018,9,27,13,0,0)"},{"v":null},{"v":null},{"v":235.885}]},
+ {"c":[{"v":"Date(2018,9,27,12,50,0)"},{"v":null},{"v":null},{"v":224.2516667}]},
+ {"c":[{"v":"Date(2018,9,27,12,40,0)"},{"v":null},{"v":null},{"v":229.29}]},
+ {"c":[{"v":"Date(2018,9,27,12,30,0)"},{"v":null},{"v":null},{"v":222.41}]},
+ {"c":[{"v":"Date(2018,9,27,12,20,0)"},{"v":null},{"v":null},{"v":226.6816667}]},
+ {"c":[{"v":"Date(2018,9,27,12,10,0)"},{"v":null},{"v":null},{"v":246.4083333}]}
+ ]
+}});
+```
+
+
diff --git a/web/api/formatters/json/json.c b/src/web/api/formatters/json/json.c
index 7e3f400e9..7e3f400e9 100644
--- a/web/api/formatters/json/json.c
+++ b/src/web/api/formatters/json/json.c
diff --git a/web/api/formatters/json/json.h b/src/web/api/formatters/json/json.h
index d1ab4f901..d1ab4f901 100644
--- a/web/api/formatters/json/json.h
+++ b/src/web/api/formatters/json/json.h
diff --git a/web/api/formatters/json_wrapper.c b/src/web/api/formatters/json_wrapper.c
index 708a0f1f1..fca5a0b83 100644
--- a/web/api/formatters/json_wrapper.c
+++ b/src/web/api/formatters/json_wrapper.c
@@ -435,23 +435,23 @@ static void query_target_summary_dimensions_v12(BUFFER *wb, QUERY_TARGET *qt, co
qm = tqm;
}
- const char *key, *id, *name;
+ const char *k, *id, *name;
if(v2) {
- key = rrdmetric_acquired_name(rma);
- id = key;
- name = key;
+ k = rrdmetric_acquired_name(rma);
+ id = k;
+ name = k;
}
else {
snprintfz(buf, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
rrdmetric_acquired_id(rma),
rrdmetric_acquired_name(rma));
- key = buf;
+ k = buf;
id = rrdmetric_acquired_id(rma);
name = rrdmetric_acquired_name(rma);
}
- z = dictionary_set(dict, key, NULL, sizeof(*z));
+ z = dictionary_set(dict, k, NULL, sizeof(*z));
if(!z->id) {
z->id = id;
z->name = name;
@@ -618,7 +618,7 @@ static void query_target_summary_alerts_v2(BUFFER *wb, QUERY_TARGET *qt, const c
rw_spinlock_read_lock(&st->alerts.spinlock);
if (st->alerts.base) {
for (RRDCALC *rc = st->alerts.base; rc; rc = rc->next) {
- z = dictionary_set(dict, string2str(rc->name), NULL, sizeof(*z));
+ z = dictionary_set(dict, string2str(rc->config.name), NULL, sizeof(*z));
switch(rc->status) {
case RRDCALC_STATUS_CLEAR:
@@ -887,7 +887,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb) {
buffer_json_member_add_time_t(wb, "after", r->view.after);
buffer_json_member_add_time_t(wb, "before", r->view.before);
buffer_json_member_add_string(wb, "group", time_grouping_tostring(qt->request.time_group_method));
- web_client_api_request_v1_data_options_to_buffer_json_array(wb, "options", options);
+ rrdr_options_to_buffer_json_array(wb, "options", options);
if(!rrdr_dimension_names(wb, "dimension_names", r, options))
rows = 0;
@@ -939,10 +939,10 @@ static void rrdset_rrdcalc_entries_v2(BUFFER *wb, RRDINSTANCE_ACQUIRED *ria) {
if(rc->status < RRDCALC_STATUS_CLEAR)
continue;
- buffer_json_member_add_object(wb, string2str(rc->name));
+ buffer_json_member_add_object(wb, string2str(rc->config.name));
buffer_json_member_add_string(wb, "st", rrdcalc_status2string(rc->status));
buffer_json_member_add_double(wb, "vl", rc->value);
- buffer_json_member_add_string(wb, "un", string2str(rc->units));
+ buffer_json_member_add_string(wb, "un", string2str(rc->config.units));
buffer_json_object_close(wb);
}
buffer_json_object_close(wb);
@@ -1299,7 +1299,7 @@ void rrdr_json_wrapper_begin2(RRDR *r, BUFFER *wb) {
buffer_json_member_add_object(wb, "request");
{
buffer_json_member_add_string(wb, "format", rrdr_format_to_string(qt->request.format));
- web_client_api_request_v1_data_options_to_buffer_json_array(wb, "options", qt->request.options);
+ rrdr_options_to_buffer_json_array(wb, "options", qt->request.options);
buffer_json_member_add_object(wb, "scope");
buffer_json_member_add_string(wb, "scope_nodes", qt->request.scope_nodes);
@@ -1538,7 +1538,7 @@ void rrdr_json_wrapper_end2(RRDR *r, BUFFER *wb) {
if(options & RRDR_OPTION_DEBUG) {
buffer_json_member_add_string(wb, "format", rrdr_format_to_string(format));
- web_client_api_request_v1_data_options_to_buffer_json_array(wb, "options", options);
+ rrdr_options_to_buffer_json_array(wb, "options", options);
buffer_json_member_add_string(wb, "time_group", time_grouping_tostring(qt->request.time_group_method));
}
diff --git a/web/api/formatters/json_wrapper.h b/src/web/api/formatters/json_wrapper.h
index a702f3a5c..a702f3a5c 100644
--- a/web/api/formatters/json_wrapper.h
+++ b/src/web/api/formatters/json_wrapper.h
diff --git a/web/api/formatters/rrd2json.c b/src/web/api/formatters/rrd2json.c
index 81c9ad5c7..81c9ad5c7 100644
--- a/web/api/formatters/rrd2json.c
+++ b/src/web/api/formatters/rrd2json.c
diff --git a/web/api/formatters/rrd2json.h b/src/web/api/formatters/rrd2json.h
index f0c0c39ba..f0c0c39ba 100644
--- a/web/api/formatters/rrd2json.h
+++ b/src/web/api/formatters/rrd2json.h
diff --git a/web/api/formatters/rrdset2json.c b/src/web/api/formatters/rrdset2json.c
index 9ada35336..542178b25 100644
--- a/web/api/formatters/rrdset2json.c
+++ b/src/web/api/formatters/rrdset2json.c
@@ -2,7 +2,7 @@
#include "rrdset2json.h"
-static int process_label_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
+static int process_label_callback(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
BUFFER *wb = data;
buffer_json_member_add_string_or_empty(wb, name, value);
return 1;
@@ -88,7 +88,7 @@ void rrdset2json(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memor
buffer_json_member_add_string_or_empty(wb, "id", rrdcalc_name(rc));
buffer_json_member_add_string_or_empty(wb, "status", rrdcalc_status2string(rc->status));
buffer_json_member_add_string_or_empty(wb, "units", rrdcalc_units(rc));
- buffer_json_member_add_int64(wb, "duration", (int64_t)rc->update_every);
+ buffer_json_member_add_int64(wb, "duration", (int64_t)rc->config.update_every);
buffer_json_object_close(wb);
}
}
diff --git a/web/api/formatters/rrdset2json.h b/src/web/api/formatters/rrdset2json.h
index 8b325c65d..8b325c65d 100644
--- a/web/api/formatters/rrdset2json.h
+++ b/src/web/api/formatters/rrdset2json.h
diff --git a/src/web/api/formatters/ssv/README.md b/src/web/api/formatters/ssv/README.md
new file mode 100644
index 000000000..b32494014
--- /dev/null
+++ b/src/web/api/formatters/ssv/README.md
@@ -0,0 +1,63 @@
+<!--
+title: "SSV formatter"
+custom_edit_url: https://github.com/netdata/netdata/edit/master/src/web/api/formatters/ssv/README.md
+sidebar_label: "SSV formatter"
+learn_status: "Published"
+learn_topic_type: "References"
+learn_rel_path: "Developers/Web/Api/Formatters"
+-->
+
+# SSV formatter
+
+The SSV formatter sums all dimensions in [results of database queries](/src/web/api/queries/README.md)
+to a single value and returns a list of such values showing how it changes through time.
+
+It supports the following formats:
+
+| format | content type | description |
+|:----:|:----------:|:----------|
+| `ssv` | text/plain | a space separated list of values |
+| `ssvcomma` | text/plain | a comma separated list of values |
+| `array` | application/json | a JSON array |
+
+The SSV formatter respects the following API `&options=`:
+
+| option | supported | description |
+| :----:|:-------:|:----------|
+| `nonzero` | yes | to return only the dimensions that have at least a non-zero value |
+| `flip` | yes | to return the numbers older to newer (the default is newer to older) |
+| `percent` | yes | to replace all values with their percentage over the row total |
+| `abs` | yes | to turn all values positive, before using them |
+| `min2max` | yes | to return the delta from the minimum value to the maximum value (across dimensions) |
+
+## Examples
+
+Get the average system CPU utilization of the last hour, in 6 values (one every 10 minutes):
+
+```bash
+# curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=system.cpu&format=ssv&after=-3600&points=6&group=average'
+1.741352 1.6800467 1.769411 1.6761112 1.629862 1.6807968
+```
+
+---
+
+Get the total mysql bandwidth (in + out) for the last hour, in 6 values (one every 10 minutes):
+
+Netdata returns bandwidth in `kilobits`.
+
+```bash
+# curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=mysql_local.net&format=ssvcomma&after=-3600&points=6&group=sum&options=abs'
+72618.7936215,72618.778889,72618.788084,72618.9195918,72618.7760612,72618.6712421
+```
+
+---
+
+Get the web server max connections for the last hour, in 12 values (one every 5 minutes)
+in a JSON array:
+
+```bash
+# curl -Ss 'https://registry.my-netdata.io/api/v1/data?chart=nginx_local.connections&format=array&after=-3600&points=12&group=max'
+[278,258,268,239,259,260,243,266,278,318,264,258]
+```
+
+
diff --git a/web/api/formatters/ssv/ssv.c b/src/web/api/formatters/ssv/ssv.c
index 2eb26b459..2eb26b459 100644
--- a/web/api/formatters/ssv/ssv.c
+++ b/src/web/api/formatters/ssv/ssv.c
diff --git a/web/api/formatters/ssv/ssv.h b/src/web/api/formatters/ssv/ssv.h
index f7d4a9548..f7d4a9548 100644
--- a/web/api/formatters/ssv/ssv.h
+++ b/src/web/api/formatters/ssv/ssv.h
diff --git a/src/web/api/formatters/value/README.md b/src/web/api/formatters/value/README.md
new file mode 100644
index 000000000..8a2df23c6
--- /dev/null
+++ b/src/web/api/formatters/value/README.md
@@ -0,0 +1,28 @@
+<!--
+title: "Value formatter"
+custom_edit_url: https://github.com/netdata/netdata/edit/master/src/web/api/formatters/value/README.md
+sidebar_label: "Value formatter"
+learn_status: "Published"
+learn_topic_type: "References"
+learn_rel_path: "Developers/Web/Api/Formatters"
+-->
+
+# Value formatter
+
+The Value formatter presents [results of database queries](/src/web/api/queries/README.md) as a single value.
+
+To calculate the single value to be returned, it sums the values of all dimensions.
+
+The Value formatter respects the following API `&options=`:
+
+| option | supported | description |
+|:----: |:-------: |:---------- |
+| `percent` | yes | to replace all values with their percentage over the row total|
+| `abs` | yes | to turn all values positive, before using them |
+| `min2max` | yes | to return the delta from the minimum value to the maximum value (across dimensions)|
+
+The Value formatter is not exposed by the API by itself.
+Instead it is used by the [`ssv`](/src/web/api/formatters/ssv/README.md) formatter
+and [health monitoring queries](/src/health/README.md).
+
+
diff --git a/src/web/api/formatters/value/value.c b/src/web/api/formatters/value/value.c
new file mode 100644
index 000000000..0ec1b1265
--- /dev/null
+++ b/src/web/api/formatters/value/value.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "value.h"
+
+inline NETDATA_DOUBLE rrdr2value(RRDR *r, long i, RRDR_OPTIONS options, int *all_values_are_null, NETDATA_DOUBLE *anomaly_rate) {
+ size_t c;
+
+ NETDATA_DOUBLE *cn = &r->v[ i * r->d ];
+ RRDR_VALUE_FLAGS *co = &r->o[ i * r->d ];
+ NETDATA_DOUBLE *ar = &r->ar[ i * r->d ];
+
+ NETDATA_DOUBLE sum = 0, min = NAN, max = NAN, v = NAN;
+ size_t dims = 0;
+
+ NETDATA_DOUBLE total_anomaly_rate = 0;
+
+ // for each dimension
+ for (c = 0; c < r->d ; c++) {
+ if(unlikely(!rrdr_dimension_should_be_exposed(r->od[c], options)))
+ continue;
+
+ if(unlikely((co[c] & RRDR_VALUE_EMPTY)))
+ continue;
+
+ NETDATA_DOUBLE n = cn[c];
+
+ if(unlikely(!dims))
+ min = max = n;
+
+ sum += n;
+
+ if (n < min) min = n;
+ if (n > max) max = n;
+
+ total_anomaly_rate += ar[c];
+
+ dims++;
+ }
+
+ if(!dims) {
+ if(anomaly_rate)
+ *anomaly_rate = 0;
+
+ if(all_values_are_null)
+ *all_values_are_null = 1;
+
+ return (options & RRDR_OPTION_NULL2ZERO) ? 0 : NAN;
+ }
+
+ if(anomaly_rate)
+ *anomaly_rate = total_anomaly_rate / (NETDATA_DOUBLE)dims;
+
+ if(all_values_are_null)
+ *all_values_are_null = 0;
+
+ if(options & RRDR_OPTION_DIMS_MIN2MAX)
+ v = max - min;
+ else if(options & RRDR_OPTION_DIMS_AVERAGE)
+ v = sum / (NETDATA_DOUBLE)dims;
+ else if(options & RRDR_OPTION_DIMS_MIN)
+ v = min;
+ else if(options & RRDR_OPTION_DIMS_MAX)
+ v = max;
+ else
+ v = sum;
+
+ if((options & RRDR_OPTION_NULL2ZERO) && (isnan(v) || isinf(v)))
+ v = 0;
+
+ return v;
+}
+
+QUERY_VALUE rrdmetric2value(RRDHOST *host,
+ struct rrdcontext_acquired *rca, struct rrdinstance_acquired *ria, struct rrdmetric_acquired *rma,
+ time_t after, time_t before,
+ RRDR_OPTIONS options, RRDR_TIME_GROUPING time_group_method, const char *time_group_options,
+ size_t tier, time_t timeout, QUERY_SOURCE query_source, STORAGE_PRIORITY priority
+) {
+ QUERY_TARGET_REQUEST qtr = {
+ .version = 1,
+ .host = host,
+ .rca = rca,
+ .ria = ria,
+ .rma = rma,
+ .after = after,
+ .before = before,
+ .points = 1,
+ .options = options,
+ .time_group_method = time_group_method,
+ .time_group_options = time_group_options,
+ .tier = tier,
+ .timeout_ms = timeout,
+ .query_source = query_source,
+ .priority = priority,
+ };
+
+ ONEWAYALLOC *owa = onewayalloc_create(16 * 1024);
+ QUERY_TARGET *qt = query_target_create(&qtr);
+ RRDR *r = rrd2rrdr(owa, qt);
+
+ QUERY_VALUE qv;
+
+ if(!r || rrdr_rows(r) == 0) {
+ qv = (QUERY_VALUE) {
+ .value = NAN,
+ .anomaly_rate = NAN,
+ .sp = {
+ .count = 0,
+ .min = NAN,
+ .max = NAN,
+ .sum = NAN,
+ .anomaly_count = 0,
+ },
+ .duration_ut = (r) ? r->internal.qt->timings.executed_ut - r->internal.qt->timings.received_ut : 0,
+ };
+ }
+ else {
+ qv = (QUERY_VALUE) {
+ .after = r->view.after,
+ .before = r->view.before,
+ .points_read = r->stats.db_points_read,
+ .result_points = r->stats.result_points_generated,
+ .sp = {
+ .count = 0,
+ },
+ .duration_ut = r->internal.qt->timings.executed_ut - r->internal.qt->timings.received_ut,
+ };
+
+ for(size_t d = 0; d < r->internal.qt->query.used ;d++) {
+ if(!rrdr_dimension_should_be_exposed(r->internal.qt->query.array[d].status, options))
+ continue;
+
+ storage_point_merge_to(qv.sp, r->internal.qt->query.array[d].query_points);
+ }
+
+ for(size_t t = 0; t < storage_tiers ;t++)
+ qv.storage_points_per_tier[t] = r->internal.qt->db.tiers[t].points;
+
+ long i = (!(options & RRDR_OPTION_REVERSED))?(long)rrdr_rows(r) - 1:0;
+ int all_values_are_null = 0;
+ qv.value = rrdr2value(r, i, options, &all_values_are_null, &qv.anomaly_rate);
+ if(all_values_are_null) {
+ qv.value = NAN;
+ qv.anomaly_rate = NAN;
+ }
+ }
+
+ rrdr_free(owa, r);
+ query_target_release(qt);
+ onewayalloc_destroy(owa);
+
+ return qv;
+}
diff --git a/web/api/formatters/value/value.h b/src/web/api/formatters/value/value.h
index 072ca14f8..072ca14f8 100644
--- a/web/api/formatters/value/value.h
+++ b/src/web/api/formatters/value/value.h