00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
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
00039 static const int g_numPriority = (int)(sizeof(g_priority) /
00040 sizeof(g_priority[0]));
00041
00042
00043 #if defined(NDEBUG)
00044 static const int g_defaultMaxPriority = 4;
00045 #else
00046 static const int g_defaultMaxPriority = 5;
00047 #endif
00048
00049
00050 static const int g_maxPriorityLength = 7;
00051
00052
00053 static const int g_prioritySuffixLength = 2;
00054
00055
00056 static const int g_priorityPad = g_maxPriorityLength +
00057 g_prioritySuffixLength;
00058
00059
00060
00061
00062
00063
00064 CLog* CLog::s_log = NULL;
00065
00066 CLog::CLog()
00067 {
00068 assert(s_log == NULL);
00069
00070
00071 m_mutex = ARCH->newMutex();
00072
00073
00074 m_maxPriority = g_defaultMaxPriority;
00075 m_maxNewlineLength = 0;
00076 insert(new CConsoleLogOutputter);
00077 }
00078
00079 CLog::~CLog()
00080 {
00081
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
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
00108 int priority = 4;
00109 if (fmt[0] == '%' && fmt[1] == 'z') {
00110 priority = fmt[2] - '\060';
00111 fmt += 3;
00112 }
00113
00114
00115 if (priority > getFilter()) {
00116 return;
00117 }
00118
00119
00120 char stack[1024];
00121
00122
00123 int sPad = m_maxNewlineLength;
00124
00125
00126
00127 char* buffer = stack;
00128 int len = (int)(sizeof(stack) / sizeof(stack[0]));
00129 while (true) {
00130
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
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
00146 else {
00147 break;
00148 }
00149 }
00150
00151
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
00161
00162
00163 sprintf(message, "%s %s: %s\n\t%s,%d", tmp, g_priority[priority], buffer, file, line);
00164
00165
00166
00167
00168
00169
00170
00171
00172 output(priority, message);
00173 } else {
00174 output(priority, buffer);
00175 }
00176
00177
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
00203
00204
00205
00206
00207
00208
00209
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
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
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
00289 CArchMutexLock lock(m_mutex);
00290 for (COutputterList::const_iterator index = m_alwaysOutputters.begin();
00291 index != m_alwaysOutputters.end();
00292 ++index) {
00293
00294 ILogOutputter* outputter = *index;
00295
00296
00297 strcpy(end, outputter->getNewline());
00298
00299
00300 outputter->write(static_cast<ILogOutputter::ELevel>(priority),
00301 tmp );
00302 }
00303 for (COutputterList::const_iterator index = m_outputters.begin();
00304 index != m_outputters.end(); ++index) {
00305
00306 ILogOutputter* outputter = *index;
00307
00308
00309 strcpy(end, outputter->getNewline());
00310
00311
00312 if (!outputter->write(static_cast<ILogOutputter::ELevel>(priority),
00313 tmp )) {
00314 break;
00315 }
00316 }
00317
00318 delete[] tmp;
00319 }