reSIProcate/rutil  9694
Log.cxx
Go to the documentation of this file.
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  */