Forráskód Böngészése

modules/debugger: add dbg_pv_dump config function.

It dumps the content of pv_cache on json format.
Victor Seva 12 éve
szülő
commit
77f5db57c4

+ 2 - 0
modules/debugger/Makefile

@@ -9,4 +9,6 @@ LIBS=
 
 DEFS+=-DKAMAILIO_MOD_INTERFACE
 
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
 include ../../Makefile.modules

+ 376 - 0
modules/debugger/debugger_api.c

@@ -38,6 +38,9 @@
 #include "../../locking.h"
 #include "../../lvalue.h"
 #include "../../hashes.h"
+#include "../../lib/srutils/srjson.h"
+#include "../../xavp.h"
+#include "../pv/pv_xavp.h"
 
 #include "debugger_act.h"
 #include "debugger_api.h"
@@ -1280,3 +1283,376 @@ int dbg_level_mode_fixup(void *temp_handle,
 	}
 	return 0;
 }
+
+int _dbg_get_array_avp_vals(struct sip_msg *msg,
+		pv_param_t *param, srjson_doc_t *jdoc, srjson_t **jobj,
+		str *item_name)
+{
+	struct usr_avp *avp;
+	unsigned short name_type;
+	int_str avp_name;
+	int_str avp_value;
+	struct search_state state;
+	srjson_t *jobjt;
+	memset(&state, 0, sizeof(struct search_state));
+
+	if(pv_get_avp_name(msg, param, &avp_name, &name_type)!=0)
+	{
+		LM_ERR("invalid name\n");
+		return -1;
+	}
+	*jobj = srjson_CreateArray(jdoc);
+	if(*jobj==NULL)
+	{
+		LM_ERR("cannot create json object\n");
+		return -1;
+	}
+	if ((avp=search_first_avp(name_type, avp_name, &avp_value, &state))==0)
+	{
+		goto ok;
+	}
+	do
+	{
+		if(avp->flags & AVP_VAL_STR)
+		{
+			jobjt = srjson_CreateStr(jdoc, avp_value.s.s, avp_value.s.len);
+			if(jobjt==NULL)
+			{
+				LM_ERR("cannot create json object\n");
+				return -1;
+			}
+		} else {
+			jobjt = srjson_CreateNumber(jdoc, avp_value.n);
+			if(jobjt==NULL)
+			{
+				LM_ERR("cannot create json object\n");
+				return -1;
+			}
+		}
+		srjson_AddItemToArray(jdoc, *jobj, jobjt);
+	} while ((avp=search_next_avp(&state, &avp_value))!=0);
+ok:
+	item_name->s = avp_name.s.s;
+	item_name->len = avp_name.s.len;
+	return 0;
+}
+#define DBG_XAVP_DUMP_SIZE 32
+static str* _dbg_xavp_dump[DBG_XAVP_DUMP_SIZE];
+int _dbg_xavp_dump_lookup(pv_param_t *param)
+{
+	unsigned int i = 0;
+	pv_xavp_name_t *xname;
+
+	if(param==NULL)
+		return -1;
+
+	xname = (pv_xavp_name_t*)param->pvn.u.dname;
+
+	while(_dbg_xavp_dump[i]!=NULL&&i<DBG_XAVP_DUMP_SIZE)
+	{
+		if(_dbg_xavp_dump[i]->len==xname->name.len)
+		{
+			if(strncmp(_dbg_xavp_dump[i]->s, xname->name.s, xname->name.len)==0)
+				return 1; /* already dump before */
+		}
+		i++;
+	}
+	if(i==DBG_XAVP_DUMP_SIZE)
+	{
+		LM_WARN("full _dbg_xavp_dump cache array\n");
+		return 0; /* end cache names */
+	}
+	_dbg_xavp_dump[i] = &xname->name;
+	return 0;
+}
+
+void _dbg_get_obj_xavp_val(sr_xavp_t *avp, srjson_doc_t *jdoc, srjson_t **jobj)
+{
+	static char _pv_xavp_buf[128];
+	int result = 0;
+
+	switch(avp->val.type) {
+		case SR_XTYPE_NULL:
+			*jobj = srjson_CreateNull(jdoc);
+		break;
+		case SR_XTYPE_INT:
+			*jobj = srjson_CreateNumber(jdoc, avp->val.v.i);
+		break;
+		case SR_XTYPE_STR:
+			*jobj = srjson_CreateStr(jdoc, avp->val.v.s.s, avp->val.v.s.len);
+		break;
+		case SR_XTYPE_TIME:
+			result = snprintf(_pv_xavp_buf, 128, "%lu", (long unsigned)avp->val.v.t);
+		break;
+		case SR_XTYPE_LONG:
+			result = snprintf(_pv_xavp_buf, 128, "%ld", (long unsigned)avp->val.v.l);
+		break;
+		case SR_XTYPE_LLONG:
+			result = snprintf(_pv_xavp_buf, 128, "%lld", avp->val.v.ll);
+		break;
+		case SR_XTYPE_XAVP:
+			result = snprintf(_pv_xavp_buf, 128, "<<xavp:%p>>", avp->val.v.xavp);
+		break;
+		case SR_XTYPE_DATA:
+			result = snprintf(_pv_xavp_buf, 128, "<<data:%p>>", avp->val.v.data);
+		break;
+		default:
+			LM_WARN("unknown data type\n");
+			*jobj = srjson_CreateNull(jdoc);
+	}
+	if(result<0)
+	{
+		LM_ERR("cannot convert to str\n");
+		*jobj = srjson_CreateNull(jdoc);
+	}
+	else if(*jobj==NULL)
+	{
+		*jobj = srjson_CreateStr(jdoc, _pv_xavp_buf, 128);
+	}
+}
+
+int _dbg_get_obj_avp_vals(str name, sr_xavp_t *xavp, srjson_doc_t *jdoc, srjson_t **jobj)
+{
+	sr_xavp_t *avp = NULL;
+	srjson_t *jobjt = NULL;
+
+	*jobj = srjson_CreateArray(jdoc);
+	if(*jobj==NULL)
+	{
+		LM_ERR("cannot create json object\n");
+		return -1;
+	}
+	avp = xavp;
+	while(avp!=NULL&&!STR_EQ(avp->name,name))
+	{
+		avp = avp->next;
+	}
+	while(avp!=NULL)
+	{
+		_dbg_get_obj_xavp_val(avp, jdoc, &jobjt);
+		srjson_AddItemToArray(jdoc, *jobj, jobjt);
+		jobjt = NULL;
+		avp = xavp_get_next(avp);
+	}
+
+	return 0;
+}
+
+int _dbg_get_obj_xavp_vals(struct sip_msg *msg,
+		pv_param_t *param, srjson_doc_t *jdoc, srjson_t **jobjr,
+		str *item_name)
+{
+	pv_xavp_name_t *xname = (pv_xavp_name_t*)param->pvn.u.dname;
+	sr_xavp_t *xavp = NULL;
+	sr_xavp_t *avp = NULL;
+	srjson_t *jobj = NULL;
+	srjson_t *jobjt = NULL;
+	struct str_list *keys;
+	struct str_list *k;
+
+	*jobjr = srjson_CreateArray(jdoc);
+	if(*jobjr==NULL)
+	{
+		LM_ERR("cannot create json object\n");
+		return -1;
+	}
+
+	item_name->s = xname->name.s;
+	item_name->len = xname->name.len;
+	xavp = xavp_get_by_index(&xname->name, 0, NULL);
+	if(xavp==NULL)
+	{
+		return 0; /* empty */
+	}
+
+	do
+	{
+		if(xavp->val.type==SR_XTYPE_XAVP)
+		{
+			avp = xavp->val.v.xavp;
+			jobj = srjson_CreateObject(jdoc);
+			if(jobj==NULL)
+			{
+				LM_ERR("cannot create json object\n");
+				return -1;
+			}
+			keys = xavp_get_list_key_names(xavp);
+			if(keys!=NULL)
+			{
+				do
+				{
+					_dbg_get_obj_avp_vals(keys->s, avp, jdoc, &jobjt);
+					srjson_AddStrItemToObject(jdoc, jobj, keys->s.s,
+						keys->s.len, jobjt);
+					k = keys;
+					keys = keys->next;
+					pkg_free(k);
+					jobjt = NULL;
+				}while(keys!=NULL);
+			}
+		}
+		if(jobj!=NULL)
+		{
+			srjson_AddItemToArray(jdoc, *jobjr, jobj);
+			jobj = NULL;
+		}
+	}while((xavp = xavp_get_next(xavp))!=0);
+
+	return 0;
+}
+
+int dbg_dump_json(struct sip_msg* msg, unsigned int mask, int level)
+{
+	int i;
+	pv_value_t value;
+	pv_cache_t **_pv_cache = pv_cache_get_table();
+	pv_cache_t *el = NULL;
+	srjson_doc_t jdoc;
+	srjson_t *jobj = NULL;
+	char *output = NULL;
+	str item_name = STR_NULL;
+	static char iname[128];
+	int result = -1;
+
+	if(_pv_cache==NULL)
+	{
+		LM_ERR("cannot access pv_cache\n");
+		return -1;
+	}
+
+	memset(_dbg_xavp_dump, 0, sizeof(str*)*DBG_XAVP_DUMP_SIZE);
+	srjson_InitDoc(&jdoc, NULL);
+	if(jdoc.root==NULL)
+	{
+		jdoc.root = srjson_CreateObject(&jdoc);
+		if(jdoc.root==NULL)
+		{
+			LM_ERR("cannot create json root\n");
+			goto error;
+		}
+	}
+	for(i=0;i<PV_CACHE_SIZE;i++)
+	{
+		el = _pv_cache[i];
+		while(el)
+		{
+			if(!(el->spec.type==PVT_AVP||
+				el->spec.type==PVT_SCRIPTVAR||
+				el->spec.type==PVT_XAVP||
+				el->spec.type==PVT_OTHER)||
+				!((el->spec.type==PVT_AVP&&mask&DBG_DP_AVP)||
+				(el->spec.type==PVT_XAVP&&mask&DBG_DP_XAVP)||
+				(el->spec.type==PVT_SCRIPTVAR&&mask&DBG_DP_SCRIPTVAR)||
+				(el->spec.type==PVT_OTHER&&mask&DBG_DP_OTHER))||
+				(el->spec.trans!=NULL))
+			{
+				el = el->next;
+				continue;
+			}
+			jobj = NULL;
+			item_name.len = 0;
+			item_name.s = 0;
+			iname[0] = '\0';
+			if(el->spec.type==PVT_AVP)
+			{
+				if(el->spec.pvp.pvi.type==PV_IDX_ALL||
+					(el->spec.pvp.pvi.type==PV_IDX_INT&&el->spec.pvp.pvi.u.ival!=0))
+				{
+					el = el->next;
+					continue;
+				}
+				else
+				{
+					if(_dbg_get_array_avp_vals(msg, &el->spec.pvp, &jdoc, &jobj, &item_name)!=0)
+					{
+						LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s);
+						el = el->next;
+						continue;
+					}
+					if(srjson_GetArraySize(&jdoc, jobj)==0 && !(mask&DBG_DP_NULL))
+					{
+						el = el->next;
+						continue;
+					}
+					snprintf(iname, 128, "$avp(%.*s)", item_name.len, item_name.s);
+				}
+			}
+			else if(el->spec.type==PVT_XAVP)
+			{
+				if(_dbg_xavp_dump_lookup(&el->spec.pvp)!=0)
+				{
+					el = el->next;
+					continue;
+				}
+				if(_dbg_get_obj_xavp_vals(msg, &el->spec.pvp, &jdoc, &jobj, &item_name)!=0)
+				{
+					LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s);
+					el = el->next;
+					continue;
+				}
+				if(srjson_GetArraySize(&jdoc, jobj)==0 && !(mask&DBG_DP_NULL))
+				{
+					el = el->next;
+					continue;
+				}
+				snprintf(iname, 128, "$xavp(%.*s)", item_name.len, item_name.s);
+			}
+			else
+			{
+				if(pv_get_spec_value(msg, &el->spec, &value)!=0)
+				{
+					LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s);
+					el = el->next;
+					continue;
+				}
+				if(value.flags&(PV_VAL_NULL|PV_VAL_EMPTY|PV_VAL_NONE))
+				{
+					if(mask&DBG_DP_NULL)
+					{
+						jobj = srjson_CreateNull(&jdoc);
+					}
+					else
+					{
+						el = el->next;
+						continue;
+					}
+				}else if(value.flags&(PV_VAL_INT)){
+					jobj = srjson_CreateNumber(&jdoc, value.ri);
+				}else if(value.flags&(PV_VAL_STR)){
+					jobj = srjson_CreateStr(&jdoc, value.rs.s, value.rs.len);
+				}else {
+					LM_WARN("el->pvname[%.*s] value[%d] unhandled\n", el->pvname.len, el->pvname.s,
+						value.flags);
+					el = el->next;
+					continue;
+				}
+				if(jobj==NULL)
+				{
+					LM_ERR("el->pvname[%.*s] empty json object\n", el->pvname.len,
+						el->pvname.s);
+					goto error;
+				}
+				snprintf(iname, 128, "%.*s", el->pvname.len, el->pvname.s);
+			}
+			if(jobj!=NULL)
+			{
+				srjson_AddItemToObject(&jdoc, jdoc.root, iname, jobj);
+			}
+			el = el->next;
+		}
+	}
+	output = srjson_PrintUnformatted(&jdoc, jdoc.root);
+	if(output==NULL)
+	{
+		LM_ERR("cannot print json doc\n");
+		goto error;
+	}
+	LOG(level, "%s\n", output);
+	result = 0;
+
+error:
+	if(output!=NULL) jdoc.free_fn(output);
+	srjson_DestroyDoc(&jdoc);
+
+	return result;
+}

