libcw/cwLog.cpp
kevin fa33ac00c9 cwFileSys.h/cpp : Added makeDir().
cwLog.h/cpp : Added cwLogPrint() functions.
cwMtx.h : Many addtions.
cwObject.h : Added find_child() functions.
cwUtility.h/cpp : Added x80ToDouble() and doubleToX80().
cwCommon.h : Added new RC codes
cwCommonImpl.h : Added swapping macros and is_int<T>().
2020-09-01 15:46:21 -04:00

224 lines
5.4 KiB
C++

#include "cwCommon.h"
#include "cwLog.h"
#include "cwCommonImpl.h"
#include "cwMem.h"
namespace cw
{
namespace log
{
typedef struct log_str
{
logOutputCbFunc_t outCbFunc;
void* outCbArg;
logFormatCbFunc_t fmtCbFunc;
void* fmtCbArg;
unsigned level;
} log_t;
handle_t __logGlobalHandle__;
idLabelPair_t logLevelLabelArray[] =
{
{ kPrint_LogLevel, "" },
{ kDebug_LogLevel, "debug" },
{ kInfo_LogLevel, "info" },
{ kWarning_LogLevel, "warning" },
{ kError_LogLevel, "error" },
{ kFatal_LogLevel, "fatal" },
{ kInvalid_LogLevel, "<invalid>" }
};
log_t* _handleToPtr( handle_t h ) { return handleToPtr<handle_t,log_t>(h); }
}
}
cw::rc_t cw::log::create( handle_t& hRef, unsigned level, logOutputCbFunc_t outCbFunc, void* outCbArg, logFormatCbFunc_t fmtCbFunc, void* fmtCbArg )
{
rc_t rc;
if((rc = destroy(hRef)) != kOkRC)
return rc;
log_t* p = mem::allocZ<log_t>();
p->outCbFunc = outCbFunc == nullptr ? defaultOutput : outCbFunc;
p->outCbArg = outCbArg;
p->fmtCbFunc = fmtCbFunc == nullptr ? defaultFormatter : fmtCbFunc;
p->fmtCbArg = fmtCbArg;
p->level = level;
hRef.p = p;
return rc;
}
cw::rc_t cw::log::destroy( handle_t& hRef )
{
rc_t rc = kOkRC;
if( hRef.p == nullptr )
return rc;
mem::release( hRef.p );
return rc;
}
cw::rc_t cw::log::msg( handle_t h, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t rc, const char* fmt, va_list vl )
{
log_t* p = _handleToPtr(h);
va_list vl1;
va_copy(vl1,vl);
int n = vsnprintf(nullptr,0,fmt,vl);
cwAssert(n != -1);
if( n != -1 )
{
char msg[n+1]; // add 1 to allow space for the terminating zero
int m = vsnprintf(msg,n+1,fmt,vl1);
cwAssert(m==n);
p->fmtCbFunc( p->fmtCbArg, p->outCbFunc, p->outCbArg, level, function, filename, line, systemErrorCode, rc, msg );
}
va_end(vl1);
return rc;
}
cw::rc_t cw::log::msg( handle_t h, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t returnCode, const char* fmt, ... )
{
rc_t rc;
va_list vl;
va_start(vl,fmt);
rc = msg( h, level, function, filename, line, systemErrorCode, returnCode, fmt, vl );
va_end(vl);
return rc;
}
void cw::log::setLevel( handle_t h, unsigned level )
{
log_t* p = _handleToPtr(h);
p->level = level;
}
unsigned cw::log::level( handle_t h )
{
log_t* p = _handleToPtr(h);
return p->level;
}
const char* cw::log::levelToLabel( unsigned level )
{
const char* label;
if((label = idToLabel(logLevelLabelArray,level,kInvalid_LogLevel)) == nullptr)
label = "<unknown>";
return label;
}
void cw::log::defaultOutput( void* arg, unsigned level, const char* text )
{
FILE* f = level >= kWarning_LogLevel ? stderr : stdout;
fprintf(f,"%s",text);
fflush(f);
}
void cw::log::defaultFormatter( void* cbArg, logOutputCbFunc_t outFunc, void* outCbArg, unsigned level, const char* function, const char* filename, unsigned lineno, int sys_errno, rc_t rc, const char* msg )
{
// TODO: This code is avoids the use of dynamic memory allocation but relies on stack allocation. It's a security vulnerability.
//
const char* systemLabel = sys_errno==0 ? "" : "System Error: ";
const char* systemMsg = sys_errno==0 ? "" : strerror(sys_errno);
const char* levelStr = levelToLabel(level);
const char* rcFmt = "rc:%i";
int rcn = snprintf(nullptr,0,rcFmt,rc);
char rcs[rcn+1];
int rcm = snprintf(rcs,rcn+1,rcFmt,rc);
cwAssert(rcn==rcm);
const char* rcStr = rcs;
const char* syFmt = "%s%s";
int syn = snprintf(nullptr,0,syFmt,systemLabel,systemMsg);
char sys[syn+1];
int sym = snprintf(sys,syn+1,syFmt,systemLabel,systemMsg);
cwAssert(syn==sym);
const char* syStr = sys;
const char* loFmt = "%s line:%i %s";
int lon = snprintf(nullptr,0,loFmt,function,lineno,filename);
char los[lon+1];
int lom = snprintf(los,lon+1,loFmt,function,lineno,filename);
cwAssert(lon==lom);
const char* loStr = los;
// don't print the function,file,line when this is an 'info' msg.
if( level == kInfo_LogLevel )
loStr = "";
// dont' print the rc msg if this is info or debug
if( level < kWarning_LogLevel )
rcStr = "";
if( level == kPrint_LogLevel )
{
const char* fmt = "%s";
int n = snprintf(nullptr,0,fmt,msg);
cwAssert(n != -1);
char s[n+1];
int m = snprintf(s,n+1,fmt,msg);
cwAssert(m==n);
outFunc(outCbArg,level,s);
}
else
{
// levelStr, msg,sys_msg, rc, function, lineno, filename
const char* fmt = "%s: %s %s %s %s\n";
int n = snprintf(nullptr,0,fmt,levelStr,msg,syStr,rcStr,loStr);
cwAssert(n != -1);
char s[n+1];
int m = snprintf(s,n+1,fmt,levelStr,msg,syStr,rcStr,loStr);
cwAssert(m==n);
outFunc(outCbArg,level,s);
}
}
cw::rc_t cw::log::createGlobal( unsigned level, logOutputCbFunc_t outCb, void* outCbArg, logFormatCbFunc_t fmtCb, void* fmtCbArg )
{
handle_t h;
rc_t rc;
if((rc = create(h, level, outCb, outCbArg, fmtCb, fmtCbArg )) == kOkRC )
setGlobalHandle(h);
return rc;
}
cw::rc_t cw::log::destroyGlobal()
{
return destroy(__logGlobalHandle__);
}
void cw::log::setGlobalHandle( handle_t h )
{
__logGlobalHandle__ = h;
}
cw::log::handle_t cw::log::globalHandle()
{
return __logGlobalHandle__;
}