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