+ 8 - 0
modules/debugger/debugger_api.h

@@ -39,5 +39,13 @@ void dbg_enable_mod_levels(void);
 
 int dbg_init_pvcache(void);
 void dbg_enable_log_assign(void);
+
+#define DBG_DP_NULL			1
+#define DBG_DP_AVP			2
+#define DBG_DP_SCRIPTVAR	4
+#define DBG_DP_XAVP			8
+#define DBG_DP_OTHER		16
+#define DBG_DP_ALL			31
+int dbg_dump_json(struct sip_msg* msg, unsigned int mask, int level);
 #endif
 

+ 67 - 0
modules/debugger/debugger_mod.c

@@ -47,6 +47,9 @@ static int w_dbg_breakpoint(struct sip_msg* msg, char* point, char* str2);
 static int fixup_dbg_breakpoint(void** param, int param_no);
 static int dbg_mod_level_param(modparam_t type, void *val);
 
+static int fixup_dbg_pv_dump(void** param, int param_no);
+static int w_dbg_dump(struct sip_msg* msg, char* mask, char* level);
+
 /* parameters */
 extern int _dbg_cfgtrace;
 extern int _dbg_breakpoint;
@@ -62,6 +65,12 @@ static int _dbg_log_assign = 0;
 static cmd_export_t cmds[]={
 	{"dbg_breakpoint", (cmd_function)w_dbg_breakpoint, 1,
 		fixup_dbg_breakpoint, 0, ANY_ROUTE},
+	{"dbg_pv_dump", (cmd_function)w_dbg_dump, 0,
+		fixup_dbg_pv_dump, 0, ANY_ROUTE},
+	{"dbg_pv_dump", (cmd_function)w_dbg_dump, 1,
+		fixup_dbg_pv_dump, 0, ANY_ROUTE},
+	{"dbg_pv_dump", (cmd_function)w_dbg_dump, 2,
+		fixup_dbg_pv_dump, 0, ANY_ROUTE},
 	{0, 0, 0, 0, 0, 0}
 };
 
