#ifndef WIN32 #include #else #include #include #endif #include #include #include #include "GLTB/logging.h" #include "GLTB/exception.h" namespace gltb { Config::Config() { level = LogNone; enabled = false; prefix = true; } Config::Config(LogLevel level,bool enabled,bool prefix) { this->level = level; this->enabled = enabled; this->prefix = prefix; } Stream::Stream() { channels[Console] = Config(); channels[SysLog] = Config(); channels[File] = Config(); channels[Callback] = Config(LogNone,false,false); #ifdef WIN32 channels[DebugString] = Config(); #endif #ifndef WIN32 openlog("jadeds_lxsrv",0,LOG_DAEMON); #endif } Stream::~Stream() { if(fileStream.is_open() == true) { fileStream.flush(); fileStream.close(); } #ifndef WIN32 closelog(); #else FreeConsole(); #endif } bool Stream::setFileChannel(std::string fileName) { return setFileChannel(fileName.c_str()); } bool Stream::setFileChannel(const char *fileNamePtr) { if(fileStream.is_open() == true) { fileStream.flush(); fileStream.close(); } fileStream.open(fileNamePtr,std::ios::out|std::ios::trunc); if(fileStream.good() == false) return false; return true; } void Stream::addCallbackChannel(LogCallback *callbackPtr) { if(std::find(callbackList.begin(),callbackList.end(),callbackPtr) == callbackList.end()) callbackList.push_back(callbackPtr); } void Stream::removeCallbackChannel(LogCallback *callbackPtr) { std::list::iterator callback = std::find(callbackList.begin(),callbackList.end(),callbackPtr); if(callback != callbackList.end()) callbackList.erase(callback); } bool Stream::outChannel(Channel channel,LogLevel level,bool enable,bool prefix) { bool wasEnabled = channels[channel].enabled; channels[channel] = Config(level,level == LogNone ? false : enable,prefix); return wasEnabled; } #ifdef WIN32 DWORD dwStreamIdx = TLS_OUT_OF_INDEXES; #endif Stream::PerThread *Stream::perThread(void) { #ifdef WIN32 Stream::PerThread *perThreadPtr = (PerThread *) TlsGetValue(dwStreamIdx); if(dwStreamIdx == TLS_OUT_OF_INDEXES) dwStreamIdx = TlsAlloc(); #else static THREAD Stream::PerThread *perThreadPtr = 0L; #endif if(perThreadPtr == 0L) { perThreadPtr = new Stream::PerThread; perThreadPtr->streamPtr = new std::stringstream(); perThreadPtr->lineLevel = LogInfo; perThreadPtr->newLine = true; #ifdef WIN32 TlsSetValue(dwStreamIdx,perThreadPtr); #endif } return perThreadPtr; } void Stream::detachThread(void) { #ifdef WIN32 Stream::PerThread *perThreadPtr = (Stream::PerThread *) TlsGetValue(dwStreamIdx); if(perThreadPtr != 0L) delete perThreadPtr; #endif } void Stream::detachProcess(void) { #ifdef WIN32 if(dwStreamIdx == TLS_OUT_OF_INDEXES) TlsFree(dwStreamIdx); #endif } void Stream::flush(void) { std::stringstream outMessage; std::string prefix; #ifndef WIN32 int sysLogLevel = LOG_DAEMON; #endif if(perThread()->streamPtr->str().length() == 0) return; if(perThread()->newLine == true) { switch(perThread()->lineLevel) { case LogCritical : prefix = "[CRIT] "; #ifndef WIN32 sysLogLevel |= LOG_CRIT; #endif break; case LogError : prefix = "[ERRO] "; #ifndef WIN32 sysLogLevel |= LOG_ERR; #endif break; case LogWarning : prefix = "[WARN] "; #ifndef WIN32 sysLogLevel |= LOG_WARNING; #endif break; case LogInfo : prefix = "[INFO] "; #ifndef WIN32 sysLogLevel |= LOG_INFO; #endif break; case LogDebug : prefix = "[DBUG] "; #ifndef WIN32 sysLogLevel |= LOG_DEBUG; #endif break; case LogDetail : prefix = "[DTAL] "; #ifndef WIN32 sysLogLevel |= LOG_DEBUG; #endif break; default : prefix = "[UKWN] "; #ifndef WIN32 sysLogLevel |= LOG_DEBUG; #endif break; } perThread()->newLine = false; } outMessage << perThread()->streamPtr->str() << std::endl; if((channels[Console].enabled == true) && (channels[Console].level >= perThread()->lineLevel)) { if(channels[Console].prefix == true) std::cout << prefix; std::cout << outMessage.str(); } #ifndef WIN32 if((channels[SysLog].enabled == true) && (channels[SysLog].level >= perThread()->lineLevel)) { std::string logMsg = outMessage.str(); if(channels[SysLog].prefix == true) logMsg = prefix + logMsg; syslog(sysLogLevel, "%s", logMsg.c_str()); } #else if((channels[DebugString].enabled == true) && (channels[DebugString].level >= perThread()->lineLevel)) { std::string logMsg = outMessage.str(); if(channels[DebugString].prefix == true) logMsg = prefix + logMsg; OutputDebugStringA((LPCSTR) logMsg.c_str()); } #endif if((channels[File].enabled == true) && (channels[File].level >= perThread()->lineLevel) && (fileStream.good() == true)) { if(channels[File].prefix == true) fileStream << prefix; fileStream << outMessage.str(); fileStream.flush(); } if((channels[Callback].enabled == true) && (channels[Callback].level >= perThread()->lineLevel)) { std::string logMsg = outMessage.str(); if(channels[Callback].prefix == true) logMsg = prefix + logMsg; for(std::list::iterator callback = callbackList.begin(); callback != callbackList.end(); callback++) (*callback)->log(channels[Callback].level,logMsg); } perThread()->streamPtr->str(std::string()); perThread()->lineLevel = LogInfo; } void Stream::endLine(void) { flush(); perThread()->newLine = true; } Stream &Stream::operator<<(Marker marker) { switch(marker) { case EndL : endLine(); break; case Flush : break; } return (*this); } Stream &Stream::operator<<(LogLevel level) { endLine(); perThread()->lineLevel = level; return (*this); } Stream &Stream::operator<<(long long longOut) { (*perThread()->streamPtr) << longOut; return (*this); } Stream &Stream::operator<<(unsigned long long longOut) { (*perThread()->streamPtr) << longOut; return (*this); } Stream &Stream::operator<<(long longOut) { (*perThread()->streamPtr) << longOut; return (*this); } Stream &Stream::operator<<(unsigned long longOut) { (*perThread()->streamPtr) << longOut; return (*this); } Stream &Stream::operator<<(int integerOut) { (*perThread()->streamPtr) << integerOut; return (*this); } Stream &Stream::operator<<(unsigned int integerOut) { (*perThread()->streamPtr) << integerOut; return (*this); } Stream &Stream::operator<<(float floatOut) { (*perThread()->streamPtr) << floatOut; return (*this); } Stream &Stream::operator<<(double doubleOut) { (*perThread()->streamPtr) << doubleOut; return (*this); } Stream &Stream::operator<<(std::string stringOut) { (*perThread()->streamPtr) << stringOut; return (*this); } void dumpBinary(Stream &stream, LogLevel lineLevel, void *binaryPtr, int length) { const static char map[] = "0123456789ABCDEF"; std::stringstream binaryStream; unsigned char *charPtr = (unsigned char *) binaryPtr; for(int index = 0; index < length; index++) { if((index % 32) == 0) { binaryStream << std::setfill('0') << std::setw(4) << index << "] "; } binaryStream << map[(charPtr[index] & 0xF0) >> 4]; binaryStream << map[charPtr[index] & 0xF]; binaryStream << " "; if(((index % 32) == 31) || ((index + 1) == length)) { stream << lineLevel << binaryStream.str() << EndL; binaryStream.str(""); } } } std::string logLevelToString(LogLevel level) { switch(level) { case LogCritical : return "Critical"; case LogError : return "Error"; case LogWarning : return "Warning"; case LogInfo : return "Info"; case LogDebug : return "Debug"; case LogDetail : return "Detail"; default : case LogNone : return "None"; } } LogLevel stringToLogLevel(std::string str) { if(str == "Critical") return LogCritical; else if(str == "Error") return LogError; else if(str == "Warning") return LogWarning; else if(str == "Info") return LogInfo; else if(str == "Debug") return LogDebug; else if(str == "Detail") return LogDetail; else return LogNone; } std::string channelToString(Channel channel) { switch(channel) { case Console: return "Console"; case SysLog: return "SysLog"; case File: return "File"; case Callback: return "Callback"; #ifdef WIN32 case DebugString: return "DebugString"; #endif default: return "None"; } } Channel stringToChannel(std::string channelName) { if(channelName=="Console") { return Console; } else if(channelName=="SysLog") { return SysLog; } else if(channelName=="File") { return File; } else if(channelName=="Callback") { return Callback; #ifdef WIN32 } else if(channelName=="DebugString") { return DebugString; #endif } throw Exception("unknown channel name","gltb::stringToChannel()"); } }