From: Sebastian Harl Date: Sun, 25 Sep 2016 18:54:24 +0000 (+0200) Subject: Merge branch 'master' of git://git.tokkee.org/sysdb X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=commitdiff_plain;h=233d70fd5ffdc770e639da722a8070cb73ec4fc6;hp=2d74729ad602709cae9f48c96c2810ee0c5e340b Merge branch 'master' of git://git.tokkee.org/sysdb --- diff --git a/configure.ac b/configure.ac index c39c4af..c671004 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/src/Makefile.am b/src/Makefile.am index 0a6c8b3..a3a65fd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/core/plugin.c b/src/core/plugin.c index ecd84b5..67f9dfe 100644 --- a/src/core/plugin.c +++ b/src/core/plugin.c @@ -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)) { diff --git a/src/frontend/query.c b/src/frontend/query.c index 302c586..af0aa54 100644 --- a/src/frontend/query.c +++ b/src/frontend/query.c @@ -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", diff --git a/src/include/core/plugin.h b/src/include/core/plugin.h index 6574330..5c299dd 100644 --- a/src/include/core/plugin.h +++ b/src/include/core/plugin.h @@ -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, diff --git a/src/tools/sysdb/command.c b/src/tools/sysdb/command.c index c7ca310..4de2b44 100644 --- a/src/tools/sysdb/command.c +++ b/src/tools/sysdb/command.c @@ -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 index 0000000..703b22e --- /dev/null +++ b/src/tools/sysdb/json.c @@ -0,0 +1,159 @@ +/* + * SysDB - src/tools/sysdb/json.c + * Copyright (C) 2016 Sebastian 'tokkee' Harl + * 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 +#include + +#include +#include + +#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 index 0000000..9fc1a70 --- /dev/null +++ b/src/tools/sysdb/json.h @@ -0,0 +1,44 @@ +/* + * SysDB - src/tools/sysdb/json.h + * Copyright (C) 2016 Sebastian 'tokkee' Harl + * 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 : */ +