From e5250430035b6e620dd1ac86d2fb9ebcbc717d84 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Mon, 25 May 2015 12:34:25 +0300 Subject: [PATCH] debugger: add support for static and dynamic, module specific, logging facility Added two new debugger params which will support setting per module logging facility. This is useful when one might want to change logging for a certain module to a different file. mod_facility_mode (0/1) is used for enabling this. mod_facility (str) is used for setting the facility. --- dprint.c | 45 +++++++- dprint.h | 17 ++- modules/debugger/debugger_api.c | 176 ++++++++++++++++++++++++++++- modules/debugger/debugger_api.h | 2 + modules/debugger/debugger_config.c | 6 +- modules/debugger/debugger_config.h | 3 +- modules/debugger/debugger_mod.c | 47 +++++++- 7 files changed, 282 insertions(+), 14 deletions(-) diff --git a/dprint.c b/dprint.c index 71b89e6dd59..ebb5059a307 100644 --- a/dprint.c +++ b/dprint.c @@ -103,12 +103,15 @@ int log_facility_fixup(void *handle, str *gname, str *name, void **val) */ /* value for unset local log level */ -#define UNSET_LOCAL_DEBUG_LEVEL -255 +#define UNSET_LOCAL_DEBUG_LEVEL -255 +#define UNSET_LOCAL_DEBUG_FACILITY -255 /* the local debug log level */ static int _local_debug_level = UNSET_LOCAL_DEBUG_LEVEL; +static int _local_debug_facility = UNSET_LOCAL_DEBUG_FACILITY; /* callback to get per module debug level */ static get_module_debug_level_f _module_debug_level = NULL; +static get_module_debug_facility_f _module_debug_facility = NULL; /** * @brief set callback function for per module debug level @@ -118,12 +121,17 @@ void set_module_debug_level_cb(get_module_debug_level_f f) _module_debug_level = f; } +void set_module_debug_facility_cb(get_module_debug_facility_f f) +{ + _module_debug_facility = f; +} + /** * @brief return the log level - the local one if it set, * otherwise the global value */ int get_debug_level(char *mname, int mnlen) { - int mlevel = L_DBG; + int mlevel; /*important -- no LOGs inside, because it will loop */ if(unlikely(_module_debug_level!=NULL && mnlen>0)) { if(_module_debug_level(mname, mnlen, &mlevel)==0) { @@ -134,6 +142,23 @@ int get_debug_level(char *mname, int mnlen) { _local_debug_level : cfg_get(core, core_cfg, debug); } +/** + * @brief return the log facility - the local one if it set, + * otherwise the global value + */ +int get_debug_facility(char *mname, int mnlen) { + int mfacility; + /*important -- no LOGs inside, because it will loop */ + if(unlikely(_module_debug_facility!=NULL && mnlen>0)) { + if(_module_debug_facility(mname, mnlen, &mfacility)==0) { + return mfacility; + } + } + return (_local_debug_facility != UNSET_LOCAL_DEBUG_FACILITY) ? + _local_debug_facility : cfg_get(core, core_cfg, log_facility); +} + + /** * @brief set the local debug log level */ @@ -150,6 +175,22 @@ void reset_local_debug_level(void) _local_debug_level = UNSET_LOCAL_DEBUG_LEVEL; } +/** + * @brief set the local debug log facility + */ +void set_local_debug_facility(int facility) +{ + _local_debug_facility = facility; +} + +/** + * @brief reset the local debug log facility + */ +void reset_local_debug_facility(void) +{ + _local_debug_facility = UNSET_LOCAL_DEBUG_FACILITY; +} + typedef struct log_level_color { char f; char b; diff --git a/dprint.h b/dprint.h index 5729f96607e..a16f0ae96a2 100644 --- a/dprint.h +++ b/dprint.h @@ -130,10 +130,15 @@ struct log_level_info { /** @brief per process debug level handling */ int get_debug_level(char *mname, int mnlen); +int get_debug_facility(char *mname, int mnlen); void set_local_debug_level(int level); +void set_local_debug_facility(int facility); void reset_local_debug_level(void); +void reset_local_debug_facility(void); typedef int (*get_module_debug_level_f)(char *mname, int mnlen, int *mlevel); +typedef int (*get_module_debug_facility_f)(char *mname, int mnlen, int *mfacility); void set_module_debug_level_cb(get_module_debug_level_f f); +void set_module_debug_facility_cb(get_module_debug_facility_f f); #define is_printable(level) (get_debug_level(LOG_MNAME, LOG_MNAME_LEN)>=(level)) extern struct log_level_info log_level_info[]; @@ -141,7 +146,7 @@ extern char *log_name; #ifndef NO_SIG_DEBUG /** @brief protection against "simultaneous" printing from signal handlers */ -extern volatile int dprint_crit; +extern volatile int dprint_crit; #endif int str2facility(char *s); @@ -210,7 +215,7 @@ void log_prefix_init(void); syslog(LOG2SYSLOG_LEVEL(level) | \ (((facility) != DEFAULT_FACILITY) ? \ (facility) : \ - cfg_get(core, core_cfg, log_facility)), \ + get_debug_facility(LOG_MNAME, LOG_MNAME_LEN)), \ "%s: %s" fmt, \ (lname)?(lname):LOG_LEVEL2NAME(level),\ (prefix), __VA_ARGS__); \ @@ -227,13 +232,13 @@ void log_prefix_init(void); syslog(LOG2SYSLOG_LEVEL(L_ALERT) | \ (((facility) != DEFAULT_FACILITY) ? \ (facility) : \ - cfg_get(core, core_cfg, log_facility)),\ + get_debug_facility(LOG_MNAME, LOG_MNAME_LEN)), \ "%s" fmt, (prefix), __VA_ARGS__); \ else \ syslog(LOG2SYSLOG_LEVEL(L_DBG) | \ (((facility) != DEFAULT_FACILITY) ? \ (facility) : \ - cfg_get(core, core_cfg, log_facility)),\ + get_debug_facility(LOG_MNAME, LOG_MNAME_LEN)), \ "%s" fmt, (prefix), __VA_ARGS__); \ } \ } \ @@ -298,7 +303,7 @@ void log_prefix_init(void); syslog(LOG2SYSLOG_LEVEL(__llevel) |\ (((facility) != DEFAULT_FACILITY) ? \ (facility) : \ - cfg_get(core, core_cfg, log_facility)), \ + get_debug_facility(LOG_MNAME, LOG_MNAME_LEN)), \ "%.*s%s: %s" fmt,\ log_prefix_val->len, log_prefix_val->s, \ (lname)?(lname):LOG_LEVEL2NAME(__llevel),\ @@ -307,7 +312,7 @@ void log_prefix_init(void); syslog(LOG2SYSLOG_LEVEL(__llevel) |\ (((facility) != DEFAULT_FACILITY) ? \ (facility) : \ - cfg_get(core, core_cfg, log_facility)), \ + get_debug_facility(LOG_MNAME, LOG_MNAME_LEN)), \ "%s: %s" fmt,\ (lname)?(lname):LOG_LEVEL2NAME(__llevel),\ (prefix) , ## args); \ diff --git a/modules/debugger/debugger_api.c b/modules/debugger/debugger_api.c index 5031c1fd9f9..3912c33e789 100644 --- a/modules/debugger/debugger_api.c +++ b/modules/debugger/debugger_api.c @@ -985,12 +985,44 @@ static void dbg_rpc_mod_level(rpc_t* rpc, void* ctx){ if(dbg_set_mod_debug_level(value.s, value.len, &l)<0) { - rpc->fault(ctx, 500, "cannot store parameter\n"); + rpc->fault(ctx, 500, "cannot store parameter"); return; } rpc->add(ctx, "s", "200 ok"); } +/** + * + */ +static const char* dbg_rpc_mod_facility_doc[2] = { + "Specify module log facility", + 0 +}; + +static void dbg_rpc_mod_facility(rpc_t* rpc, void* ctx) { + int fl; + str value = {0, 0}; + str facility = {0, 0}; + + if (rpc->scan(ctx, "SS", &value, &facility) < 1) + { + rpc->fault(ctx, 500, "invalid parameters"); + return; + } + + if ((fl = str2facility(facility.s)) == -1) { + rpc->fault(ctx, 500, "facility not found"); + return; + } + + if(dbg_set_mod_debug_facility(value.s, value.len, &fl) < 0) + { + rpc->fault(ctx, 500, "cannot store parameter"); + return; + } + rpc->add(ctx, "s", "200 ok"); +} + /** * */ @@ -1032,6 +1064,7 @@ rpc_export_t dbg_rpc[] = { {"dbg.ls", dbg_rpc_list, dbg_rpc_list_doc, 0}, {"dbg.trace", dbg_rpc_trace, dbg_rpc_trace_doc, 0}, {"dbg.mod_level", dbg_rpc_mod_level, dbg_rpc_mod_level_doc, 0}, + {"dbg.mod_facility", dbg_rpc_mod_facility, dbg_rpc_mod_facility_doc, 0}, {"dbg.reset_msgid", dbg_rpc_reset_msgid, dbg_rpc_reset_msgid_doc, 0}, {0, 0, 0, 0} }; @@ -1056,10 +1089,19 @@ typedef struct _dbg_mod_level { struct _dbg_mod_level *next; } dbg_mod_level_t; +typedef struct _dbg_mod_facility { + str name; + unsigned int hashid; + int facility; + struct _dbg_mod_facility *next; +} dbg_mod_facility_t; + typedef struct _dbg_mod_slot { dbg_mod_level_t *first; gen_lock_t lock; + dbg_mod_facility_t *first_ft; + gen_lock_t lock_ft; } dbg_mod_slot_t; static dbg_mod_slot_t *_dbg_mod_table = NULL; @@ -1086,13 +1128,15 @@ int dbg_init_mod_levels(int dbg_mod_hash_size) for(i=0; i<_dbg_mod_table_size; i++) { - if(lock_init(&_dbg_mod_table[i].lock)==0) + if(lock_init(&_dbg_mod_table[i].lock)==0 || + lock_init(&_dbg_mod_table[i].lock_ft)==0) { LM_ERR("cannot initialize lock[%d]\n", i); i--; while(i>=0) { lock_destroy(&_dbg_mod_table[i].lock); + lock_destroy(&_dbg_mod_table[i].lock_ft); i--; } shm_free(_dbg_mod_table); @@ -1209,6 +1253,82 @@ int dbg_set_mod_debug_level(char *mname, int mnlen, int *mlevel) } +int dbg_set_mod_debug_facility(char *mname, int mnlen, int *mfacility) +{ + unsigned int idx; + unsigned int hid; + dbg_mod_facility_t *it; + dbg_mod_facility_t *itp; + dbg_mod_facility_t *itn; + + if(_dbg_mod_table==NULL) + return -1; + + hid = dbg_compute_hash(mname, mnlen); + idx = hid&(_dbg_mod_table_size-1); + + lock_get(&_dbg_mod_table[idx].lock_ft); + it = _dbg_mod_table[idx].first_ft; + itp = NULL; + while(it!=NULL && it->hashid < hid) { + itp = it; + it = it->next; + } + while(it!=NULL && it->hashid==hid) + { + if(mnlen==it->name.len + && strncmp(mname, it->name.s, mnlen)==0) + { + /* found */ + if(mfacility==NULL) { + /* remove */ + if(itp!=NULL) { + itp->next = it->next; + } else { + _dbg_mod_table[idx].first_ft = it->next; + } + shm_free(it); + } else { + /* set */ + it->facility = *mfacility; + } + lock_release(&_dbg_mod_table[idx].lock_ft); + return 0; + } + itp = it; + it = it->next; + } + /* not found - add */ + if(mfacility==NULL) { + lock_release(&_dbg_mod_table[idx].lock_ft); + return 0; + } + itn = (dbg_mod_facility_t*)shm_malloc(sizeof(dbg_mod_facility_t) + (mnlen+1)*sizeof(char)); + if(itn==NULL) { + LM_ERR("no more shm\n"); + lock_release(&_dbg_mod_table[idx].lock_ft); + return -1; + } + memset(itn, 0, sizeof(dbg_mod_facility_t) + (mnlen+1)*sizeof(char)); + itn->facility = *mfacility; + itn->hashid = hid; + itn->name.s = (char*)(itn) + sizeof(dbg_mod_facility_t); + itn->name.len = mnlen; + strncpy(itn->name.s, mname, mnlen); + itn->name.s[itn->name.len] = '\0'; + + if(itp==NULL) { + itn->next = _dbg_mod_table[idx].first_ft; + _dbg_mod_table[idx].first_ft = itn; + } else { + itn->next = itp->next; + itp->next = itn; + } + lock_release(&_dbg_mod_table[idx].lock_ft); + return 0; + +} + static int _dbg_get_mod_debug_level = 0; int dbg_get_mod_debug_level(char *mname, int mnlen, int *mlevel) { @@ -1252,6 +1372,49 @@ int dbg_get_mod_debug_level(char *mname, int mnlen, int *mlevel) return -1; } +static int _dbg_get_mod_debug_facility = 0; +int dbg_get_mod_debug_facility(char *mname, int mnlen, int *mfacility) +{ + unsigned int idx; + unsigned int hid; + dbg_mod_facility_t *it; + /* no LOG*() usage in this function and those executed insite it + * - use fprintf(stderr, ...) if need for troubleshooting + * - it will loop otherwise */ + if(_dbg_mod_table==NULL) + return -1; + + if(cfg_get(dbg, dbg_cfg, mod_facility_mode)==0) + return -1; + + if(_dbg_get_mod_debug_facility!=0) + return -1; + _dbg_get_mod_debug_facility = 1; + + hid = dbg_compute_hash(mname, mnlen); + idx = hid&(_dbg_mod_table_size-1); + lock_get(&_dbg_mod_table[idx].lock_ft); + it = _dbg_mod_table[idx].first_ft; + while(it!=NULL && it->hashid < hid) + it = it->next; + while(it!=NULL && it->hashid == hid) + { + if(mnlen==it->name.len + && strncmp(mname, it->name.s, mnlen)==0) + { + /* found */ + *mfacility = it->facility; + lock_release(&_dbg_mod_table[idx].lock_ft); + _dbg_get_mod_debug_facility = 0; + return 0; + } + it = it->next; + } + lock_release(&_dbg_mod_table[idx].lock_ft); + _dbg_get_mod_debug_facility = 0; + return -1; +} + /** * */ @@ -1262,6 +1425,13 @@ void dbg_enable_mod_levels(void) set_module_debug_level_cb(dbg_get_mod_debug_level); } +void dbg_enable_mod_facilities(void) +{ + if(_dbg_mod_table==NULL) + return; + set_module_debug_facility_cb(dbg_get_mod_debug_facility); +} + #define DBG_PVCACHE_SIZE 32 typedef struct _dbg_pvcache { @@ -1423,7 +1593,7 @@ void dbg_enable_log_assign(void) set_log_assign_action_cb(dbg_log_assign); } -int dbg_level_mode_fixup(void *temp_handle, +int dbg_mode_fixup(void *temp_handle, str *group_name, str *var_name, void **value){ if(_dbg_mod_table==NULL) { diff --git a/modules/debugger/debugger_api.h b/modules/debugger/debugger_api.h index ef69964262c..04760254059 100644 --- a/modules/debugger/debugger_api.h +++ b/modules/debugger/debugger_api.h @@ -35,7 +35,9 @@ int dbg_init_rpc(void); int dbg_init_mod_levels(int _dbg_mod_hash_size); int dbg_set_mod_debug_level(char *mname, int mnlen, int *mlevel); +int dbg_set_mod_debug_facility(char *mname, int mnlen, int *mfacility); void dbg_enable_mod_levels(void); +void dbg_enable_mod_facilities(void); int dbg_init_pvcache(void); void dbg_enable_log_assign(void); diff --git a/modules/debugger/debugger_config.c b/modules/debugger/debugger_config.c index 0d0dbce6d35..2ad61e1e0c9 100644 --- a/modules/debugger/debugger_config.c +++ b/modules/debugger/debugger_config.c @@ -32,6 +32,7 @@ struct cfg_group_dbg default_dbg_cfg = { 0, /* level_mode */ + 0, /* facility_mode */ 0 /* hash_size */ }; @@ -39,8 +40,11 @@ void *dbg_cfg = &default_dbg_cfg; cfg_def_t dbg_cfg_def[] = { {"mod_level_mode", CFG_VAR_INT|CFG_ATOMIC, 0, 1, - dbg_level_mode_fixup, 0, + dbg_mode_fixup, 0, "Enable or disable per module log level (0 - disabled, 1 - enabled)"}, + {"mod_facility_mode", CFG_VAR_INT|CFG_ATOMIC, 0, 1, + dbg_mode_fixup, 0, + "Enable or disable per module log facility (0 - disabled, 1 - enabled)"}, {"mod_hash_size", CFG_VAR_INT|CFG_READONLY, 0, 0, 0, 0, "power of two as size of internal hash table to store levels per module"}, diff --git a/modules/debugger/debugger_config.h b/modules/debugger/debugger_config.h index 96de4931df6..e633a008180 100644 --- a/modules/debugger/debugger_config.h +++ b/modules/debugger/debugger_config.h @@ -34,6 +34,7 @@ struct cfg_group_dbg { unsigned int mod_level_mode; + unsigned int mod_facility_mode; unsigned int mod_hash_size; }; @@ -41,6 +42,6 @@ extern struct cfg_group_dbg default_dbg_cfg; extern void *dbg_cfg; extern cfg_def_t dbg_cfg_def[]; -extern int dbg_level_mode_fixup(void *temp_handle, +extern int dbg_mode_fixup(void *temp_handle, str *group_name, str *var_name, void **value); #endif diff --git a/modules/debugger/debugger_mod.c b/modules/debugger/debugger_mod.c index 496492facce..5603c81befd 100644 --- a/modules/debugger/debugger_mod.c +++ b/modules/debugger/debugger_mod.c @@ -47,6 +47,7 @@ static void mod_destroy(void); 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 dbg_mod_facility_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); @@ -91,6 +92,8 @@ static param_export_t params[]={ {"mod_hash_size", INT_PARAM, &default_dbg_cfg.mod_hash_size}, {"mod_level_mode", INT_PARAM, &default_dbg_cfg.mod_level_mode}, {"mod_level", PARAM_STRING|USE_FUNC_PARAM, (void*)dbg_mod_level_param}, + {"mod_facility_mode", INT_PARAM, &default_dbg_cfg.mod_facility_mode}, + {"mod_facility", PARAM_STRING|USE_FUNC_PARAM, (void*)dbg_mod_facility_param}, {"reset_msgid", INT_PARAM, &_dbg_reset_msgid}, {"cfgpkgcheck", INT_PARAM, &_dbg_cfgpkgcheck}, {0, 0, 0} @@ -141,8 +144,9 @@ static int mod_init(void) LM_ERR("Fail to declare the configuration\n"); return -1; } - LM_DBG("cfg level_mode:%d hash_size:%d\n", + LM_DBG("cfg level_mode:%d facility_mode:%d hash_size:%d\n", cfg_get(dbg, dbg_cfg, mod_level_mode), + cfg_get(dbg, dbg_cfg, mod_facility_mode), cfg_get(dbg, dbg_cfg, mod_hash_size)); if(dbg_init_mod_levels(cfg_get(dbg, dbg_cfg, mod_hash_size))<0) @@ -179,6 +183,7 @@ static int child_init(int rank) LM_DBG("rank is (%d)\n", rank); if (rank==PROC_INIT) { dbg_enable_mod_levels(); + dbg_enable_mod_facilities(); dbg_enable_log_assign(); return dbg_init_pid_list(); } @@ -328,3 +333,43 @@ static int dbg_mod_level_param(modparam_t type, void *val) } +static int dbg_mod_facility_param(modparam_t type, void *val) +{ + char *p; + str s; + int fl; + if(val==NULL) + return -1; + + p = strchr((char*)val, '='); + if(p==NULL) { + LM_ERR("invalid parameter value: %s\n", (char*)val); + return -1; + } + s.s = p + 1; + s.len = strlen(s.s); + + if ((fl = str2facility(s.s)) == -1) { + LM_ERR("invalid parameter - facility value: %s\n", (char*)val); + return -1; + } + + s.s = (char*)val; + s.len = p - s.s; + LM_DBG("cfg facility_mode:%d hash_size:%d\n", + cfg_get(dbg, dbg_cfg, mod_facility_mode), + cfg_get(dbg, dbg_cfg, mod_hash_size)); + if(dbg_init_mod_levels(cfg_get(dbg, dbg_cfg, mod_hash_size))<0) + { + LM_ERR("failed to init per module log level\n"); + return -1; + } + if(dbg_set_mod_debug_facility(s.s, s.len, &fl)<0) + { + LM_ERR("cannot store parameter: %s\n", (char*)val); + return -1; + } + return 0; + +} +