hooking: Add hook at global scope
authorJosé Bollo <jose.bollo@iot.bzh>
Tue, 29 Aug 2017 15:58:08 +0000 (17:58 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Tue, 29 Aug 2017 16:02:15 +0000 (18:02 +0200)
Actually the global scope only allows to trace
log messages.

Change-Id: Ib73edf2e3168311b2ad694d857e6647e34884313
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
src/afb-hook.c
src/afb-hook.h
src/afb-trace.c
src/verbose.c
test/monitoring/monitor-base.css
test/monitoring/monitor-demo.css
test/monitoring/monitor-pastel.css
test/monitoring/monitor.html
test/monitoring/monitor.js

index a07d842..1407628 100644 (file)
@@ -90,6 +90,17 @@ struct afb_hook_evt {
        void *closure; /**< closure for callbacks */
 };
 
+/**
+ * Definition of a hook for global
+ */
+struct afb_hook_global {
+       struct afb_hook_global *next; /**< next hook */
+       unsigned refcount; /**< reference count */
+       unsigned flags; /**< hook flags */
+       struct afb_hook_global_itf *itf; /**< interface of hook */
+       void *closure; /**< closure for callbacks */
+};
+
 /* synchronisation across threads */
 static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
 
@@ -105,6 +116,9 @@ static struct afb_hook_svc *list_of_svc_hooks = NULL;
 /* list of hooks for evt */
 static struct afb_hook_evt *list_of_evt_hooks = NULL;
 
+/* list of hooks for global */
+static struct afb_hook_global *list_of_global_hooks = NULL;
+
 /* hook id */
 static unsigned next_hookid = 0;
 
@@ -1159,7 +1173,7 @@ static struct afb_hook_evt_itf hook_evt_default_itf = {
 };
 
 /******************************************************************************
- * section: hooks for tracing service interface (evt)
+ * section: hooks for tracing events interface (evt)
  *****************************************************************************/
 
 #define _HOOK_EVT_(what,...)   \
@@ -1300,3 +1314,144 @@ void afb_hook_unref_evt(struct afb_hook_evt *hook)
                }
        }
 }