@@ -175,6 +184,64 @@ static int w_dbg_breakpoint(struct sip_msg* msg, char* point, char* str2)
 	return 1;
 }
 
+/**
+ * fixup for cfg dbg_pv_dump
+ */
+static int fixup_dbg_pv_dump(void** param, int param_no)
+{
+	unsigned int mask;
+	int level;
+	str s = STR_NULL;
+
+	switch(param_no)
+	{
+		case 2:
+			switch(((char*)(*param))[2])
+			{
+				case 'A': level = L_ALERT; break;
+				case 'B': level = L_BUG; break;
+				case 'C': level = L_CRIT2; break;
+				case 'E': level = L_ERR; break;
+				case 'W': level = L_WARN; break;
+				case 'N': level = L_NOTICE; break;
+				case 'I': level = L_INFO; break;
+				case 'D': level = L_DBG; break;
+				default:
+					LM_ERR("unknown log level\n");
+					return E_UNSPEC;
+			}
+			*param = (void*)(long)level;
+		break;
+		case 1:
+			s.s = *param;
+			s.len = strlen(s.s);
+			if(str2int(&s, &mask) == 0) {
+				*param = (void*)(long)mask;
+			}
+			else return E_UNSPEC;
+		break;
+	}
+
+    return 0;
+}
+
+/**
+ * dump pv_cache contents as json
+ */
+static int w_dbg_dump(struct sip_msg* msg, char* mask, char* level)
+{
+	unsigned int umask = DBG_DP_ALL;
+	int ilevel = L_DBG;
+	if(level!=NULL){
+		ilevel = (int)(long)level;
+	}
+	if(mask!=NULL){
+		umask = (unsigned int)(unsigned long)mask;
+	}
+	dbg_dump_json(msg, umask, ilevel);
+	return 1;
+}
+
 /**
  * get the pointer to action structure
  */