libcw/cwLog.cpp
2019-12-18 22:24:12 -05:00

210 lines
5.0 KiB
C++

#include "cwCommon.h"
#include "cwLog.h"
#include "cwCommonImpl.h"
#include "cwMem.h"
namespace cw
{
typedef struct log_str
{
logOutputCbFunc_t outCbFunc;
void* outCbArg;
logFormatCbFunc_t fmtCbFunc;
void* fmtCbArg;
unsigned level;
} log_t;
logHandle_t __logGlobalHandle__;
logHandle_t logNullHandle;
#define logHandleToPtr(h) handleToPtr<logHandle_t,log_t>(h)
idLabelPair_t logLevelLabelArray[] =
{
{ kDebug_LogLevel, "debug" },
{ kInfo_LogLevel, "info" },
{ kWarning_LogLevel, "warning" },
{ kError_LogLevel, "error" },
{ kFatal_LogLevel, "fatal" },
{ kInvalid_LogLevel, "<invalid>" }
};
}
cw::rc_t cw::logCreate( logHandle_t& hRef, unsigned level, logOutputCbFunc_t outCbFunc, void* outCbArg, logFormatCbFunc_t fmtCbFunc, void* fmtCbArg )
{
rc_t rc;
if((rc = logDestroy(hRef)) != kOkRC)
return rc;
log_t* p = memAllocZ<log_t>();
p->outCbFunc = outCbFunc == nullptr ? logDefaultOutput : outCbFunc;
p->outCbArg = outCbArg;
p->fmtCbFunc = fmtCbFunc == nullptr ? logDefaultFormatter : fmtCbFunc;
p->fmtCbArg = fmtCbArg;
p->level = level;
hRef.p = p;
return rc;
}
cw::rc_t cw::logDestroy( logHandle_t& hRef )
{
rc_t rc = kOkRC;
if( hRef.p == nullptr )
return rc;
memRelease( hRef.p );
return rc;
}
cw::rc_t cw::logMsg( logHandle_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 = logHandleToPtr(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];
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::logMsg( logHandle_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 = logMsg( h, level, function, filename, line, systemErrorCode, returnCode, fmt, vl );
va_end(vl);
return rc;
}
void cw::logSetLevel( logHandle_t h, unsigned level )
{
log_t* p = logHandleToPtr(h);
p->level = level;
}
unsigned cw::logLevel( logHandle_t h )
{
log_t* p = logHandleToPtr(h);
return p->level;
}
const char* cw::logLevelToLabel( unsigned level )
{
const char* label;
if((label = idToLabel(logLevelLabelArray,level,kInvalid_LogLevel)) == nullptr)
label = "<unknown>";
return label;
}
void cw::logDefaultOutput( void* arg, unsigned level, const char* text )
{
FILE* f = level >= kWarning_LogLevel ? stderr : stdout;
fprintf(f,"%s",text);
}
void cw::logDefaultFormatter( 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 = logLevelToLabel(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 = "";
// 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::logCreateGlobal( unsigned level, logOutputCbFunc_t outCb, void* outCbArg, logFormatCbFunc_t fmtCb, void* fmtCbArg )
{
logHandle_t h;
rc_t rc;
if((rc = logCreate(h, level, outCb, outCbArg, fmtCb, fmtCbArg )) == kOkRC )
logSetGlobalHandle(h);
return rc;
}
cw::rc_t cw::logDestroyGlobal()
{
return logDestroy(__logGlobalHandle__);
}
void cw::logSetGlobalHandle( logHandle_t h )
{
__logGlobalHandle__ = h;
}
cw::logHandle_t cw::logGlobalHandle()
{
return __logGlobalHandle__;
}