reSIProcate/rutil  9694
Log.hxx
Go to the documentation of this file.
00001 #ifndef RESIP_Log_hxx
00002 #define RESIP_Log_hxx
00003 
00004 #include "rutil/Data.hxx"
00005 
00006 #ifndef WIN32
00007 #include <syslog.h>
00008 #include <unistd.h>
00009 #endif
00010 
00011 #include <set>
00012 
00013 #include "rutil/Mutex.hxx"
00014 #include "rutil/Lock.hxx"
00015 #include "rutil/HashMap.hxx"
00016 #include "rutil/ThreadIf.hxx"
00017 #include <iostream>
00018 
00019 // !ipse! I think that this remark is no more valid with recent changes,
00020 // but I don't have MacOs X to test with. Someone should take this duty.
00021 //
00022 // NOTE: disabling thread setting code for native mac os applications.
00023 // since some logging takes place during static initialization we can't
00024 // be sure all the pthread stuff is ready to go. this eventually causes
00025 // crashes in the Mac OS native API.
00026 #if !defined(TARGET_OS_MAC)
00027 #define LOG_ENABLE_THREAD_SETTING
00028 // defining hash function in mac os (non-sdk api) and cygwin because
00029 // ThreadIf::Id is a pointer,  (this assumes it's always the same pointer)
00030 #if defined(__APPLE__) || defined(__CYGWIN__)
00031 HashValue(resip::ThreadIf::Id);
00032 #endif
00033 #endif
00034 
00035 extern "C"
00036 {
00037    // Forward declaration to make it friend of Log class.
00038    void freeLocalLogger(void* pThreadData);
00039 };
00040 
00041 
00042 namespace resip
00043 {
00044 
00045 class ExternalLogger;
00046 class Subsystem;
00047 
00053 class Log
00054 {
00055    public:
00056       enum Type
00057       {
00058          Cout = 0,
00059          Syslog, 
00060          File, 
00061          Cerr,
00062          VSDebugWindow,        
00063          OnlyExternal,         
00064          OnlyExternalNoHeaders 
00065 
00066       };
00067       
00068       enum Level
00069       {
00070          None = -1,
00071 #ifdef WIN32
00072          Crit = 2,
00073          Err = 3,
00074          Warning = 4,
00075          Info = 6,
00076          Debug = 7,
00077 #else
00078          Crit = LOG_CRIT,
00079 // #ifdef ERR // ncurses defines a macro called ERR 
00080 //          SIP2_ERR = LOG_ERR,
00081 // #else
00082 //          ERR = LOG_ERR,
00083 // #endif
00084          Err,
00085          Warning = LOG_WARNING,
00086          Info = LOG_INFO,
00087          Debug = LOG_DEBUG,
00088 #endif
00089          Stack = 8,
00090          StdErr = 9,
00091          Bogus = 666
00092       };
00093 
00095       typedef int LocalLoggerId;
00096 
00102       class Guard
00103       {
00104          public:
00107             Guard(Level level,
00108                   const Subsystem& system,
00109                   const char* file,
00110                   int line);
00111 
00113             ~Guard();
00114 
00115             EncodeStream& asStream() {return mStream;}
00116             operator EncodeStream&() {return mStream;}
00117 
00118          private:
00119             resip::Log::Level mLevel;
00120             const resip::Subsystem& mSubsystem;
00121             resip::Data::size_type mHeaderLength;
00122             const char* mFile;
00123             int mLine;
00124             char mBuffer[128];
00125             Data mData;
00126             oDataStream mStream;
00127             Guard& operator=(const Guard&);
00128       };
00129 
00130       class ThreadSetting
00131       {
00132          public:
00133             ThreadSetting()
00134                : mService(-1),
00135                  mLevel(Err)
00136             {}
00137 
00138             ThreadSetting(int serv, Level level)
00139                : mService(serv),
00140                  mLevel(level)
00141             {
00142             }
00143             
00144             int mService;
00145             Level mLevel;
00146       };
00147 
00149       static EncodeStream& tags(Log::Level level,
00150                                 const Subsystem& subsystem, 
00151                                 const char* file,
00152                                 int line,
00153                                 EncodeStream& strm);
00154 
00155       static Data& timestamp(Data& result);
00156       static Data timestamp();
00157       static ExternalLogger* getExternal()
00158       {
00159          return getLoggerData().mExternalLogger;
00160       }
00161       static Data getAppName()
00162       {
00163          return mAppName;
00164       }
00165 
00166       static void initialize(Type type,
00167                              Level level,
00168                              const Data& appName,
00169                              const char * logFileName = 0,
00170                              ExternalLogger* externalLogger = 0);
00171       static void initialize(const Data& type,
00172                              const Data& level,
00173                              const Data& appName,
00174                              const char * logFileName = 0,
00175                              ExternalLogger* externalLogger = 0);
00176       static void initialize(const char* type,
00177                              const char* level,
00178                              const char* appName,
00179                              const char * logFileName = 0,
00180                              ExternalLogger* externalLogger = 0);
00181       static void initialize(Type type,
00182                              Level level,
00183                              const Data& appName,
00184                              ExternalLogger& logger);
00185 
00189       static void setLevel(Level level);
00191       static void setLevel(Level level, Subsystem& s);
00193       static void setLevel(Level level, LocalLoggerId loggerId);
00197       static Level level() { Lock lock(_mutex); return getLoggerData().mLevel; }
00199       static Level level(LocalLoggerId loggerId);
00200       static LocalLoggerId id() { Lock lock(_mutex); return getLoggerData().id(); }
00201       static void setMaxLineCount(unsigned int maxLineCount);
00202       static void setMaxLineCount(unsigned int maxLineCount, LocalLoggerId loggerId);
00203       static void setMaxByteCount(unsigned int maxByteCount);
00204       static void setMaxByteCount(unsigned int maxByteCount, LocalLoggerId loggerId);
00205       static Level toLevel(const Data& l);
00206       static Type toType(const Data& t);
00207       static Data toString(Level l);
00208 
00210       static void setServiceLevel(int service, Level l);
00211       static Level getServiceLevel(int service);
00212 
00214       static const ThreadSetting* getThreadSetting();
00215       static void setThreadSetting(ThreadSetting info);
00216       static void setThreadSetting(int serv, Level l);
00217       static void setThreadSetting(int serv);
00218 
00220       static LocalLoggerId localLoggerCreate(Type type,
00221                                              Level level,
00222                                              const char * logFileName = NULL,
00223                                              ExternalLogger* externalLogger = NULL);
00224 
00229       static int localLoggerReinitialize(LocalLoggerId loggerId,
00230                                          Type type,
00231                                          Level level,
00232                                          const char * logFileName = NULL,
00233                                          ExternalLogger* externalLogger = NULL);                                                
00234 
00241       static int localLoggerRemove(LocalLoggerId loggerId);
00242 
00249       static int setThreadLocalLogger(LocalLoggerId loggerId);
00250 
00251 
00252       static std::ostream& Instance(unsigned int bytesToWrite);
00253       static bool isLogging(Log::Level level, const Subsystem&);
00254       static void OutputToWin32DebugWindow(const Data& result);      
00255       static void reset(); 
00256 
00257    public:
00258       static unsigned int MaxLineCount; 
00259       static unsigned int MaxByteCount; 
00260 
00261    protected:
00262       static Mutex _mutex;
00263       static volatile short touchCount;
00264       static const Data delim;
00265 
00266       class ThreadData
00267       {
00268          public:
00269             ThreadData(LocalLoggerId id, Type type=Cout, Level level=Info,
00270                        const char *logFileName=NULL,
00271                        ExternalLogger *pExternalLogger=NULL)
00272                : mLevel(level),
00273                  mMaxLineCount(0),
00274                  mMaxByteCount(0),
00275                  mExternalLogger(pExternalLogger),
00276                  mId(id),
00277                  mType(type),
00278                  mLogger(NULL),
00279                  mLineCount(0)
00280             {
00281                if (logFileName)
00282                {
00283                   mLogFileName = logFileName;
00284                }
00285             }
00286             ~ThreadData() { reset(); }
00287 
00288             void set(Type type=Cout, Level level=Info,
00289                      const char *logFileName=NULL,
00290                      ExternalLogger *pExternalLogger=NULL)
00291             {
00292                mType = type;
00293                mLevel = level;
00294 
00295                if (logFileName)
00296                {
00297                   mLogFileName = logFileName;
00298                }
00299                mExternalLogger = pExternalLogger;
00300             }
00301 
00302             LocalLoggerId id() const {return mId;}
00303             unsigned int maxLineCount() { return mMaxLineCount ? mMaxLineCount : MaxLineCount; }  // return local max, if not set use global max
00304             unsigned int maxByteCount() { return mMaxByteCount ? mMaxByteCount : MaxByteCount; }  // return local max, if not set use global max
00305 
00306             std::ostream& Instance(unsigned int bytesToWrite); 
00307             void reset(); 
00308 
00309             volatile Level mLevel;
00310             volatile unsigned int mMaxLineCount;
00311             volatile unsigned int mMaxByteCount;
00312             ExternalLogger* mExternalLogger;
00313 
00314          protected:
00315             friend class Guard;
00316             const LocalLoggerId mId;
00317             Type mType;
00318             Data mLogFileName;
00319             std::ostream* mLogger;
00320             unsigned int mLineCount;
00321       };
00322 
00323       static ThreadData mDefaultLoggerData; 
00324       static Data mAppName;
00325       static Data mHostname;
00326 #ifndef WIN32
00327       static pid_t mPid;
00328 #else   
00329       static int mPid;
00330 #endif
00331       static const char mDescriptions[][32];
00332 
00333       static ThreadData &getLoggerData()
00334       {
00335          ThreadData* pData = static_cast<ThreadData*>(ThreadIf::tlsGetValue(*Log::mLocalLoggerKey));
00336          return pData?*pData:mDefaultLoggerData;
00337       }
00338 
00340       class LocalLoggerMap
00341       {
00342       public:
00343          LocalLoggerMap()
00344             : mLastLocalLoggerId(0) {};
00345 
00347          LocalLoggerId create(Type type,
00348                               Level level,
00349                               const char * logFileName = NULL,
00350                               ExternalLogger* externalLogger = NULL);
00351 
00356          int reinitialize(LocalLoggerId loggerId,
00357                           Type type,
00358                           Level level,
00359                           const char * logFileName = NULL,
00360                           ExternalLogger* externalLogger = NULL);                                               
00361 
00368          int remove(LocalLoggerId loggerId);
00369 
00372          ThreadData *getData(LocalLoggerId loggerId);
00373 
00375          void decreaseUseCount(LocalLoggerId loggerId);
00376 
00377       protected:
00379          typedef HashMap<LocalLoggerId, std::pair<ThreadData*, int> > LoggerInstanceMap;
00380          LoggerInstanceMap mLoggerInstancesMap;
00382          LocalLoggerId mLastLocalLoggerId;
00384          Mutex mLoggerInstancesMapMutex;
00385       };
00386 
00387       friend void ::freeLocalLogger(void* pThreadData);
00388       friend class LogStaticInitializer;
00389       static LocalLoggerMap mLocalLoggerMap;
00390       static ThreadIf::TlsKey* mLocalLoggerKey;
00391 
00392 
00394 #ifdef LOG_ENABLE_THREAD_SETTING
00395       static HashMap<ThreadIf::Id, std::pair<ThreadSetting, bool> > mThreadToLevel;
00396       static HashMap<int, std::set<ThreadIf::Id> > mServiceToThreads;
00397       static ThreadIf::TlsKey* mLevelKey;
00398 #endif
00399       static HashMap<int, Level> mServiceToLevel;
00400 };
00401 
00404 class ExternalLogger
00405 {
00406 public:
00407    virtual ~ExternalLogger() {};
00409    virtual bool operator()(Log::Level level,
00410       const Subsystem& subsystem, 
00411       const Data& appName,
00412       const char* file,
00413       int line,
00414       const Data& message,
00415       const Data& messageWithHeaders) = 0;
00416 };
00417 
00419 class LogStaticInitializer {
00420 public:
00421    LogStaticInitializer();
00422    ~LogStaticInitializer();
00423 protected:
00424    static unsigned int mInstanceCounter;
00425     
00426 #ifdef WIN32
00427    // LogStaticInitializer calls ThreadIf::tlsKeyCreate which 
00428    // relies on the static TlsDestructorInitializer having set
00429    // up mTlsDestructorsMutex which is used to Lock TLS access
00430    // Since the order of static initialization is not reliable,
00431    // we must make sure that TlsDestructorInitializer is initialized
00432    // before LogStaticInitializer is inizialized:
00433    TlsDestructorInitializer tlsDestructorInitializer;
00434 #endif
00435 };
00436 static LogStaticInitializer _staticLogInit;
00437 
00438 }
00439 
00440 #endif
00441 
00442 /* ====================================================================
00443  * The Vovida Software License, Version 1.0 
00444  * 
00445  * Copyright (c) 2000-2005.
00446  * 
00447  * Redistribution and use in source and binary forms, with or without
00448  * modification, are permitted provided that the following conditions
00449  * are met:
00450  * 
00451  * 1. Redistributions of source code must retain the above copyright
00452  *    notice, this list of conditions and the following disclaimer.
00453  * 
00454  * 2. Redistributions in binary form must reproduce the above copyright
00455  *    notice, this list of conditions and the following disclaimer in
00456  *    the documentation and/or other materials provided with the
00457  *    distribution.
00458  * 
00459  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00460  *    and "Vovida Open Communication Application Library (VOCAL)" must
00461  *    not be used to endorse or promote products derived from this
00462  *    software without prior written permission. For written
00463  *    permission, please contact vocal@vovida.org.
00464  *
00465  * 4. Products derived from this software may not be called "VOCAL", nor
00466  *    may "VOCAL" appear in their name, without prior written
00467  *    permission of Vovida Networks, Inc.
00468  * 
00469  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00470  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00471  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00472  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00473  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00474  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00475  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00476  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00477  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00478  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00479  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00480  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00481  * DAMAGE.
00482  * 
00483  * ====================================================================
00484  * 
00485  * This software consists of voluntary contributions made by Vovida
00486  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00487  * Inc.  For more information on Vovida Networks, Inc., please see
00488  * <http://www.vovida.org/>.
00489  *
00490  */