Code

Merge branch 'master' of git://git.tokkee.org/sysdb
authorSebastian Harl <sh@tokkee.org>
Sun, 25 Sep 2016 18:54:24 +0000 (20:54 +0200)
committerSebastian Harl <sh@tokkee.org>
Sun, 25 Sep 2016 18:54:24 +0000 (20:54 +0200)
configure.ac
src/Makefile.am
src/core/plugin.c
src/frontend/query.c
src/include/core/plugin.h
src/tools/sysdb/command.c
src/tools/sysdb/json.c [new file with mode: 0644]
src/tools/sysdb/json.h [new file with mode: 0644]

index c39c4af2fc726a3779b641954e054781a9d76430..c6710041cb5c631f50041f73f1e2f662b1dc7109 100644 (file)
@@ -473,6 +473,17 @@ if test "x$with_libdbi" = "xyes"; then
 fi
 AM_CONDITIONAL([BUILD_WITH_LIBDBI], test "x$with_libdbi" = "xyes")
 
+AC_ARG_WITH([libyajl],
+               [AS_HELP_STRING([--with-liyajl], [libyajl support (default: auto)])],
+               [with_libyajl="$withval"],
+               [with_libyajl="yes"])
+if test "x$with_libyajl" = "xyes" || test "x$with_libyajl" = "xauto"; then
+       PKG_CHECK_MODULES([YAJL], [yajl], [have_libyajl="yes"], [have_libyajl="no"])
+fi
+if test "x$with_libyajl" = "xyes"; then
+       AC_DEFINE([HAVE_LIBYAJL], 1, [Define to 1 if you have the 'yajl' library.])
+fi
+
 dnl Required for mocking FILE related functions.
 orig_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -D_GNU_SOURCE"
@@ -730,6 +741,10 @@ librrd_info="$have_librrd"
 if test "x$have_librrd" = "xyes"; then
        librrd_info="yes (version `$PKG_CONFIG --modversion librrd`)"
 fi
+libyajl_info="$have_libyajl"
+if test "x$have_libyajl" = "xyes"; then
+       libyajl_info="yes (version `$PKG_CONFIG --modversion yajl`)"
+fi
 
 AC_MSG_RESULT()
 AC_MSG_RESULT([$PACKAGE_NAME has been configured successfully.])
@@ -760,6 +775,7 @@ AC_MSG_RESULT([    libedit:  . . . . . . . . . $libedit_info])
 AC_MSG_RESULT([    libopenssl: . . . . . . . . $openssl_info])
 AC_MSG_RESULT([    libreadline:  . . . . . . . $have_libreadline])
 AC_MSG_RESULT([    librrd: . . . . . . . . . . $librrd_info])
+AC_MSG_RESULT([    libyajl:  . . . . . . . . . $libyajl_info])
 AC_MSG_RESULT()
 AC_MSG_RESULT([  Backends:])
 AC_MSG_RESULT([    collectd::unixsock: . . . . $enable_collectd_unixsock])
index 0a6c8b33ec13038582e99124c1b15d7bef95d7f1..a3a65fd7ecc27b4e3477a420de916e6554a261dc 100644 (file)
@@ -135,12 +135,14 @@ libsysdb_scanner_la_CFLAGS = @COVERAGE_CFLAGS@ @PROFILING_CFLAGS@ \
 sysdb_SOURCES = tools/sysdb/main.c include/client/sysdb.h \
                tools/sysdb/command.c tools/sysdb/command.h \
                tools/sysdb/input.c tools/sysdb/input.h \
+               tools/sysdb/json.c tools/sysdb/json.h \
                core/object.c include/core/object.h \
                utils/llist.c include/utils/llist.h \
                utils/os.c include/utils/os.h
 sysdb_CFLAGS = -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" \
-               $(AM_CFLAGS) @READLINE_CFLAGS@
-sysdb_LDADD = libsysdb_scanner.la libsysdbclient.la @READLINE_LIBS@ -lm
+               $(AM_CFLAGS) @READLINE_CFLAGS@ @YAJL_CFLAGS@
+sysdb_LDADD = libsysdb_scanner.la libsysdbclient.la \
+               @READLINE_LIBS@ @YAJL_LIBS@ -lm
 endif
 
 sysdbd_SOURCES = tools/sysdbd/main.c include/sysdb.h \
