Browse Source

TT#82401 add statistics NG command

closes #992
Change-Id: I73284b8da6bc64c6e801f47cf6e00e52235b65ba
changes/15/40715/3
Richard Fuchs 6 years ago
parent
commit
cdcf80c2c1
6 changed files with 197 additions and 0 deletions
  1. +106
    -0
      README.md
  2. +5
    -0
      daemon/control_ng.c
  3. +74
    -0
      daemon/statistics.c
  4. +9
    -0
      include/bencode.h
  5. +1
    -0
      include/control_ng.h
  6. +2
    -0
      include/statistics.h

+ 106
- 0
README.md View File

@ -522,6 +522,7 @@ a string and determines the type of message. Currently the following commands ar
* play media
* stop media
* play DTMF
* statistics
The response dictionary must contain at least one key called `result`. The value can be either `ok` or `error`.
For the `ping` command, the additional value `pong` is allowed. If the result is `error`, then another key
@ -1672,3 +1673,108 @@ received during a generated DTMF event will be suppressed.
The call must be marked for DTMF injection using the `inject DTMF` flag used in both `offer` and `answer`
messages. Enabling this flag forces all audio to go through the transcoding engine, even if input and output
codecs are the same (similar to DTMF transcoding, see above).
`statistics` Message
--------------------
Returns a set of general statistics metrics with identical content and format as the `list jsonstats` CLI
command. Sample return dictionary:
{
"statistics": {
"currentstatistics": {
"sessionsown": 0,
"sessionsforeign": 0,
"sessionstotal": 0,
"transcodedmedia": 0,
"packetrate": 0,
"byterate": 0,
"errorrate": 0
},
"totalstatistics": {
"uptime": "18",
"managedsessions": 0,
"rejectedsessions": 0,
"timeoutsessions": 0,
"silenttimeoutsessions": 0,
"finaltimeoutsessions": 0,
"offertimeoutsessions": 0,
"regularterminatedsessions": 0,
"forcedterminatedsessions": 0,
"relayedpackets": 0,
"relayedpacketerrors": 0,
"zerowaystreams": 0,
"onewaystreams": 0,
"avgcallduration": "0.000000"
},
"intervalstatistics": {
"totalcallsduration": "0.000000",
"minmanagedsessions": 0,
"maxmanagedsessions": 0,
"minofferdelay": "0.000000",
"maxofferdelay": "0.000000",
"avgofferdelay": "0.000000",
"minanswerdelay": "0.000000",
"maxanswerdelay": "0.000000",
"avganswerdelay": "0.000000",
"mindeletedelay": "0.000000",
"maxdeletedelay": "0.000000",
"avgdeletedelay": "0.000000",
"minofferrequestrate": 0,
"maxofferrequestrate": 0,
"avgofferrequestrate": 0,
"minanswerrequestrate": 0,
"maxanswerrequestrate": 0,
"avganswerrequestrate": 0,
"mindeleterequestrate": 0,
"maxdeleterequestrate": 0,
"avgdeleterequestrate": 0
},
"controlstatistics": {
"proxies": [
{
"proxy": "127.0.0.1",
"pingcount": 0,
"offercount": 0,
"answercount": 0,
"deletecount": 0,
"querycount": 0,
"listcount": 0,
"startreccount": 0,
"stopreccount": 0,
"startfwdcount": 0,
"stopfwdcount": 0,
"blkdtmfcount": 0,
"unblkdtmfcount": 0,
"blkmedia": 0,
"unblkmedia": 0,
"playmedia": 0,
"stopmedia": 0,
"playdtmf": 0,
"statistics": 0,
"errorcount": 0
}
],
"totalpingcount": 0,
"totaloffercount": 0,
"totalanswercount": 0,
"totaldeletecount": 0,
"totalquerycount": 0,
"totallistcount": 0,
"totalstartreccount": 0,
"totalstopreccount": 0,
"totalstartfwdcount": 0,
"totalstopfwdcount": 0,
"totalblkdtmfcount": 0,
"totalunblkdtmfcount": 0,
"totalblkmedia": 0,
"totalunblkmedia": 0,
"totalplaymedia": 0,
"totalstopmedia": 0,
"totalplaydtmf": 0,
"totalstatistics": 0,
"totalerrorcount": 0
}
},
"result": "ok"
}

+ 5
- 0
daemon/control_ng.c View File

@ -15,6 +15,7 @@
#include "socket.h"
#include "log_funcs.h"
#include "main.h"
#include "statistics.h"
mutex_t rtpe_cngs_lock;
@ -260,6 +261,10 @@ static void control_ng_incoming(struct obj *obj, str *buf, const endpoint_t *sin
errstr = call_play_dtmf_ng(dict, resp);
g_atomic_int_inc(&cur->play_dtmf);
break;
case CSH_LOOKUP("statistics"):
errstr = statistics_ng(dict, resp);
g_atomic_int_inc(&cur->statistics);
break;
default:
errstr = "Unrecognized command";
}


+ 74
- 0
daemon/statistics.c View File

