You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules/counters/counters.c

462 lines
10 KiB

/*
* Copyright (C) 2010 iptelorg GmbH
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
* @brief counters/statistics rpcs and script functions
* @file
* @ingroup counters
* Module: counters.
* @author andrei
*/
/*!
* \defgroup counters Counters/statistics
*
*/
#include "../../modparam.h"
#include "../../dprint.h"
#include "../../compiler_opt.h"
#include "../../counters.h"
MODULE_VERSION
/* default script counter group name */
static char* cnt_script_grp = "script";
static int add_script_counter(modparam_t type, void* val);
static int cnt_inc_f(struct sip_msg*, char*, char*);
static int cnt_add_f(struct sip_msg*, char*, char*);
static int cnt_reset_f(struct sip_msg*, char*, char*);
static int cnt_fixup1(void** param, int param_no);
static int cnt_int_fixup(void** param, int param_no);
static cmd_export_t cmds[] = {
{"cnt_inc", cnt_inc_f, 1, cnt_fixup1,
REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|ONSEND_ROUTE},
{"cnt_add", cnt_add_f, 2, cnt_int_fixup,
REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|ONSEND_ROUTE},
{"cnt_reset", cnt_reset_f, 1, cnt_fixup1,
REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|ONSEND_ROUTE},
{0,0,0,0,0}
};
static param_export_t params[] = {
{"script_cnt_grp_name", PARAM_STRING, &cnt_script_grp},
{"script_counter", PARAM_STRING|PARAM_USE_FUNC, add_script_counter},
{0,0,0}
};
static void cnt_get_rpc(rpc_t* rpc, void* ctx);
static const char* cnt_get_doc[] = {
"get counter value (takes group and counter name as parameters)", 0
};
static void cnt_reset_rpc(rpc_t* rpc, void* ctx);
static const char* cnt_reset_doc[] = {
"reset counter (takes group and counter name as parameters)", 0
};
static void cnt_get_raw_rpc(rpc_t* rpc, void* ctx);
static const char* cnt_get_raw_doc[] = {
"get raw counter value (debugging version)", 0
};
static void cnt_grps_list_rpc(rpc_t* rpc, void* ctx);
static const char* cnt_grps_list_doc[] = {
"list all the counter group names", 0
};
static void cnt_var_list_rpc(rpc_t* rpc, void* ctx);
static const char* cnt_var_list_doc[] = {
"list all the counters names in a specified group", 0
};
static void cnt_grp_get_all_rpc(rpc_t* rpc, void* ctx);
static const char* cnt_grp_get_all_doc[] = {
"list all counter names and values in a specified group", 0
};
static void cnt_help_rpc(rpc_t* rpc, void* ctx);
static const char* cnt_help_doc[] = {
"print the description of a counter (group and counter name required).", 0
};
static rpc_export_t counters_rpc[] = {
{"cnt.get", cnt_get_rpc, cnt_get_doc, 0 },
{"cnt.reset", cnt_reset_rpc, cnt_reset_doc, 0 },
{"cnt.get_raw", cnt_get_raw_rpc, cnt_get_raw_doc, 0 },
{"cnt.grps_list", cnt_grps_list_rpc, cnt_grps_list_doc, RET_ARRAY },
{"cnt.var_list", cnt_var_list_rpc, cnt_var_list_doc, RET_ARRAY },
{"cnt.grp_get_all", cnt_grp_get_all_rpc, cnt_grp_get_all_doc, 0 },
{"cnt.help", cnt_help_rpc, cnt_help_doc, 0},
{ 0, 0, 0, 0}
};
struct module_exports exports= {
"counters",
cmds,
counters_rpc, /* RPC methods */
params,
0, /* module initialization function */
0, /* response function */
0, /* destroy function */
0, /* on_cancel function */
0, /* per-child init function */
};
/** parse the the script_counter modparam.
* Format: [grp.]name[( |:)desc]
* E.g.:
* "name" => new counter: *cnt_script_grp."name"
* "grp.name" => new counter: "grp"."name"
* "name desc" => new counter "name", desc = "desc"
* "grp.name desc" => "grp"."name", desc = "desc".
*/
static int add_script_counter(modparam_t type, void* val)
{
char* name;
counter_handle_t h;
int ret;
char* grp;
char* desc;
char* p;
if ((type & PARAM_STRING) == 0) {
BUG("bad parameter type %d\n", type);
goto error;
}
name = (char*) val;
grp = cnt_script_grp; /* default group */
desc = "custom script counter."; /* default desc. */
if ((p = strchr(name, ':')) != 0 ||
(p = strchr(name, ' ')) != 0) {
/* found desc. */
*p = 0;
for(p = p+1; *p && (*p == ' ' || *p == '\t'); p++);
if (*p)
desc = p;
}
if ((p = strchr(name, '.')) != 0) {
/* found group */
grp = name;
*p = 0;
name = p+1;
}
ret = counter_register(&h, grp, name, 0, 0, 0, desc, 0);
if (ret < 0) {
if (ret == -2) {
ERR("counter %s.%s already registered\n", grp, name);
return 0;
}
ERR("failed to register counter %s.%s\n", grp, name);
goto error;
}
return 0;
error:
return -1;
}
static int cnt_fixup1(void** param, int param_no)
{
char* name;
char* grp;
char* p;
counter_handle_t h;
name = (char*)*param;
grp = cnt_script_grp; /* default group */
if ((p = strchr(name, '.')) != 0) {
/* found group */
grp = name;
name = p+1;
*p = 0;
}
if (counter_lookup(&h, grp, name) < 0) {
ERR("counter %s.%s does not exist (forgot to define it?)\n",
grp, name);
return -1;
}
*param = (void*)(long)h.id;
return 0;
}
static int cnt_int_fixup(void** param, int param_no)
{
char* name;
char* grp;
char* p;
counter_handle_t h;
if (param_no == 1) {
name = (char*)*param;
grp = cnt_script_grp; /* default group */
if ((p = strchr(name, '.')) != 0) {
/* found group */
grp = name;
name = p+1;
*p = 0;
}
if (counter_lookup(&h, grp, name) < 0) {
ERR("counter %s.%s does not exist (forgot to define it?)\n",
grp, name);
return -1;
}
*param = (void*)(long)h.id;
} else
return fixup_var_int_2(param, param_no);
return 0;
}
static int cnt_inc_f(struct sip_msg* msg, char* handle, char* bar)
{
counter_handle_t h;
h.id = (long)(void*)handle;
counter_inc(h);
return 1;
}
static int cnt_add_f(struct sip_msg* msg, char* handle, char* val)
{
counter_handle_t h;
int v;
h.id = (long)(void*)handle;
if (unlikely(get_int_fparam(&v, msg, (fparam_t*)val) < 0)) {
ERR("non integer parameter\n");
return -1;
}
counter_add(h, v);
return 1;
}
static int cnt_reset_f(struct sip_msg* msg, char* handle, char* bar)
{
counter_handle_t h;
h.id = (long)(void*)handle;
counter_reset(h);
return 1;
}
static void cnt_grp_get_all(rpc_t* rpc, void* c, char* group);
static void cnt_get_rpc(rpc_t* rpc, void* c)
{
char* group;
char* name;
counter_val_t v;
counter_handle_t h;
if (rpc->scan(c, "s", &group) < 1)
return;
if (rpc->scan(c, "*s", &name) < 1) {
cnt_grp_get_all(rpc, c, group);
return;
}
/* group & name read */
if (counter_lookup(&h, group, name) < 0) {
rpc->fault(c, 400, "non-existent counter %s.%s\n", group, name);
return;
}
v = counter_get_val(h);
rpc->add(c, "d", (int)v);
return;
}
static void cnt_get_raw_rpc(rpc_t* rpc, void* c)
{
char* group;
char* name;
counter_val_t v;
counter_handle_t h;
if (rpc->scan(c, "ss", &group, &name) < 2) {
/* rpc->fault(c, 400, "group and counter name required"); */
return;
}
if (counter_lookup(&h, group, name) < 0) {
rpc->fault(c, 400, "non-existent counter %s.%s\n", group, name);
return;
}
v = counter_get_raw_val(h);
rpc->add(c, "d", (int)v);
return;
}
static void cnt_reset_rpc(rpc_t* rpc, void* c)
{
char* group;
char* name;
counter_handle_t h;
if (rpc->scan(c, "ss", &group, &name) < 2) {
/* rpc->fault(c, 400, "group and counter name required"); */
return;
}
if (counter_lookup(&h, group, name) < 0) {
rpc->fault(c, 400, "non-existent counter %s.%s\n", group, name);
return;
}
counter_reset(h);
return;
}
struct rpc_list_params {
rpc_t* rpc;
void* ctx;
};
/* helper callback for iterating groups or names */
static void rpc_print_name(void* param, str* n)
{
struct rpc_list_params* p;
rpc_t* rpc;
void* ctx;
p = param;
rpc = p->rpc;
ctx = p->ctx;
rpc->add(ctx, "S", n);
}
/* helper callback for iterating on variable names & values*/
static void rpc_print_name_val(void* param, str* g, str* n,
counter_handle_t h)
{
struct rpc_list_params* p;
rpc_t* rpc;
void* s;
p = param;
rpc = p->rpc;
s = p->ctx;
rpc->struct_add(s, "d", n->s, (int)counter_get_val(h));
}
static void cnt_grps_list_rpc(rpc_t* rpc, void* c)
{
struct rpc_list_params packed_params;
packed_params.rpc = rpc;
packed_params.ctx = c;
counter_iterate_grp_names(rpc_print_name, &packed_params);
}
static void cnt_var_list_rpc(rpc_t* rpc, void* c)
{
char* group;
struct rpc_list_params packed_params;
if (rpc->scan(c, "s", &group) < 1) {
/* rpc->fault(c, 400, "group name required"); */
return;
}
packed_params.rpc = rpc;
packed_params.ctx = c;
counter_iterate_grp_var_names(group, rpc_print_name, &packed_params);
}
static void cnt_grp_get_all(rpc_t* rpc, void* c, char* group)
{
void* s;
struct rpc_list_params packed_params;
if (rpc->add(c, "{", &s) < 0) return;
packed_params.rpc = rpc;
packed_params.ctx = s;
counter_iterate_grp_vars(group, rpc_print_name_val, &packed_params);
}
static void cnt_grp_get_all_rpc(rpc_t* rpc, void* c)
{
char* group;
if (rpc->scan(c, "s", &group) < 1) {
/* rpc->fault(c, 400, "group name required"); */
return;
}
cnt_grp_get_all(rpc, c, group);
}
static void cnt_help_rpc(rpc_t* rpc, void* ctx)
{
char* group;
char* name;
char* desc;
counter_handle_t h;
if (rpc->scan(ctx, "ss", &group, &name) < 2) {
/* rpc->fault(c, 400, "group and counter name required"); */
return;
}
if (counter_lookup(&h, group, name) < 0) {
rpc->fault(ctx, 400, "non-existent counter %s.%s\n", group, name);
return;
}
desc = counter_get_doc(h);
if (desc)
rpc->add(ctx, "s", desc);
else
rpc->fault(ctx, 400, "no description for counter %s.%s\n",
group, name);
return;
}
/* vi: set ts=4 sw=4 tw=79:ai:cindent: */