+
+/******************************************************************************
+ * section: default callbacks for globals (global)
+ *****************************************************************************/
+
+static void _hook_global_(const char *format, ...)
+{
+       va_list ap;
+       va_start(ap, format);
+       _hook_("global", format, ap);
+       va_end(ap);
+}
+
+static void hook_global_vverbose_default_cb(void *closure, const struct afb_hookid *hookid, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
+{
+       int len;
+       char *msg;
+       va_list ap;
+
+       va_copy(ap, args);
+       len = vasprintf(&msg, fmt, ap);
+       va_end(ap);
+
+       if (len < 0)
+               _hook_global_("vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, func, fmt);
+       else {
+               _hook_global_("vverbose(%d, %s, %d, %s) -> %s", level, file, line, func, msg);
+               free(msg);
+       }
+}
+
+static struct afb_hook_global_itf hook_global_default_itf = {
+       .hook_global_vverbose = hook_global_vverbose_default_cb
+};
+
+/******************************************************************************
+ * section: hooks for tracing globals (global)
+ *****************************************************************************/
+
+#define _HOOK_GLOBAL_(what,...)   \
+       struct afb_hook_global *hook; \
+       struct afb_hookid hookid; \
+       pthread_rwlock_rdlock(&rwlock); \
+       init_hookid(&hookid); \
+       hook = list_of_global_hooks; \
+       while (hook) { \
+               if (hook->itf->hook_global_##what \
+                && (hook->flags & afb_hook_flag_global_##what) != 0) { \
+                       hook->itf->hook_global_##what(hook->closure, &hookid, __VA_ARGS__); \
+               } \
+               hook = hook->next; \
+       } \
+       pthread_rwlock_unlock(&rwlock);
+
+static void afb_hook_global_vverbose(int level, const char *file, int line, const char *func, const char *fmt, va_list args)
+{
+       _HOOK_GLOBAL_(vverbose, level, file ?: "?", line, func ?: "?", fmt, args);
+}
+
+/******************************************************************************
+ * section: hooking globals (global)
+ *****************************************************************************/
+
+static void update_global()
+{
+       struct afb_hook_global *hook;
+       int flags = 0;
+
+       pthread_rwlock_rdlock(&rwlock);
+       hook = list_of_global_hooks;
+       while (hook) {
+               flags = hook->flags;
+               hook = hook->next;
+       }
+       verbose_observer = (flags & afb_hook_flag_global_vverbose) ? afb_hook_global_vverbose : NULL;
+       pthread_rwlock_unlock(&rwlock);
+}
+
+struct afb_hook_global *afb_hook_create_global(int flags, struct afb_hook_global_itf *itf, void *closure)
+{
+       struct afb_hook_global *hook;
+
+       /* alloc the result */
+       hook = calloc(1, sizeof *hook);
+       if (hook == NULL)
+               return NULL;
+
+       /* initialise the rest */
+       hook->refcount = 1;
+       hook->flags = flags;
+       hook->itf = itf ? itf : &hook_global_default_itf;
+       hook->closure = closure;
+
+       /* record the hook */
+       pthread_rwlock_wrlock(&rwlock);
+       hook->next = list_of_global_hooks;
+       list_of_global_hooks = hook;
+       pthread_rwlock_unlock(&rwlock);
+
+       /* update hooking */
+       update_global();
+
+       /* returns it */
+       return hook;
+}
+
+struct afb_hook_global *afb_hook_addref_global(struct afb_hook_global *hook)
+{
+       pthread_rwlock_wrlock(&rwlock);
+       hook->refcount++;
+       pthread_rwlock_unlock(&rwlock);
+       return hook;
+}
+
+void afb_hook_unref_global(struct afb_hook_global *hook)
+{
+       struct afb_hook_global **prv;
+
+       if (hook) {
+               pthread_rwlock_wrlock(&rwlock);
+               if (--hook->refcount)
+                       hook = NULL;
+               else {
+                       /* unlink */
+                       prv = &list_of_global_hooks;
+                       while (*prv && *prv != hook)
+                               prv = &(*prv)->next;
+                       if(*prv)
+                               *prv = hook->next;
+               }
+               pthread_rwlock_unlock(&rwlock);
+               if (hook) {
+                       /* free */
+                       free(hook);
+
+                       /* update hooking */
+                       update_global();
+               }
+       }
+}
+
index 8f7f61d..4334124 100644 (file)
@@ -32,6 +32,11 @@ struct afb_svc;
 struct afb_stored_req;
 struct sd_bus;
 struct sd_event;
+struct afb_hook_xreq;
+struct afb_hook_ditf;
+struct afb_hook_svc;
+struct afb_hook_evt;
+struct afb_hook_global;
 
 /*********************************************************
 * section hookid
@@ -45,7 +50,6 @@ struct afb_hookid
 /*********************************************************
 * section hooking xreq
 *********************************************************/
-struct afb_hook_xreq;
 
 /* individual flags */
 #define afb_hook_flag_req_begin                        0x000001
@@ -301,7 +305,23 @@ extern void afb_hook_evt_name(const char *evt, int id);
 extern void afb_hook_evt_drop(const char *evt, int id);
 
 extern int afb_hook_flags_evt(const char *name);
-extern struct afb_hook_evt *afb_hook_create_evt(const char *name, int flags, struct afb_hook_evt_itf *itf, void *closure);
+extern struct afb_hook_evt *afb_hook_create_evt(const char *pattern, int flags, struct afb_hook_evt_itf *itf, void *closure);
 extern struct afb_hook_evt *afb_hook_addref_evt(struct afb_hook_evt *hook);
 extern void afb_hook_unref_evt(struct afb_hook_evt *hook);
 
+/*********************************************************
+* section hooking global (global interface)
+*********************************************************/
+
+#define afb_hook_flag_global_vverbose                  0x000001
+
+#define afb_hook_flags_global_all      (afb_hook_flag_global_vverbose)
+
+struct afb_hook_global_itf {
+       void (*hook_global_vverbose)(void *closure, const struct afb_hookid *hookid, int level, const char *file, int line, const char *function, const char *fmt, va_list args);
+};
+
+extern struct afb_hook_global *afb_hook_create_global(int flags, struct afb_hook_global_itf *itf, void *closure);
+extern struct afb_hook_global *afb_hook_addref_global(struct afb_hook_global *hook);
+extern void afb_hook_unref_global(struct afb_hook_global *hook);
+
index bc2de6d..2d09840 100644 (file)
@@ -98,6 +98,7 @@ enum trace_type
        Trace_Type_Ditf,        /* ditf hooks */
        Trace_Type_Svc,         /* svc hooks */
        Trace_Type_Evt,         /* evt hooks */
+       Trace_Type_Global,      /* global hooks */
        Trace_Type_Count        /* count of types of hooks */
 };
 
@@ -820,6 +821,60 @@ static struct afb_hook_evt_itf hook_evt_itf = {
        .hook_evt_drop = hook_evt_drop
 };
 
+/*******************************************************************************/
+/*****  trace the globals                                                  *****/
+/*******************************************************************************/
+
+static struct flag global_flags[] = { /* must be sorted by names */
+               { "all",                afb_hook_flags_global_all },
+               { "vverbose",           afb_hook_flag_global_vverbose },
+};
+
+/* get the global value for flag of 'name' */
+static int get_global_flag(const char *name)
+{
+       return get_flag(name, global_flags, (int)(sizeof global_flags / sizeof *global_flags));
+}
+
+static void hook_global(void *closure, const struct afb_hookid *hookid, const char *action, const char *format, ...)
+{
+       va_list ap;
+
+       va_start(ap, format);
+       emit(closure, hookid, "global", "{ss}", format, ap, "action", action);
+       va_end(ap);
+}
+
+static void hook_global_vverbose(void *closure, const struct afb_hookid *hookid, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
+{
+       struct json_object *pos;
+       int len;
+       char *msg;
+       va_list ap;
+
+       pos = NULL;
+       msg = NULL;
+
+       va_copy(ap, args);
+       len = vasprintf(&msg, fmt, ap);
+       va_end(ap);
+
+       if (file)
+               wrap_json_pack(&pos, "{ss si ss*}", "file", file, "line", line, "function", function);
+
+       hook_global(closure, hookid, "vverbose", "{si ss* ss? so*}",
+                                       "level", level,
+                                       "type", verbosity_level_name(level),
+                                       len < 0 ? "format" : "message", len < 0 ? fmt : msg,
+                                       "position", pos);
+
+       free(msg);
+}
+
+static struct afb_hook_global_itf hook_global_itf = {
+       .hook_global_vverbose = hook_global_vverbose,
+};
+
 /*******************************************************************************/
 /*****  abstract types                                                     *****/
 /*******************************************************************************/
@@ -856,7 +911,13 @@ abstracting[Trace_Type_Count] =
                .name = "event",
                .unref =  (void(*)(void*))afb_hook_unref_evt,
                .get_flag = get_evt_flag
-       }
+       },
+       [Trace_Type_Global] =
+       {
+               .name = "global",
+               .unref =  (void(*)(void*))afb_hook_unref_global,
+               .get_flag = get_global_flag
+       },
 };
 
 /*******************************************************************************/