@ -521,6 +521,7 @@ GQueue *statistics_gather_metrics(void) {
total.play_media += cur->play_media;
total.stop_media += cur->stop_media;
total.play_dtmf += cur->play_dtmf;
total.statistics += cur->statistics;
total.errors += cur->errors;
HEADER("{", NULL);
METRICsva("proxy", "\"%s\"", sockaddr_print_buf(&cur->proxy));
@ -541,6 +542,7 @@ GQueue *statistics_gather_metrics(void) {
METRICs("playmedia", "%u", cur->play_media);
METRICs("stopmedia", "%u", cur->stop_media);
METRICs("playdtmf", "%u", cur->play_dtmf);
METRICs("statistics", "%u", cur->statistics);
METRICs("errorcount", "%u", cur->errors);
HEADER("}", NULL);
@ -567,6 +569,7 @@ GQueue *statistics_gather_metrics(void) {
METRICs("totalplaymedia", "%u", total.play_media);
METRICs("totalstopmedia", "%u", total.stop_media);
METRICs("totalplaydtmf", "%u", total.play_dtmf);
METRICs("totalstatistics", "%u", total.statistics);
METRICs("totalerrorcount", "%u", total.errors);
HEADER("}", "");
@ -613,3 +616,74 @@ void statistics_init() {
mutex_init(&rtpe_codec_stats_lock);
rtpe_codec_stats = g_hash_table_new(g_str_hash, g_str_equal);
}
const char *statistics_ng(bencode_item_t *input, bencode_item_t *output) {
AUTO_CLEANUP_INIT(GQueue *metrics, statistics_free_metrics, statistics_gather_metrics());
AUTO_CLEANUP_INIT(GQueue bstack, g_queue_clear, G_QUEUE_INIT);
bencode_item_t *dict = output;
const char *sub_label = "statistics"; // top level
bencode_buffer_t *buf = output->buffer;
for (GList *l = metrics->head; l; l = l->next) {
struct stats_metric *m = l->data;
if (!m->label)
continue;
// key:value entry?
if (m->value_short) {
if (m->is_int)
bencode_dictionary_add_integer(dict, bencode_strdup(buf, m->label),
m->int_value);
else {
size_t len = strlen(m->value_short);
if (len >= 2 && m->value_short[0] == '"' && m->value_short[len-1] == '"')
bencode_dictionary_add(dict, bencode_strdup(buf, m->label),
bencode_string_len_dup(buf, m->value_short+1, len-2));
else
bencode_dictionary_add_string_dup(dict, bencode_strdup(buf, m->label),
m->value_short);
}
continue;
}
// list or dict end?
if (m->is_close_bracket) {
dict = g_queue_pop_tail(&bstack);
assert(dict != NULL);
continue;
}
// label without value precedes an immediate sub-entry, so save the label
if (!m->is_bracket) {
assert(sub_label == NULL);
sub_label = m->label;
continue;
}
// open bracket of some sort - new sub-entry follows
bencode_item_t *sub = NULL;
if (m->is_brace)
sub = bencode_dictionary(buf);
else
sub = bencode_list(buf);
assert(sub != NULL);
// is this a dictionary?
if (dict->type == BENCODE_DICTIONARY) {
assert(sub_label != NULL);
bencode_dictionary_add(dict, bencode_strdup(buf, sub_label), sub);
}
else if (dict->type == BENCODE_LIST)
bencode_list_add(dict, sub);
else
abort();
sub_label = NULL;
g_queue_push_tail(&bstack, dict);
dict = sub;
}
return NULL;
}

+ 9
- 0
include/bencode.h View File

@ -86,6 +86,9 @@ void bencode_buffer_destroy_add(bencode_buffer_t *buf, free_func_t, void *);
/* Returns the buffer associated with an item, or NULL if pointer given is NULL */
INLINE bencode_buffer_t *bencode_item_buffer(bencode_item_t *);
/* like strdup() but uses the bencode buffer to store the string */
INLINE char *bencode_strdup(bencode_buffer_t *, const char *);
@ -373,6 +376,12 @@ INLINE bencode_item_t *bencode_str_dup(bencode_buffer_t *buf, const str *s) {
return bencode_string_len_dup(buf, s->s, s->len);
}
INLINE char *bencode_strdup(bencode_buffer_t *buf, const char *s) {
char *ret = bencode_buffer_alloc(buf, strlen(s) + 1);
strcpy(ret, s);
return ret;
}
INLINE bencode_item_t *bencode_dictionary_add(bencode_item_t *dict, const char *key, bencode_item_t *val) {
if (!key)
return NULL;


+ 1
- 0
include/control_ng.h View File

@ -28,6 +28,7 @@ struct control_ng_stats {
int play_media;
int stop_media;
int play_dtmf;
int statistics;
int errors;
};


+ 2
- 0
include/statistics.h View File

@ -2,6 +2,7 @@
#define STATISTICS_H_
#include "aux.h"
#include "bencode.h"
struct call;
struct packet_stream;
@ -126,6 +127,7 @@ void statistics_update_totals(struct packet_stream *) ;
GQueue *statistics_gather_metrics(void);
void statistics_free_metrics(GQueue **);
const char *statistics_ng(bencode_item_t *input, bencode_item_t *output);
void statistics_init(void);


Loading…
Cancel
Save