rrdtool plugin: Added more error reporting
[collectd.git] / src / utils_format_json.c
1 /**
2  * collectd - src/utils_format_json.c
3  * Copyright (C) 2009-2015  Florian octo Forster
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Florian octo Forster <octo at collectd.org>
25  **/
26
27 #include "collectd.h"
28
29 #include "utils_format_json.h"
30
31 #include "common.h"
32 #include "plugin.h"
33 #include "utils_cache.h"
34
35 #if HAVE_LIBYAJL
36 #include <yajl/yajl_common.h>
37 #include <yajl/yajl_gen.h>
38 #if HAVE_YAJL_YAJL_VERSION_H
39 #include <yajl/yajl_version.h>
40 #endif
41 #if defined(YAJL_MAJOR) && (YAJL_MAJOR > 1)
42 #define HAVE_YAJL_V2 1
43 #endif
44 #endif
45
46 static int json_escape_string(char *buffer, size_t buffer_size, /* {{{ */
47                               const char *string) {
48   size_t dst_pos;
49
50   if ((buffer == NULL) || (string == NULL))
51     return -EINVAL;
52
53   if (buffer_size < 3)
54     return -ENOMEM;
55
56   dst_pos = 0;
57
58 #define BUFFER_ADD(c)                                                          \
59   do {                                                                         \
60     if (dst_pos >= (buffer_size - 1)) {                                        \
61       buffer[buffer_size - 1] = 0;                                             \
62       return -ENOMEM;                                                          \
63     }                                                                          \
64     buffer[dst_pos] = (c);                                                     \
65     dst_pos++;                                                                 \
66   } while (0)
67
68   /* Escape special characters */
69   BUFFER_ADD('"');
70   for (size_t src_pos = 0; string[src_pos] != 0; src_pos++) {
71     if ((string[src_pos] == '"') || (string[src_pos] == '\\')) {
72       BUFFER_ADD('\\');
73       BUFFER_ADD(string[src_pos]);
74     } else if (string[src_pos] <= 0x001F)
75       BUFFER_ADD('?');
76     else
77       BUFFER_ADD(string[src_pos]);
78   } /* for */
79   BUFFER_ADD('"');
80   buffer[dst_pos] = 0;
81
82 #undef BUFFER_ADD
83
84   return 0;
85 } /* }}} int json_escape_string */
86
87 static int values_to_json(char *buffer, size_t buffer_size, /* {{{ */
88                           const data_set_t *ds, const value_list_t *vl,
89                           int store_rates) {
90   size_t offset = 0;
91   gauge_t *rates = NULL;
92
93   memset(buffer, 0, buffer_size);
94
95 #define BUFFER_ADD(...)                                                        \
96   do {                                                                         \
97     int status;                                                                \
98     status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__);     \
99     if (status < 1) {                                                          \
100       sfree(rates);                                                            \
101       return -1;                                                               \
102     } else if (((size_t)status) >= (buffer_size - offset)) {                   \
103       sfree(rates);                                                            \
104       return -ENOMEM;                                                          \
105     } else                                                                     \
106       offset += ((size_t)status);                                              \
107   } while (0)
108
109   BUFFER_ADD("[");
110   for (size_t i = 0; i < ds->ds_num; i++) {
111     if (i > 0)
112       BUFFER_ADD(",");
113
114     if (ds->ds[i].type == DS_TYPE_GAUGE) {
115       if (isfinite(vl->values[i].gauge))
116         BUFFER_ADD(JSON_GAUGE_FORMAT, vl->values[i].gauge);
117       else
118         BUFFER_ADD("null");
119     } else if (store_rates) {
120       if (rates == NULL)
121         rates = uc_get_rate(ds, vl);
122       if (rates == NULL) {
123         WARNING("utils_format_json: uc_get_rate failed.");
124         sfree(rates);
125         return -1;
126       }
127
128       if (isfinite(rates[i]))
129         BUFFER_ADD(JSON_GAUGE_FORMAT, rates[i]);
130       else
131         BUFFER_ADD("null");
132     } else if (ds->ds[i].type == DS_TYPE_COUNTER)
133       BUFFER_ADD("%" PRIu64, (uint64_t)vl->values[i].counter);
134     else if (ds->ds[i].type == DS_TYPE_DERIVE)
135       BUFFER_ADD("%" PRIi64, vl->values[i].derive);
136     else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
137       BUFFER_ADD("%" PRIu64, vl->values[i].absolute);
138     else {
139       ERROR("format_json: Unknown data source type: %i", ds->ds[i].type);
140       sfree(rates);
141       return -1;
142     }
143   } /* for ds->ds_num */
144   BUFFER_ADD("]");
145
146 #undef BUFFER_ADD
147
148   DEBUG("format_json: values_to_json: buffer = %s;", buffer);
149   sfree(rates);
150   return 0;
151 } /* }}} int values_to_json */
152
153 static int dstypes_to_json(char *buffer, size_t buffer_size, /* {{{ */
154                            const data_set_t *ds) {
155   size_t offset = 0;
156
157   memset(buffer, 0, buffer_size);
158
159 #define BUFFER_ADD(...)                                                        \
160   do {                                                                         \
161     int status;                                                                \
162     status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__);     \
163     if (status < 1)                                                            \
164       return -1;                                                               \
165     else if (((size_t)status) >= (buffer_size - offset))                       \
166       return -ENOMEM;                                                          \
167     else                                                                       \
168       offset += ((size_t)status);                                              \
169   } while (0)
170
171   BUFFER_ADD("[");
172   for (size_t i = 0; i < ds->ds_num; i++) {
173     if (i > 0)
174       BUFFER_ADD(",");
175
176     BUFFER_ADD("\"%s\"", DS_TYPE_TO_STRING(ds->ds[i].type));
177   } /* for ds->ds_num */
178   BUFFER_ADD("]");
179
180 #undef BUFFER_ADD
181
182   DEBUG("format_json: dstypes_to_json: buffer = %s;", buffer);
183
184   return 0;
185 } /* }}} int dstypes_to_json */
186
187 static int dsnames_to_json(char *buffer, size_t buffer_size, /* {{{ */
188                            const data_set_t *ds) {
189   size_t offset = 0;
190
191   memset(buffer, 0, buffer_size);
192
193 #define BUFFER_ADD(...)                                                        \
194   do {                                                                         \
195     int status;                                                                \
196     status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__);     \
197     if (status < 1)                                                            \
198       return -1;                                                               \
199     else if (((size_t)status) >= (buffer_size - offset))                       \
200       return -ENOMEM;                                                          \
201     else                                                                       \
202       offset += ((size_t)status);                                              \
203   } while (0)
204
205   BUFFER_ADD("[");
206   for (size_t i = 0; i < ds->ds_num; i++) {
207     if (i > 0)
208       BUFFER_ADD(",");
209
210     BUFFER_ADD("\"%s\"", ds->ds[i].name);
211   } /* for ds->ds_num */
212   BUFFER_ADD("]");
213
214 #undef BUFFER_ADD
215
216   DEBUG("format_json: dsnames_to_json: buffer = %s;", buffer);
217
218   return 0;
219 } /* }}} int dsnames_to_json */
220
221 static int meta_data_keys_to_json(char *buffer, size_t buffer_size, /* {{{ */
222                                   meta_data_t *meta, char **keys,
223                                   size_t keys_num) {
224   size_t offset = 0;
225   int status;
226
227   buffer[0] = 0;
228
229 #define BUFFER_ADD(...)                                                        \
230   do {                                                                         \
231     status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__);     \
232     if (status < 1)                                                            \
233       return -1;                                                               \
234     else if (((size_t)status) >= (buffer_size - offset))                       \
235       return -ENOMEM;                                                          \
236     else                                                                       \
237       offset += ((size_t)status);                                              \
238   } while (0)
239
240   for (size_t i = 0; i < keys_num; ++i) {
241     int type;
242     char *key = keys[i];
243
244     type = meta_data_type(meta, key);
245     if (type == MD_TYPE_STRING) {
246       char *value = NULL;
247       if (meta_data_get_string(meta, key, &value) == 0) {
248         char temp[512] = "";
249
250         status = json_escape_string(temp, sizeof(temp), value);
251         sfree(value);
252         if (status != 0)
253           return status;
254
255         BUFFER_ADD(",\"%s\":%s", key, temp);
256       }
257     } else if (type == MD_TYPE_SIGNED_INT) {
258       int64_t value = 0;
259       if (meta_data_get_signed_int(meta, key, &value) == 0)
260         BUFFER_ADD(",\"%s\":%" PRIi64, key, value);
261     } else if (type == MD_TYPE_UNSIGNED_INT) {
262       uint64_t value = 0;
263       if (meta_data_get_unsigned_int(meta, key, &value) == 0)
264         BUFFER_ADD(",\"%s\":%" PRIu64, key, value);
265     } else if (type == MD_TYPE_DOUBLE) {
266       double value = 0.0;
267       if (meta_data_get_double(meta, key, &value) == 0)
268         BUFFER_ADD(",\"%s\":%f", key, value);
269     } else if (type == MD_TYPE_BOOLEAN) {
270       bool value = false;
271       if (meta_data_get_boolean(meta, key, &value) == 0)
272         BUFFER_ADD(",\"%s\":%s", key, value ? "true" : "false");
273     }
274   } /* for (keys) */
275
276   if (offset == 0)
277     return ENOENT;
278
279   buffer[0] = '{'; /* replace leading ',' */
280   BUFFER_ADD("}");
281
282 #undef BUFFER_ADD
283
284   return 0;
285 } /* }}} int meta_data_keys_to_json */
286
287 static int meta_data_to_json(char *buffer, size_t buffer_size, /* {{{ */
288                              meta_data_t *meta) {
289   char **keys = NULL;
290   size_t keys_num;
291   int status;
292
293   if ((buffer == NULL) || (buffer_size == 0) || (meta == NULL))
294     return EINVAL;
295
296   status = meta_data_toc(meta, &keys);
297   if (status <= 0)
298     return status;
299   keys_num = (size_t)status;
300
301   status = meta_data_keys_to_json(buffer, buffer_size, meta, keys, keys_num);
302
303   for (size_t i = 0; i < keys_num; ++i)
304     sfree(keys[i]);
305   sfree(keys);
306
307   return status;
308 } /* }}} int meta_data_to_json */
309
310 static int value_list_to_json(char *buffer, size_t buffer_size, /* {{{ */
311                               const data_set_t *ds, const value_list_t *vl,
312                               int store_rates) {
313   char temp[512];
314   size_t offset = 0;
315   int status;
316
317   memset(buffer, 0, buffer_size);
318
319 #define BUFFER_ADD(...)                                                        \
320   do {                                                                         \
321     status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__);     \
322     if (status < 1)                                                            \
323       return -1;                                                               \
324     else if (((size_t)status) >= (buffer_size - offset))                       \
325       return -ENOMEM;                                                          \
326     else                                                                       \
327       offset += ((size_t)status);                                              \
328   } while (0)
329
330   /* All value lists have a leading comma. The first one will be replaced with
331    * a square bracket in `format_json_finalize'. */
332   BUFFER_ADD(",{");
333
334   status = values_to_json(temp, sizeof(temp), ds, vl, store_rates);
335   if (status != 0)
336     return status;
337   BUFFER_ADD("\"values\":%s", temp);
338
339   status = dstypes_to_json(temp, sizeof(temp), ds);
340   if (status != 0)
341     return status;
342   BUFFER_ADD(",\"dstypes\":%s", temp);
343
344   status = dsnames_to_json(temp, sizeof(temp), ds);
345   if (status != 0)
346     return status;
347   BUFFER_ADD(",\"dsnames\":%s", temp);
348
349   BUFFER_ADD(",\"time\":%.3f", CDTIME_T_TO_DOUBLE(vl->time));
350   BUFFER_ADD(",\"interval\":%.3f", CDTIME_T_TO_DOUBLE(vl->interval));
351
352 #define BUFFER_ADD_KEYVAL(key, value)                                          \
353   do {                                                                         \
354     status = json_escape_string(temp, sizeof(temp), (value));                  \
355     if (status != 0)                                                           \
356       return status;                                                           \
357     BUFFER_ADD(",\"%s\":%s", (key), temp);                                     \
358   } while (0)
359
360   BUFFER_ADD_KEYVAL("host", vl->host);
361   BUFFER_ADD_KEYVAL("plugin", vl->plugin);
362   BUFFER_ADD_KEYVAL("plugin_instance", vl->plugin_instance);
363   BUFFER_ADD_KEYVAL("type", vl->type);
364   BUFFER_ADD_KEYVAL("type_instance", vl->type_instance);
365
366   if (vl->meta != NULL) {
367     char meta_buffer[buffer_size];
368     memset(meta_buffer, 0, sizeof(meta_buffer));
369     status = meta_data_to_json(meta_buffer, sizeof(meta_buffer), vl->meta);
370     if (status != 0)
371       return status;
372
373     BUFFER_ADD(",\"meta\":%s", meta_buffer);
374   } /* if (vl->meta != NULL) */
375
376   BUFFER_ADD("}");
377
378 #undef BUFFER_ADD_KEYVAL
379 #undef BUFFER_ADD
380
381   DEBUG("format_json: value_list_to_json: buffer = %s;", buffer);
382
383   return 0;
384 } /* }}} int value_list_to_json */
385
386 static int format_json_value_list_nocheck(char *buffer, /* {{{ */
387                                           size_t *ret_buffer_fill,
388                                           size_t *ret_buffer_free,
389                                           const data_set_t *ds,
390                                           const value_list_t *vl,
391                                           int store_rates, size_t temp_size) {
392   char temp[temp_size];
393   int status;
394
395   status = value_list_to_json(temp, sizeof(temp), ds, vl, store_rates);
396   if (status != 0)
397     return status;
398   temp_size = strlen(temp);
399
400   memcpy(buffer + (*ret_buffer_fill), temp, temp_size + 1);
401   (*ret_buffer_fill) += temp_size;
402   (*ret_buffer_free) -= temp_size;
403
404   return 0;
405 } /* }}} int format_json_value_list_nocheck */
406
407 int format_json_initialize(char *buffer, /* {{{ */
408                            size_t *ret_buffer_fill, size_t *ret_buffer_free) {
409   size_t buffer_fill;
410   size_t buffer_free;
411
412   if ((buffer == NULL) || (ret_buffer_fill == NULL) ||
413       (ret_buffer_free == NULL))
414     return -EINVAL;
415
416   buffer_fill = *ret_buffer_fill;
417   buffer_free = *ret_buffer_free;
418
419   buffer_free = buffer_fill + buffer_free;
420   buffer_fill = 0;
421
422   if (buffer_free < 3)
423     return -ENOMEM;
424
425   memset(buffer, 0, buffer_free);
426   *ret_buffer_fill = buffer_fill;
427   *ret_buffer_free = buffer_free;
428
429   return 0;
430 } /* }}} int format_json_initialize */
431
432 int format_json_finalize(char *buffer, /* {{{ */
433                          size_t *ret_buffer_fill, size_t *ret_buffer_free) {
434   size_t pos;
435
436   if ((buffer == NULL) || (ret_buffer_fill == NULL) ||
437       (ret_buffer_free == NULL))
438     return -EINVAL;
439
440   if (*ret_buffer_free < 2)
441     return -ENOMEM;
442
443   /* Replace the leading comma added in `value_list_to_json' with a square
444    * bracket. */
445   if (buffer[0] != ',')
446     return -EINVAL;
447   buffer[0] = '[';
448
449   pos = *ret_buffer_fill;
450   buffer[pos] = ']';
451   buffer[pos + 1] = 0;
452
453   (*ret_buffer_fill)++;
454   (*ret_buffer_free)--;
455
456   return 0;
457 } /* }}} int format_json_finalize */
458
459 int format_json_value_list(char *buffer, /* {{{ */
460                            size_t *ret_buffer_fill, size_t *ret_buffer_free,
461                            const data_set_t *ds, const value_list_t *vl,
462                            int store_rates) {
463   if ((buffer == NULL) || (ret_buffer_fill == NULL) ||
464       (ret_buffer_free == NULL) || (ds == NULL) || (vl == NULL))
465     return -EINVAL;
466
467   if (*ret_buffer_free < 3)
468     return -ENOMEM;
469
470   return format_json_value_list_nocheck(buffer, ret_buffer_fill,
471                                         ret_buffer_free, ds, vl, store_rates,
472                                         (*ret_buffer_free) - 2);
473 } /* }}} int format_json_value_list */
474
475 #if HAVE_LIBYAJL
476 static int json_add_string(yajl_gen g, char const *str) /* {{{ */
477 {
478   if (str == NULL)
479     return (int)yajl_gen_null(g);
480
481   return (int)yajl_gen_string(g, (const unsigned char *)str,
482                               (unsigned int)strlen(str));
483 } /* }}} int json_add_string */
484
485 #define JSON_ADD(g, str)                                                       \
486   do {                                                                         \
487     yajl_gen_status status = json_add_string(g, str);                          \
488     if (status != yajl_gen_status_ok) {                                        \
489       return -1;                                                               \
490     }                                                                          \
491   } while (0)
492
493 #define JSON_ADDF(g, format, ...)                                              \
494   do {                                                                         \
495     char *str = ssnprintf_alloc(format, __VA_ARGS__);                          \
496     yajl_gen_status status = json_add_string(g, str);                          \
497     free(str);                                                                 \
498     if (status != yajl_gen_status_ok) {                                        \
499       return -1;                                                               \
500     }                                                                          \
501   } while (0)
502
503 #define CHECK_SUCCESS(cmd)                                                     \
504   do {                                                                         \
505     yajl_gen_status s = (cmd);                                                 \
506     if (s != yajl_gen_status_ok) {                                             \
507       return (int)s;                                                           \
508     }                                                                          \
509   } while (0)
510
511 static int format_json_meta(yajl_gen g, notification_meta_t *meta) /* {{{ */
512 {
513   if (meta == NULL)
514     return 0;
515
516   JSON_ADD(g, meta->name);
517   switch (meta->type) {
518   case NM_TYPE_STRING:
519     JSON_ADD(g, meta->nm_value.nm_string);
520     break;
521   case NM_TYPE_SIGNED_INT:
522     JSON_ADDF(g, "%" PRIi64, meta->nm_value.nm_signed_int);
523     break;
524   case NM_TYPE_UNSIGNED_INT:
525     JSON_ADDF(g, "%" PRIu64, meta->nm_value.nm_unsigned_int);
526     break;
527   case NM_TYPE_DOUBLE:
528     JSON_ADDF(g, JSON_GAUGE_FORMAT, meta->nm_value.nm_double);
529     break;
530   case NM_TYPE_BOOLEAN:
531     JSON_ADD(g, meta->nm_value.nm_boolean ? "true" : "false");
532     break;
533   default:
534     ERROR("format_json_meta: unknown meta data type %d (name \"%s\")",
535           meta->type, meta->name);
536     CHECK_SUCCESS(yajl_gen_null(g));
537   }
538
539   return format_json_meta(g, meta->next);
540 } /* }}} int format_json_meta */
541
542 static int format_time(yajl_gen g, cdtime_t t) /* {{{ */
543 {
544   char buffer[RFC3339NANO_SIZE] = "";
545
546   if (rfc3339nano(buffer, sizeof(buffer), t) != 0)
547     return -1;
548
549   JSON_ADD(g, buffer);
550   return 0;
551 } /* }}} int format_time */
552
553 static int format_alert(yajl_gen g, notification_t const *n) /* {{{ */
554 {
555   CHECK_SUCCESS(yajl_gen_array_open(g)); /* BEGIN array */
556   CHECK_SUCCESS(yajl_gen_map_open(g));   /* BEGIN alert */
557
558   /*
559    * labels
560    */
561   JSON_ADD(g, "labels");
562   CHECK_SUCCESS(yajl_gen_map_open(g)); /* BEGIN labels */
563
564   JSON_ADD(g, "alertname");
565   if (strncmp(n->plugin, n->type, strlen(n->plugin)) == 0)
566     JSON_ADDF(g, "collectd_%s", n->type);
567   else
568     JSON_ADDF(g, "collectd_%s_%s", n->plugin, n->type);
569
570   JSON_ADD(g, "instance");
571   JSON_ADD(g, n->host);
572
573   /* mangling of plugin instance and type instance into labels is copied from
574    * the Prometheus collectd exporter. */
575   if (strlen(n->plugin_instance) > 0) {
576     JSON_ADD(g, n->plugin);
577     JSON_ADD(g, n->plugin_instance);
578   }
579   if (strlen(n->type_instance) > 0) {
580     if (strlen(n->plugin_instance) > 0)
581       JSON_ADD(g, "type");
582     else
583       JSON_ADD(g, n->plugin);
584     JSON_ADD(g, n->type_instance);
585   }
586
587   JSON_ADD(g, "severity");
588   JSON_ADD(g,
589            (n->severity == NOTIF_FAILURE)
590                ? "FAILURE"
591                : (n->severity == NOTIF_WARNING)
592                      ? "WARNING"
593                      : (n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN");
594
595   JSON_ADD(g, "service");
596   JSON_ADD(g, "collectd");
597
598   CHECK_SUCCESS(yajl_gen_map_close(g)); /* END labels */
599
600   /*
601    * annotations
602    */
603   JSON_ADD(g, "annotations");
604   CHECK_SUCCESS(yajl_gen_map_open(g)); /* BEGIN annotations */
605
606   JSON_ADD(g, "summary");
607   JSON_ADD(g, n->message);
608
609   if (format_json_meta(g, n->meta) != 0) {
610     return -1;
611   }
612
613   CHECK_SUCCESS(yajl_gen_map_close(g)); /* END annotations */
614
615   JSON_ADD(g, "startsAt");
616   if (format_time(g, n->time) != 0) {
617     return -1;
618   }
619
620   CHECK_SUCCESS(yajl_gen_map_close(g));   /* END alert */
621   CHECK_SUCCESS(yajl_gen_array_close(g)); /* END array */
622
623   return 0;
624 } /* }}} format_alert */
625
626 /*
627  * Format (prometheus/alertmanager v1):
628  *
629  * [{
630  *   "labels": {
631  *     "alertname": "collectd_cpu",
632  *     "instance":  "host.example.com",
633  *     "severity":  "FAILURE",
634  *     "service":   "collectd",
635  *     "cpu":       "0",
636  *     "type":      "wait"
637  *   },
638  *   "annotations": {
639  *     "summary": "...",
640  *     // meta
641  *   },
642  *   "startsAt": <rfc3339 time>,
643  *   "endsAt": <rfc3339 time>, // not used
644  * }]
645  */
646 int format_json_notification(char *buffer, size_t buffer_size, /* {{{ */
647                              notification_t const *n) {
648   yajl_gen g;
649   unsigned char const *out;
650 #if HAVE_YAJL_V2
651   size_t unused_out_len;
652 #else
653   unsigned int unused_out_len;
654 #endif
655
656   if ((buffer == NULL) || (n == NULL))
657     return EINVAL;
658
659 #if HAVE_YAJL_V2
660   g = yajl_gen_alloc(NULL);
661   if (g == NULL)
662     return -1;
663 #if COLLECT_DEBUG
664   yajl_gen_config(g, yajl_gen_beautify, 1);
665   yajl_gen_config(g, yajl_gen_validate_utf8, 1);
666 #endif
667
668 #else /* !HAVE_YAJL_V2 */
669   yajl_gen_config conf = {0};
670 #if COLLECT_DEBUG
671   conf.beautify = 1;
672   conf.indentString = "  ";
673 #endif
674   g = yajl_gen_alloc(&conf, NULL);
675   if (g == NULL)
676     return -1;
677 #endif
678
679   if (format_alert(g, n) != 0) {
680     yajl_gen_clear(g);
681     yajl_gen_free(g);
682     return -1;
683   }
684
685   /* copy to output buffer */
686   if (yajl_gen_get_buf(g, &out, &unused_out_len) != yajl_gen_status_ok) {
687     yajl_gen_clear(g);
688     yajl_gen_free(g);
689     return -1;
690   }
691   sstrncpy(buffer, (void *)out, buffer_size);
692
693   yajl_gen_clear(g);
694   yajl_gen_free(g);
695   return 0;
696 } /* }}} format_json_notification */
697 #else
698 int format_json_notification(char *buffer, size_t buffer_size, /* {{{ */
699                              notification_t const *n) {
700   ERROR("format_json_notification: Not available (requires libyajl).");
701   return ENOTSUP;
702 } /* }}} int format_json_notification */
703 #endif