/* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "lib.h"
+#include "unichar.h"
#include "ioloop.h"
#include "array.h"
#include "lib-event-private.h"
#include "event-exporter.h"
#include "str.h"
-#include "json-parser.h"
+#include "json-ostream.h"
#include "hostpid.h"
-static void append_str(string_t *dest, const char *str)
-{
- str_append_c(dest, '"');
- json_append_escaped(dest, str);
- str_append_c(dest, '"');
-}
-
-static void append_str_max_len(string_t *dest, const char *str,
+static void append_str_max_len(struct json_ostream *joutput, const char *str,
const struct metric_export_info *info)
{
- str_append_c(dest, '"');
- if (info->exporter->format_max_field_len == 0)
- json_append_escaped(dest, str);
- else {
- size_t len = strlen(str);
- json_append_escaped_data(dest, (const unsigned char *)str,
- I_MIN(len, info->exporter->format_max_field_len));
- if (len > info->exporter->format_max_field_len)
- str_append(dest, "...");
+ if (info->exporter->format_max_field_len == 0) {
+ json_ostream_nwrite_string(joutput, NULL, str);
+ return;
+ }
+
+ size_t len = strlen(str);
+
+ if (len < info->exporter->format_max_field_len) {
+ json_ostream_nwrite_string(joutput, NULL, str);
+ return;
}
- str_append_c(dest, '"');
+
+ len = uni_utf8_data_truncate((const unsigned char *)str, len,
+ info->exporter->format_max_field_len);
+ json_ostream_nopen_string(joutput, NULL);
+ json_ostream_nwrite_string_data(joutput, NULL, str, len);
+ json_ostream_nwrite_string(joutput, NULL, "...");
+ json_ostream_nclose_string(joutput);
}
static void
-append_strlist(string_t *dest, const ARRAY_TYPE(const_string) *strlist,
+append_strlist(struct json_ostream *joutput,
+ const ARRAY_TYPE(const_string) *strlist,
const struct metric_export_info *info)
{
const char *value;
- bool first = TRUE;
-
- str_append_c(dest, '[');
- array_foreach_elem(strlist, value) {
- if (first)
- first = FALSE;
- else
- str_append_c(dest, ',');
- append_str_max_len(dest, value, info);
- }
- str_append_c(dest, ']');
+
+ json_ostream_ndescend_array(joutput, NULL);
+ array_foreach_elem(strlist, value)
+ append_str_max_len(joutput, value, info);
+ json_ostream_nascend_array(joutput);
}
-static void append_int(string_t *dest, intmax_t val)
+static void append_int(struct json_ostream *joutput, intmax_t val)
{
- str_printfa(dest, "%jd", val);
+ json_ostream_nwrite_number(joutput, NULL, val);
}
-static void append_time(string_t *dest, const struct timeval *time,
- enum event_exporter_time_fmt fmt)
+static void
+append_time(struct json_ostream *joutput, const struct timeval *time,
+ enum event_exporter_time_fmt fmt)
{
+ string_t *time_str = t_str_new(64);
+
switch (fmt) {
case EVENT_EXPORTER_TIME_FMT_NATIVE:
i_panic("JSON does not have a native date/time type");
case EVENT_EXPORTER_TIME_FMT_UNIX:
- event_export_helper_fmt_unix_time(dest, time);
+ event_export_helper_fmt_unix_time(time_str, time);
+ json_ostream_nwrite_number_raw(joutput, NULL, str_c(time_str));
break;
case EVENT_EXPORTER_TIME_FMT_RFC3339:
- str_append_c(dest, '"');
- event_export_helper_fmt_rfc3339_time(dest, time);
- str_append_c(dest, '"');
+ event_export_helper_fmt_rfc3339_time(time_str, time);
+ json_ostream_nwrite_string_buffer(joutput, NULL, time_str);
break;
}
}
-static void append_ip(string_t *dest, const struct ip_addr *ip)
+static void append_ip(struct json_ostream *joutput, const struct ip_addr *ip)
{
- str_append_c(dest, '"');
- str_append(dest, net_ip2addr(ip));
- str_append_c(dest, '"');
+ json_ostream_nwrite_string(joutput, NULL, net_ip2addr(ip));
}
-static void append_field_value(string_t *dest, const struct event_field *field,
- const struct metric_export_info *info)
+static void
+append_field_value(struct json_ostream *joutput,
+ const struct event_field *field,
+ const struct metric_export_info *info)
{
switch (field->value_type) {
case EVENT_FIELD_VALUE_TYPE_STR:
- append_str_max_len(dest, field->value.str, info);
+ append_str_max_len(joutput, field->value.str, info);
break;
case EVENT_FIELD_VALUE_TYPE_INTMAX:
- append_int(dest, field->value.intmax);
+ append_int(joutput, field->value.intmax);
break;
case EVENT_FIELD_VALUE_TYPE_TIMEVAL:
- append_time(dest, &field->value.timeval,
+ append_time(joutput, &field->value.timeval,
info->exporter->time_format);
break;
case EVENT_FIELD_VALUE_TYPE_IP:
- append_ip(dest, &field->value.ip);
+ append_ip(joutput, &field->value.ip);
break;
case EVENT_FIELD_VALUE_TYPE_STRLIST:
- append_strlist(dest, &field->value.strlist, info);
+ append_strlist(joutput, &field->value.strlist, info);
break;
}
}
-static void json_export_name(string_t *dest, struct event *event,
- const struct metric_export_info *info)
+static void
+json_export_name(struct json_ostream *joutput, struct event *event,
+ const struct metric_export_info *info)
{
if ((info->include & EVENT_EXPORTER_INCL_NAME) == 0)
return;
- append_str(dest, "event");
- str_append_c(dest, ':');
- append_str(dest, event->sending_name);
- str_append_c(dest, ',');
+ json_ostream_nwrite_string(joutput, "event", event->sending_name);
}
-static void json_export_hostname(string_t *dest,
- const struct metric_export_info *info)
+static void
+json_export_hostname(struct json_ostream *joutput,
+ const struct metric_export_info *info)
{
if ((info->include & EVENT_EXPORTER_INCL_HOSTNAME) == 0)
return;
- append_str(dest, "hostname");
- str_append_c(dest, ':');
- append_str(dest, my_hostname);
- str_append_c(dest, ',');
+ json_ostream_nwrite_string(joutput, "hostname", my_hostname);
}
-static void json_export_timestamps(string_t *dest, struct event *event,
- const struct metric_export_info *info)
+static void
+json_export_timestamps(struct json_ostream *joutput, struct event *event,
+ const struct metric_export_info *info)
{
if ((info->include & EVENT_EXPORTER_INCL_TIMESTAMPS) == 0)
return;
- append_str(dest, "start_time");
- str_append_c(dest, ':');
- append_time(dest, &event->tv_created, info->exporter->time_format);
- str_append_c(dest, ',');
+ json_ostream_nwrite_object_member(joutput, "start_time");
+ append_time(joutput, &event->tv_created, info->exporter->time_format);
- append_str(dest, "end_time");
- str_append_c(dest, ':');
- append_time(dest, &ioloop_timeval, info->exporter->time_format);
- str_append_c(dest, ',');
+ json_ostream_nwrite_object_member(joutput, "end_time");
+ append_time(joutput, &ioloop_timeval, info->exporter->time_format);
}
-static void json_export_categories(string_t *dest, struct event *event,
- const struct metric_export_info *info)
+static void
+json_export_categories(struct json_ostream *joutput, struct event *event,
+ const struct metric_export_info *info)
{
+ struct event_category_iterator *iter;
+ const struct event_category *cat;
+
if ((info->include & EVENT_EXPORTER_INCL_CATEGORIES) == 0)
return;
- append_str(dest, "categories");
- str_append(dest, ":[");
+ json_ostream_ndescend_array(joutput, "categories");
- event_export_helper_fmt_categories(dest, event, append_str, ",");
+ iter = event_categories_iterate_init(event);
+ while (event_categories_iterate(iter, &cat))
+ json_ostream_nwrite_string(joutput, NULL, cat->name);
+ event_categories_iterate_deinit(&iter);
- str_append(dest, "],");
+ json_ostream_nascend_array(joutput);
}
-static void json_export_fields(string_t *dest, struct event *event,
- const struct metric_export_info *info,
- const unsigned int fields_count,
- const struct metric_field *fields)
+static void
+json_export_fields(struct json_ostream *joutput, struct event *event,
+ const struct metric_export_info *info,
+ const unsigned int fields_count,
+ const struct metric_field *fields)
{
- bool appended = FALSE;
-
if ((info->include & EVENT_EXPORTER_INCL_FIELDS) == 0)
return;
- append_str(dest, "fields");
- str_append(dest, ":{");
+ json_ostream_ndescend_object(joutput, "fields");
if (fields_count == 0) {
/* include all fields */
for (unsigned int i = 0; i < count; i++) {
const struct event_field *field = &fields[i];
- append_str(dest, field->key);
- str_append_c(dest, ':');
- append_field_value(dest, field, info);
- str_append_c(dest, ',');
-
- appended = TRUE;
+ json_ostream_nwrite_object_member(joutput, field->key);
+ append_field_value(joutput, field, info);
}
} else {
for (unsigned int i = 0; i < fields_count; i++) {
if (field == NULL)
continue; /* doesn't exist, skip it */
- append_str(dest, name);
- str_append_c(dest, ':');
- append_field_value(dest, field, info);
- str_append_c(dest, ',');
-
- appended = TRUE;
+ json_ostream_nwrite_object_member(joutput, name);
+ append_field_value(joutput, field, info);
}
}
- /* remove trailing comma */
- if (appended)
- str_truncate(dest, str_len(dest) - 1);
-
- str_append(dest, "},");
+ json_ostream_nascend_object(joutput);
}
/*
return;
}
- str_append_c(dest, '{');
+ struct json_ostream *joutput;
- json_export_name(dest, event, info);
- json_export_hostname(dest, info);
- json_export_timestamps(dest, event, info);
- json_export_categories(dest, event, info);
- json_export_fields(dest, event, info, metric->fields_count,
- metric->fields);
+ joutput = json_ostream_create_str(dest, 0);
+ json_ostream_ndescend_object(joutput, NULL);
- /* remove trailing comma */
- str_truncate(dest, str_len(dest) - 1);
+ json_export_name(joutput, event, info);
+ json_export_hostname(joutput, info);
+ json_export_timestamps(joutput, event, info);
+ json_export_categories(joutput, event, info);
+ json_export_fields(joutput, event, info, metric->fields_count,
+ metric->fields);
- str_append_c(dest, '}');
+ json_ostream_nascend_object(joutput);
+ json_ostream_nfinish_destroy(&joutput);
}