|
reSIProcate/rutil
9694
|
00001 #include "rutil/Socket.hxx" 00002 00003 #include <cassert> 00004 #include <iostream> 00005 #include <fstream> 00006 #include <stdio.h> 00007 #include "rutil/Data.hxx" 00008 00009 #ifndef WIN32 00010 #include <sys/time.h> 00011 #endif 00012 00013 #include <sys/types.h> 00014 #include <time.h> 00015 00016 #include "rutil/Log.hxx" 00017 #include "rutil/Logger.hxx" 00018 #include "rutil/ParseBuffer.hxx" 00019 #include "rutil/ThreadIf.hxx" 00020 #include "rutil/Subsystem.hxx" 00021 #include "rutil/SysLogStream.hxx" 00022 #include "rutil/WinLeakCheck.hxx" 00023 00024 using namespace resip; 00025 using namespace std; 00026 00027 const Data Log::delim(" | "); 00028 Log::ThreadData Log::mDefaultLoggerData(0, Log::Cout, Log::Info, NULL, NULL); 00029 Data Log::mAppName; 00030 Data Log::mHostname; 00031 unsigned int Log::MaxLineCount = 0; // no limit by default 00032 unsigned int Log::MaxByteCount = 0; // no limit by default 00033 00034 #ifdef WIN32 00035 int Log::mPid=0; 00036 #else 00037 pid_t Log::mPid=0; 00038 #endif 00039 00040 volatile short Log::touchCount = 0; 00041 00042 00044 #ifdef LOG_ENABLE_THREAD_SETTING 00045 #if defined(__APPLE__) || defined(__CYGWIN__) 00046 HashValueImp(ThreadIf::Id, (size_t)data); 00047 #endif 00048 HashMap<ThreadIf::Id, std::pair<Log::ThreadSetting, bool> > Log::mThreadToLevel; 00049 HashMap<int, std::set<ThreadIf::Id> > Log::mServiceToThreads; 00050 ThreadIf::TlsKey* Log::mLevelKey; 00051 #endif 00052 HashMap<int, Log::Level> Log::mServiceToLevel; 00053 00054 Log::LocalLoggerMap Log::mLocalLoggerMap; 00055 ThreadIf::TlsKey* Log::mLocalLoggerKey; 00056 00057 const char 00058 Log::mDescriptions[][32] = {"NONE", "EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG", "STACK", "CERR", ""}; 00059 00060 Mutex Log::_mutex; 00061 00062 extern "C" 00063 { 00064 void freeThreadSetting(void* setting) 00065 { 00066 delete static_cast<Log::ThreadSetting*>(setting); 00067 } 00068 00069 void freeLocalLogger(void* pThreadData) 00070 { 00071 if (pThreadData) 00072 { 00073 // There was some local logger installed. Decrease its use count before we 00074 // continue. 00075 Log::mLocalLoggerMap.decreaseUseCount((static_cast<Log::ThreadData*>(pThreadData))->id()); 00076 } 00077 } 00078 } 00079 00080 unsigned int LogStaticInitializer::mInstanceCounter=0; 00081 LogStaticInitializer::LogStaticInitializer() 00082 { 00083 if (mInstanceCounter++ == 0) 00084 { 00085 #ifdef LOG_ENABLE_THREAD_SETTING 00086 Log::mLevelKey = new ThreadIf::TlsKey; 00087 ThreadIf::tlsKeyCreate(*Log::mLevelKey, freeThreadSetting); 00088 #endif 00089 00090 Log::mLocalLoggerKey = new ThreadIf::TlsKey; 00091 ThreadIf::tlsKeyCreate(*Log::mLocalLoggerKey, freeLocalLogger); 00092 } 00093 } 00094 LogStaticInitializer::~LogStaticInitializer() 00095 { 00096 if (--mInstanceCounter == 0) 00097 { 00098 #ifdef LOG_ENABLE_THREAD_SETTING 00099 ThreadIf::tlsKeyDelete(*Log::mLevelKey); 00100 delete Log::mLevelKey; 00101 #endif 00102 00103 ThreadIf::tlsKeyDelete(*Log::mLocalLoggerKey); 00104 delete Log::mLocalLoggerKey; 00105 } 00106 } 00107 00108 void 00109 Log::initialize(const char* typed, const char* leveld, const char* appName, const char *logFileName, ExternalLogger* externalLogger) 00110 { 00111 Log::initialize(Data(typed), Data(leveld), Data(appName), logFileName, externalLogger); 00112 } 00113 00114 void 00115 Log::initialize(const Data& typed, const Data& leveld, const Data& appName, 00116 const char *logFileName, ExternalLogger* externalLogger) 00117 { 00118 Type type = Log::Cout; 00119 if (isEqualNoCase(typed, "cout")) type = Log::Cout; 00120 else if (isEqualNoCase(typed, "cerr")) type = Log::Cerr; 00121 else if (isEqualNoCase(typed, "file")) type = Log::File; 00122 else type = Log::Syslog; 00123 00124 Level level = Log::Info; 00125 level = toLevel(leveld); 00126 00127 Log::initialize(type, level, appName, logFileName, externalLogger); 00128 } 00129 00130 void 00131 Log::initialize(Type type, Level level, const Data& appName, 00132 const char * logFileName, 00133 ExternalLogger* externalLogger) 00134 { 00135 Lock lock(_mutex); 00136 mDefaultLoggerData.reset(); 00137 00138 mDefaultLoggerData.set(type, level, logFileName, externalLogger); 00139 00140 ParseBuffer pb(appName); 00141 pb.skipToEnd(); 00142 #ifdef _WIN32 00143 pb.skipBackToChar('\\'); 00144 #else 00145 pb.skipBackToChar('/'); 00146 #endif 00147 mAppName = pb.position(); 00148 00149 char buffer[1024]; 00150 gethostname(buffer, sizeof(buffer)); 00151 mHostname = buffer; 00152 #ifdef WIN32 00153 mPid = (int)GetCurrentProcess(); 00154 #else 00155 mPid = getpid(); 00156 #endif 00157 } 00158 00159 void 00160 Log::initialize(Type type, 00161 Level level, 00162 const Data& appName, 00163 ExternalLogger& logger) 00164 { 00165 initialize(type, level, appName, 0, &logger); 00166 } 00167 00168 void 00169 Log::setLevel(Level level) 00170 { 00171 Lock lock(_mutex); 00172 getLoggerData().mLevel = level; 00173 } 00174 00175 void 00176 Log::setLevel(Level level, Subsystem& s) 00177 { 00178 Lock lock(_mutex); 00179 s.setLevel(level); 00180 } 00181 00182 void 00183 Log::setLevel(Level level, Log::LocalLoggerId loggerId) 00184 { 00185 if (loggerId) 00186 { 00187 ThreadData *pData = mLocalLoggerMap.getData(loggerId); 00188 if (pData) 00189 { 00190 // Local logger found. Set logging level. 00191 pData->mLevel = level; 00192 00193 // We don't need local logger instance anymore. 00194 mLocalLoggerMap.decreaseUseCount(loggerId); 00195 pData = NULL; 00196 } 00197 } 00198 else 00199 { 00200 Lock lock(_mutex); 00201 mDefaultLoggerData.mLevel = level; 00202 } 00203 } 00204 00205 Log::Level 00206 Log::level(Log::LocalLoggerId loggerId) 00207 { 00208 Level level; 00209 ThreadData *pData; 00210 if (loggerId && (pData = mLocalLoggerMap.getData(loggerId))) 00211 { 00212 // Local logger found. Set logging level. 00213 level = pData->mLevel; 00214 00215 // We don't need local logger instance anymore. 00216 mLocalLoggerMap.decreaseUseCount(loggerId); 00217 pData = NULL; 00218 } 00219 else 00220 { 00221 Lock lock(_mutex); 00222 level = mDefaultLoggerData.mLevel; 00223 } 00224 return level; 00225 } 00226 00227 void 00228 Log::setMaxLineCount(unsigned int maxLineCount) 00229 { 00230 Lock lock(_mutex); 00231 getLoggerData().mMaxLineCount = maxLineCount; 00232 } 00233 00234 void 00235 Log::setMaxLineCount(unsigned int maxLineCount, Log::LocalLoggerId loggerId) 00236 { 00237 if (loggerId) 00238 { 00239 ThreadData *pData = mLocalLoggerMap.getData(loggerId); 00240 if (pData) 00241 { 00242 // Local logger found. Set logging level. 00243 pData->mMaxLineCount = maxLineCount; 00244 00245 // We don't need local logger instance anymore. 00246 mLocalLoggerMap.decreaseUseCount(loggerId); 00247 pData = NULL; 00248 } 00249 } 00250 else 00251 { 00252 Lock lock(_mutex); 00253 mDefaultLoggerData.mMaxLineCount = maxLineCount; 00254 } 00255 } 00256 00257 void 00258 Log::setMaxByteCount(unsigned int maxByteCount) 00259 { 00260 Lock lock(_mutex); 00261 getLoggerData().mMaxByteCount = maxByteCount; 00262 } 00263 00264 void 00265 Log::setMaxByteCount(unsigned int maxByteCount, Log::LocalLoggerId loggerId) 00266 { 00267 if (loggerId) 00268 { 00269 ThreadData *pData = mLocalLoggerMap.getData(loggerId); 00270 if (pData) 00271 { 00272 // Local logger found. Set logging level. 00273 pData->mMaxByteCount = maxByteCount; 00274 00275 // We don't need local logger instance anymore. 00276 mLocalLoggerMap.decreaseUseCount(loggerId); 00277 pData = NULL; 00278 } 00279 } 00280 else 00281 { 00282 Lock lock(_mutex); 00283 mDefaultLoggerData.mMaxByteCount = maxByteCount; 00284 } 00285 } 00286 00287 const static Data log_("LOG_"); 00288 00289 Data 00290 Log::toString(Level l) 00291 { 00292 return log_ + mDescriptions[l+1]; 00293 } 00294 00295 Log::Level 00296 Log::toLevel(const Data& l) 00297 { 00298 Data pri( l.prefix("LOG_") ? l.substr(4) : l); 00299 00300 int i=0; 00301 while (strlen(mDescriptions[i])) 00302 { 00303 if (strcmp(pri.c_str(), mDescriptions[i]) == 0) 00304 { 00305 return Level(i-1); 00306 } 00307 i++; 00308 } 00309 00310 cerr << "Choosing Debug level since string was not understood: " << l << endl; 00311 return Log::Debug; 00312 } 00313 00314 Log::Type 00315 Log::toType(const Data& arg) 00316 { 00317 if (arg == "cout" || arg == "COUT") 00318 { 00319 return Log::Cout; 00320 } 00321 else if (arg == "cerr" || arg == "CERR") 00322 { 00323 return Log::Cerr; 00324 } 00325 else if (arg == "file" || arg == "FILE") 00326 { 00327 return Log::File; 00328 } 00329 else 00330 { 00331 return Log::Syslog; 00332 } 00333 } 00334 00335 EncodeStream & 00336 Log::tags(Log::Level level, 00337 const Subsystem& subsystem, 00338 const char* pfile, 00339 int line, 00340 EncodeStream& strm) 00341 { 00342 char buffer[256]; 00343 Data ts(Data::Borrow, buffer, sizeof(buffer)); 00344 #if defined( __APPLE__ ) 00345 strm << mDescriptions[level+1] << Log::delim 00346 << timestamp(ts) << Log::delim 00347 << mAppName << Log::delim 00348 << subsystem << Log::delim 00349 << pthread_self() << Log::delim 00350 << pfile << ":" << line; 00351 #elif defined( WIN32 ) 00352 const char* file = pfile + strlen(pfile); 00353 while (file != pfile && 00354 *file != '\\') 00355 { 00356 --file; 00357 } 00358 if (file != pfile) 00359 { 00360 ++file; 00361 } 00362 strm << mDescriptions[level+1] << Log::delim 00363 << timestamp(ts) << Log::delim 00364 << mAppName << Log::delim 00365 << subsystem << Log::delim 00366 << GetCurrentThreadId() << Log::delim 00367 << file << ":" << line; 00368 #else // #if defined( WIN32 ) || defined( __APPLE__ ) 00369 strm << mDescriptions[level+1] << Log::delim 00370 << timestamp(ts) << Log::delim 00371 // << mHostname << Log::delim 00372 << mAppName << Log::delim 00373 << subsystem << Log::delim 00374 // << mPid << Log::delim 00375 << pthread_self() << Log::delim 00376 << pfile << ":" << line; 00377 #endif 00378 return strm; 00379 } 00380 00381 Data 00382 Log::timestamp() 00383 { 00384 char buffer[256]; 00385 Data result(Data::Borrow, buffer, sizeof(buffer)); 00386 return timestamp(result); 00387 } 00388 00389 Data& 00390 Log::timestamp(Data& res) 00391 { 00392 char* datebuf = const_cast<char*>(res.data()); 00393 const unsigned int datebufSize = 256; 00394 res.clear(); 00395 00396 #ifdef WIN32 00397 int result = 1; 00398 SYSTEMTIME systemTime; 00399 struct { time_t tv_sec; int tv_usec; } tv = {0,0}; 00400 time(&tv.tv_sec); 00401 GetLocalTime(&systemTime); 00402 tv.tv_usec = systemTime.wMilliseconds * 1000; 00403 #else 00404 struct timeval tv; 00405 int result = gettimeofday (&tv, NULL); 00406 #endif 00407 00408 if (result == -1) 00409 { 00410 /* If we can't get the time of day, don't print a timestamp. 00411 Under Unix, this will never happen: gettimeofday can fail only 00412 if the timezone is invalid which it can't be, since it is 00413 uninitialized]or if tv or tz are invalid pointers. */ 00414 datebuf [0] = 0; 00415 } 00416 else 00417 { 00418 /* The tv_sec field represents the number of seconds passed since 00419 the Epoch, which is exactly the argument gettimeofday needs. */ 00420 const time_t timeInSeconds = (time_t) tv.tv_sec; 00421 strftime (datebuf, 00422 datebufSize, 00423 "%Y%m%d-%H%M%S", /* guaranteed to fit in 256 chars, 00424 hence don't check return code */ 00425 localtime (&timeInSeconds)); 00426 } 00427 00428 char msbuf[5]; 00429 /* Dividing (without remainder) by 1000 rounds the microseconds 00430 measure to the nearest millisecond. */ 00431 sprintf(msbuf, ".%3.3ld", long(tv.tv_usec / 1000)); 00432 00433 int datebufCharsRemaining = datebufSize - (int)strlen(datebuf); 00434 strncat (datebuf, msbuf, datebufCharsRemaining - 1); 00435 00436 datebuf[datebufSize - 1] = '\0'; /* Just in case strncat truncated msbuf, 00437 thereby leaving its last character at 00438 the end, instead of a null terminator */ 00439 00440 // ugh, resize the Data 00441 res.at(strlen(datebuf)-1); 00442 return res; 00443 } 00444 00445 Log::Level 00446 Log::getServiceLevel(int service) 00447 { 00448 Lock lock(_mutex); 00449 HashMap<int, Level>::iterator res = Log::mServiceToLevel.find(service); 00450 if(res == Log::mServiceToLevel.end()) 00451 { 00453 //default level of LOG_ERROR, but nobody uses this yet 00454 Log::mServiceToLevel[service] = Err; 00455 return Err; 00456 } 00457 return res->second; 00458 } 00459 00460 const Log::ThreadSetting* 00461 Log::getThreadSetting() 00462 { 00463 #ifndef LOG_ENABLE_THREAD_SETTING 00464 return 0; 00465 #else 00466 ThreadSetting* setting = static_cast<ThreadSetting*>(ThreadIf::tlsGetValue(*Log::mLevelKey)); 00467 if (setting == 0) 00468 { 00469 return 0; 00470 } 00471 if (Log::touchCount > 0) 00472 { 00473 Lock lock(_mutex); 00474 ThreadIf::Id thread = ThreadIf::selfId(); 00475 HashMap<ThreadIf::Id, pair<ThreadSetting, bool> >::iterator res = Log::mThreadToLevel.find(thread); 00476 assert(res != Log::mThreadToLevel.end()); 00477 if (res->second.second) 00478 { 00479 setting->mLevel = res->second.first.mLevel; 00480 res->second.second = false; 00481 touchCount--; 00482 // cerr << "**Log::getThreadSetting:touchCount: " << Log::touchCount << "**" << endl; 00483 00484 //cerr << "touchcount decremented" << endl; 00485 } 00486 } 00487 return setting; 00488 #endif 00489 } 00490 00491 void 00492 Log::setThreadSetting(int serv) 00493 { 00494 Log::setThreadSetting(ThreadSetting(serv, getServiceLevel(serv))); 00495 } 00496 00497 void 00498 Log::setThreadSetting(int serv, Log::Level l) 00499 { 00500 Log::setThreadSetting(ThreadSetting(serv, l)); 00501 } 00502 00503 void 00504 Log::setThreadSetting(ThreadSetting info) 00505 { 00506 #ifndef LOG_ENABLE_THREAD_SETTING 00507 assert(0); 00508 #else 00509 //cerr << "Log::setThreadSetting: " << "service: " << info.service << " level " << toString(info.level) << " for " << pthread_self() << endl; 00510 ThreadIf::Id thread = ThreadIf::selfId(); 00511 ThreadIf::tlsSetValue(*mLevelKey, (void *) new ThreadSetting(info)); 00512 Lock lock(_mutex); 00513 00514 if (Log::mThreadToLevel.find(thread) != Log::mThreadToLevel.end()) 00515 { 00516 if (Log::mThreadToLevel[thread].second == true) 00517 { 00518 touchCount--; 00519 } 00520 } 00521 Log::mThreadToLevel[thread].first = info; 00522 Log::mThreadToLevel[thread].second = false; 00523 Log::mServiceToThreads[info.mService].insert(thread); 00524 #endif 00525 } 00526 00527 void 00528 Log::setServiceLevel(int service, Level l) 00529 { 00530 Lock lock(_mutex); 00531 Log::mServiceToLevel[service] = l; 00532 #ifndef LOG_ENABLE_THREAD_SETTING 00533 assert(0); 00534 #else 00535 set<ThreadIf::Id>& threads = Log::mServiceToThreads[service]; 00536 for (set<ThreadIf::Id>::iterator i = threads.begin(); i != threads.end(); i++) 00537 { 00538 Log::mThreadToLevel[*i].first.mLevel = l; 00539 Log::mThreadToLevel[*i].second = true; 00540 } 00541 Log::touchCount += (short)threads.size(); 00542 #endif 00543 // cerr << "**Log::setServiceLevel:touchCount: " << Log::touchCount << "**" << endl; 00544 } 00545 00546 Log::LocalLoggerId Log::localLoggerCreate(Log::Type type, 00547 Log::Level level, 00548 const char * logFileName, 00549 ExternalLogger* externalLogger) 00550 { 00551 return mLocalLoggerMap.create(type, level, logFileName, externalLogger); 00552 } 00553 00554 int Log::localLoggerReinitialize(Log::LocalLoggerId loggerId, 00555 Log::Type type, 00556 Log::Level level, 00557 const char * logFileName, 00558 ExternalLogger* externalLogger) 00559 { 00560 return mLocalLoggerMap.reinitialize(loggerId, type, level, logFileName, externalLogger); 00561 } 00562 00563 int Log::localLoggerRemove(Log::LocalLoggerId loggerId) 00564 { 00565 return mLocalLoggerMap.remove(loggerId); 00566 } 00567 00568 int Log::setThreadLocalLogger(Log::LocalLoggerId loggerId) 00569 { 00570 ThreadData* pData = static_cast<ThreadData*>(ThreadIf::tlsGetValue(*Log::mLocalLoggerKey)); 00571 if (pData) 00572 { 00573 // There was some local logger installed. Decrease its use count before we 00574 // continue. 00575 mLocalLoggerMap.decreaseUseCount(pData->id()); 00576 pData = NULL; 00577 } 00578 if (loggerId) 00579 { 00580 pData = mLocalLoggerMap.getData(loggerId); 00581 } 00582 ThreadIf::tlsSetValue(*mLocalLoggerKey, (void *) pData); 00583 return (loggerId == 0) || (pData != NULL)?0:1; 00584 } 00585 00586 std::ostream& 00587 Log::Instance(unsigned int bytesToWrite) 00588 { 00589 return getLoggerData().Instance(bytesToWrite); 00590 } 00591 00592 void 00593 Log::reset() 00594 { 00595 getLoggerData().reset(); 00596 } 00597 00598 bool 00599 Log::isLogging(Log::Level level, const resip::Subsystem& sub) 00600 { 00601 if (sub.getLevel() != Log::None) 00602 { 00603 return level <= sub.getLevel(); 00604 } 00605 else 00606 { 00607 return (level <= Log::getLoggerData().mLevel); 00608 } 00609 } 00610 00611 void 00612 Log::OutputToWin32DebugWindow(const Data& result) 00613 { 00614 #ifdef WIN32 00615 const char *text = result.c_str(); 00616 #ifdef UNDER_CE 00617 LPWSTR lpwstrText = resip::ToWString(text); 00618 OutputDebugStringW(lpwstrText); 00619 FreeWString(lpwstrText); 00620 #else 00621 OutputDebugStringA(text); 00622 #endif 00623 #endif 00624 } 00625 00626 Log::LocalLoggerId Log::LocalLoggerMap::create(Log::Type type, 00627 Log::Level level, 00628 const char * logFileName, 00629 ExternalLogger* externalLogger) 00630 { 00631 Lock lock(mLoggerInstancesMapMutex); 00632 Log::LocalLoggerId id = ++mLastLocalLoggerId; 00633 Log::ThreadData *pNewData = new Log::ThreadData(id, type, level, logFileName, 00634 externalLogger); 00635 mLoggerInstancesMap[id].first = pNewData; 00636 mLoggerInstancesMap[id].second = 0; 00637 return id; 00638 } 00639 00640 int Log::LocalLoggerMap::reinitialize(Log::LocalLoggerId loggerId, 00641 Log::Type type, 00642 Log::Level level, 00643 const char * logFileName, 00644 ExternalLogger* externalLogger) 00645 { 00646 Lock lock(mLoggerInstancesMapMutex); 00647 LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId); 00648 if (it == mLoggerInstancesMap.end()) 00649 { 00650 // No such logger ID 00651 std::cerr << "Log::LocalLoggerMap::remove(): Unknown local logger id=" << loggerId << std::endl; 00652 return 1; 00653 } 00654 it->second.first->reset(); 00655 it->second.first->set(type, level, logFileName, externalLogger); 00656 return 0; 00657 } 00658 00659 int Log::LocalLoggerMap::remove(Log::LocalLoggerId loggerId) 00660 { 00661 Lock lock(mLoggerInstancesMapMutex); 00662 LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId); 00663 if (it == mLoggerInstancesMap.end()) 00664 { 00665 // No such logger ID 00666 std::cerr << "Log::LocalLoggerMap::remove(): Unknown local logger id=" << loggerId << std::endl; 00667 return 1; 00668 } 00669 if (it->second.second > 0) 00670 { 00671 // Non-zero use-count. 00672 std::cerr << "Log::LocalLoggerMap::remove(): Use count is non-zero (" << it->second.second << ")!" << std::endl; 00673 return 2; 00674 } 00675 delete it->second.first; // delete ThreadData 00676 mLoggerInstancesMap.erase(it); 00677 return 0; 00678 } 00679 00680 Log::ThreadData *Log::LocalLoggerMap::getData(Log::LocalLoggerId loggerId) 00681 { 00682 Lock lock(mLoggerInstancesMapMutex); 00683 LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId); 00684 if (it == mLoggerInstancesMap.end()) 00685 { 00686 // No such logger ID 00687 return NULL; 00688 } 00689 it->second.second++; 00690 return it->second.first; 00691 } 00692 00693 void Log::LocalLoggerMap::decreaseUseCount(Log::LocalLoggerId loggerId) 00694 { 00695 Lock lock(mLoggerInstancesMapMutex); 00696 LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId); 00697 if (it != mLoggerInstancesMap.end()) 00698 { 00699 it->second.second--; 00700 assert(it->second.second >= 0); 00701 } 00702 } 00703 00704 00705 Log::Guard::Guard(resip::Log::Level level, 00706 const resip::Subsystem& subsystem, 00707 const char* file, 00708 int line) : 00709 mLevel(level), 00710 mSubsystem(subsystem), 00711 mFile(file), 00712 mLine(line), 00713 mData(Data::Borrow, mBuffer, sizeof(mBuffer)), 00714 mStream(mData.clear()) 00715 { 00716 00717 if (resip::Log::getLoggerData().mType != resip::Log::OnlyExternalNoHeaders) 00718 { 00719 Log::tags(mLevel, mSubsystem, mFile, mLine, mStream); 00720 mStream << resip::Log::delim; 00721 mStream.flush(); 00722 00723 mHeaderLength = mData.size(); 00724 } 00725 else 00726 { 00727 mHeaderLength = 0; 00728 } 00729 } 00730 00731 Log::Guard::~Guard() 00732 { 00733 mStream.flush(); 00734 00735 if (resip::Log::getExternal()) 00736 { 00737 const resip::Data rest(resip::Data::Share, 00738 mData.data() + mHeaderLength, 00739 (int)mData.size() - mHeaderLength); 00740 if (!(*resip::Log::getExternal())(mLevel, 00741 mSubsystem, 00742 resip::Log::getAppName(), 00743 mFile, 00744 mLine, 00745 rest, 00746 mData)) 00747 { 00748 return; 00749 } 00750 } 00751 00752 Type logType = resip::Log::getLoggerData().mType; 00753 00754 if(logType == resip::Log::OnlyExternal || 00755 logType == resip::Log::OnlyExternalNoHeaders) 00756 { 00757 return; 00758 } 00759 00760 resip::Lock lock(resip::Log::_mutex); 00761 // !dlb! implement VSDebugWindow as an external logger 00762 if (logType == resip::Log::VSDebugWindow) 00763 { 00764 mData += "\r\n"; 00765 OutputToWin32DebugWindow(mData); 00766 } 00767 else 00768 { 00769 // endl is magic in syslog -- so put it here 00770 Instance((int)mData.size()+2) << mData << std::endl; 00771 } 00772 } 00773 00774 std::ostream& 00775 Log::ThreadData::Instance(unsigned int bytesToWrite) 00776 { 00777 // std::cerr << "Log::ThreadData::Instance() id=" << mId << " type=" << mType << std::endl; 00778 switch (mType) 00779 { 00780 case Log::Syslog: 00781 if (mLogger == 0) 00782 { 00783 std::cerr << "Creating a syslog stream" << std::endl; 00784 mLogger = new SysLogStream; 00785 } 00786 return *mLogger; 00787 00788 case Log::Cerr: 00789 return std::cerr; 00790 00791 case Log::Cout: 00792 return std::cout; 00793 00794 case Log::File: 00795 if (mLogger == 0 || 00796 (maxLineCount() && mLineCount >= maxLineCount()) || 00797 (maxByteCount() && ((unsigned int)mLogger->tellp()+bytesToWrite) >= maxByteCount())) 00798 { 00799 std::cerr << "Creating a logger for file \"" << mLogFileName.c_str() << "\"" << std::endl; 00800 Data logFileName(mLogFileName != "" ? mLogFileName : "resiprocate.log"); 00801 if (mLogger) 00802 { 00803 Data oldLogFileName(logFileName + ".old"); 00804 delete mLogger; 00805 // Keep one backup file: Delete .old file, Rename log file to .old 00806 // Could be expanded in the future to keep X backup log files 00807 remove(oldLogFileName.c_str()); 00808 rename(logFileName.c_str(), oldLogFileName.c_str()); 00809 } 00810 // Append to log if we have a line count or byte count limit - otherwise truncate 00811 mLogger = new std::ofstream(logFileName.c_str(), std::ios_base::out | ((maxLineCount() > 0 || maxByteCount() > 0) ? std::ios_base::app : std::ios_base::trunc)); 00812 mLineCount = 0; 00813 } 00814 mLineCount++; 00815 return *mLogger; 00816 default: 00817 assert(0); 00818 return std::cout; 00819 } 00820 } 00821 00822 void 00823 Log::ThreadData::reset() 00824 { 00825 delete mLogger; 00826 mLogger = NULL; 00827 } 00828 00829 /* ==================================================================== 00830 * The Vovida Software License, Version 1.0 00831 * 00832 * Copyright (c) 2000-2005 00833 * 00834 * Redistribution and use in source and binary forms, with or without 00835 * modification, are permitted provided that the following conditions 00836 * are met: 00837 * 00838 * 1. Redistributions of source code must retain the above copyright 00839 * notice, this list of conditions and the following disclaimer. 00840 * 00841 * 2. Redistributions in binary form must reproduce the above copyright 00842 * notice, this list of conditions and the following disclaimer in 00843 * the documentation and/or other materials provided with the 00844 * distribution. 00845 * 00846 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 00847 * and "Vovida Open Communication Application Library (VOCAL)" must 00848 * not be used to endorse or promote products derived from this 00849 * software without prior written permission. For written 00850 * permission, please contact vocal@vovida.org. 00851 * 00852 * 4. Products derived from this software may not be called "VOCAL", nor 00853 * may "VOCAL" appear in their name, without prior written 00854 * permission of Vovida Networks, Inc. 00855 * 00856 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 00857 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00858 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 00859 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 00860 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 00861 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 00862 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00863 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00864 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00865 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00866 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 00867 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00868 * DAMAGE. 00869 * 00870 * ==================================================================== 00871 * 00872 * This software consists of voluntary contributions made by Vovida 00873 * Networks, Inc. and many individuals on behalf of Vovida Networks, 00874 * Inc. For more information on Vovida Networks, Inc., please see 00875 * <http://www.vovida.org/>. 00876 * 00877 */
1.7.5.1