From e3fe8e7f88c53e8ce69d776e21b78531d604783d Mon Sep 17 00:00:00 2001 From: Lucian Balaceanu Date: Thu, 7 Nov 2019 15:46:13 +0200 Subject: [PATCH 1/2] acc: adding CDR engine functionality - the engine allows the extension of the acc module for anyone wanting to add another format (e.g. JSON) or another backend for CDRs --- src/modules/acc/acc_api.h | 38 +++++++++++++++ src/modules/acc/acc_cdr.c | 41 +++++++++++++++- src/modules/acc/acc_cdr.h | 6 ++- src/modules/acc/acc_logic.c | 10 ++++ src/modules/acc/acc_logic.h | 2 + src/modules/acc/acc_mod.c | 93 +++++++++++++++++++++++++++++++++++++ 6 files changed, 187 insertions(+), 3 deletions(-) diff --git a/src/modules/acc/acc_api.h b/src/modules/acc/acc_api.h index d01f075aedf..93f8acc1001 100644 --- a/src/modules/acc/acc_api.h +++ b/src/modules/acc/acc_api.h @@ -38,6 +38,7 @@ #include "../../core/dprint.h" #include "../../core/sr_module.h" #include "../../core/mem/mem.h" +#include "../dialog/dlg_load.h" /* param trasnporter */ typedef struct acc_param { @@ -65,6 +66,10 @@ typedef struct acc_extra { struct acc_extra *next; } acc_extra_t; +typedef acc_param_t cdr_param_t; +typedef acc_enviroment_t cdr_enviroment_t; +typedef acc_extra_t cdr_extra_t; + typedef int (*core2strar_f)( struct sip_msg *req, str *c_vals, int *i_vals, char *t_vals); typedef int (*extra2strar_f)(struct acc_extra *extra, struct sip_msg *rq, str *val_arr, @@ -73,6 +78,12 @@ typedef int (*legs2strar_f)( struct acc_extra *legs, struct sip_msg *rq, str *va int *int_arr, char *type_arr, int start); typedef acc_extra_t* (*leg_info_f)(void); +/* cdr related fuctions */ +typedef int (*cdr_core2strar_f)( struct dlg_cell* dlg, + str* values, int* unused, char* types); +typedef int (*extra2strar_dlg_only_f)(struct acc_extra *extra, struct dlg_cell* dlg, str *val_arr, + int *int_arr, char *type_arr, const struct dlg_binds* p_dlgb); + /* acc event data structures */ typedef struct acc_info { acc_enviroment_t *env; @@ -82,6 +93,13 @@ typedef struct acc_info { acc_extra_t *leg_info; } acc_info_t; +/* cdr event data structures */ +typedef struct cdr_info { + str *varr; + int *iarr; + char *tarr; +} cdr_info_t; + /* acc engine initialization data structures */ typedef struct acc_init_info { acc_extra_t *leg_info; @@ -90,6 +108,8 @@ typedef struct acc_init_info { typedef int (*acc_init_f)(acc_init_info_t *inf); typedef int (*acc_req_f)(struct sip_msg *req, acc_info_t *data); +typedef int (*cdr_init_f)(void); +typedef int (*cdr_write_f)(struct dlg_cell *dlg, struct sip_msg *req, cdr_info_t *data); /* acc engine structure */ typedef struct acc_engine { char name[16]; @@ -101,6 +121,14 @@ typedef struct acc_engine { struct acc_engine *next; } acc_engine_t; +/* cdr engine structure */ +typedef struct cdr_engine { + char name[16]; + cdr_init_f cdr_init; + cdr_write_f cdr_write; + struct cdr_engine *next; +} cdr_engine_t; + #define MAX_ACC_EXTRA 64 #define MAX_ACC_LEG 16 #define ACC_CORE_LEN 6 @@ -114,6 +142,9 @@ typedef int (*acc_api_exec_f)(struct sip_msg *rq, acc_engine_t *eng, acc_param_t* comment); typedef acc_extra_t* (*parse_extra_f)(char *extra_str); +typedef int (*register_cdr_engine_f)(cdr_engine_t *eng); +typedef int (*cdr_api_exec_f)(struct dlg_cell *dlg, struct sip_msg *rq, cdr_engine_t *eng, acc_param_t* comment); + /* the acc API */ typedef struct acc_api { leg_info_f get_leg_info; @@ -123,6 +154,10 @@ typedef struct acc_api { parse_extra_f parse_extra; register_engine_f register_engine; acc_api_exec_f exec; + cdr_core2strar_f get_core_cdr_attrs; + extra2strar_dlg_only_f get_extra_dlg_attrs; + register_cdr_engine_f register_cdr_engine; + cdr_api_exec_f exec_cdr; } acc_api_t; typedef int (*bind_acc_f)(acc_api_t* api); @@ -131,6 +166,9 @@ int acc_run_engines(struct sip_msg *msg, int type, int *reset); acc_engine_t *acc_api_get_engines(void); void acc_api_set_arrays(acc_info_t *inf); +int cdr_run_engines(struct dlg_cell *dlg, struct sip_msg *msg); +cdr_engine_t *cdr_api_get_engines(void); +void cdr_api_set_arrays(cdr_info_t *inf); /** * @brief Load the SL API diff --git a/src/modules/acc/acc_cdr.c b/src/modules/acc/acc_cdr.c index 8a0cdfa2a45..7b052440e63 100644 --- a/src/modules/acc/acc_cdr.c +++ b/src/modules/acc/acc_cdr.c @@ -39,7 +39,6 @@ #include "../../core/str.h" #include "../dialog/dlg_load.h" -#include "acc_api.h" #include "acc_cdr.h" #include "acc_mod.h" #include "acc_extra.h" @@ -92,7 +91,7 @@ extern int _acc_cdr_on_failed; static int string2time( str* time_str, struct timeval* time_value); /* write all basic information to buffers(e.g. start-time ...) */ -static int cdr_core2strar( struct dlg_cell* dlg, +int cdr_core2strar( struct dlg_cell* dlg, str* values, int* unused, char* types) @@ -383,6 +382,10 @@ static int write_cdr( struct dlg_cell* dialog, LM_ERR( "dialog is empty!"); return -1; } + + /* engines decide if they have cdr_expired_dlg_enable set or not */ + cdr_run_engines(dialog, message); + /* message can be null when logging expired dialogs */ if ( !cdr_expired_dlg_enable && !message ){ LM_ERR( "message is empty!"); @@ -950,3 +953,37 @@ void destroy_cdr_generation( void) destroy_extras( cdr_extra); } + +/** + * @brief execute all acc engines for a SIP request event + */ +int cdr_run_engines(struct dlg_cell *dlg, struct sip_msg *msg) +{ + cdr_info_t inf; + cdr_engine_t *e; + + e = cdr_api_get_engines(); + + if(e==NULL) + return 0; + + memset(&inf, 0, sizeof(cdr_info_t)); + inf.varr = cdr_value_array; + inf.iarr = cdr_int_array; + inf.tarr = cdr_type_array; + while(e) { + e->cdr_write(dlg, msg, &inf); + e = e->next; + } + return 0; +} + +/** + * @brief set hooks to acc_info_t attributes + */ +void cdr_api_set_arrays(cdr_info_t *inf) +{ + inf->varr = cdr_value_array; + inf->iarr = cdr_int_array; + inf->tarr = cdr_type_array; +} diff --git a/src/modules/acc/acc_cdr.h b/src/modules/acc/acc_cdr.h index ac28eb88ce2..0043dfba74e 100644 --- a/src/modules/acc/acc_cdr.h +++ b/src/modules/acc/acc_cdr.h @@ -35,6 +35,9 @@ * version). * */ +#ifndef _ACC_CDR_H_ +#define _ACC_CDR_H_ + #define MAX_CDR_CORE 3 #define MAX_CDR_EXTRA 64 @@ -44,6 +47,7 @@ int set_cdr_extra( char* cdr_extra_value); int set_cdr_facility( char* cdr_facility); int init_cdr_generation( void); void destroy_cdr_generation( void); +int cdr_core2strar( struct dlg_cell* dlg, str* values, int* unused, char* types); - +#endif diff --git a/src/modules/acc/acc_logic.c b/src/modules/acc/acc_logic.c index cc66bc67dfc..3cceaf3a3ce 100644 --- a/src/modules/acc/acc_logic.c +++ b/src/modules/acc/acc_logic.c @@ -675,6 +675,16 @@ int acc_api_exec(struct sip_msg *rq, acc_engine_t *eng, return eng->acc_req(rq, &inf); } +/** + * @brief execute an acc event via a specific engine + */ +int cdr_api_exec(struct dlg_cell *dlg, struct sip_msg *rq, cdr_engine_t *eng, acc_param_t* comment) +{ + cdr_info_t inf; + memset(&inf, 0, sizeof(cdr_info_t)); + cdr_api_set_arrays(&inf); + return eng->cdr_write(dlg, rq, &inf); +} static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps ) { diff --git a/src/modules/acc/acc_logic.h b/src/modules/acc/acc_logic.h index ab85c673c86..b2639b6266a 100644 --- a/src/modules/acc/acc_logic.h +++ b/src/modules/acc/acc_logic.h @@ -50,5 +50,7 @@ int ki_acc_request(sip_msg_t *rq, str *comment, str *dbtable); int acc_api_exec(struct sip_msg *rq, acc_engine_t *eng, acc_param_t* comment); +int cdr_api_exec(struct dlg_cell *dlg, struct sip_msg *rq, cdr_engine_t *eng, + acc_param_t* comment); #endif diff --git a/src/modules/acc/acc_mod.c b/src/modules/acc/acc_mod.c index ba18a8f8f64..0b04f3e82c6 100644 --- a/src/modules/acc/acc_mod.c +++ b/src/modules/acc/acc_mod.c @@ -161,6 +161,11 @@ static int acc_init_engines(void); static acc_engine_t *_acc_engines=NULL; static int _acc_module_initialized = 0; +static int cdr_register_engine(cdr_engine_t *eng); +static int cdr_init_engines(void); +static cdr_engine_t *_cdr_engines=NULL; +static int cdr_module_initialized = 0; + /* ------------- fixup function --------------- */ static int acc_fixup(void** param, int param_no); static int free_acc_fixup(void** param, int param_no); @@ -560,6 +565,12 @@ static int mod_init( void ) return -1; } + cdr_module_initialized = 1; + if(cdr_init_engines()<0) { + LM_ERR("failed to init extra engines\n"); + return -1; + } + return 0; } @@ -613,6 +624,19 @@ static int bind_acc(acc_api_t* api) api->get_leg_attrs = legs2strar; api->parse_extra = parse_acc_extra; api->exec = acc_api_exec; + + if (cdr_enable) { + api->register_cdr_engine = cdr_register_engine; + api->get_core_cdr_attrs = cdr_core2strar; + api->get_extra_dlg_attrs = extra2strar_dlg_only; + api->exec_cdr = cdr_api_exec; + } + else { + api->register_cdr_engine = NULL; + api->get_core_cdr_attrs = NULL; + api->get_extra_dlg_attrs = NULL; + api->exec_cdr = NULL; + } return 0; } @@ -685,6 +709,67 @@ static int acc_register_engine(acc_engine_t *eng) return 0; } +/** + * @brief init an acc engine + */ +static int cdr_init_engine(cdr_engine_t *e) +{ + if(cdr_module_initialized==0) + return 0; + + if(e->cdr_init()<0) + { + LM_ERR("failed to initialize extra cdr engine\n"); + return -1; + } + return 0; +} + +/** + * @brief init registered acc engines + */ +static int cdr_init_engines(void) +{ + cdr_engine_t *e; + e = _cdr_engines; + while(e) { + if(cdr_init_engine(e)<0) + return -1; + e = e->next; + } + return 0; +} + +/** + * @brief register an accounting engine + * @return 0 on success, <0 on failure + */ +static int cdr_register_engine(cdr_engine_t *eng) +{ + cdr_engine_t *e; + + if(eng==NULL) + return -1; + e = (cdr_engine_t*)pkg_malloc(sizeof(cdr_engine_t)); + if(e ==NULL) + { + PKG_MEM_ERROR; + return -1; + } + memcpy(e, eng, sizeof(cdr_engine_t)); + + if(cdr_init_engine(e)<0) + { + pkg_free(e); + return -1; + } + + e->next = _cdr_engines; + _cdr_engines = e; + LM_DBG("new acc engine registered: %s\n", e->name); + return 0; +} + /** * */ @@ -693,6 +778,14 @@ acc_engine_t *acc_api_get_engines(void) return _acc_engines; } +/** + * + */ +cdr_engine_t *cdr_api_get_engines(void) +{ + return _cdr_engines; +} + /** * */ From 09f1c59bfef99867e4a006ba882ba13951b01276 Mon Sep 17 00:00:00 2001 From: Lucian Balaceanu Date: Thu, 7 Nov 2019 15:46:52 +0200 Subject: [PATCH 2/2] acc_json: adding CDR as JSON functionality --- src/modules/acc_json/acc_json_mod.c | 226 +++++++++++++++++--- src/modules/acc_json/acc_json_mod.h | 10 +- src/modules/acc_json/doc/acc_json_admin.xml | 175 ++++++++++++++- 3 files changed, 374 insertions(+), 37 deletions(-) diff --git a/src/modules/acc_json/acc_json_mod.c b/src/modules/acc_json/acc_json_mod.c index f1ce4e71f38..e50e3cc9c40 100644 --- a/src/modules/acc_json/acc_json_mod.c +++ b/src/modules/acc_json/acc_json_mod.c @@ -43,22 +43,36 @@ static int child_init(int rank); int acc_json_init(acc_init_info_t *inf); int acc_json_send_request(struct sip_msg *req, acc_info_t *inf); +int cdr_json_init(void); +int cdr_json_write(struct dlg_cell *dlg, struct sip_msg *req, cdr_info_t *inf); // acc API acc_api_t accb; acc_engine_t _acc_json_engine; +cdr_engine_t _cdr_json_engine; // mqueue API mq_api_t mq_api; +// dlg API +struct dlg_binds dlgb; int acc_flag = -1; int acc_missed_flag = -1; int acc_time_mode = 0; static char *acc_extra_str = 0; acc_extra_t *acc_extra = 0; -int output_syslog = -1; -char *output_mqueue_str = 0; /* see mqueue module queue name */ -str q_name = {0, 0}; -static char *log_facility_str = 0; +int acc_output_syslog = -1; +char *acc_output_mqueue_str = 0; /* see mqueue module queue name */ +str acc_q_name = {0, 0}; +static char *acc_log_facility_str = 0; + +int cdr_enable = 0; +static char *cdr_extra_str = 0; +acc_extra_t *cdr_extra = 0; +int cdr_expired_dlg_enable = 0; +int cdr_output_syslog = -1; +char *cdr_output_mqueue_str = 0; /* see mqueue module queue name */ +str cdr_q_name = {0, 0}; +static char *cdr_log_facility_str = 0; static cmd_export_t cmds[] = {{0, 0, 0, 0, 0, 0}}; @@ -68,10 +82,17 @@ static param_export_t params[] = {{"acc_flag", INT_PARAM, &acc_flag}, {"acc_extra", PARAM_STRING, &acc_extra_str}, {"acc_time_mode", INT_PARAM, &acc_time_mode}, {"acc_time_format", PARAM_STRING, &acc_time_format}, - {"log_level", INT_PARAM, &log_level}, - {"log_facility", PARAM_STRING, &log_facility_str}, - {"output_mqueue", PARAM_STRING, &output_mqueue_str}, - {"output_syslog", INT_PARAM, &output_syslog}, {0, 0, 0}}; + {"acc_log_level", INT_PARAM, &acc_log_level}, + {"acc_log_facility", PARAM_STRING, &acc_log_facility_str}, + {"acc_output_mqueue", PARAM_STRING, &acc_output_mqueue_str}, + {"acc_output_syslog", INT_PARAM, &acc_output_syslog}, + {"cdr_extra", PARAM_STRING, &cdr_extra_str}, + {"cdr_enable", INT_PARAM, &cdr_enable}, + {"cdr_expired_dlg_enable", INT_PARAM, &cdr_expired_dlg_enable}, + {"cdr_log_level", INT_PARAM, &cdr_log_level}, + {"cdr_log_facility", PARAM_STRING, &cdr_log_facility_str}, + {"cdr_output_mqueue", PARAM_STRING, &cdr_output_mqueue_str}, + {"cdr_output_syslog", INT_PARAM, &cdr_output_syslog}, {0, 0, 0}}; struct module_exports exports = { @@ -96,15 +117,34 @@ static int mod_init(void) return -1; } + if( cdr_enable < 0 || cdr_enable > 1) { + LM_ERR("cdr_enable is out of range\n"); + return -1; + } + if( cdr_expired_dlg_enable < 0 || cdr_expired_dlg_enable > 1) { + LM_ERR("cdr_expired_dlg_enable is out of range\n"); + return -1; + } + LM_INFO("janson version : %s\n", JANSSON_VERSION); #if JANSSON_VERSION_HEX >= 0x010300 /* Code specific to version 1.3 and above */ #endif - if(log_facility_str) { - int tmp = str2facility(log_facility_str); + if(acc_log_facility_str) { + int tmp = str2facility(acc_log_facility_str); if(tmp != -1) - log_facility = tmp; + acc_log_facility = tmp; + else { + LM_ERR("invalid log facility configured"); + return -1; + } + } + + if (cdr_log_facility_str) { + int tmp = str2facility(cdr_log_facility_str); + if (tmp != -1) + cdr_log_facility = tmp; else { LM_ERR("invalid log facility configured"); return -1; @@ -112,15 +152,18 @@ static int mod_init(void) } /* load the MQUEUE API */ - if(output_mqueue_str && (load_mq_api(&mq_api) != 0)) { + if((acc_output_mqueue_str || cdr_output_mqueue_str) && (load_mq_api(&mq_api) != 0)) { LM_ERR("can't load mqueue module API, disabling json acc to mqueue\n"); - output_mqueue_str = NULL; + acc_output_mqueue_str = NULL; } - if(output_mqueue_str) { - q_name.s = output_mqueue_str; - q_name.len = strlen(output_mqueue_str); + if(acc_output_mqueue_str) { + acc_q_name.s = acc_output_mqueue_str; + acc_q_name.len = strlen(acc_output_mqueue_str); + } + if(cdr_output_mqueue_str) { + cdr_q_name.s = cdr_output_mqueue_str; + cdr_q_name.len = strlen(cdr_output_mqueue_str); } - /* parse the extra string, if any */ if(acc_extra_str && (acc_extra = accb.parse_extra(acc_extra_str)) == 0) { LM_ERR("failed to parse acc_extra param\n"); @@ -141,6 +184,29 @@ static int mod_init(void) return -1; } + if (cdr_enable) { + if(load_dlg_api( &dlgb) != 0) { + LM_ERR("can't load dialog API\n"); + return -1; + } + /* parse the extra string, if any */ + if(cdr_extra_str && (cdr_extra = accb.parse_extra(cdr_extra_str)) == 0) { + LM_ERR("failed to parse cdr_extra param\n"); + return -1; + } + memset(&_cdr_json_engine, 0, sizeof(cdr_engine_t)); + + _cdr_json_engine.cdr_write = cdr_json_write; + _cdr_json_engine.cdr_init = cdr_json_init; + memcpy(_cdr_json_engine.name, "json", 4); + + if (!accb.register_cdr_engine + || (accb.register_cdr_engine + && (accb.register_cdr_engine(&_cdr_json_engine) < 0))) { + LM_ERR("cannot register ACC CDR JSON engine\n"); + return -1; + } + } return 0; } @@ -166,11 +232,20 @@ int acc_json_init(acc_init_info_t *inf) } -void syslog_write(const char *acc) +void acc_syslog_write(const char *acc) { //setlogmask(LOG_UPTO (LOG_NOTICE)); - openlog("json_acc", LOG_CONS | LOG_PID | LOG_NDELAY, log_facility); - syslog(log_level, "%s", acc); + openlog("json_acc", LOG_CONS | LOG_PID | LOG_NDELAY, acc_log_facility); + syslog(acc_log_level, "%s", acc); + closelog(); +} + + +void cdr_syslog_write(const char *cdr) +{ + //setlogmask(LOG_UPTO (LOG_NOTICE)); + openlog("json_acc", LOG_CONS | LOG_PID | LOG_NDELAY, cdr_log_facility); + syslog(cdr_log_level, "%s", cdr); closelog(); } @@ -279,9 +354,9 @@ int acc_json_send_request(struct sip_msg *req, acc_info_t *inf) str acc_str = {json_string, strlen(json_string)}; // json acc output to mqueue - if(output_mqueue_str) { + if(acc_output_mqueue_str) { str key = str_init("acc"); - if(mq_api.add(&q_name, &key, &acc_str)) { + if(mq_api.add(&acc_q_name, &key, &acc_str)) { LM_DBG("ACC queued [%d][%s]\n", acc_str.len, acc_str.s); } else { LM_DBG("ACC mqueue add error [%d][%s]\n", acc_str.len, @@ -289,8 +364,8 @@ int acc_json_send_request(struct sip_msg *req, acc_info_t *inf) } } // json acc output to syslog - if(output_syslog) - syslog_write(json_string); + if(acc_output_syslog) + acc_syslog_write(json_string); free(json_string); json_object_clear(object); json_decref(object); @@ -299,3 +374,106 @@ int acc_json_send_request(struct sip_msg *req, acc_info_t *inf) free_strar_mem(&(inf->tarr[m - o]), &(inf->varr[m - o]), o, m); return 1; } + + +int cdr_json_init(void) +{ + LM_DBG(" init ...\n"); + return 0; +} + + +int cdr_json_write(struct dlg_cell *dlg, struct sip_msg *req, cdr_info_t *inf) +{ + int attr_cnt = 0; + int i; + int extra_cnt = 0; + int core_cnt = 0; + + json_t *object = json_object(); + + /* get default values */ + core_cnt = accb.get_core_cdr_attrs( dlg, inf->varr, inf->iarr, inf->tarr); + attr_cnt += core_cnt; + + for(i = 0; i < attr_cnt; i++) { + LM_DBG("[%d][%.*s]\n", i, inf->varr[i].len, inf->varr[i].s); + char *tmp = strndup(inf->varr[i].s, inf->varr[i].len); + json_t *value = json_string(tmp); + if(!value) + value = json_string("NON-UTF8"); + if(i == 0) { + json_object_set_new(object, cdr_start_str.s, value); + } else if(i == 1) { + json_object_set_new(object, cdr_end_str.s, value); + } else if(i == 2) { + json_object_set_new(object, cdr_duration_str.s, value); + } + free(tmp); + } + + /* get extra values */ + if (req) + { + /* free memory allocated by get_extra_attrs */ + extra_cnt += accb.get_extra_attrs( cdr_extra, + req, + inf->varr + attr_cnt, + inf->iarr + attr_cnt, + inf->tarr + attr_cnt); + attr_cnt += extra_cnt; + } else if (cdr_expired_dlg_enable){ + int dlg_index = 0; + dlg_index += accb.get_extra_dlg_attrs( cdr_extra, + dlg, + inf->varr + attr_cnt, + inf->iarr + attr_cnt, + inf->tarr + attr_cnt, + &dlgb); + attr_cnt += dlg_index; + } + + struct acc_extra *extra = cdr_extra; + for( ; i < attr_cnt; i++) + { + LM_DBG("[%d][%s][%.*s]\n", i, extra->name.s, inf->varr[i].len, + inf->varr[i].s); + char *tmp = strndup(inf->varr[i].s, inf->varr[i].len); + json_t *value = json_string(tmp); + if(!value) + value = json_string("NON-UTF8"); + json_object_set_new(object, extra->name.s, value); + free(tmp); + extra = extra->next; + } + + if(object) { + if(json_object_size(object) == 0) { + LM_ERR("json object empty\n"); + json_decref(object); + return 0; + } + char *json_string = json_dumps(object, JSON_ENSURE_ASCII); + str cdr_str = {json_string, strlen(json_string)}; + + // json acc output to mqueue + if (cdr_output_mqueue_str) { + str key = str_init("cdr"); + if (mq_api.add(&cdr_q_name, &key, &cdr_str)) { + LM_DBG("CDR queued [%d][%s]\n", cdr_str.len, cdr_str.s); + } else { + LM_DBG("CDR mqueue add error [%d][%s]\n", cdr_str.len, + cdr_str.s); + } + } + // json acc output to syslog + if(cdr_output_syslog) + cdr_syslog_write(json_string); + free(json_string); + json_object_clear(object); + json_decref(object); + } + /* free memory allocated by get_extra_attrs */ + free_strar_mem(&(inf->tarr[core_cnt]), &(inf->varr[core_cnt]), extra_cnt, attr_cnt); + return 1; +} diff --git a/src/modules/acc_json/acc_json_mod.h b/src/modules/acc_json/acc_json_mod.h index 45a5755317a..25a3ac120ea 100644 --- a/src/modules/acc_json/acc_json_mod.h +++ b/src/modules/acc_json/acc_json_mod.h @@ -32,11 +32,17 @@ str acc_sipcode_key = str_init("sip_code"); str acc_sipreason_key = str_init("sip_reason"); str acc_time_key = str_init("time"); +str cdr_start_str = str_init("start_time"); +str cdr_end_str = str_init("end_time"); +str cdr_duration_str = str_init("duration"); + #define ACC_TIME_FORMAT_SIZE 128 static char acc_time_format_buf[ACC_TIME_FORMAT_SIZE]; char *acc_time_format = "%Y-%m-%d %H:%M:%S"; -int log_level = L_NOTICE; -int log_facility = LOG_DAEMON; +int acc_log_level = L_NOTICE; +int acc_log_facility = LOG_DAEMON; +int cdr_log_level = L_NOTICE; +int cdr_log_facility = LOG_DAEMON; #endif diff --git a/src/modules/acc_json/doc/acc_json_admin.xml b/src/modules/acc_json/doc/acc_json_admin.xml index 2dcfbcd0f22..70b6df1d2b3 100644 --- a/src/modules/acc_json/doc/acc_json_admin.xml +++ b/src/modules/acc_json/doc/acc_json_admin.xml @@ -232,7 +232,8 @@ route[RUN_ACC_PUBLISH] { ... - + +
<varname>output_syslog</varname> (integer) @@ -249,15 +250,15 @@ route[RUN_ACC_PUBLISH] { ... modparam("acc_json", "output_syslog", 1) -modparam("acc_json", "log_level", 2) -modparam("acc_json", "log_facility", "LOG_DAEMON") +modparam("acc_json", "acc_log_level", 2) +modparam("acc_json", "acc_log_facility", "LOG_DAEMON") ...
-
- <varname>log_facility</varname> (integer) +
+ <varname>acc_log_facility</varname> (integer) Log facility to which accounting messages are issued to syslog. This allows to easily separate the accounting specific logging @@ -267,10 +268,10 @@ modparam("acc_json", "log_facility", "LOG_DAEMON") Default value is LOG_DAEMON. - log_facility example + acc_log_facility example ... -modparam("acc_json", "log_facility", "LOG_LOCAL0") +modparam("acc_json", "acc_log_facility", "LOG_LOCAL0") # modify you syslog/rsyslog config # /etc/rsyslog.d/default.conf @@ -283,8 +284,160 @@ modparam("acc_json", "log_facility", "LOG_LOCAL0")
-
- <varname>log_level</varname> (integer) +
+ <varname>acc_log_level</varname> (integer) + + Log level at which accounting messages are issued to syslog. + + + Default value is 1 (L_NOTICE). + + + acc_log_level example + +... +modparam("acc_json", "acc_log_level", 2) # Set acc_log_level to 2 (L_INFO) +... + + +
+ +
+ <varname>cdr_enable</varname> (str) + + Enable Call Data Record generation. + + + Default value is 0 (disabled). + + + cdr_enable example + +... +modparam("acc_json", "cdr_enable", 1) +... + + +
+ +
+ <varname>cdr_extra</varname> (str) + + Set of pseudo-variables defining custom CDR fields. + + + Default value is NULL. + + + cdr_extra example + +... +modparam("acc_json", "cdr_extra", "ci=$dlg_var(call_id);ft=$dlg_var(from_tag)") +... + + +
+ + +
+ <varname>cdr_expired_dlg_enable</varname> (str) + + Should CDR-based logging be enabled in case of expired dialogs? + + + 0 - off (default). 1 - on. + + + cdr_expired_dlg_enable example + +... +modparam("acc_json", "cdr_expired_dlg_enable", 1) +... + + +
+ +
+ <varname>cdr_output_mqueue</varname> (integer) + + Requires the mqueue module. + The acc module will queue json cdr events in the specified mqueue. + Using a rtimer module exec you can access the queue and process them. + + + You can also fetch the cdr events using mqueue.fetch over JSON-RPC. + + + Default value is not-set mqueue will not be required. + + + cdr_output_mqueue usage example + +... +# example using json_mqueue/http_client to publish to NSQD +modparam("mqueue", "mqueue", "name=cdr_events;size=100000") +modparam("acc_json", "cdr_enable", 1) +modparam("acc_json", "cdr_output_mqueue", "cdr_events") +modparam("acc_json", "cdr_extra", "ci=$dlg_var(call_id)") +modparam("rtimer", "timer", "name=nsqt;interval=1;mode=1;") +modparam("rtimer", "exec", "timer=nsqt;route=RUN_CDR_PUBLISH") +modparam("http_client", "keep_connections", 1) +modparam("http_client", "httpcon", "nsqd=>http://localhost:4151/pub?topic=acc") + +route[RUN_CDR_PUBLISH] { + $var(count) = 0; + while (mq_fetch("cdr_events")) { + $var(q_size) = mq_size("cdr_events"); + $var(count) = $var(count) + 1; + xinfo("[RUN_CDR_PUBLISH][$var(q_size)][$var(count)][$mqk(cdr_events)][$mqv(cdr_events)]\n"); + $var(res) = http_connect_raw("nsqd", "", "application/json", $mqv(cdr_events), "$var(nsq_res)"); + if ($var(res) < 0) { + xerr("[RUN_CDR_PUBLISH][$var(res)] http_connect_raw: timeout or error !\n"); + mq_add("cdr_events", "cdr_key", "$mqv(cdr_events)"); + } else if ($var(res) < 200 || $var(res) > 299) { + xerr("[RUN_CDR_PUBLISH][$var(res)] http unexpected response code !\n"); + mq_add("cdr_dead_letter_queue", "cdr_key", "$mqv(cdr_events)"); + return; + } + } + if ($var(count) > 0 ) { + xinfo("[RUN_CDR_PUBLISH]done count[$var(count)]\n"); + } +} +... + + +
+ +
+ <varname>cdr_log_facility</varname> (integer) + + Log facility to which accounting messages are issued to syslog. + This allows to easily separate the accounting specific logging + from the other log messages. + + + Default value is LOG_DAEMON. + + + cdr_log_facility example + +... +modparam("acc_json", "cdr_log_facility", "LOG_LOCAL0") + +# modify you syslog/rsyslog config +# /etc/rsyslog.d/default.conf +# remove local0 from default log file +# *.*;local0,auth,authpriv.none /var/log/syslog +# add local0 to another log file +# local0.* /var/log/json_cdr.log +... + + +
+ +
+ <varname>cdr_log_level</varname> (integer) Log level at which accounting messages are issued to syslog. @@ -292,10 +445,10 @@ modparam("acc_json", "log_facility", "LOG_LOCAL0") Default value is 1 (L_NOTICE). - log_level example + cdr_log_level example ... -modparam("acc_json", "log_level", 2) # Set log_level to 2 (L_INFO) +modparam("acc_json", "cdr_log_level", 2) # Set cdr_log_level to 2 (L_INFO) ...