blob: b5c02b03a290fddf9c33f753bbb67cd4dd505e54 [file] [log] [blame]
// Copyright (C) 2005-2009 Angelo Naselli, Penta Engineering s.r.l.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// As a special exception, you may use this file as part of a free software
// library without restriction. Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License. This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
//
// This exception applies only to the code released under the name GNU
// Common C++. If you copy code from other releases into a copy of GNU
// Common C++, as the General Public License permits, the exception does
// not apply to the code that you add in this way. To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own for GNU Common C++, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.
//
#include <cc++/config.h>
#include <cc++/thread.h>
#include <cc++/slog.h>
#include <cc++/buffer.h>
#include <string>
#include <iomanip>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <stdarg.h>
#include <errno.h>
// TODO sc: test if has to move up now that it is into commoncpp
// NOTE: the order of inclusion is important do not move following include line
// redefinition of __EXPORT needed if we're compiling our dll
#include <cc++/export.h>
// local includes
#include <cc++/applog.h>
#ifdef CCXX_NAMESPACES
using namespace std;
namespace ost
{
#endif
class logStruct
{
public:
string _ident;
int _priority;
Slog::Level _level;
bool _enable;
bool _clogEnable;
bool _slogEnable;
size_t _msgpos;
enum logEnum
{
BUFF_SIZE = 512,
LAST_CHAR = BUFF_SIZE - 1
};
char _msgbuf[BUFF_SIZE];
logStruct() : _ident("") , _priority(Slog::levelDebug),
_level(Slog::levelDebug), _enable(false),
_clogEnable(false), _slogEnable(false), _msgpos(0)
{
memset(_msgbuf, 0, BUFF_SIZE);
};
~logStruct() {};
};
struct levelNamePair
{
const char *name;
Slog::Level level;
};
#ifdef WIN32
template class std::map<string, Slog::Level >;
#endif
class LevelName : public map<string, Slog::Level>
{
public:
LevelName(const levelNamePair initval[], int num)
{
for (int i = 0; i < num; i++)
insert(make_pair(initval[i].name, initval[i].level));
};
};
class logger : public ost::ThreadQueue
{
private:
string _nomeFile;
std::fstream _logfs;
bool _usePipe;
protected:
// to dequeue log messages and write them to file if not log_directly
virtual void runQueue(void *data);
virtual void startQueue(void);
virtual void stopQueue(void);
virtual void onTimer(void);
virtual void final(void);
public:
logger(const char* logFileName = NULL, bool usePipe = false);
virtual ~logger();
// To change log file name
void logFileName(const char* FileName, bool usePipe = false);
};
// mapping thread ID <-> logStruct (buffer)
typedef map <cctid_t, logStruct> LogPrivateData;
// map ident <-> levels
typedef map <string, Slog::Level> IdentLevel;
class AppLogPrivate
{
public:
// subscription and unsubsciption must be protected as well
ost::Mutex _subMutex;
// mapping thread ID <-> logStruct (buffer)
LogPrivateData _logs;
// map ident <-> levels
IdentLevel _identLevel;
// log directly into file
bool _logDirectly;
bool _logPipe;
// log spooler
logger *_pLogger;
string _nomeFile;
Mutex _lock;
std::fstream _logfs;
static const levelNamePair _values[];
static LevelName _assoc;
AppLogPrivate() : _pLogger(NULL) {}
~AppLogPrivate()
{
if (_pLogger)
delete _pLogger;
}
};
const levelNamePair AppLogPrivate::_values[] =
{
{ "emerg", Slog::levelEmergency },
{ "alert", Slog::levelAlert },
{ "critical", Slog::levelCritical },
{ "error", Slog::levelError },
{ "warn", Slog::levelWarning },
{ "notice", Slog::levelNotice },
{ "info", Slog::levelInfo },
{ "debug", Slog::levelDebug }
};
AppLog alog;
LevelName AppLogPrivate::_assoc(_values, sizeof AppLogPrivate::_values / sizeof *AppLogPrivate::_values);
map<string, Slog::Level> *AppLog::assoc = &AppLogPrivate::_assoc;
HEXdump::HEXdump(const unsigned char *buffer, int len, int max_len) : _str()
{
std::stringstream sstr;
if (buffer == NULL || len <= 0)
return ;
long buf_len = (max_len > 0 && len > max_len) ? max_len : len;
long int addr = 0;
int cnt2 = 0;
int n;
int i;
sstr.str("");
// get exception from ifstream failures
sstr.exceptions(ifstream::failbit | ifstream::badbit);
try
{
sstr << std::endl;
sstr << "dump " << len << " byte." << std::endl;
for (n = 0; n < buf_len; n++)
{
if (cnt2 == 0)
{
// Print address.
sstr << std::setw(7) << std::setfill('0') << int (addr) << " - ";
addr = addr + 16;
}
cnt2 = (cnt2 + 1) % 18;
if (cnt2 <= 16)
{
// print hex value
sstr << std::hex << std::setw(2) << std::setfill('0') << int (buffer[n]) << " ";
}
else
{
sstr << " ";
sstr << std::setfill(' ');
for (i = n - cnt2 + 1; i < n; i++)
{
// print ascii value
if (buffer[i] < 32 || 126 < buffer[i])
{
sstr << '.';
}
else
{
sstr << buffer[i];
}
}
sstr << std::endl;
sstr << std::dec;
cnt2 = 0;
n--;
}
}
sstr << std::setfill(' ');
for (i = cnt2 + 1; i <= 16 ; i++)
{
sstr << std::setw(2) << "--" << " ";
}
sstr << " ";
for (i = n - cnt2; cnt2 <= 16 && i < n; i++)
{
if (buffer[i] < 32 || 126 < buffer[i])
{
sstr << '.';
}
else
{
sstr << buffer[i];
}
}
sstr << std::dec;
if (max_len > 0 && len > max_len)
sstr << std::endl << "dump troncato a " << max_len << " byte." << std::endl;
}
catch (...)
{
sstr.str("HEXdump failed!");
}
_str = sstr.str();
}
// class logger
logger::logger(const char* logFileName, bool usePipe) : ThreadQueue(NULL, 0, 0), _usePipe(usePipe)
{
_nomeFile = "";
if (logFileName)
_nomeFile = logFileName;
if (!_nomeFile.empty())
{
if (!_usePipe)
{
_logfs.open(_nomeFile.c_str(), std::ofstream::out | std::ofstream::app | std::ofstream::ate);
}
#ifndef WIN32
else
{
// create pipe
int err = mkfifo(_nomeFile.c_str(), S_IREAD | S_IWRITE);
if (err == 0 || errno == EEXIST)
{
// and open it
_logfs.open(_nomeFile.c_str(), std::fstream::in | std::fstream::out);
}
else
THROW(AppLogException("Can't create pipe"));
}
#endif
if (_logfs.fail())
THROW(AppLogException("Can't open log file name"));
}
}
logger::~logger()
{
Semaphore::post();
Thread::terminate();
_logfs.flush();
_logfs.close();
}
// New log file name
void logger::logFileName(const char* FileName, bool usePipe)
{
if (!FileName)
return;
_usePipe = usePipe;
_nomeFile = FileName;
if (_logfs.is_open())
_logfs.close();
if (!_nomeFile.empty())
{
if (!_usePipe)
{
_logfs.open(_nomeFile.c_str(), std::ofstream::out | std::ofstream::app | std::ofstream::ate);
}
#ifndef WIN32
else
{
// create pipe
int err = mkfifo(_nomeFile.c_str(), S_IREAD | S_IWRITE);
if (err == 0 || errno == EEXIST)
{
// and open it
_logfs.open(_nomeFile.c_str(), std::fstream::in | std::fstream::out);
}
else
THROW(AppLogException("Can't create pipe"));
}
#endif
if (_logfs.fail())
THROW(AppLogException("Can't open log file name"));
}
}
// writes into filename enqueued messages
void logger::runQueue(void * data)
{
char *str = (char *) data;
if (_logfs.is_open())
{
Thread::setCancel(cancelDisabled);
_logfs << str;
_logfs.flush();
Thread::setCancel(cancelImmediate);
}
}
void logger::startQueue()
{
testCancel();
}
void logger::stopQueue()
{
testCancel();
}
void logger::onTimer()
{
}
void logger::final()
{
if (started)
{
data_t *pFirst = first;
while (pFirst)
{
runQueue(pFirst->data);
pFirst = pFirst->next;
}
}
}
#ifndef WIN32
AppLog::AppLog(const char* logFileName, bool logDirectly, bool usePipe) :
streambuf(), ostream((streambuf*) this)
#else
AppLog::AppLog(const char* logFileName, bool logDirectly) :
streambuf(), ostream((streambuf*) this)
#endif
{
d= NULL; // pedantic fussy about initing members before base classes...
d = new AppLogPrivate();
if (!d)
THROW(AppLogException("Memory allocation problem"));
d->_nomeFile = "";
d->_logDirectly = logDirectly;
#ifndef WIN32
d->_logPipe = usePipe;
#else
d->_logPipe = false;
#endif
// level string to level value
// assoc["emerg"] = levelEmergency;
// assoc["alert"] = levelAlert;
// assoc["critical"] = levelCritical;
// assoc["error"] = levelError;
// assoc["warn"] = levelWarning;
// assoc["notice"] = levelNotice;
// assoc["info"] = levelInfo;
// assoc["debug"] = levelDebug;
if (logFileName)
d->_nomeFile = logFileName;
if (!d->_logDirectly && logFileName)
d->_pLogger = new logger(logFileName, d->_logPipe);
else
d->_pLogger = NULL;
// writes to file directly
if (!d->_nomeFile.empty() && d->_logDirectly)
{
if (!d->_logPipe)
{
d->_logfs.open(d->_nomeFile.c_str(), std::fstream::in | std::fstream::out);
if (!d->_logfs.is_open())
{
d->_logfs.open(d->_nomeFile.c_str(), std::fstream::out | std::fstream::app);
}
else
d->_logfs.seekg(0, std::fstream::end);
}
// on Windows pipe are not used as they are not supported on WinNT
#ifndef WIN32
else
{
// create pipe
int err = mkfifo(d->_nomeFile.c_str(), S_IREAD | S_IWRITE);
if (err == 0 || errno == EEXIST)
{
// and open it
d->_logfs.open(d->_nomeFile.c_str(), std::fstream::in | std::fstream::out);
}
else
THROW(AppLogException("Can't create pipe"));
}
#endif
if (d->_logfs.fail())
THROW(AppLogException("Can't open log file name"));
}
//from Error level on write to syslog also
slog.level(Slog::levelError);
slog.clogEnable(false);
}
AppLog::~AppLog()
{
// if _logDirectly
close();
if (d) delete d;
}
void AppLog::subscribe()
{
ost::MutexLock mtx(d->_subMutex);
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
{
// subscribes new thread
d->_logs[tid];
}
}
}
void AppLog::unsubscribe()
{
ost::MutexLock mtx(d->_subMutex);
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt != d->_logs.end())
{
// unsubscribes thread
d->_logs.erase(logIt);
}
}
}
#ifndef WIN32
void AppLog::logFileName(const char* FileName, bool logDirectly, bool usePipe)
#else
void AppLog::logFileName(const char* FileName, bool logDirectly)
#endif
{
if (!FileName)
{
slog.error("Null file name!");
return;
}
d->_lock.enterMutex();
d->_nomeFile = FileName;
close();
d->_logDirectly = logDirectly;
#ifndef WIN32
d->_logPipe = usePipe;
#else
d->_logPipe = false;
#endif
if (!d->_logDirectly)
{
d->_nomeFile = FileName;
if (d->_pLogger)
d->_pLogger->logFileName(FileName, d->_logPipe);
else
d->_pLogger = new logger(FileName, d->_logPipe);
d->_lock.leaveMutex();
return;
}
// log directly
if (!d->_nomeFile.empty())
{
if (!d->_logPipe)
{
d->_logfs.open(d->_nomeFile.c_str(), std::fstream::out | std::fstream::app);
}
#ifndef WIN32
else
{
// create pipe
int err = mkfifo(d->_nomeFile.c_str(), S_IREAD | S_IWRITE);
if (err == 0 || errno == EEXIST)
{
// and open it
d->_logfs.open(d->_nomeFile.c_str(), std::fstream::in | std::fstream::out);
}
else
THROW(AppLogException("Can't create pipe"));
}
#endif
if (d->_logfs.fail())
THROW(AppLogException("Can't open log file name"));
}
d->_lock.leaveMutex();
}
// writes to log
void AppLog::writeLog(bool endOfLine)
{
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
if ((d->_logDirectly && !d->_logfs.is_open() && !logIt->second._clogEnable) ||
(!d->_logDirectly && !d->_pLogger && !logIt->second._clogEnable))
{
logIt->second._msgpos = 0;
logIt->second._msgbuf[0] = '\0';
return;
}
if (logIt->second._enable)
{
time_t now;
struct tm *dt;
time(&now);
struct timeval detail_time;
gettimeofday(&detail_time, NULL);
dt = localtime(&now);
char buf[50];
const char *p = "unknown";
switch (logIt->second._priority)
{
case Slog::levelEmergency:
p = "emerg";
break;
case Slog::levelInfo:
p = "info";
break;
case Slog::levelError:
p = "error";
break;
case Slog::levelAlert:
p = "alert";
break;
case Slog::levelDebug:
p = "debug";
break;
case Slog::levelNotice:
p = "notice";
break;
case Slog::levelWarning:
p = "warn";
break;
case Slog::levelCritical:
p = "crit";
break;
}
snprintf(buf, sizeof(buf) - 1, "%04d-%02d-%02d %02d:%02d:%02d.%03d ",
dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday,
dt->tm_hour, dt->tm_min, dt->tm_sec, (int)(detail_time.tv_usec / 1000));
buf[sizeof(buf)-1] = 0; // per sicurezza
if (d->_logDirectly)
{
d->_lock.enterMutex();
if (d->_logfs.is_open())
{
d->_logfs << buf;
if (!logIt->second._ident.empty())
d->_logfs << logIt->second._ident.c_str() << ": ";
d->_logfs << "[" << p << "] ";
d->_logfs << logIt->second._msgbuf;
if (endOfLine)
d->_logfs << endl;
d->_logfs.flush();
}
}
else if (d->_pLogger)
{
// ThreadQueue
std::stringstream sstr;
sstr.str(""); // reset contents
sstr << buf;
if (!logIt->second._ident.empty())
sstr << logIt->second._ident.c_str() << ": ";
sstr << "[" << p << "] ";
sstr << logIt->second._msgbuf;
if (endOfLine)
sstr << endl;
sstr.flush();
if (sstr.fail())
cerr << "stringstream failed!!!! " << endl;
// enqueues log message
d->_pLogger->post((void *) sstr.str().c_str(), sstr.str().length() + 1);
d->_lock.enterMutex();
}
// slog it if error level is right
if (logIt->second._slogEnable && logIt->second._priority <= Slog::levelError)
{
slog((Slog::Level) logIt->second._priority) << logIt->second._msgbuf;
if (endOfLine) slog << endl;
}
if (logIt->second._clogEnable
#ifndef WIN32
&& (getppid() > 1)
#endif
)
{
clog << logIt->second._msgbuf;
if (endOfLine)
clog << endl;
}
d->_lock.leaveMutex();
}
logIt->second._msgpos = 0;
logIt->second._msgbuf[0] = '\0';
}
}
void AppLog::close(void)
{
if (d->_logDirectly)
{
d->_lock.enterMutex();
if (d->_logfs.is_open())
{
d->_logfs.flush();
d->_logfs.close();
}
d->_lock.leaveMutex();
}
}
void AppLog::open(const char *ident)
{
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
if (d->_nomeFile.empty())
{
std::cerr << "Empty file name" << std::endl;
slog.emerg("Empty file nane!\n");
}
if (d->_logDirectly)
{
d->_lock.enterMutex();
if (!d->_logfs.is_open())
{
d->_logfs.open(d->_nomeFile.c_str(), std::fstream::out | std::fstream::app);
}
if (!d->_logfs.is_open())
{
std::cerr << "Can't open file name!" << std::endl;
slog.emerg("Can't open file name!\n");
}
d->_lock.leaveMutex();
}
if (ident != NULL)
logIt->second._ident = ident;
}
}
void AppLog::identLevel(const char *ident, Slog::Level level)
{
if (!ident)
return;
string id = ident;
IdentLevel::iterator idLevIt = d->_identLevel.find(id);
if (idLevIt == d->_identLevel.end())
{
d->_identLevel[id] = level;
}
else
idLevIt->second = level;
}
void AppLog::level(Slog::Level enable)
{
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
logIt->second._level = enable;
}
}
void AppLog::clogEnable(bool f)
{
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
logIt->second._clogEnable = f;
}
}
void AppLog::slogEnable(bool en)
{
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
logIt->second._slogEnable = en;
}
}
int AppLog::sync()
{
int retVal = (pbase() != pptr());
if (fail())
{
slog(Slog::levelNotice) << "fail() is true, calling clear()" << endl;
clear();
}
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt != d->_logs.end())
{
retVal = (logIt->second._msgpos > 0);
if (retVal)
{
slog(Slog::levelNotice) << "sync called and msgpos > 0" << endl;
}
}
}
overflow(EOF);
return retVal;
}
int AppLog::overflow(int c)
{
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return c;
if (!logIt->second._enable)
return c;
if (c == '\n' || !c || c == EOF)
{
if (!logIt->second._msgpos)
{
if (c == '\n') writeLog(true);
return c;
}
if (logIt->second._msgpos < (int)(sizeof(logIt->second._msgbuf) - 1))
logIt->second._msgbuf[logIt->second._msgpos] = 0;
else
logIt->second._msgbuf[logIt->second._msgpos-1] = 0;
writeLog(c == '\n');
//reset buffer
logIt->second._msgpos = 0;
return c;
}
if (logIt->second._msgpos < (int)(sizeof(logIt->second._msgbuf) - 1))
logIt->second._msgbuf[logIt->second._msgpos++] = c;
}
return c;
}
#ifdef HAVE_SNPRINTF
void AppLog::error(const char *format, ...)
{
va_list args;
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
error();
if (!logIt->second._enable)
return;
overflow(EOF);
va_start(args, format);
logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
overflow(EOF);
if (logIt->second._slogEnable)
slog.error(logIt->second._msgbuf);
va_end(args);
}
}
void AppLog::warn(const char *format, ...)
{
va_list args;
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
warn();
if (!logIt->second._enable)
return;
overflow(EOF);
va_start(args, format);
logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
overflow(EOF);
if (logIt->second._slogEnable)
slog.warn(logIt->second._msgbuf);
va_end(args);
}
}
void AppLog::debug(const char *format, ...)
{
va_list args;
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
debug();
if (!logIt->second._enable)
return;
overflow(EOF);
va_start(args, format);
logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
overflow(EOF);
va_end(args);
}
}
void AppLog::emerg(const char *format, ...)
{
va_list args;
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
emerg();
if (!logIt->second._enable)
return;
overflow(EOF);
va_start(args, format);
logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
overflow(EOF);
if (logIt->second._slogEnable)
slog.emerg(logIt->second._msgbuf);
va_end(args);
}
}
void AppLog::alert(const char *format, ...)
{
va_list args;
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
alert();
if (!logIt->second._enable)
return;
overflow(EOF);
va_start(args, format);
logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
overflow(EOF);
if (logIt->second._slogEnable)
slog.alert(logIt->second._msgbuf);
va_end(args);
}
}
void AppLog::critical(const char *format, ...)
{
va_list args;
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
critical();
if (!logIt->second._enable)
return;
overflow(EOF);
va_start(args, format);
logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
overflow(EOF);
if (logIt->second._slogEnable)
slog.critical(logIt->second._msgbuf);
va_end(args);
}
}
void AppLog::notice(const char *format, ...)
{
va_list args;
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
notice();
if (!logIt->second._enable)
return;
overflow(EOF);
va_start(args, format);
logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
overflow(EOF);
if (logIt->second._slogEnable)
slog.notice(logIt->second._msgbuf);
va_end(args);
}
}
void AppLog::info(const char *format, ...)
{
va_list args;
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return;
info();
if (!logIt->second._enable)
return;
overflow(EOF);
va_start(args, format);
logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
overflow(EOF);
va_end(args);
}
}
#endif //HAVE_SNPRINTF
AppLog &AppLog::operator()(Slog::Level lev)
{
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return *this;
// needed? overflow(EOF);
// enables log
Slog::Level th_lev = logIt->second._level;
logIt->second._enable = (th_lev >= lev);
// is there a log level per module?
if (!logIt->second._ident.empty())
{
std::string st = logIt->second._ident;
IdentLevel::iterator idLevIt = d->_identLevel.find(st);
if (idLevIt != d->_identLevel.end())
{
th_lev = idLevIt->second;
logIt->second._enable = (th_lev >= lev);
}
}
logIt->second._priority = lev;
}
return *this;
}
AppLog &AppLog::operator()(const char *ident, Slog::Level lev)
{
Thread *pThr = getThread();
if (pThr)
{
cctid_t tid = pThr->getId();
LogPrivateData::iterator logIt = d->_logs.find(tid);
if (logIt == d->_logs.end())
return this->operator()(lev);
logIt->second._enable = true;
open(ident);
}
return this->operator()(lev);
}
AppLog& AppLog::operator<< (AppLog& (*pfManipulator)(AppLog&))
{
return (*pfManipulator)(*this);
}
AppLog& AppLog::operator<< (ostream& (*pfManipulator)(ostream&))
{
(*pfManipulator)(*(dynamic_cast<ostream*>(this)));
return *this ;
}
#ifdef CCXX_NAMESPACES
}
#endif