Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members

CLog.cpp

00001 /*
00002  * synergy -- mouse and keyboard sharing utility
00003  * Copyright (C) 2002 Chris Schoeneman
00004  *
00005  * This package is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * found in the file COPYING that should have accompanied this file.
00008  *
00009  * This package is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  */
00014 
00015 #include "CLog.h"
00016 #include "CString.h"
00017 #include "CStringUtil.h"
00018 #include "LogOutputters.h"
00019 #include "CArch.h"
00020 #include "Version.h"
00021 #include <cstdio>
00022 #include <cstring>
00023 #include <iostream>
00024 #include <ctime> 
00025 
00026 // names of priorities
00027 static const char*    g_priority[] = {
00028                 "FATAL",
00029                 "ERROR",
00030                 "WARNING",
00031                 "NOTE",
00032                 "INFO",
00033                 "DEBUG",
00034                 "DEBUG1",
00035                 "DEBUG2"
00036               };
00037 
00038 // number of priorities
00039 static const int    g_numPriority = (int)(sizeof(g_priority) /
00040                       sizeof(g_priority[0]));
00041 
00042 // the default priority
00043 #if defined(NDEBUG)
00044 static const int    g_defaultMaxPriority = 4;
00045 #else
00046 static const int    g_defaultMaxPriority = 5;
00047 #endif
00048 
00049 // length of longest string in g_priority
00050 static const int    g_maxPriorityLength = 7;
00051 
00052 // length of suffix string (": ")
00053 static const int    g_prioritySuffixLength = 2;
00054 
00055 // amount of padded required to fill in the priority prefix
00056 static const int    g_priorityPad = g_maxPriorityLength +
00057                     g_prioritySuffixLength;
00058 
00059 
00060 //
00061 // CLog
00062 //
00063 
00064 CLog*         CLog::s_log = NULL;
00065 
00066 CLog::CLog()
00067 {
00068   assert(s_log == NULL);
00069 
00070   // create mutex for multithread safe operation
00071   m_mutex            = ARCH->newMutex();
00072 
00073   // other initalization
00074   m_maxPriority      = g_defaultMaxPriority;
00075   m_maxNewlineLength = 0;
00076   insert(new CConsoleLogOutputter);
00077 }
00078 
00079 CLog::~CLog()
00080 {
00081   // clean up
00082   for (COutputterList::iterator index  = m_outputters.begin();
00083                   index != m_outputters.end(); ++index) {
00084     delete *index;
00085   }
00086   for (COutputterList::iterator index  = m_alwaysOutputters.begin();
00087                   index != m_alwaysOutputters.end(); ++index) {
00088     delete *index;
00089   }
00090   ARCH->closeMutex(m_mutex);
00091   s_log = NULL;
00092 }
00093 
00094 CLog*
00095 CLog::getInstance()
00096 {
00097   // note -- not thread safe;  client must initialize log safely
00098   if (s_log == NULL) {
00099     s_log = new CLog;
00100   }
00101   return s_log;
00102 }
00103 
00104 void
00105 CLog::print(const char* file, int line, const char* fmt, ...) const
00106 {
00107   // check if fmt begins with a priority argument
00108   int priority = 4;
00109   if (fmt[0] == '%' && fmt[1] == 'z') {
00110     priority = fmt[2] - '\060';
00111     fmt += 3;
00112   }
00113 
00114   // done if below priority threshold
00115   if (priority > getFilter()) {
00116     return;
00117   }
00118 
00119   // compute prefix padding length
00120   char stack[1024];
00121 
00122   // compute suffix padding length
00123   int sPad = m_maxNewlineLength;
00124 
00125   // print to buffer, leaving space for a newline at the end and prefix
00126   // at the beginning.
00127   char* buffer = stack;
00128   int len      = (int)(sizeof(stack) / sizeof(stack[0]));
00129   while (true) {
00130     // try printing into the buffer
00131     va_list args;
00132     va_start(args, fmt);
00133     int n = ARCH->vsnprintf(buffer, len  - sPad, fmt, args);
00134     va_end(args);
00135 
00136     // if the buffer wasn't big enough then make it bigger and try again
00137     if (n < 0 || n > (int)len) {
00138       if (buffer != stack) {
00139         delete[] buffer;
00140       }
00141       len   *= 2;
00142       buffer = new char[len];
00143     }
00144 
00145     // if the buffer was big enough then continue
00146     else {
00147       break;
00148     }
00149   }
00150 
00151   // print the prefix to the buffer.  leave space for priority label.
00152   if (file != NULL) {
00153       char message[2048];
00154       struct tm *tm;
00155       char tmp[220];
00156       time_t t;
00157       time(&t);
00158       tm = localtime(&t);
00159       sprintf(tmp, "%04i-%02i-%02iT%02i:%02i:%02i", tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
00160       //strcpy(msg, tmp);
00161 
00162       
00163       sprintf(message, "%s %s: %s\n\t%s,%d", tmp, g_priority[priority], buffer, file, line);
00164 //    buffer[pPad - 1] = ' ';
00165 
00166     // discard file and line if priority < 0
00167     /*if (priority < 0) {
00168       message += pPad - g_priorityPad;
00169     }
00170     */
00171       // output buffer
00172       output(priority, message);
00173   } else {
00174       output(priority, buffer);
00175   }
00176 
00177   // clean up
00178   if (buffer != stack) {
00179     delete[] buffer;
00180   }
00181 }
00182 
00183 void
00184 CLog::insert(ILogOutputter* outputter, bool alwaysAtHead)
00185 {
00186   assert(outputter               != NULL);
00187   assert(outputter->getNewline() != NULL);
00188 
00189   CArchMutexLock lock(m_mutex);
00190   if (alwaysAtHead) {
00191     m_alwaysOutputters.push_front(outputter);
00192   }
00193   else {
00194     m_outputters.push_front(outputter);
00195   }
00196   int newlineLength = strlen(outputter->getNewline());
00197   if (newlineLength > m_maxNewlineLength) {
00198     m_maxNewlineLength = newlineLength;
00199   }
00200   outputter->open(kAppVersion);
00201 
00202   // Issue 41
00203   // don't show log unless user requests it, as some users find this
00204   // feature irritating (i.e. when they lose network connectivity).
00205   // in windows the log window can be displayed by selecting "show log"
00206   // from the synergy system tray icon.
00207   // if this causes problems for other architectures, then a different
00208   // work around should be attempted.
00209   //outputter->show(false);
00210 }
00211 
00212 void
00213 CLog::remove(ILogOutputter* outputter)
00214 {
00215   CArchMutexLock lock(m_mutex);
00216   m_outputters.remove(outputter);
00217   m_alwaysOutputters.remove(outputter);
00218 }
00219 
00220 void
00221 CLog::pop_front(bool alwaysAtHead)
00222 {
00223   CArchMutexLock lock(m_mutex);
00224   COutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters;
00225   if (!list->empty()) {
00226     delete list->front();
00227     list->pop_front();
00228   }
00229 }
00230 
00231 bool
00232 CLog::setFilter(const char* maxPriority)
00233 {
00234   if (maxPriority != NULL) {
00235     for (int i = 0; i < g_numPriority; ++i) {
00236       if (strcmp(maxPriority, g_priority[i]) == 0) {
00237         setFilter(i);
00238         return true;
00239       }
00240     }
00241     return false;
00242   }
00243   return true;
00244 }
00245 
00246 void
00247 CLog::setFilter(int maxPriority)
00248 {
00249   CArchMutexLock lock(m_mutex);
00250   m_maxPriority = maxPriority;
00251 }
00252 
00253 int
00254 CLog::getFilter() const
00255 {
00256   CArchMutexLock lock(m_mutex);
00257   return m_maxPriority;
00258 }
00259 
00260 void
00261 CLog::output(int priority, char* msg) const
00262 {
00263   assert(priority >= -1 && priority < g_numPriority);
00264   assert(msg != NULL);
00265 
00266   // insert priority label
00267   //int n = -g_prioritySuffixLength;
00268   /*
00269   if (priority >= 0) {
00270 
00271       
00272     n = strlen(g_priority[priority]);
00273     strcpy(msg + g_maxPriorityLength - n, g_priority[priority]);
00274     msg[g_maxPriorityLength + 0] = ':';
00275     msg[g_maxPriorityLength + 1] = ' ';
00276     msg[g_maxPriorityLength + 1] = ' ';
00277 
00278     
00279   }
00280 */
00281   // find end of message
00282   //char* end = msg + g_priorityPad + strlen(msg + g_priorityPad);
00283   int len = strlen(msg);
00284   char* tmp = new char[len+m_maxNewlineLength+1];
00285   char* end = tmp + len;
00286   strcpy(tmp, msg);
00287 
00288   // write to each outputter
00289   CArchMutexLock lock(m_mutex);
00290   for (COutputterList::const_iterator index  = m_alwaysOutputters.begin();
00291                     index != m_alwaysOutputters.end();
00292                     ++index) {
00293     // get outputter
00294     ILogOutputter* outputter = *index;
00295     
00296     // put an appropriate newline at the end
00297     strcpy(end, outputter->getNewline());
00298 
00299     // write message
00300     outputter->write(static_cast<ILogOutputter::ELevel>(priority),
00301               tmp /*+ g_maxPriorityLength - n*/);
00302   }
00303   for (COutputterList::const_iterator index  = m_outputters.begin();
00304                     index != m_outputters.end(); ++index) {
00305     // get outputter
00306     ILogOutputter* outputter = *index;
00307 
00308     // put an appropriate newline at the end
00309     strcpy(end, outputter->getNewline());
00310 
00311     // write message and break out of loop if it returns false
00312     if (!outputter->write(static_cast<ILogOutputter::ELevel>(priority),
00313               tmp /*+ g_maxPriorityLength - n*/)) {
00314       break;
00315     }
00316   }
00317 
00318   delete[] tmp;
00319 }

Generated on Fri Nov 6 00:21:14 2009 for synergy-plus by  doxygen 1.3.9.1