afb-export: refactor of binder interface
[src/app-framework-binder.git] / src / afb-monitor.c
1 /*
2  * Copyright (C) 2016, 2017 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
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
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <string.h>
21
22 #include <json-c/json.h>
23
24 #include <afb/afb-binding-v2.h>
25
26 #include "afb-api.h"
27 #include "afb-apiset.h"
28 #include "afb-api-so-v2.h"
29 #include "afb-evt.h"
30 #include "afb-xreq.h"
31 #include "afb-trace.h"
32 #include "verbose.h"
33 #include "wrap-json.h"
34
35 #include "monitor-api.inc"
36
37 extern struct afb_apiset *main_apiset;
38
39 static struct afb_binding_data_v2 datav2;
40
41 int afb_monitor_init()
42 {
43         return afb_api_so_v2_add_binding(&_afb_binding_v2_monitor, NULL, main_apiset, &datav2);
44 }
45
46 /******************************************************************************
47 **** Monitoring verbosity
48 ******************************************************************************/
49
50 static const char _debug_[] = "debug";
51 static const char _info_[] = "info";
52 static const char _notice_[] = "notice";
53 static const char _warning_[] = "warning";
54 static const char _error_[] = "error";
55
56 /**
57  * Translate verbosity indication to an integer value.
58  * @param v the verbosity indication
59  * @return the verbosity level (0, 1, 2 or 3) or -1 in case of error
60  */
61 static int decode_verbosity(struct json_object *v)
62 {
63         const char *s;
64         int level = -1;
65
66         if (!wrap_json_unpack(v, "i", &level)) {
67                 level = level < Verbosity_Level_Error ? Verbosity_Level_Error : level > Verbosity_Level_Debug ? Verbosity_Level_Debug : level;
68         } else if (!wrap_json_unpack(v, "s", &s)) {
69                 switch(*s&~' ') {
70                 case 'D':
71                         if (!strcasecmp(s, _debug_))
72                                 level = Verbosity_Level_Debug;
73                         break;
74                 case 'I':
75                         if (!strcasecmp(s, _info_))
76                                 level = Verbosity_Level_Info;
77                         break;
78                 case 'N':
79                         if (!strcasecmp(s, _notice_))
80                                 level = Verbosity_Level_Notice;
81                         break;
82                 case 'W':
83                         if (!strcasecmp(s, _warning_))
84                                 level = Verbosity_Level_Warning;
85                         break;
86                 case 'E':
87                         if (!strcasecmp(s, _error_))
88                                 level = Verbosity_Level_Error;
89                         break;
90                 }
91         }
92         return level;
93 }
94
95 /**
96  * callback for setting verbosity on all apis
97  * @param set the apiset
98  * @param the name of the api to set
99  * @param closure the verbosity to set as an integer casted to a pointer
100  */
101 static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, void *closure)
102 {
103         afb_apiset_set_verbosity(set, name, (int)(intptr_t)closure);
104 }
105
106 /**
107  * set the verbosity 'level' of the api of 'name'
108  * @param name the api name or "*" for any api or NULL or "" for global verbosity
109  * @param level the verbosity level to set
110  */
111 static void set_verbosity_to(const char *name, int level)
112 {
113         if (!name || !name[0])
114                 verbosity = level;
115         else if (name[0] == '*' && !name[1])
116                 afb_apiset_enum(main_apiset, 1, set_verbosity_to_all_cb, (void*)(intptr_t)level);
117         else
118                 afb_apiset_set_verbosity(main_apiset, name, level);
119 }
120
121 /**
122  * Set verbosities accordling to specification in 'spec'
123  * @param spec specification of the verbosity to set
124  */
125 static void set_verbosity(struct json_object *spec)
126 {
127         int l;
128         struct json_object_iterator it, end;
129
130         if (json_object_is_type(spec, json_type_object)) {
131                 it = json_object_iter_begin(spec);
132                 end = json_object_iter_end(spec);
133                 while (!json_object_iter_equal(&it, &end)) {
134                         l = decode_verbosity(json_object_iter_peek_value(&it));
135                         if (l >= 0)
136                                 set_verbosity_to(json_object_iter_peek_name(&it), l);
137                         json_object_iter_next(&it);
138                 }
139         } else {
140                 l = decode_verbosity(spec);
141                 if (l >= 0) {
142                         set_verbosity_to("", l);
143                         set_verbosity_to("*", l);
144                 }
145         }
146 }
147
148 /**
149  * Translate verbosity level to a protocol indication.
150  * @param level the verbosity
151  * @return the encoded verbosity
152  */
153 static struct json_object *encode_verbosity(int level)
154 {
155         switch(level) {
156         case Verbosity_Level_Error:     return json_object_new_string(_error_);
157         case Verbosity_Level_Warning:   return json_object_new_string(_warning_);
158         case Verbosity_Level_Notice:    return json_object_new_string(_notice_);
159         case Verbosity_Level_Info:      return json_object_new_string(_info_);
160         case Verbosity_Level_Debug:     return json_object_new_string(_debug_);
161         default: return json_object_new_int(level);
162         }
163 }
164
165 /**
166  * callback for getting verbosity of all apis
167  * @param set the apiset
168  * @param the name of the api to set
169  * @param closure the json object to build
170  */
171 static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, void *closure)
172 {
173         struct json_object *resu = closure;
174         int l = afb_apiset_get_verbosity(set, name);
175         if (l >= 0)
176                 json_object_object_add(resu, name, encode_verbosity(l));
177 }
178
179 /**
180  * get in resu the verbosity of the api of 'name'
181  * @param resu the json object to build
182  * @param name the api name or "*" for any api or NULL or "" for global verbosity
183  */
184 static void get_verbosity_of(struct json_object *resu, const char *name)
185 {
186         int l;
187         if (!name || !name[0])
188                 json_object_object_add(resu, "", encode_verbosity(verbosity));
189         else if (name[0] == '*' && !name[1])
190                 afb_apiset_enum(main_apiset, 1, get_verbosity_of_all_cb, resu);
191         else {
192                 l = afb_apiset_get_verbosity(main_apiset, name);
193                 if (l >= 0)
194                         json_object_object_add(resu, name, encode_verbosity(l));
195         }
196 }
197
198 /**
199  * get verbosities accordling to specification in 'spec'
200  * @param resu the json object to build
201  * @param spec specification of the verbosity to set
202  */
203 static struct json_object *get_verbosity(struct json_object *spec)
204 {
205         int i, n;
206         struct json_object *resu;
207         struct json_object_iterator it, end;
208
209         resu = json_object_new_object();
210         if (json_object_is_type(spec, json_type_object)) {
211                 it = json_object_iter_begin(spec);
212                 end = json_object_iter_end(spec);
213                 while (!json_object_iter_equal(&it, &end)) {
214                         get_verbosity_of(resu, json_object_iter_peek_name(&it));
215                         json_object_iter_next(&it);
216                 }
217         } else if (json_object_is_type(spec, json_type_array)) {
218                 n = json_object_array_length(spec);
219                 for (i = 0 ; i < n ; i++)
220                         get_verbosity_of(resu, json_object_get_string(json_object_array_get_idx(spec, i)));
221         } else if (json_object_is_type(spec, json_type_string)) {
222                 get_verbosity_of(resu, json_object_get_string(spec));
223         } else if (json_object_get_boolean(spec)) {
224                 get_verbosity_of(resu, "");
225                 get_verbosity_of(resu, "*");
226         }
227         return resu;
228 }
229
230 /******************************************************************************
231 **** Monitoring apis
232 ******************************************************************************/
233
234 /**
235  * get apis accordling to specification in 'spec'
236  * @param resu the json object to build
237  * @param spec specification of the verbosity to set
238  */
239 static void get_one_api(struct json_object *resu, const char *name, struct json_object *spec)
240 {
241         struct json_object *o;
242
243         o = afb_apiset_describe(main_apiset, name);
244         if (o || afb_apiset_lookup(main_apiset, name, 1))
245                 json_object_object_add(resu, name, o);
246 }
247
248 /**
249  * callback for getting verbosity of all apis
250  * @param set the apiset
251  * @param the name of the api to set
252  * @param closure the json object to build
253  */
254 static void get_apis_of_all_cb(struct afb_apiset *set, const char *name, void *closure)
255 {
256         struct json_object *resu = closure;
257         get_one_api(resu, name, NULL);
258 }
259
260 /**
261  * get apis accordling to specification in 'spec'
262  * @param resu the json object to build
263  * @param spec specification of the verbosity to set
264  */
265 static struct json_object *get_apis(struct json_object *spec)
266 {
267         int i, n;
268         struct json_object *resu;
269         struct json_object_iterator it, end;
270
271         resu = json_object_new_object();
272         if (json_object_is_type(spec, json_type_object)) {
273                 it = json_object_iter_begin(spec);
274                 end = json_object_iter_end(spec);
275                 while (!json_object_iter_equal(&it, &end)) {
276                         get_one_api(resu, json_object_iter_peek_name(&it), json_object_iter_peek_value(&it));
277                         json_object_iter_next(&it);
278                 }
279         } else if (json_object_is_type(spec, json_type_array)) {
280                 n = json_object_array_length(spec);
281                 for (i = 0 ; i < n ; i++)
282                         get_one_api(resu, json_object_get_string(json_object_array_get_idx(spec, i)), NULL);
283         } else if (json_object_is_type(spec, json_type_string)) {
284                 get_one_api(resu, json_object_get_string(spec), NULL);
285         } else if (json_object_get_boolean(spec)) {
286                 afb_apiset_enum(main_apiset, 1, get_apis_of_all_cb, resu);
287         }
288         return resu;
289 }
290
291 /******************************************************************************
292 **** Implementation monitoring verbs
293 ******************************************************************************/
294
295 static const char _verbosity_[] = "verbosity";
296 static const char _apis_[] = "apis";
297
298 static void f_get(struct afb_req req)
299 {
300         struct json_object *r;
301         struct json_object *apis = NULL;
302         struct json_object *verbosity = NULL;
303
304         wrap_json_unpack(afb_req_json(req), "{s?:o,s?:o}", _verbosity_, &verbosity, _apis_, &apis);
305         if (verbosity)
306                 verbosity = get_verbosity(verbosity);
307         if (apis)
308                 apis = get_apis(apis);
309
310         wrap_json_pack(&r, "{s:o*,s:o*}", _verbosity_, verbosity, _apis_, apis);
311         afb_req_success(req, r, NULL);
312 }
313
314 static void f_set(struct afb_req req)
315 {
316         struct json_object *verbosity = NULL;
317
318         wrap_json_unpack(afb_req_json(req), "{s?:o}", _verbosity_, &verbosity);
319         if (verbosity)
320                 set_verbosity(verbosity);
321
322         afb_req_success(req, NULL, NULL);
323 }
324
325 static void *context_create()
326 {
327         return afb_trace_create(&datav2.daemon, NULL);
328 }
329
330 static void context_destroy(void *pointer)
331 {
332         struct afb_trace *trace = pointer;
333         afb_trace_unref(trace);
334 }
335
336 static void f_trace(struct afb_req req)
337 {
338         int rc;
339         struct json_object *add = NULL;
340         struct json_object *drop = NULL;
341         struct afb_trace *trace;
342
343         trace = afb_req_context(req, context_create, context_destroy);
344         wrap_json_unpack(afb_req_json(req), "{s?o s?o}", "add", &add, "drop", &drop);
345         if (add) {
346                 rc = afb_trace_add(req, add, trace);
347                 if (rc)
348                         goto end;
349         }
350         if (drop) {
351                 rc = afb_trace_drop(req, drop, trace);
352                 if (rc)
353                         goto end;
354         }
355         afb_req_success(req, NULL, NULL);
356 end:
357         afb_apiset_update_hooks(main_apiset, NULL);
358         afb_evt_update_hooks();
359 }
360