@@ -1149,6 +1210,9 @@ static void addhook(struct desc *desc, enum trace_type type)
        case Trace_Type_Evt:
                hook->handler = afb_hook_create_evt(desc->pattern, desc->flags[type], &hook_evt_itf, hook);
                break;
+       case Trace_Type_Global:
+               hook->handler = afb_hook_create_global(desc->flags[type], &hook_global_itf, hook);
+               break;
        default:
                break;
        }
@@ -1214,17 +1278,22 @@ static void add_evt_flags(void *closure, struct json_object *object)
        add_flags(closure, object, Trace_Type_Evt);
 }
 
+static void add_global_flags(void *closure, struct json_object *object)
+{
+       add_flags(closure, object, Trace_Type_Global);
+}
+
 /* add hooks */
 static void add(void *closure, struct json_object *object)
 {
        int rc;
        struct desc desc;
-       struct json_object *request, *event, *daemon, *service, *sub;
+       struct json_object *request, *event, *daemon, *service, *sub, *global;
 
        memcpy (&desc, closure, sizeof desc);
-       request = event = daemon = service = sub = NULL;
+       request = event = daemon = service = sub = global = NULL;
 
-       rc = wrap_json_unpack(object, "{s?s s?s s?s s?s s?s s?s s?o s?o s?o s?o s?o}",
+       rc = wrap_json_unpack(object, "{s?s s?s s?s s?s s?s s?s s?o s?o s?o s?o s?o s?o}",
                        "name", &desc.name,
                        "tag", &desc.tag,
                        "api", &desc.api,
@@ -1235,6 +1304,7 @@ static void add(void *closure, struct json_object *object)
                        "daemon", &daemon,
                        "service", &service,
                        "event", &event,
+                       "global", &global,
                        "for", &sub);
 
        if (!rc) {
@@ -1261,6 +1331,9 @@ static void add(void *closure, struct json_object *object)
                if (event)
                        wrap_json_optarray_for_all(event, add_evt_flags, &desc);
 
+               if (global)
+                       wrap_json_optarray_for_all(global, add_global_flags, &desc);
+
                /* apply */
                if (sub)
                        wrap_json_optarray_for_all(sub, add, &desc);
index 2d60dfc..e0e3824 100644 (file)
@@ -132,12 +132,16 @@ void verbose(int loglevel, const char *file, int line, const char *function, con
 
 void vverbose(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
 {
-       if (verbose_observer) {
+       void (*observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) = verbose_observer;
+
+       if (!observer)
+               _vverbose_(loglevel, file, line, function, fmt, args);
+       else {
                va_list ap;
                va_copy(ap, args);
-               verbose_observer(loglevel, file, line, function, fmt, ap);
+               _vverbose_(loglevel, file, line, function, fmt, args);
+               observer(loglevel, file, line, function, fmt, ap);
                va_end(ap);
        }
-       _vverbose_(loglevel, file, line, function, fmt, args);
 }
 
index f2de1d9..ff761ae 100644 (file)
@@ -88,8 +88,7 @@ body.on #params, body.on #connect, body.off #disconnect { display: none; }
 /*******************************************************************/
 /* setting for traces */
 
-#apis .trace-evt {
-       visibility: hidden;
+#apis .event, #apis .global {
        display: none;
 }
 
index 87cf0a0..1025b12 100644 (file)
@@ -244,6 +244,7 @@ html {
 .traceevent.daemon, .trace-box.daemon { color: #5af; }
 .traceevent.service, .trace-box.service { color: #0f0; }
 .traceevent.event, .trace-box.event { color: #f52; }
+.traceevent.global, .trace-box.global { color: white; }
 
 .traceevent.closed {
        max-height: 16px;
index 0264bf5..d5cf3f6 100644 (file)
@@ -224,6 +224,7 @@ body {
 .traceevent.daemon, .trace-box.daemon { background: #fdf; }
 .traceevent.service, .trace-box.service { background: #ddf; }
 .traceevent.event, .trace-box.event { background: #dfd; }
+.traceevent.global, .trace-box.global { background: #eee; }
 
 .traceevent.closed {
        max-height: 16px;
index f22a62b..e9572ba 100644 (file)
         <div class="trace-item"><input type="radio" value="extra">extra</input></div>
         <div class="trace-item"><input type="radio" value="all">all</input></div>
       </div>
+      <div class="trace-box global" data-trace="global">
+        <div class="trace-title">trace globals:</div>
+        <div class="trace-item"><input type="radio" value="no" checked>no</input></div>
+        <div class="trace-item"><input type="radio" value="all">all</input></div>
+      </div>
     </div>
   </template>
 
index e1d4be5..bee87e4 100644 (file)
@@ -445,6 +445,7 @@ function gottraceevent(obj) {
                service: function(r) { return r.api + "@" + r.action; },
                daemon: function(r) { return r.api + ":" + r.action; },
                event: function(r) { return r.name + "!" + r.action; },
+               global: function(r) { return "$" + r.action; },
                })[type](desc);
        var tab = makeobj(desc, 4);
        if ("data" in data)