2 * Copyright (C) 2015-2020 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
22 #include <json-c/json.h>
24 #define AFB_BINDING_VERSION 3
25 #define AFB_BINDING_NO_ROOT
26 #include <afb/afb-binding.h>
29 #include "afb-apiset.h"
30 #include "afb-api-v3.h"
33 #include "afb-trace.h"
34 #include "afb-session.h"
35 #include "afb-error-text.h"
37 #include "wrap-json.h"
39 #include "monitor-api.inc"
42 static const char _verbosity_[] = "verbosity";
43 static const char _apis_[] = "apis";
45 static const char _debug_[] = "debug";
46 static const char _info_[] = "info";
47 static const char _notice_[] = "notice";
48 static const char _warning_[] = "warning";
49 static const char _error_[] = "error";
52 static struct afb_apiset *target_set;
54 int afb_monitor_init(struct afb_apiset *declare_set, struct afb_apiset *call_set)
56 target_set = call_set;
57 return -!afb_api_v3_from_binding(&_afb_binding_monitor, declare_set, call_set);
60 /******************************************************************************
61 **** Monitoring verbosity
62 ******************************************************************************/
65 * Translate verbosity indication to an integer value.
66 * @param v the verbosity indication
67 * @return the verbosity level (0, 1, 2 or 3) or -1 in case of error
69 static int decode_verbosity(struct json_object *v)
74 if (!wrap_json_unpack(v, "i", &level)) {
75 level = level < _VERBOSITY_(Log_Level_Error) ? _VERBOSITY_(Log_Level_Error) : level > _VERBOSITY_(Log_Level_Debug) ? _VERBOSITY_(Log_Level_Debug) : level;
76 } else if (!wrap_json_unpack(v, "s", &s)) {
79 if (!strcasecmp(s, _debug_))
80 level = _VERBOSITY_(Log_Level_Debug);
83 if (!strcasecmp(s, _info_))
84 level = _VERBOSITY_(Log_Level_Info);
87 if (!strcasecmp(s, _notice_))
88 level = _VERBOSITY_(Log_Level_Notice);
91 if (!strcasecmp(s, _warning_))
92 level = _VERBOSITY_(Log_Level_Warning);
95 if (!strcasecmp(s, _error_))
96 level = _VERBOSITY_(Log_Level_Error);
104 * callback for setting verbosity on all apis
105 * @param set the apiset
106 * @param the name of the api to set
107 * @param closure the verbosity to set as an integer casted to a pointer
109 static void set_verbosity_to_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias)
112 afb_apiset_set_logmask(set, name, (int)(intptr_t)closure);
116 * set the verbosity 'level' of the api of 'name'
117 * @param name the api name or "*" for any api or NULL or "" for global verbosity
118 * @param level the verbosity level to set
120 static void set_verbosity_to(const char *name, int level)
122 int mask = verbosity_to_mask(level);
123 if (!name || !name[0])
124 verbosity_set(level);
125 else if (name[0] == '*' && !name[1])
126 afb_apiset_enum(target_set, 1, set_verbosity_to_all_cb, (void*)(intptr_t)mask);
128 afb_apiset_set_logmask(target_set, name, mask);
132 * Set verbosities accordling to specification in 'spec'
133 * @param spec specification of the verbosity to set
135 static void set_verbosity(struct json_object *spec)
138 struct json_object_iterator it, end;
140 if (json_object_is_type(spec, json_type_object)) {
141 it = json_object_iter_begin(spec);
142 end = json_object_iter_end(spec);
143 while (!json_object_iter_equal(&it, &end)) {
144 l = decode_verbosity(json_object_iter_peek_value(&it));
146 set_verbosity_to(json_object_iter_peek_name(&it), l);
147 json_object_iter_next(&it);
150 l = decode_verbosity(spec);
152 set_verbosity_to("", l);
153 set_verbosity_to("*", l);
159 * Translate verbosity level to a protocol indication.
160 * @param level the verbosity
161 * @return the encoded verbosity
163 static struct json_object *encode_verbosity(int level)
165 switch(_DEVERBOSITY_(level)) {
166 case Log_Level_Error: return json_object_new_string(_error_);
167 case Log_Level_Warning: return json_object_new_string(_warning_);
168 case Log_Level_Notice: return json_object_new_string(_notice_);
169 case Log_Level_Info: return json_object_new_string(_info_);
170 case Log_Level_Debug: return json_object_new_string(_debug_);
171 default: return json_object_new_int(level);
176 * callback for getting verbosity of all apis
177 * @param set the apiset
178 * @param the name of the api to set
179 * @param closure the json object to build
181 static void get_verbosity_of_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias)
183 struct json_object *resu = closure;
184 int m = afb_apiset_get_logmask(set, name);
186 json_object_object_add(resu, name, encode_verbosity(verbosity_from_mask(m)));
190 * get in resu the verbosity of the api of 'name'
191 * @param resu the json object to build
192 * @param name the api name or "*" for any api or NULL or "" for global verbosity
194 static void get_verbosity_of(struct json_object *resu, const char *name)
197 if (!name || !name[0])
198 json_object_object_add(resu, "", encode_verbosity(verbosity_get()));
199 else if (name[0] == '*' && !name[1])
200 afb_apiset_enum(target_set, 1, get_verbosity_of_all_cb, resu);
202 m = afb_apiset_get_logmask(target_set, name);
204 json_object_object_add(resu, name, encode_verbosity(verbosity_from_mask(m)));
209 * get verbosities accordling to specification in 'spec'
210 * @param resu the json object to build
211 * @param spec specification of the verbosity to set
213 static struct json_object *get_verbosity(struct json_object *spec)
216 struct json_object *resu;
217 struct json_object_iterator it, end;
219 resu = json_object_new_object();
220 if (json_object_is_type(spec, json_type_object)) {
221 it = json_object_iter_begin(spec);
222 end = json_object_iter_end(spec);
223 while (!json_object_iter_equal(&it, &end)) {
224 get_verbosity_of(resu, json_object_iter_peek_name(&it));
225 json_object_iter_next(&it);
227 } else if (json_object_is_type(spec, json_type_array)) {
228 n = (int)json_object_array_length(spec);
229 for (i = 0 ; i < n ; i++)
230 get_verbosity_of(resu, json_object_get_string(json_object_array_get_idx(spec, i)));
231 } else if (json_object_is_type(spec, json_type_string)) {
232 get_verbosity_of(resu, json_object_get_string(spec));
233 } else if (json_object_get_boolean(spec)) {
234 get_verbosity_of(resu, "");
235 get_verbosity_of(resu, "*");
240 /******************************************************************************
241 **** Manage namelist of api names
242 ******************************************************************************/
245 struct namelist *next;
250 static struct namelist *reverse_namelist(struct namelist *head)
252 struct namelist *previous, *next;
257 head->next = previous;
264 static void add_one_name_to_namelist(struct namelist **head, const char *name, struct json_object *data)
266 size_t length = strlen(name) + 1;
267 struct namelist *item = malloc(length + sizeof *item);
269 ERROR("out of memory");
273 memcpy(item->name, name, length);
278 static void get_apis_namelist_of_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias)
280 struct namelist **head = closure;
281 add_one_name_to_namelist(head, name, NULL);
285 * get apis names as a list accordling to specification in 'spec'
286 * @param spec specification of the apis to get
288 static struct namelist *get_apis_namelist(struct json_object *spec)
291 struct json_object_iterator it, end;
292 struct namelist *head;
295 if (json_object_is_type(spec, json_type_object)) {
296 it = json_object_iter_begin(spec);
297 end = json_object_iter_end(spec);
298 while (!json_object_iter_equal(&it, &end)) {
299 add_one_name_to_namelist(&head,
300 json_object_iter_peek_name(&it),
301 json_object_iter_peek_value(&it));
302 json_object_iter_next(&it);
304 } else if (json_object_is_type(spec, json_type_array)) {
305 n = (int)json_object_array_length(spec);
306 for (i = 0 ; i < n ; i++)
307 add_one_name_to_namelist(&head,
308 json_object_get_string(
309 json_object_array_get_idx(spec, i)),
311 } else if (json_object_is_type(spec, json_type_string)) {
312 add_one_name_to_namelist(&head, json_object_get_string(spec), NULL);
313 } else if (json_object_get_boolean(spec)) {
314 afb_apiset_enum(target_set, 1, get_apis_namelist_of_all_cb, &head);
316 return reverse_namelist(head);
319 /******************************************************************************
321 ******************************************************************************/
324 struct namelist *names;
325 struct json_object *resu;
326 struct json_object *apis;
330 static void describe_first_api(struct desc_apis *desc);
332 static void on_api_description(void *closure, struct json_object *apidesc)
334 struct desc_apis *desc = closure;
335 struct namelist *head = desc->names;
337 if (apidesc || afb_apiset_lookup(target_set, head->name, 1))
338 json_object_object_add(desc->apis, head->name, apidesc);
339 desc->names = head->next;
341 describe_first_api(desc);
344 static void describe_first_api(struct desc_apis *desc)
346 struct namelist *head = desc->names;
348 afb_apiset_describe(target_set, head->name, on_api_description, desc);
350 afb_req_success(desc->req, desc->resu, NULL);
351 afb_req_unref(desc->req);
356 static void describe_apis(afb_req_t req, struct json_object *resu, struct json_object *spec)
358 struct desc_apis *desc;
360 desc = malloc(sizeof *desc);
362 afb_req_fail(req, "out-of-memory", NULL);
364 desc->req = afb_req_addref(req);
366 desc->apis = json_object_new_object();
367 json_object_object_add(desc->resu, _apis_, desc->apis);
368 desc->names = get_apis_namelist(spec);
369 describe_first_api(desc);
373 /******************************************************************************
374 **** Implementation monitoring verbs
375 ******************************************************************************/
377 static void f_get(afb_req_t req)
379 struct json_object *r;
380 struct json_object *apis = NULL;
381 struct json_object *verbosity = NULL;
383 wrap_json_unpack(afb_req_json(req), "{s?:o,s?:o}", _verbosity_, &verbosity, _apis_, &apis);
384 if (!verbosity && !apis)
385 afb_req_success(req, NULL, NULL);
387 r = json_object_new_object();
389 afb_req_fail(req, "out-of-memory", NULL);
392 verbosity = get_verbosity(verbosity);
393 json_object_object_add(r, _verbosity_, verbosity);
396 afb_req_success(req, r, NULL);
398 describe_apis(req, r, apis);
403 static void f_set(afb_req_t req)
405 struct json_object *verbosity = NULL;
407 wrap_json_unpack(afb_req_json(req), "{s?:o}", _verbosity_, &verbosity);
409 set_verbosity(verbosity);
411 afb_req_success(req, NULL, NULL);
415 static void *context_create(void *closure)
417 return afb_trace_create(_afb_binding_monitor.api, NULL);
420 static void context_destroy(void *pointer)
422 struct afb_trace *trace = pointer;
423 afb_trace_unref(trace);
426 static void f_trace(afb_req_t req)
429 struct json_object *add = NULL;
430 struct json_object *drop = NULL;
431 struct afb_trace *trace;
433 trace = afb_req_context(req, 0, context_create, context_destroy, NULL);
434 wrap_json_unpack(afb_req_json(req), "{s?o s?o}", "add", &add, "drop", &drop);
436 rc = afb_trace_add(req, add, trace);
441 rc = afb_trace_drop(req, drop, trace);
445 afb_req_success(req, NULL, NULL);
447 afb_apiset_update_hooks(target_set, NULL);
448 afb_evt_update_hooks();
452 static void f_trace(afb_req_t req)
454 afb_req_reply(req, NULL, afb_error_text_not_available, NULL);
458 static void f_session(afb_req_t req)
460 struct json_object *r = NULL;
461 struct afb_xreq *xreq = xreq_from_req_x2(req);
463 /* check right to call it */
464 if (xreq->context.super) {
465 afb_req_fail(req, "invalid", "reserved to direct clients");
469 /* make the result */
470 wrap_json_pack(&r, "{s:s,s:i,s:i}",
471 "uuid", afb_session_uuid(xreq->context.session),
472 "timeout", afb_session_timeout(xreq->context.session),
473 "remain", afb_session_what_remains(xreq->context.session));
474 afb_req_success(req, r, NULL);