diff --git a/apps/examples/di_log/DILog.cpp b/apps/examples/di_log/DILog.cpp new file mode 100644 index 00000000..7b512cc82 --- /dev/null +++ b/apps/examples/di_log/DILog.cpp @@ -0,0 +1,77 @@ +#include "AmPlugIn.h" +#include "log.h" +#include "DILog.h" + + +#include +#include +#include + +#include + +using namespace std; + +#define MOD_NAME "di_log" + +EXPORT_LOG_FACILITY_FACTORY(DILog, MOD_NAME); +EXPORT_PLUGIN_CLASS_FACTORY(DILog, MOD_NAME); + +char DILog::ring_buf[MAX_LINES][MAX_LINE_LEN] = {{0}}; +int DILog::pos = 0; + +DILog::DILog(const string& name) : AmLoggingFacility(name), AmDynInvokeFactory(name) { +} + +DILog* DILog::_instance=0; + +DILog* DILog::instance() { + if(_instance == NULL){ + _instance = new DILog(MOD_NAME); + } + return _instance; +} + +int DILog::onLoad() { + DBG("DILog logging ring-buffer loaded.\n"); + return 0; +} + +DILog::~DILog() { } + +void DILog::invoke(const string& method, const AmArgArray& args, AmArgArray& ret) { + if(method == "dumplog") { + ret.push(dumpLog().c_str()); + } else if(method == "dumplogtodisk") { + dumpLog(args.get(0).asCStr()); + ret.push("dumped to disk.\n"); + } else if(method == "help") { + ret.push("dumplog\n" + "dumplogtodisk \n" + ); + } else throw AmDynInvoke::NotImplemented(method); +} + +void DILog::dumpLog(const char* path) { + fstream fs(path, ios::out); + int start = (pos + 1) % MAX_LINES; + for(int i=0; i +#include + +#define MAX_LINES 1000 +#define MAX_LINE_LEN 256 + +class DILog : public AmLoggingFacility, public AmDynInvoke, public AmDynInvokeFactory +{ + private: + void dumpLog(const char* path); + string dumpLog(); + static DILog* _instance; + static char ring_buf[MAX_LINES][MAX_LINE_LEN]; + static int pos; + + public: + DILog(const string& name); + ~DILog(); + // DI factory + AmDynInvoke* getInstance() { return instance(); } + // DI API + static DILog* instance(); + void invoke(const string& method, const AmArgArray& args, AmArgArray& ret); + + int onLoad(); + + // LF API + void log(int level, const char* fmt); +}; diff --git a/apps/examples/di_log/Makefile b/apps/examples/di_log/Makefile new file mode 100644 index 00000000..121b4edd --- /dev/null +++ b/apps/examples/di_log/Makefile @@ -0,0 +1,7 @@ +plug_in_name = di_log + +module_ldflags = +module_cflags = + +COREPATH ?=../../core +include $(COREPATH)/plug-in/Makefile.app_module diff --git a/apps/examples/di_log/Readme.di_log b/apps/examples/di_log/Readme.di_log new file mode 100644 index 00000000..5403bc22 --- /dev/null +++ b/apps/examples/di_log/Readme.di_log @@ -0,0 +1,186 @@ +di_log Readme +------------- +The di_log module provides a ring buffer logging facility +which on request dumps the ring buffer contents either as +result of the DI call or in a file on HD. dumping the ring +buffer can be invoked via DI interface (for example remotely +from the stats module). + +ring buffer size and string length can be customized at compile +time, see DILog.h + +exported functions +------------------ + + help : return help string + + dumplog : return contents of buffer + + dumplogtodisk(string filename) : dump buffer contents into file + +examples of invocation through query_stats +------------------------------------------ + +./query_stats -c "DI di_log help" +./query_stats -c "DI di_log dumplog" + the dump will most probably be truncated due to string length + constraint + +./query_stats -c "DI di_log dumplogtodisk log_file.log" + + +about performance +----------------- + +snprintf'ing and vsnprintf'ing all debug messages does consume +quite some CPU power, especially on call setup and tear down as +there are a lot of debug messages print out. + +for G711 announcement (from file) over loopback interface, the +following was measured over 2000 calls using sipp and valgrind: + + call length CPU consumed by logging (log_fac_print, incl) + 5s 34% + 1s 58% + +for 50 participants G711 conference, 30s/ call, logging +used 16%. + +valgrind command: + valgrind --tool=callgrind --instr-atstart=no ./sems -f sems.conf -D 1 -E + +sipp command: + conference: + sipp -sf sippuac.xml -i 127.0.0.1 \ + -rtp_echo -m 2000 -l 50 -d 30000 -s 8 127.0.0.1:5060 + announcement 1s: + sipp -sf sippuac.xml -i 127.0.0.1 \ + -rtp_echo -m 2000 -l 50 -d 1000 -s 7 127.0.0.1:5060 + announcement 5s: + sipp -sf sippuac.xml -i 127.0.0.1 \ + -rtp_echo -m 2000 -l 50 -d 5000 -s 7 127.0.0.1:5060 + + +sippuac.xml is -sn uac scenario, with 5070 as contact +(no target updating from contact implemented in sipp) + +sippuac.xml: +--------------------------------------------------------------------------- + + + + + + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut + Call-ID: [call_id] + CSeq: 1 INVITE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] + s=- + c=IN IP[media_ip_type] [media_ip] + t=0 0 + m=audio [media_port] RTP/AVP 0 + a=rtpmap:0 PCMU/8000 + + ]]> + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 1 ACK + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 2 BYE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + + + + + + + + + diff --git a/core/AmApi.h b/core/AmApi.h index e61710fe..55bce948 100644 --- a/core/AmApi.h +++ b/core/AmApi.h @@ -202,7 +202,7 @@ class AmLoggingFacility : public AmPluginFactory /** will be called on logging messages */ - virtual void log(int level, const char* fmt, va_list ap) = 0; + virtual void log(int level, const char* msg) = 0; }; #if __GNUC__ < 3 diff --git a/core/log.cpp b/core/log.cpp index 79569ae5..088e36e4 100644 --- a/core/log.cpp +++ b/core/log.cpp @@ -83,15 +83,19 @@ void log_fac_print(int level, const char* fct, char* file, int line, char* fmt, { va_list ap; char logline[512]; + int len; if(log_hooks.empty()) return; - snprintf(logline, sizeof(logline), "(%i) %s: %s (%s:%i): ",(int)getpid(), level2txt(level), fct, file, line); - strncat(logline, fmt, sizeof(logline)); - + // file, line etc + len = snprintf(logline, sizeof(logline), "(%i) %s: %s (%s:%i): ", + (int)getpid(), level2txt(level), fct, file, line); + // dbg msg va_start(ap, fmt); - for(unsigned i=0; ilog(level, logline, ap); + vsnprintf(logline+len, sizeof(logline)-len, fmt, ap); va_end(ap); + + for(unsigned i=0; ilog(level, logline); } void register_logging_fac(void* vp)