index ecd84b5f9c5f5f525017872ecdf54fe234a6267f..67f9dfea05259610299d5838623b863f820fc87f 100644 (file)
@@ -276,8 +276,13 @@ typedef struct {
        sdb_object_t super;
        sdb_store_writer_t *w;
        sdb_object_t *ud;
+       sdb_query_opts_t opts;
 } query_writer_t;
-#define QUERY_WRITER_INIT(w, ud) { SDB_OBJECT_INIT, (w), (ud) }
+#define QUERY_WRITER_INIT(w, ud) { \
+       SDB_OBJECT_INIT, \
+       (w), (ud), \
+       SDB_DEFAULT_QUERY_OPTS \
+}
 #define QUERY_WRITER(obj) ((query_writer_t *)(obj))
 
 static int
@@ -305,8 +310,11 @@ query_store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data)
        int status;
        size_t i;
 
+       if (! qw->opts.describe_timeseries)
+               /* nothing further to do */
+               return qw->w->store_metric(metric, qw->ud);
+
        for (i = 0; i < metric->stores_num; i++) {
-               /* TODO: Make this optional using query options. */
                sdb_metric_store_t *s = stores + i;
                *s = metric->stores[i];
                infos[i] = sdb_plugin_describe_timeseries(s->type, s->id);
@@ -875,7 +883,7 @@ get_interval(int obj_type, const char *hostname,
        fetch.name = n;
 
        status = sdb_plugin_query(SDB_AST_NODE(&fetch),
-                       &interval_fetcher, SDB_OBJ(&obj), NULL);
+                       &interval_fetcher, SDB_OBJ(&obj), NULL, NULL);
        if ((status < 0) || (lu.obj_type != obj_type) || (lu.last_update == 0)) {
                *interval_out = 0;
                return 0;
@@ -1649,7 +1657,8 @@ sdb_plugin_describe_timeseries(const char *type, const char *id)
 
 int
 sdb_plugin_query(sdb_ast_node_t *ast,
-               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf)
+               sdb_store_writer_t *w, sdb_object_t *wd,
+               sdb_query_opts_t *opts, sdb_strbuf_t *errbuf)
 {
        query_writer_t qw = QUERY_WRITER_INIT(w, wd);
        reader_t *reader;
@@ -1661,6 +1670,9 @@ sdb_plugin_query(sdb_ast_node_t *ast,
        if (! ast)
                return 0;
 
+       if (opts)
+               qw.opts = *opts;
+
        if ((ast->type != SDB_AST_TYPE_FETCH)
                        && (ast->type != SDB_AST_TYPE_LIST)
                        && (ast->type != SDB_AST_TYPE_LOOKUP)) {
index 302c586a6c227de98b7e3ae035f58224a135a7de..af0aa5424eb7eee46af1fb5561dcb27170275f09 100644 (file)
@@ -136,7 +136,8 @@ exec_query(sdb_ast_node_t *ast, sdb_strbuf_t *buf, sdb_strbuf_t *errbuf)
 
        f = sdb_store_json_formatter(buf, type, flags);
        sdb_strbuf_memcpy(buf, &res_type, sizeof(res_type));
-       status = sdb_plugin_query(ast, &sdb_store_json_writer, SDB_OBJ(f), errbuf);
+       status = sdb_plugin_query(ast, &sdb_store_json_writer, SDB_OBJ(f),
+                       &(sdb_query_opts_t){ true }, errbuf);
        if (status < 0)
                sdb_strbuf_clear(buf);
        sdb_store_json_finish(f);
@@ -250,7 +251,8 @@ exec_timeseries(sdb_ast_timeseries_t *ts, sdb_strbuf_t *buf, sdb_strbuf_t *errbu
        opts.end = ts->end;
 
        status = sdb_plugin_query(SDB_AST_NODE(&fetch),
-                       &metric_fetcher, SDB_OBJ(&obj), errbuf);
+                       &metric_fetcher, SDB_OBJ(&obj),
+                       &(sdb_query_opts_t){ true }, errbuf);
        if ((status < 0) || (! st.type) || (! st.id)) {
                sdb_log(SDB_LOG_ERR, "frontend: Failed to fetch time-series '%s/%s' "
                                "- no data-store configured for the stored metric",
index 6574330412417dee9de23b98715fc9ba4882eafe..5c299ddc13193ba0df9073d8b006dcaeab88b975 100644 (file)
@@ -448,10 +448,21 @@ sdb_plugin_fetch_timeseries(const char *type, const char *id,
 sdb_timeseries_info_t *
 sdb_plugin_describe_timeseries(const char *type, const char *id);
 
+/*
+ * sdb_query_opts_t:
+ * Options for tuning the behavior of a query.
+ */
+typedef struct {
+       /* If enabled, populate the time-series info field of each metric. */
+       bool describe_timeseries;
+} sdb_query_opts_t;
+#define SDB_DEFAULT_QUERY_OPTS { false }
+
 /*
  * sdb_plugin_query:
  * Query the store using the query specified by 'ast'. The result will be
- * written to 'buf' and any errors will be written to 'errbuf'.
+ * written to 'buf' and any errors will be written to 'errbuf'. The query
+ * options default to SDB_DEFAULT_QUERY_OPTS.
  *
  * Returns:
  *  - 0 on success
@@ -459,7 +470,8 @@ sdb_plugin_describe_timeseries(const char *type, const char *id);
  */
 int
 sdb_plugin_query(sdb_ast_node_t *ast,
-               sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf);
+               sdb_store_writer_t *w, sdb_object_t *wd,
+               sdb_query_opts_t *opts, sdb_strbuf_t *errbuf);
 
 /*
  * sdb_plugin_store_host, sdb_plugin_store_service, sdb_plugin_store_metric,
index c7ca310a086230268272b46dcb7c268733b106b8..4de2b44e4fc79245027a22c5c2932bd82b46f742 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "tools/sysdb/command.h"
 #include "tools/sysdb/input.h"
+#include "tools/sysdb/json.h"
 
 #include "frontend/proto.h"
 #include "utils/error.h"
@@ -89,7 +90,9 @@ data_printer(sdb_strbuf_t *buf)
        /* At the moment, we don't care about the result type. We simply print the
         * result without further parsing it. */
        sdb_strbuf_skip(buf, 0, sizeof(uint32_t));
-       printf("%s\n", sdb_strbuf_string(buf));
+       if (sdb_json_print(buf))
+               sdb_log(SDB_LOG_ERR, "Failed to print result");
+       printf("\n");
 } /* data_printer */
 
 static struct {
diff --git a/src/tools/sysdb/json.c b/src/tools/sysdb/json.c
new file mode 100644 (file)
index 0000000..703b22e
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * SysDB - src/tools/sysdb/json.c
+ * Copyright (C) 2016 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#      include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "sysdb.h"
+
+#include "utils/error.h"
+#include "utils/strbuf.h"
+#include "tools/sysdb/json.h"
+
+#include <yajl/yajl_parse.h>
+#include <yajl/yajl_gen.h>
+
+#include <unistd.h>
+#include <stdio.h>
+
+#ifdef HAVE_LIBYAJL
+
+/*
+ * YAJL callbacks
+ */
+
+#define GEN(obj) ((yajl_gen)(obj))
+#define OK(cb) ((cb) == yajl_gen_status_ok)
+
+static int
+gen_null(void *ctx) { return OK(yajl_gen_null(GEN(ctx))); }
+
+static int
+gen_boolean(void *ctx, int v) { return OK(yajl_gen_bool(GEN(ctx), v)); }
+
+static int
+gen_number(void *ctx, const char *v, size_t l)
+{
+       return OK(yajl_gen_number(GEN(ctx), v, l));
+}
+
+static int
+gen_string(void *ctx, const unsigned char *v, size_t l)
+{
+       return OK(yajl_gen_string(GEN(ctx), v, l));
+}
+
+static int
+gen_start_map(void *ctx) { return OK(yajl_gen_map_open(GEN(ctx))); }
+
+static int
+gen_end_map(void *ctx) { return OK(yajl_gen_map_close(GEN(ctx))); }
+
+static int
+gen_start_array(void *ctx) { return OK(yajl_gen_array_open(GEN(ctx))); }
+
+static int
+gen_end_array(void *ctx) { return OK(yajl_gen_array_close(GEN(ctx))); }
+
+static yajl_callbacks reformatters = {
+       gen_null,
+       gen_boolean,
+       NULL, /* gen_integer; */
+       NULL, /* gen_doube; both default to gen_number */
+       gen_number,
+       gen_string,
+       gen_start_map,
+       gen_string,
+       gen_end_map,
+       gen_start_array,
+       gen_end_array,
+};
+
+static void
+printer(void __attribute__((unused)) *ctx, const char *str, size_t len)
+{
+       write(1, str, len);
+} /* printer */
+
+#endif /* HAVE_LIBYAJL */
+
+/*
+ * public API
+ */
+
+int
+sdb_json_print(sdb_strbuf_t *buf)
+{
+#ifdef HAVE_LIBYAJL
+       const unsigned char *json;
+       size_t json_len;
+
+       yajl_handle h;
+       yajl_gen gen;
+       yajl_status status;
+
+       int ret = 0;
+
+       gen = yajl_gen_alloc(/* alloc_funcs */ NULL);
+       if (! gen)
+               return -1;
+
+       yajl_gen_config(gen, yajl_gen_beautify, 1);
+       yajl_gen_config(gen, yajl_gen_validate_utf8, 1);
+       yajl_gen_config(gen, yajl_gen_print_callback, printer, NULL);
+
+       h = yajl_alloc(&reformatters, /* alloc_funcs */ NULL, (void *)gen);
+       if (! h) {
+               yajl_gen_free(gen);
+               return -1;
+       }
+
+       json = (const unsigned char *)sdb_strbuf_string(buf);
+       json_len = sdb_strbuf_len(buf);
+       status = yajl_parse(h, json, json_len);
+       if (status == yajl_status_ok)
+               status = yajl_complete_parse(h);
+
+       if (status != yajl_status_ok) {
+               unsigned char *err = yajl_get_error(h, 1, json, json_len);
+               sdb_log(SDB_LOG_ERR, "%s", err);
+               yajl_free_error(h, err);
+               ret = -1;
+       }
+
+       yajl_gen_free(gen);
+       yajl_free(h);
+       return ret;
+#else /* HAVE_LIBYAJL */
+       printf("%s\n", sdb_strbuf_string(buf));
+       return 0;
+#endif /* HAVE_LIBYAJL */
+} /* sdb_json_print */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
diff --git a/src/tools/sysdb/json.h b/src/tools/sysdb/json.h
new file mode 100644 (file)
index 0000000..9fc1a70
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * SysDB - src/tools/sysdb/json.h
+ * Copyright (C) 2016 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "utils/strbuf.h"
+
+#ifndef SYSDB_JSON_H
+#define SYSDB_JSON_H 1
+
+/*
+ * sdb_json_print:
+ * Format the JSON string stored in the specified buffer. The output is
+ * printed to the standard output channel.
+ */
+int
+sdb_json_print(sdb_strbuf_t *buf);
+
+#endif /* SYSDB_JSON_H */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+