aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/supervisor-api.c
diff options
context:
space:
mode:
authorSebastien Douheret <sebastien.douheret@iot.bzh>2018-06-18 00:36:06 +0200
committerSebastien Douheret <sebastien.douheret@iot.bzh>2018-07-10 23:59:54 +0200
commit81c7dd2c3248f0df563c21b444441ef92067167f (patch)
tree9da6ba813af1945eee7026dbefb68ab5e377226c /src/plugins/supervisor-api.c
parent5d0e551a25edeba7df7f64b1370bad7558b9b2f1 (diff)
Improved trace verb to support list of pids
Change-Id: Ia6e650f2a7edf29d1f135fb47e5a513bcd83b3c8 Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
Diffstat (limited to 'src/plugins/supervisor-api.c')
-rw-r--r--src/plugins/supervisor-api.c193
1 files changed, 151 insertions, 42 deletions
diff --git a/src/plugins/supervisor-api.c b/src/plugins/supervisor-api.c
index c21cd8d..bfe448c 100644
--- a/src/plugins/supervisor-api.c
+++ b/src/plugins/supervisor-api.c
@@ -27,6 +27,20 @@
#include "supervisor.h"
#include "wrap-json.h"
+// TODO: replace by a chained list of DAEMON_T*
+static int TracePidsNum = 0;
+static int* TracePidsArr = NULL;
+
+#define TRACE_DAEMON(src, nb, dd, lvl, res) \
+ { \
+ nb++; \
+ json_object_array_add(res, json_object_new_int(dd->pid)); \
+ if ((rc = trace_daemon(src->api, dd, lvl)) < 0) { \
+ AFB_ReqFailF(src->request, "failed", "Trace pid %d error %d", dd->pid, rc); \
+ goto error; \
+ } \
+ }
+
CTLP_CAPI_REGISTER("supervisor");
CTLP_ONLOAD(plugin, ret)
@@ -41,7 +55,7 @@ CTLP_CAPI(list, source, argsJ, eventJ)
getDaemons(source->api, &daemons);
if (daemons == NULL) {
- AFB_ApiError(source->api, "failed");
+ AFB_ReqFail(source->request, "Failed", "Error daemon list null");
return ERROR;
}
@@ -66,7 +80,7 @@ CTLP_CAPI(list, source, argsJ, eventJ)
return 0;
}
-CTLP_CAPI(trace, source, argsJ, queryJ)
+CTLP_CAPI(trace_start, source, argsJ, queryJ)
{
int rc;
json_object* result = NULL;
@@ -74,72 +88,167 @@ CTLP_CAPI(trace, source, argsJ, queryJ)
const char* ws_name = "";
const char* level = NULL;
pid_t pid = -1;
+ json_object* j_pids = NULL;
+ int nb_traced_daemons = 0;
- if (wrap_json_unpack(queryJ, "{s:?i s:?s s:?s}",
- "pid", &pid, "ws", &ws_name, "level", &level)) {
+ // User can ask to trace either
+ // a specific pid or an array of pids or a specific ws name
+ if (wrap_json_unpack(queryJ, "{s:?i s:?o s:?s s:?s s:?s}",
+ "pid", &pid, "pids", &j_pids, "ws", &ws_name, "level", &level)) {
AFB_ReqFail(source->request, "Failed", "Error processing arguments.");
return ERROR;
}
- if (pid == -1 && strlen(ws_name) == 0) {
- AFB_ReqFail(source->request, "failed", "one of pid or ws parameter must be set");
+ if (pid == -1 && j_pids == NULL && strlen(ws_name) == 0) {
+ AFB_ReqFail(source->request, "failed", "one of pid or pids or ws parameter must be set");
+ return ERROR;
+ }
+
+ if (TracePidsNum > 0) {
+ AFB_ReqFail(source->request, "failed", "already tracing");
return ERROR;
}
- AFB_ApiDebug(source->api, "Trace pid: %d ws: %s", pid, ws_name);
+ AFB_ApiDebug(source->api, "Trace ws=%s, pid=%d, pids=%s", ws_name, pid, json_object_to_json_string(j_pids));
+
+ if (j_pids != NULL && json_object_is_type(j_pids, json_type_array)) {
+ TracePidsNum = (int)json_object_array_length(j_pids);
+ TracePidsArr = malloc(sizeof(int) * TracePidsNum);
+ if (TracePidsArr == NULL) {
+ AFB_ReqFail(source->request, "failed", "out of memory");
+ goto error;
+ }
+ int i = 0;
+ while (i < TracePidsNum) {
+ json_object* j_ppid = json_object_array_get_idx(j_pids, i);
+ TracePidsArr[i++] = json_object_get_int(j_ppid);
+ }
+ }
getDaemons(source->api, &daemons);
if (daemons == NULL || daemons->count <= 0) {
AFB_ReqFail(source->request, "failed", "No daemon found");
- return ERROR;
+ goto error;
}
- // search server and client pid
- DAEMON_T *pid_s = NULL, *pid_c = NULL;
+ // search which daemons should be traced
const char* wsn;
+ nb_traced_daemons = 0;
+ result = json_object_new_array();
for (int i = 0; i < daemons->count; i++) {
AFB_ApiDebug(source->api, "_DEBUG_ svr %s",
json_object_to_json_string(daemons->daemons[i]->ws_servers));
AFB_ApiDebug(source->api, "_DEBUG_ cli %s",
json_object_to_json_string(daemons->daemons[i]->ws_clients));
- json_object* ws_servers = daemons->daemons[i]->ws_servers;
- for (int j = 0; j < json_object_array_length(ws_servers); j++) {
-
- wsn = json_object_get_string(json_object_array_get_idx(ws_servers, j++));
- if (wsn && strstr(wsn, ws_name) != NULL) {
- pid_s = daemons->daemons[i];
- break;
+ if (pid != -1 && pid == daemons->daemons[i]->pid) {
+ // Trace a specific pid
+ TRACE_DAEMON(source, nb_traced_daemons, daemons->daemons[i], level, result);
+ TracePidsNum = 1;
+ TracePidsArr = malloc(sizeof(int) * TracePidsNum);
+ if (TracePidsArr == NULL) {
+ AFB_ReqFail(source->request, "failed", "out of memory");
+ goto error;
}
- }
+ TracePidsArr[0] = daemons->daemons[i]->pid;
+ break;
- json_object* ws_clients = daemons->daemons[i]->ws_clients;
- for (int j = 0; j < json_object_array_length(ws_clients); j++) {
- wsn = json_object_get_string(json_object_array_get_idx(ws_clients, j++));
- if (wsn && strstr(wsn, ws_name) != NULL) {
- pid_c = daemons->daemons[i];
- break;
+ } else if (j_pids != NULL) {
+ // Trace from a list of pids
+ for (int j = 0; j < TracePidsNum; j++) {
+ if (TracePidsArr[j] == daemons->daemons[i]->pid) {
+ TRACE_DAEMON(source, nb_traced_daemons, daemons->daemons[i], level, result);
+ }
+ }
+ } else if (ws_name != NULL) {
+ // Trace based on WS name
+ json_object* ws_servers = daemons->daemons[i]->ws_servers;
+ for (int j = 0; j < json_object_array_length(ws_servers); j++) {
+ wsn = json_object_get_string(json_object_array_get_idx(ws_servers, j));
+ if (wsn && strstr(wsn, ws_name) != NULL) {
+ TRACE_DAEMON(source, nb_traced_daemons, daemons->daemons[i], level, result);
+
+ TracePidsNum++;
+ int* tmpPtr = realloc(TracePidsArr, sizeof(int) * TracePidsNum);
+ if (tmpPtr == NULL) {
+ AFB_ReqFail(source->request, "failed", "out of memory");
+ goto error;
+ }
+ TracePidsArr = tmpPtr;
+ TracePidsArr[TracePidsNum - 1] = daemons->daemons[i]->pid;
+ break;
+ }
}
- }
- if (pid_s != NULL && pid_c != NULL) {
- if ((rc = trace_exchange(source->api, pid_s, pid_c, level)) < 0) {
- AFB_ReqFailF(source->request, "failed", "Trace error %d", rc);
+ json_object* ws_clients = daemons->daemons[i]->ws_clients;
+ for (int j = 0; j < json_object_array_length(ws_clients); j++) {
+ wsn = json_object_get_string(json_object_array_get_idx(ws_clients, j));
+ if (wsn && strstr(wsn, ws_name) != NULL) {
+ TRACE_DAEMON(source, nb_traced_daemons, daemons->daemons[i], level, result);
+
+ TracePidsNum++;
+ int* tmpPtr = realloc(TracePidsArr, sizeof(int) * TracePidsNum);
+ if (tmpPtr == NULL) {
+ AFB_ReqFail(source->request, "failed", "out of memory");
+ goto error;
+ }
+ TracePidsArr = tmpPtr;
+ TracePidsArr[TracePidsNum - 1] = daemons->daemons[i]->pid;
+ break;
+ }
}
- break;
}
}
- if (pid_s == NULL || pid_c == NULL) {
- AFB_ReqFail(source->request, "failed", "Cannot determine Server or Client");
+ if (nb_traced_daemons == 0) {
+ AFB_ReqFail(source->request, "failed", "No daemon found match criteria");
+ goto error;
+ }
+
+ AFB_ReqSuccess(source->request, result, "Trace successfully started");
+
+ return 0;
+
+error:
+ if (TracePidsNum > 0)
+ free(TracePidsArr);
+ TracePidsNum = 0;
+ TracePidsArr = NULL;
+ return ERROR;
+}
+
+CTLP_CAPI(trace_stop, source, argsJ, queryJ)
+{
+ int rc, nbErr = 0;
+ json_object* result = NULL;
+
+ if (TracePidsNum == 0) {
+ AFB_ReqFail(source->request, "failed", "Trace already stopped");
return ERROR;
}
- AFB_ReqSuccessF(source->request, result, "Tracing Server pid=%d <-> Client pid=%d", pid_s->pid, pid_c->pid);
+ for (int j = 0; j < TracePidsNum; j++) {
+ rc = trace_drop(source->api, TracePidsArr[j]);
+ if (rc < 0) {
+ // FIMXE - return list of error messages
+ nbErr++;
+ }
+ }
+ if (TracePidsNum > 0)
+ free(TracePidsArr);
+ TracePidsNum = 0;
+ TracePidsArr = NULL;
+
+ if (nbErr) {
+ AFB_ReqFailF(source->request, "failed", "Error while stopping tracing (%d)", nbErr);
+ return ERROR;
+ }
+ AFB_ReqSuccess(source->request, result, "Trace successfully stopped");
return 0;
}
+#if 0 // Not used, implemented in lua for now (see xds-supervisor.lua / _trace_events_)
uint64_t get_ts()
{
struct timespec ts;
@@ -153,7 +262,6 @@ static void cb_harvester_write(void* closure, int status, struct json_object* re
AFB_ApiDebug(dynapi, "SEB cb_harvester_write");
}
-/* SEB Cleanup if move in lua */
static int harvester_post_data(CtlSourceT* source, METRIC_T* metric)
{
int rc;
@@ -177,19 +285,19 @@ static int harvester_post_data(CtlSourceT* source, METRIC_T* metric)
"values", "value", metric->data,
"timestamp", metric->timestamp);
} else {
- AFB_ApiError(source->api, "Unsupported dataType");
+ AFB_ReqFail(source->request, "Failed", "Unsupported dataType");
return ERROR;
}
if (rc < 0) {
- AFB_ApiError(source->api, "Error packing metric, rc=%d", rc);
+ AFB_ReqFail(source->request, "Failed", "Error packing metric, rc=%d", rc);
return rc;
}
rc = wrap_json_pack(&j_query, "{s:s s:i s:o }", "host",
"localhost", "port", 8086, "metric", j_metric);
if (rc < 0) {
- AFB_ApiError(source->api, "Error packing query, rc=%d", rc);
+ AFB_ReqFail(source->request, "Failed", "Error packing query, rc=%d", rc);
return rc;
}
@@ -199,7 +307,7 @@ static int harvester_post_data(CtlSourceT* source, METRIC_T* metric)
/* SEB
rc = AFB_ServiceSync(source->api, SRV_HARVESTER_NAME, "write", j_query, &j_res);
if (rc < 0) {
- AFB_ApiError(source->api, "Error %s write : rc=%d, j_res=%s", SRV_HARVESTER_NAME, rc,
+ AFB_ReqFail(source->request, "Failed", "Error %s write : rc=%d, j_res=%s", SRV_HARVESTER_NAME, rc,
json_object_to_json_string(j_res));
return rc;
}
@@ -221,22 +329,22 @@ CTLP_CAPI(tracing_events, source, argsJ, eventJ)
AFB_ApiDebug(source->api, ">>> RECV Event uid %s : %s", source->uid,
json_object_to_json_string(eventJ));
- if (strcmp(source->uid, "supervisor/trace") != 0) {
+ if (strcmp(source->uid, "xds/supervisor/trace") != 0) {
AFB_ApiNotice(source->api, "WARNING: un-handle uid '%s'", source->uid);
return 0;
}
if ((rc = wrap_json_unpack(eventJ, "{s:?s}", "type", &type)) < 0) {
- AFB_ApiError(source->api, "Cannot decode event type");
+ AFB_ReqFail(source->request, "Failed", "Cannot decode event type");
return ERROR;
}
if (strcmp(type, "request") != 0) {
- AFB_ApiError(source->api, "Cannot retrieve request");
+ AFB_ReqFail(source->request, "Failed", "Cannot retrieve request");
return ERROR;
}
if (!json_object_object_get_ex(eventJ, "request", &request)) {
- AFB_ApiError(source->api, "Cannot decode event request");
+ AFB_ReqFail(source->request, "Failed", "Cannot decode event request");
return ERROR;
}
@@ -253,9 +361,10 @@ CTLP_CAPI(tracing_events, source, argsJ, eventJ)
rc = harvester_post_data(source, &metric);
if (rc < 0) {
- AFB_ApiError(source->api, "ERROR harvester_post_data: rc %d", rc);
+ AFB_ReqFail(source->request, "Failed", "ERROR harvester_post_data: rc %d", rc);
return rc;
}
return 0;
}
+#endif