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