b4b7b6a8af4b1becfb02431e43188325355f29b4
1 /*
2 * SysDB - src/core/store_json.c
3 * Copyright (C) 2013-2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 /*
29 * This module implements JSON support.
30 */
32 #if HAVE_CONFIG_H
33 # include "config.h"
34 #endif /* HAVE_CONFIG_H */
36 #include "sysdb.h"
37 #include "core/store-private.h"
38 #include "utils/error.h"
40 #include <assert.h>
42 #include <stdlib.h>
44 /*
45 * private data types
46 */
48 struct sdb_store_json_formatter {
49 sdb_strbuf_t *buf;
51 /* The context describes the state of the formatter through
52 * the path pointing to the current object */
53 int context[8];
54 size_t current;
56 int flags;
57 };
59 /*
60 * private helper functions
61 */
63 static int
64 json_emit(sdb_store_json_formatter_t *f, sdb_store_obj_t *obj)
65 {
66 char time_str[64];
67 char interval_str[64];
68 size_t i;
70 assert(f && obj);
72 sdb_strbuf_append(f->buf, "{\"name\": \"%s\", ", SDB_OBJ(obj)->name);
73 if (obj->type == SDB_ATTRIBUTE) {
74 char tmp[sdb_data_strlen(&ATTR(obj)->value) + 1];
75 if (sdb_data_format(&ATTR(obj)->value, tmp, sizeof(tmp),
76 SDB_DOUBLE_QUOTED) < 0)
77 snprintf(tmp, sizeof(tmp), "<error>");
78 sdb_strbuf_append(f->buf, "\"value\": %s, ", tmp);
79 }
81 /* TODO: make time and interval formats configurable */
82 if (! sdb_strftime(time_str, sizeof(time_str),
83 "%F %T %z", obj->last_update))
84 snprintf(time_str, sizeof(time_str), "<error>");
85 time_str[sizeof(time_str) - 1] = '\0';
87 if (! sdb_strfinterval(interval_str, sizeof(interval_str),
88 obj->interval))
89 snprintf(interval_str, sizeof(interval_str), "<error>");
90 interval_str[sizeof(interval_str) - 1] = '\0';
92 sdb_strbuf_append(f->buf, "\"last_update\": \"%s\", "
93 "\"update_interval\": \"%s\", \"backends\": [",
94 time_str, interval_str);
96 for (i = 0; i < obj->backends_num; ++i) {
97 sdb_strbuf_append(f->buf, "\"%s\"", obj->backends[i]);
98 if (i < obj->backends_num - 1)
99 sdb_strbuf_append(f->buf, ",");
100 }
101 sdb_strbuf_append(f->buf, "]");
102 return 0;
103 } /* json_emit */
105 /*
106 * public API
107 */
109 sdb_store_json_formatter_t *
110 sdb_store_json_formatter(sdb_strbuf_t *buf, int flags)
111 {
112 sdb_store_json_formatter_t *f;
114 if (! buf)
115 return NULL;
117 f = calloc(1, sizeof(*f));
118 if (! f)
119 return NULL;
121 f->buf = buf;
122 f->context[0] = 0;
123 f->current = 0;
124 f->flags = flags;
125 return f;
126 } /* sdb_store_json_formatter */
128 int
129 sdb_store_json_emit(sdb_store_json_formatter_t *f, sdb_store_obj_t *obj)
130 {
131 if ((! f) || (! obj))
132 return -1;
134 /* first host */
135 if (! f->context[0]) {
136 if (f->flags & SDB_WANT_ARRAY)
137 sdb_strbuf_append(f->buf, "[");
138 assert(f->current == 0);
139 f->context[0] = SDB_HOST;
140 return json_emit(f, obj);
141 }
143 if (obj->type == f->context[f->current]) {
144 /* new entry of the same type */
145 sdb_strbuf_append(f->buf, "},");
146 }
147 else if ((f->context[f->current] == SDB_HOST)
148 || (obj->type == SDB_ATTRIBUTE)) {
149 assert(obj->type != SDB_HOST);
150 /* all object types may be children of a host;
151 * attributes may be children of any type */
152 sdb_strbuf_append(f->buf, ", \"%ss\": [",
153 SDB_STORE_TYPE_TO_NAME(obj->type));
154 ++f->current;
155 }
156 else if (f->current >= 1) {
157 /* new entry of a previous type or a new type on the same level
158 * -> rewind to the right state and then handle the new object */
159 assert(obj->type != SDB_ATTRIBUTE);
160 while (f->current > 0) {
161 if (f->context[f->current] == obj->type)
162 break;
163 assert(f->context[f->current] != SDB_HOST);
164 sdb_strbuf_append(f->buf, "}]");
165 --f->current;
166 }
167 return sdb_store_json_emit(f, obj);
168 }
169 else {
170 sdb_log(SDB_LOG_ERR, "store: Unexpected object of type %s "
171 "on level %zu during JSON serialization",
172 SDB_STORE_TYPE_TO_NAME(obj->type), f->current);
173 return -1;
174 }
176 json_emit(f, obj);
177 assert(f->current < SDB_STATIC_ARRAY_LEN(f->context));
178 f->context[f->current] = obj->type;
179 return 0;
180 } /* sdb_store_json_emit */
182 int
183 sdb_store_json_emit_full(sdb_store_json_formatter_t *f, sdb_store_obj_t *obj,
184 sdb_store_matcher_t *filter)
185 {
186 sdb_avltree_t *trees[] = { NULL, NULL, NULL };
187 size_t i;
189 if (sdb_store_json_emit(f, obj))
190 return -1;
192 if (obj->type == SDB_HOST) {
193 trees[0] = HOST(obj)->attributes;
194 trees[1] = HOST(obj)->metrics;
195 trees[2] = HOST(obj)->services;
196 }
197 else if (obj->type == SDB_SERVICE)
198 trees[0] = SVC(obj)->attributes;
199 else if (obj->type == SDB_METRIC)
200 trees[0] = METRIC(obj)->attributes;
201 else if (obj->type == SDB_ATTRIBUTE)
202 return 0;
203 else
204 return -1;
206 for (i = 0; i < SDB_STATIC_ARRAY_LEN(trees); ++i) {
207 sdb_avltree_iter_t *iter;
209 if (! trees[i])
210 continue;
212 iter = sdb_avltree_get_iter(trees[i]);
213 while (sdb_avltree_iter_has_next(iter)) {
214 sdb_store_obj_t *child;
215 child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
217 if (filter && (! sdb_store_matcher_matches(filter, child, NULL)))
218 continue;
220 if (sdb_store_json_emit_full(f, child, filter)) {
221 sdb_avltree_iter_destroy(iter);
222 return -1;
223 }
224 }
225 sdb_avltree_iter_destroy(iter);
226 }
227 return 0;
228 } /* sdb_store_json_emit_full */
230 int
231 sdb_store_json_finish(sdb_store_json_formatter_t *f)
232 {
233 if (! f)
234 return -1;
236 if (! f->context[0]) {
237 /* no content */
238 if (f->flags & SDB_WANT_ARRAY)
239 sdb_strbuf_append(f->buf, "[]");
240 return 0;
241 }
243 while (f->current > 0) {
244 sdb_strbuf_append(f->buf, "}]");
245 --f->current;
246 }
248 sdb_strbuf_append(f->buf, "}");
249 if (f->flags & SDB_WANT_ARRAY)
250 sdb_strbuf_append(f->buf, "]");
251 return 0;
252 } /* sdb_store_json_finish */
254 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */