From 1164734afd826ca8cef0a624aa4f4c59ecb1e228 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Fri, 21 Apr 2017 19:04:54 +0200 Subject: [PATCH] afb-monitor: draft of monitoring MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit this is a draft version to be continued. Change-Id: I1062a6f872a2b36d4e0434fb18d1857961d50aab Signed-off-by: José Bollo --- src/CMakeLists.txt | 1 + src/afb-monitor.c | 400 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/afb-monitor.h | 21 +++ src/main.c | 3 + 4 files changed, 425 insertions(+) create mode 100644 src/afb-monitor.c create mode 100644 src/afb-monitor.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fe497fc9..bec9124e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -74,6 +74,7 @@ ADD_LIBRARY(afb-lib STATIC afb-hsrv.c afb-hswitch.c afb-method.c + afb-monitor.c afb-msg-json.c afb-perm.c afb-session.c diff --git a/src/afb-monitor.c b/src/afb-monitor.c new file mode 100644 index 00000000..5d5c12d1 --- /dev/null +++ b/src/afb-monitor.c @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2016, 2017 "IoT.bzh" + * Author José Bollo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include + +#include + +#include "afb-api.h" +#include "afb-apiset.h" +#include "afb-ditf.h" +#include "afb-xreq.h" +#include "verbose.h" + +extern struct afb_apiset *main_apiset; + +/* CAUTION! KEEP VERBS SORTED */ +#define VERBS \ + V(get) \ + V(hook) \ + V(set) + +/** + * Declare functions of verbs + */ +#define F(x) static void f_##x(struct afb_xreq *xreq) +#define V(x) F(x); + VERBS +#undef V + +/** + * Name of the known verbs + */ +static const struct { + const char *name; + void (*function)(struct afb_xreq*); +} verbs[] = { +#define V(x) { .name = #x, .function = f_##x }, + VERBS +#undef V +}; + +/** + * get the function of a verb + * @param verb the name of the verb + * @return the function for the verb or NULL when no verb of name exists + */ +static void (*lookfun(const char *verb))(struct afb_xreq*) +{ + int l, u, i, c; + + l = 0; + u = (int)(sizeof verbs / sizeof *verbs); + while (l < u) { + i = (l + u) >> 1; + c = strcmp(verb, verbs[i].name); + if (c == 0) + return verbs[i].function; + if (c < 0) + u = i; + else + l = i + 1; + } + return NULL; +} + +static void call_cb(void *closure, struct afb_xreq *xreq) +{ + void (*fun)(struct afb_xreq*); + + fun = lookfun(xreq->verb); + if (!fun) + afb_xreq_fail_unknown_verb(xreq); + else + fun(xreq); +} + +static struct afb_api_itf monitor_api_itf = { + .call = call_cb +}; + +int afb_monitor_init() +{ + struct afb_api api; + api.closure = NULL; + api.itf = &monitor_api_itf; + return afb_apiset_add(main_apiset, "monitor", api); +} + +/****************************************************************************** +**** Monitoring verbosity +******************************************************************************/ + +static const char _debug_[] = "debug"; +static const char _info_[] = "info"; +static const char _notice_[] = "notice"; +static const char _warning_[] = "warning"; +static const char _error_[] = "error"; + +/** + * Translate verbosity indication to an integer value. + * @param v the verbosity indication + * @return the verbosity level (0, 1, 2 or 3) or -1 in case of error + */ +static int decode_verbosity(struct json_object *v) +{ + const char *s; + int level = -1; + if (json_object_is_type(v, json_type_int)) { + level = json_object_get_int(v); + level = level < 0 ? 0 : level > 3 ? 3 : level; + } else if (json_object_is_type(v, json_type_string)) { + s = json_object_get_string(v); + switch(*s&~' ') { + case 'D': + if (!strcasecmp(s, _debug_)) + level = 3; + break; + case 'I': + if (!strcasecmp(s, _info_)) + level = 2; + break; + case 'N': + if (!strcasecmp(s, _notice_)) + level = 1; + break; + case 'W': + if (!strcasecmp(s, _warning_)) + level = 1; + break; + case 'E': + if (!strcasecmp(s, _error_)) + level = 0; + break; + } + } + return level; +} + +/** + * callback for setting verbosity on all apis + * @param set the apiset + * @param the name of the api to set + * @param closure the verbosity to set as an integer casted to a pointer + */ +static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, void *closure) +{ + afb_apiset_set_verbosity(set, name, (int)(intptr_t)closure); +} + +/** + * set the verbosity 'level' of the api of 'name' + * @param name the api name or "*" for any api or NULL or "" for global verbosity + * @param level the verbosity level to set + */ +static void set_verbosity_to(const char *name, int level) +{ + if (!name || !name[0]) + verbosity = level; + else if (name[0] == '*' && !name[1]) + afb_apiset_enum(main_apiset, set_verbosity_to_all_cb, (void*)(intptr_t)level); + else + afb_apiset_set_verbosity(main_apiset, name, level); +} + +/** + * Set verbosities accordling to specification in 'spec' + * @param spec specification of the verbosity to set + */ +static void set_verbosity(struct json_object *spec) +{ + int l; + struct json_object_iterator it, end; + + if (json_object_is_type(spec, json_type_object)) { + it = json_object_iter_begin(spec); + end = json_object_iter_end(spec); + while (!json_object_iter_equal(&it, &end)) { + l = decode_verbosity(json_object_iter_peek_value(&it)); + if (l >= 0) + set_verbosity_to(json_object_iter_peek_name(&it), l); + json_object_iter_next(&it); + } + } else { + l = decode_verbosity(spec); + if (l >= 0) { + set_verbosity_to("", l); + set_verbosity_to("*", l); + } + } +} + +/** + * Translate verbosity level to a protocol indication. + * @param level the verbosity + * @return the encoded verbosity + */ +static struct json_object *encode_verbosity(int level) +{ + switch(level) { + case 0: return json_object_new_string(_error_); + case 1: return json_object_new_string(_notice_); + case 2: return json_object_new_string(_info_); + case 3: return json_object_new_string(_debug_); + default: return json_object_new_int(level); + } +} + +/** + * callback for getting verbosity of all apis + * @param set the apiset + * @param the name of the api to set + * @param closure the json object to build + */ +static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, void *closure) +{ + struct json_object *resu = closure; + int l = afb_apiset_get_verbosity(set, name); + if (l >= 0) + json_object_object_add(resu, name, encode_verbosity(l)); +} + +/** + * get in resu the verbosity of the api of 'name' + * @param resu the json object to build + * @param name the api name or "*" for any api or NULL or "" for global verbosity + */ +static void get_verbosity_of(struct json_object *resu, const char *name) +{ + int l; + if (!name || !name[0]) + json_object_object_add(resu, "", encode_verbosity(verbosity)); + else if (name[0] == '*' && !name[1]) + afb_apiset_enum(main_apiset, get_verbosity_of_all_cb, resu); + else { + l = afb_apiset_get_verbosity(main_apiset, name); + if (l >= 0) + json_object_object_add(resu, name, encode_verbosity(l)); + } +} + +/** + * get verbosities accordling to specification in 'spec' + * @param resu the json object to build + * @param spec specification of the verbosity to set + */ +static void get_verbosity(struct json_object *resu, struct json_object *spec) +{ + int i, n; + struct json_object_iterator it, end; + + if (json_object_is_type(spec, json_type_object)) { + it = json_object_iter_begin(spec); + end = json_object_iter_end(spec); + while (!json_object_iter_equal(&it, &end)) { + get_verbosity_of(resu, json_object_iter_peek_name(&it)); + json_object_iter_next(&it); + } + } else if (json_object_is_type(spec, json_type_array)) { + n = json_object_array_length(spec); + for (i = 0 ; i < n ; i++) + get_verbosity_of(resu, json_object_get_string(json_object_array_get_idx(spec, i))); + } else if (json_object_get_boolean(spec)) { + get_verbosity_of(resu, ""); + get_verbosity_of(resu, "*"); + } +} + +/****************************************************************************** +**** Monitoring apis +******************************************************************************/ + +/** + * get apis accordling to specification in 'spec' + * @param resu the json object to build + * @param spec specification of the verbosity to set + */ +static void get_one_api(struct json_object *resu, const char *name, struct json_object *spec) +{ + struct json_object *o; + struct afb_api api; + int rc; + + rc = afb_apiset_lookup(main_apiset, name, &api); + if (!rc) { + o = api.itf->describe ? api.itf->describe(api.closure) : NULL; + json_object_object_add(resu, name, o); + } +} + +/** + * callback for getting verbosity of all apis + * @param set the apiset + * @param the name of the api to set + * @param closure the json object to build + */ +static void get_apis_of_all_cb(struct afb_apiset *set, const char *name, void *closure) +{ + struct json_object *resu = closure; + get_one_api(resu, name, NULL); +} + +/** + * get apis accordling to specification in 'spec' + * @param resu the json object to build + * @param spec specification of the verbosity to set + */ +static void get_apis(struct json_object *resu, struct json_object *spec) +{ + int i, n; + struct json_object_iterator it, end; + + if (json_object_is_type(spec, json_type_object)) { + it = json_object_iter_begin(spec); + end = json_object_iter_end(spec); + while (!json_object_iter_equal(&it, &end)) { + get_one_api(resu, json_object_iter_peek_name(&it), json_object_iter_peek_value(&it)); + json_object_iter_next(&it); + } + } else if (json_object_is_type(spec, json_type_array)) { + n = json_object_array_length(spec); + for (i = 0 ; i < n ; i++) + get_one_api(resu, json_object_get_string(json_object_array_get_idx(spec, i)), NULL); + } else if (json_object_get_boolean(spec)) { + afb_apiset_enum(main_apiset, get_apis_of_all_cb, resu); + } +} + +/****************************************************************************** +**** Implementation monitoring verbs +******************************************************************************/ + +static const char _verbosity_[] = "verbosity"; +static const char _apis_[] = "apis"; + +static void f_get(struct afb_xreq *xreq) +{ + struct json_object *o, *v, *r, *x; + + r = json_object_new_object(); + o = afb_xreq_json(xreq); + + if (json_object_object_get_ex(o, _verbosity_, &v)) { + x = json_object_new_object(); + json_object_object_add(r, _verbosity_, x); + get_verbosity(x, v); + } + + if (json_object_object_get_ex(o, _apis_, &v)) { + x = json_object_new_object(); + json_object_object_add(r, _apis_, x); + get_apis(x, v); + } + + if (!xreq->replied) + afb_xreq_success(xreq, json_object_get(r), NULL); + json_object_put(r); +} + +static void f_set(struct afb_xreq *xreq) +{ + struct json_object *o, *v; + + o = afb_xreq_json(xreq); + if (json_object_object_get_ex(o, _verbosity_, &v)) { + set_verbosity(v); + } + + if (!xreq->replied) + afb_xreq_success(xreq, NULL, NULL); +} + +static void f_hook(struct afb_xreq *xreq) +{ + struct json_object *o, *v; + + o = afb_xreq_json(xreq); + if (json_object_object_get_ex(o, _verbosity_, &v)) { + set_verbosity(v); + } + + if (!xreq->replied) + afb_xreq_success(xreq, NULL, NULL); +} + diff --git a/src/afb-monitor.h b/src/afb-monitor.h new file mode 100644 index 00000000..d8827b99 --- /dev/null +++ b/src/afb-monitor.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016, 2017 "IoT.bzh" + * Author: José Bollo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#pragma once + +extern int afb_monitor_init(); diff --git a/src/main.c b/src/main.c index 3541e44c..0522e708 100644 --- a/src/main.c +++ b/src/main.c @@ -45,6 +45,7 @@ #include "afb-session.h" #include "verbose.h" #include "afb-common.h" +#include "afb-monitor.h" #include "afb-hook.h" #include "sd-fds.h" @@ -560,6 +561,8 @@ static void start() ERROR("can't create main api set"); goto error; } + if (afb_monitor_init() < 0) { + ERROR("failed to setup monitor"); goto error; } -- 2.16.6