2 * collectd - src/utils_parse_json.c
3 * Copyright (C) 2018 Florian Forster
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * Florian Forster <octo at collectd.org>
33 #include "utils_parse_json.h"
35 #include <yajl/yajl_tree.h>
37 static int parse_json_gauge(yajl_val value_val, value_t *v) /* {{{ */
39 if (YAJL_IS_DOUBLE(value_val))
40 v->gauge = (gauge_t)YAJL_GET_DOUBLE(value_val);
41 else if (YAJL_IS_NULL(value_val))
47 } /* }}} int parse_json_gauge */
49 static int parse_json_derive(yajl_val value_val, value_t *v) /* {{{ */
51 if (!YAJL_IS_INTEGER(value_val)) {
52 if (YAJL_IS_NUMBER(value_val)) {
53 WARNING("parse_json_derive: %s is not an integer. The most common cause "
54 "is that the publisher has the StoreRates option enabled.",
55 YAJL_GET_NUMBER(value_val));
60 v->derive = (derive_t)YAJL_GET_INTEGER(value_val);
62 } /* }}} int parse_json_derive */
64 static int parse_json_counter(yajl_val value_val, value_t *v) /* {{{ */
66 if (!YAJL_IS_INTEGER(value_val)) {
67 if (YAJL_IS_NUMBER(value_val)) {
68 WARNING("parse_json_counter: %s is not an integer. The most common cause "
69 "is that the publisher has the StoreRates option enabled.",
70 YAJL_GET_NUMBER(value_val));
75 v->counter = (counter_t)YAJL_GET_INTEGER(value_val);
77 } /* }}} int parse_json_counter */
79 static int parse_json_absolute(yajl_val value_val, value_t *v) /* {{{ */
81 if (!YAJL_IS_INTEGER(value_val)) {
82 if (YAJL_IS_NUMBER(value_val)) {
83 WARNING("parse_json_absolute: %s is not an integer. The most common "
84 "cause is that the publisher has the StoreRates option enabled.",
85 YAJL_GET_NUMBER(value_val));
90 v->absolute = (absolute_t)YAJL_GET_INTEGER(value_val);
92 } /* }}} int parse_json_absolute */
94 static int parse_json_value(yajl_val value_val, yajl_val dstype_val,
97 char const *dstype = YAJL_GET_STRING(dstype_val);
100 NOTICE("parse_json_value: unable to get data source type");
102 } else if (strcasecmp("gauge", dstype) == 0)
103 return parse_json_gauge(value_val, v);
104 else if (strcasecmp("derive", dstype) == 0)
105 return parse_json_derive(value_val, v);
106 else if (strcasecmp("counter", dstype) == 0)
107 return parse_json_counter(value_val, v);
108 else if (strcasecmp("absolute", dstype) == 0)
109 return parse_json_absolute(value_val, v);
111 NOTICE("parse_json_value: unexpected data source type \"%s\"", dstype);
114 } /* }}} int parse_json_value */
116 static int parse_json_values(yajl_val root, value_list_t *vl) /* {{{ */
118 char const *values_path[] = {"values", NULL};
119 char const *dstypes_path[] = {"dstypes", NULL};
121 yajl_val values_val = yajl_tree_get(root, values_path, yajl_t_array);
122 yajl_val dstypes_val = yajl_tree_get(root, dstypes_path, yajl_t_array);
126 if (values_val == NULL) {
127 NOTICE("parse_json_values: key \"values\" not found (or not an array)");
130 if (dstypes_val == NULL) {
131 NOTICE("parse_json_values: key \"dstypes\" not found (or not an array)");
134 if (YAJL_GET_ARRAY(values_val)->len != YAJL_GET_ARRAY(dstypes_val)->len) {
135 NOTICE("parse_json_values: lengths of \"values\" (%zu) and "
136 "\"dstypes\" (%zu) differ",
137 YAJL_GET_ARRAY(values_val)->len, YAJL_GET_ARRAY(dstypes_val)->len);
141 vl->values = calloc(YAJL_GET_ARRAY(values_val)->len, sizeof(*vl->values));
142 if (vl->values == NULL)
144 vl->values_len = (int)YAJL_GET_ARRAY(values_val)->len;
146 for (i = 0; i < YAJL_GET_ARRAY(values_val)->len; i++) {
147 int status = parse_json_value(YAJL_GET_ARRAY(values_val)->values[i],
148 YAJL_GET_ARRAY(dstypes_val)->values[i],
159 } /* }}} int parse_json_values */
161 static int parse_json_string(yajl_val root, char *key, char *buffer,
162 size_t buffer_size) /* {{{ */
164 char const *path[] = {key, NULL};
165 yajl_val string_val = yajl_tree_get(root, path, yajl_t_string);
167 if (!YAJL_IS_STRING(string_val))
170 sstrncpy(buffer, YAJL_GET_STRING(string_val), buffer_size);
172 } /* }}} int parse_json_string */
174 static int parse_json_time(yajl_val root, char *key, cdtime_t *t) /* {{{ */
176 char const *path[] = {key, NULL};
177 yajl_val double_val = yajl_tree_get(root, path, yajl_t_number);
179 if (!YAJL_IS_DOUBLE(double_val))
182 *t = DOUBLE_TO_CDTIME_T(YAJL_GET_DOUBLE(double_val));
184 } /* }}} int parse_json_time */
186 static int parse_json_vl(yajl_val root, value_list_t *vl) /* {{{ */
190 memset(vl, 0, sizeof(*vl));
192 status = parse_json_string(root, "host", vl->host, sizeof(vl->host));
194 NOTICE("parse_json: parsing key \"host\" failed");
198 status = parse_json_string(root, "plugin", vl->plugin, sizeof(vl->plugin));
200 NOTICE("parse_json: parsing key \"plugin\" failed");
203 parse_json_string(root, "plugin_instance", vl->plugin_instance,
204 sizeof(vl->plugin_instance));
206 status = parse_json_string(root, "type", vl->type, sizeof(vl->type));
208 NOTICE("parse_json: parsing key \"type\" failed");
211 parse_json_string(root, "type_instance", vl->type_instance,
212 sizeof(vl->type_instance));
214 status = parse_json_time(root, "time", &vl->time);
216 NOTICE("parse_json: parsing key \"time\" failed");
220 status = parse_json_time(root, "interval", &vl->interval);
222 NOTICE("parse_json: parsing key \"interval\" failed");
226 status = parse_json_values(root, vl);
232 } /* }}} int parse_json_vl */
234 int parse_json(char const *json, value_list_t ***ret_vls,
235 size_t *ret_vls_num) /* {{{ */
241 value_list_t **vls = NULL;
244 root = yajl_tree_parse(json, errbuf, sizeof(errbuf));
246 ERROR("parse_json: yajl_tree_parse failed: %s", errbuf);
250 if (!YAJL_IS_ARRAY(root)) {
251 NOTICE("parse_json: root is not an array");
255 for (i = 0; i < YAJL_GET_ARRAY(root)->len; i++) {
256 yajl_val vl_json = YAJL_GET_ARRAY(root)->values[i];
259 vl = malloc(sizeof(*vl));
263 int status = parse_json_vl(vl_json, vl);
269 value_list_t **tmp = realloc(vls, sizeof(*vls) * (vls_num + 1));
271 ERROR("parse_json: realloc failed");
283 *ret_vls_num = vls_num;
285 } /* }}} int parse_json */