Module: sems Branch: master Commit: 33161cc3efbce5241d8268500832c791e9fd98c3 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sems/?a=commit;h=33161cc3efbce5241d8268500832c791e9fd98c3
Author: Stefan Sayer <[email protected]> Committer: Stefan Sayer <[email protected]> Date: Fri Oct 7 20:29:26 2011 +0200 sbc:cc_syslog_cdr: saner timestamps, connect durations, quoting --- apps/sbc/call_control/syslog_cdr/SyslogCDR.cpp | 120 ++++++++++++++++---- apps/sbc/call_control/syslog_cdr/SyslogCDR.h | 2 + .../call_control/syslog_cdr/etc/cc_syslog_cdr.conf | 11 ++ doc/Readme.syslog_cdr.txt | 16 --- 4 files changed, 113 insertions(+), 36 deletions(-) diff --git a/apps/sbc/call_control/syslog_cdr/SyslogCDR.cpp b/apps/sbc/call_control/syslog_cdr/SyslogCDR.cpp index f1e5124..273083c 100644 --- a/apps/sbc/call_control/syslog_cdr/SyslogCDR.cpp +++ b/apps/sbc/call_control/syslog_cdr/SyslogCDR.cpp @@ -66,7 +66,7 @@ SyslogCDR* SyslogCDR::instance() } SyslogCDR::SyslogCDR() - : level(2), syslog_prefix("CDR: ") + : level(2), syslog_prefix("CDR: "), quoting_enabled(true) { } @@ -92,6 +92,9 @@ int SyslogCDR::onLoad() { cdr_format = explode(cfg.getParameter("cdr_format"), ","); } + quoting_enabled = cfg.hasParameter("quoting_enabled") ? + cfg.getParameter("quoting_enabled") == "yes" : quoting_enabled; + if (level > 4) { WARN("log level > 4 not supported\n"); level = 4; @@ -155,13 +158,65 @@ void SyslogCDR::start(const string& ltag, SBCCallProfile* call_profile, call_profile->cc_vars["cdr::v"] = values; } +string getTimeDiffString(int from_ts_sec, int from_ts_usec, + int to_ts_sec, int to_ts_usec, + bool ms_precision) { + string res; + + struct timeval start; + start.tv_sec = from_ts_sec; + start.tv_usec = from_ts_usec; + struct timeval diff; + diff.tv_sec = to_ts_sec; + diff.tv_usec = to_ts_usec; + if (!from_ts_sec || !to_ts_sec || timercmp(&start, &diff, >)) { + diff.tv_sec = diff.tv_usec = 0; + } else { + timersub(&diff,&start,&diff); + } + + if (ms_precision) { + diff.tv_usec /= 1000; + string msecs = int2str((unsigned int)diff.tv_usec); + if (msecs.length()==1) + msecs = "00"+msecs; + else if (msecs.length()==2) + msecs = "0"+msecs; + + res+=int2str((unsigned int)diff.tv_sec)+"."+ msecs; + + } else { + if (diff.tv_usec>=500000) + diff.tv_sec++; + res += int2str((unsigned int)diff.tv_sec); + } + return res; +} + +string do_quote(string s) { + string res = "\""; + for (string::iterator it = s.begin();it!=s.end();it++) { + if (*it == '"') { + res +="\"\""; + } else { + res += *it; + } + } + res += "\""; + return res; +} + +// inlining (?) +#define csv_quote(_str) (quoting_enabled?do_quote(_str) : _str) + void SyslogCDR::end(const string& ltag, SBCCallProfile* call_profile, int start_ts_sec, int start_ts_usec, int connect_ts_sec, int connect_ts_usec, int end_ts_sec, int end_ts_usec) { if (!call_profile) return; - static const int log2syslog_level[] = { LOG_ERR, LOG_WARNING, LOG_INFO, LOG_DEBUG, LOG_NOTICE }; + static const int log2syslog_level[] = { LOG_ERR, LOG_WARNING, LOG_INFO, + LOG_DEBUG, LOG_NOTICE }; struct timeval start; start.tv_sec = connect_ts_sec; @@ -188,49 +243,74 @@ void SyslogCDR::end(const string& ltag, SBCCallProfile* call_profile, for (vector<string>::iterator it=cdr_format.begin(); it != cdr_format.end(); it++) { if (it->size() && (*it)[0]=='$') { if (*it == "$ltag") { - cdr+=ltag+","; + cdr+=csv_quote(ltag) +","; } else if (*it == "$start_ts") { - cdr+=int2str(start_ts_sec)+"."+int2str(start_ts_usec)+","; + cdr+=csv_quote(int2str(start_ts_sec)+"."+int2str(start_ts_usec)) +","; } else if (*it == "$connect_ts") { - cdr+=int2str(connect_ts_sec)+"."+int2str(connect_ts_usec)+","; + cdr+=csv_quote(int2str(connect_ts_sec)+"."+int2str(connect_ts_usec)) +","; } else if (*it == "$end_ts") { - cdr+=int2str(end_ts_sec)+"."+int2str(end_ts_usec)+","; + cdr+=csv_quote(int2str(end_ts_sec)+"."+int2str(end_ts_usec)) +","; } else if (*it == "$duration") { - cdr+=int2str((unsigned int)diff.tv_sec)+"."+ - int2str((unsigned int)diff.tv_usec)+","; + cdr+=csv_quote(getTimeDiffString(start_ts_sec, start_ts_usec, + end_ts_sec, end_ts_usec, true)) +","; + } else if (*it == "$duration_sec") { + cdr+=csv_quote(getTimeDiffString(start_ts_sec, start_ts_usec, + end_ts_sec, end_ts_usec, false)) +","; + } else if (*it == "$bill_duration") { + cdr+=csv_quote(getTimeDiffString(connect_ts_sec, connect_ts_usec, + end_ts_sec, end_ts_usec, true)) +","; + } else if (*it == "$bill_duration_sec") { + cdr+=csv_quote(getTimeDiffString(connect_ts_sec, connect_ts_usec, + end_ts_sec, end_ts_usec, false)) +","; + } else if (*it == "$setup_duration") { + if (!connect_ts_sec) { + cdr+=csv_quote(getTimeDiffString(start_ts_sec, start_ts_usec, + end_ts_sec, end_ts_usec, true)) +","; + } else { + cdr+=csv_quote(getTimeDiffString(start_ts_sec, start_ts_usec, + connect_ts_sec, connect_ts_usec, true)) +","; + } + } else if (*it == "$setup_duration_sec") { + if (!connect_ts_sec) { + cdr+=csv_quote(getTimeDiffString(start_ts_sec, start_ts_usec, + end_ts_sec, end_ts_usec, false)) +","; + } else { + cdr+=csv_quote(getTimeDiffString(start_ts_sec, start_ts_usec, + connect_ts_sec, connect_ts_usec, false)) +","; + } } else if (*it == "$start_tm") { - cdr+=timeString(start_ts_sec)+","; + cdr+=csv_quote(timeString(start_ts_sec)) +","; } else if (*it == "$connect_tm") { - cdr+=timeString(connect_ts_sec)+","; + cdr+=csv_quote(timeString(connect_ts_sec)) +","; } else if (*it == "$end_tm") { - cdr+=timeString(end_ts_sec)+","; + cdr+=csv_quote(timeString(end_ts_sec)) +","; } else { ERROR("in configuration: unknown value '%s' in cdr_format\n", it->c_str()); } } else { if (!values.hasMember(*it)) { - cdr+=","; + cdr+=csv_quote(string("")) + ","; } else { if (isArgCStr(values[*it])) { - cdr+=string(values[*it].asCStr())+","; + cdr+=csv_quote(string(values[*it].asCStr())) +","; } else { - cdr+=AmArg::print(values[*it])+","; + cdr+=csv_quote(AmArg::print(values[*it])) +","; } } } } } else { // default format: ltag, start_ts, connect_ts, end_ts, <other data...> - cdr = ltag + "," + - int2str(start_ts_sec)+"."+int2str(start_ts_usec)+","+ - int2str(connect_ts_sec)+"."+int2str(connect_ts_usec)+","+ - int2str(end_ts_sec)+"."+int2str(end_ts_usec)+","; + cdr = csv_quote(ltag) + "," + + csv_quote(int2str(start_ts_sec)+"."+int2str(start_ts_usec)) +","+ + csv_quote(int2str(connect_ts_sec)+"."+int2str(connect_ts_usec)) +","+ + csv_quote(int2str(end_ts_sec)+"."+int2str(end_ts_usec)) +","; for (AmArg::ValueStruct::const_iterator i=values.begin(); i!=values.end();i++) { if (isArgCStr(i->second)) { - cdr+=string(i->second.asCStr())+","; + cdr+=csv_quote(string(i->second.asCStr())) +","; } else { - cdr+=AmArg::print(i->second)+","; + cdr+=csv_quote(AmArg::print(i->second)) +","; } } } diff --git a/apps/sbc/call_control/syslog_cdr/SyslogCDR.h b/apps/sbc/call_control/syslog_cdr/SyslogCDR.h index 395d00a..77b166d 100644 --- a/apps/sbc/call_control/syslog_cdr/SyslogCDR.h +++ b/apps/sbc/call_control/syslog_cdr/SyslogCDR.h @@ -49,6 +49,8 @@ class SyslogCDR : public AmDynInvoke string syslog_prefix; vector<string> cdr_format; + bool quoting_enabled; + /* map<string, CDR*> cdrs; */ /* AmMutex cdrs_mut; */ diff --git a/apps/sbc/call_control/syslog_cdr/etc/cc_syslog_cdr.conf b/apps/sbc/call_control/syslog_cdr/etc/cc_syslog_cdr.conf index d7624ae..1a22e63 100644 --- a/apps/sbc/call_control/syslog_cdr/etc/cc_syslog_cdr.conf +++ b/apps/sbc/call_control/syslog_cdr/etc/cc_syslog_cdr.conf @@ -16,11 +16,22 @@ #Default: 2 (LOG_INFO) #loglevel=4 +#quoting_enabled=[yes, no] - enable double quotes (" ") around values +# if enabled, double quotes will be replaced with two times double quotes +# e.g. "Joe" -> """Joe""" +# default: yes + #cdr_format=<csv list of items> # items can be either # $ltag - local tag (ID for call) # $start_ts, $connect_ts, $end_ts - timestamp (sec.usec since epoch) # $start_tm, $connect_tm, $end_tm - timestamp (%F %T fmt) +# $duration - duration start to end (sec.ms) +# $duration_sec - duration start to end (sec) +# $bill_duration - duration connect to end (sec.ms) +# $bill_duration_sec - duration connect to end (sec) +# $setup_duration - duration start to connect/end (sec.ms) +# $setup_duration_sec - duration start to connect/end (sec) # or any of the configured values in sbc profile # #Example: diff --git a/doc/Readme.syslog_cdr.txt b/doc/Readme.syslog_cdr.txt deleted file mode 100644 index 9f58f66..0000000 --- a/doc/Readme.syslog_cdr.txt +++ /dev/null @@ -1,16 +0,0 @@ -syslog CDR generation (e.g. for SBC) ------------------------------------- - -This module implements the "cdr" DI interface to generate CDRs and write them in CSV -format to syslog. - -The CDR is stored in memory until the call is ended. - - -The CSV format is: - A leg local tag,Call-ID,From Tag,To Tag,start TS,connect TS,end TS, (...) - -Where (...) is all further values as configured in the profile (cdr_*) in alphabetical -order. - - _______________________________________________ Semsdev mailing list [email protected] http://lists.iptel.org/mailman/listinfo/semsdev
