00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00039 #include "blocxx/BLOCXX_config.h"
00040 #include "blocxx/LogAppender.hpp"
00041 #include "blocxx/String.hpp"
00042 #include "blocxx/Array.hpp"
00043 #include "blocxx/LogMessage.hpp"
00044 #include "blocxx/Logger.hpp"
00045 #include "blocxx/Assertion.hpp"
00046 #include "blocxx/StringBuffer.hpp"
00047 #include "blocxx/NullAppender.hpp"
00048 #ifndef BLOCXX_WIN32
00049 #include "blocxx/SyslogAppender.hpp"
00050 #endif
00051 #include "blocxx/CerrAppender.hpp"
00052 #include "blocxx/FileAppender.hpp"
00053 #include "blocxx/MultiProcessFileAppender.hpp"
00054 #include "blocxx/Format.hpp"
00055 #include "blocxx/SortedVectorMap.hpp"
00056 #include "blocxx/NonRecursiveMutex.hpp"
00057 #include "blocxx/NonRecursiveMutexLock.hpp"
00058 #include "blocxx/ThreadOnce.hpp"
00059 #include "blocxx/NullLogger.hpp"
00060 #include "blocxx/GlobalPtr.hpp"
00061
00062
00063 namespace BLOCXX_NAMESPACE
00064 {
00065
00066 #ifdef BLOCXX_WIN32
00067 DWORD dwTlsIndex = 0;
00068 #endif
00069
00070 char const LOG_1_LOCATION_opt[] = "log.%1.location";
00071 char const LOG_1_MAX_FILE_SIZE_opt[] = "log.%1.max_file_size";
00072 char const LOG_1_MAX_BACKUP_INDEX_opt[] = "log.%1.max_backup_index";
00073 char const LOG_1_FLUSH_opt[] = "log.%1.flush";
00074 char const LOG_1_SYSLOG_IDENTITY_opt[] = "log.%1.identity";
00075 char const LOG_1_SYSLOG_FACILITY_opt[] = "log.%1.facility";
00076
00077
00079 LogAppender::~LogAppender()
00080 {
00081 }
00082
00084
00085 extern "C"
00086 {
00087 static void freeThreadLogAppender(void *ptr)
00088 {
00089 delete static_cast<LogAppenderRef *>(ptr);
00090 }
00091 }
00092
00094 namespace
00095 {
00096
00097 OnceFlag g_onceGuard = BLOCXX_ONCE_INIT;
00098 NonRecursiveMutex* g_mutexGuard = NULL;
00099
00100 struct NullAppenderFactory
00101 {
00102 static LogAppenderRef* create()
00103 {
00104 return new LogAppenderRef(new NullAppender());
00105 }
00106 };
00107 ::BLOCXX_NAMESPACE::GlobalPtr<LogAppenderRef,NullAppenderFactory> g_defaultLogAppender = BLOCXX_GLOBAL_PTR_INIT;
00108
00109
00111 void initGuardAndKey()
00112 {
00113 g_mutexGuard = new NonRecursiveMutex();
00114 #ifdef BLOCXX_WIN32
00115 LPVOID thread_data = NULL;
00116 BOOL ret = TlsSetValue(dwTlsIndex, thread_data)
00117 BLOCXX_ASSERTMSG(ret, "failed create a thread specific key");
00118 #elif BLOCXX_NCR
00119 int ret = pthread_keycreate(&g_loggerKey, freeThreadLogAppender);
00120 BLOCXX_ASSERTMSG(ret == 0, "failed create a thread specific key");
00121 #else
00122 int ret = pthread_key_create(&g_loggerKey, freeThreadLogAppender);
00123 BLOCXX_ASSERTMSG(ret == 0, "failed create a thread specific key");
00124 #endif
00125 }
00126
00127
00128 }
00129
00131
00132 LogAppenderRef
00133 LogAppender::getCurrentLogAppender()
00134 {
00135 LogAppenderRef threadLogAppender = getThreadLogAppender();
00136 if(threadLogAppender)
00137 {
00138 return threadLogAppender;
00139 }
00140 else
00141 {
00142 return getDefaultLogAppender();
00143 }
00144 }
00145
00147
00148 LogAppenderRef
00149 LogAppender::getDefaultLogAppender()
00150 {
00151 callOnce(g_onceGuard, initGuardAndKey);
00152 NonRecursiveMutexLock lock(*g_mutexGuard);
00153
00154
00155
00156
00157 return *g_defaultLogAppender;
00158 }
00159
00160
00162
00163 bool
00164 LogAppender::setDefaultLogAppender(const LogAppenderRef &ref)
00165 {
00166 if (ref)
00167 {
00168 callOnce(g_onceGuard, initGuardAndKey);
00169 NonRecursiveMutexLock lock(*g_mutexGuard);
00170
00171 LogAppenderRef(ref).swap(*g_defaultLogAppender);
00172 return true;
00173 }
00174 return false;
00175 }
00176
00177
00179
00180 LogAppenderRef
00181 LogAppender::getThreadLogAppender()
00182 {
00183 callOnce(g_onceGuard, initGuardAndKey);
00184 LogAppenderRef *ptr = NULL;
00185
00186 #ifdef BLOCXX_WIN32
00187 ptr = static_cast<LogAppenderRef *>(TlsGetValue(dwTlsIndex));
00188 #elif BLOCXX_NCR
00189 pthread_addr_t addr_ptr = NULL;
00190 int ret = pthread_getspecific(g_loggerKey, &addr_ptr);
00191 if (ret == 0)
00192 {
00193 ptr = static_cast<LogAppenderRef *>(addr_ptr);
00194 }
00195 #else
00196 ptr = static_cast<LogAppenderRef *>(pthread_getspecific(g_loggerKey));
00197 #endif
00198
00199 if(ptr)
00200 {
00201 return *ptr;
00202 }
00203 else
00204 {
00205 return LogAppenderRef();
00206 }
00207 }
00208
00210
00211 bool
00212 LogAppender::setThreadLogAppender(const LogAppenderRef &ref)
00213 {
00214 callOnce(g_onceGuard, initGuardAndKey);
00215 LogAppenderRef *ptr = 0;
00216 if (ref)
00217 {
00218 ptr = new LogAppenderRef(ref);
00219 }
00220 #ifdef BLOCXX_WIN32
00221 LogAppenderRef *ptr_old = static_cast<LogAppenderRef *>(TlsGetValue(dwTlsIndex));
00222 if (ptr_old)
00223 {
00224 delete ptr_old;
00225 }
00226
00227 BOOL ret = FALSE;
00228 if (!(ret = TlsSetValue(dwTlsIndex, ptr)))
00229 {
00230 if (ptr)
00231 {
00232 delete ptr;
00233 }
00234 }
00235 BLOCXX_ASSERTMSG(ret, "failed to set a thread specific logger");
00236 #elif BLOCXX_NCR
00237 pthread_addr_t addr_ptr = NULL;
00238 pthread_getspecific(g_loggerKey, &addr_ptr);
00239 freeThreadLogAppender(addr_ptr);
00240 int ret = pthread_setspecific(g_loggerKey, ptr);
00241 BLOCXX_ASSERTMSG(ret == 0, "failed to set a thread specific logger");
00242 #else
00243 freeThreadLogAppender(pthread_getspecific(g_loggerKey));
00244
00245 int ret = pthread_setspecific(g_loggerKey, ptr);
00246 if (ret != 0)
00247 {
00248 delete ptr;
00249 }
00250 BLOCXX_ASSERTMSG(ret == 0, "failed to set a thread specific logger");
00251 #endif
00252
00253 return (ref != 0);
00254 }
00255
00256
00258 void
00259 LogAppender::logMessage(const LogMessage& message) const
00260 {
00261 if (componentAndCategoryAreEnabled(message.component, message.category))
00262 {
00263 StringBuffer buf;
00264 m_formatter.formatMessage(message, buf);
00265 doProcessLogMessage(buf.releaseString(), message);
00266 }
00267 }
00268
00270 bool
00271 LogAppender::categoryIsEnabled(const String& category) const
00272 {
00273 return m_allCategories || m_categories.count(category) > 0;
00274 }
00275
00277 bool
00278 LogAppender::componentAndCategoryAreEnabled(const String& component, const String& category) const
00279 {
00280 return (m_allComponents || m_components.count(component) > 0) &&
00281 categoryIsEnabled(category);
00282 }
00283
00285 namespace
00286 {
00287 String
00288 getConfigItem(const LoggerConfigMap& configItems, const String &itemName, const String& defRetVal = "")
00289 {
00290 LoggerConfigMap::const_iterator i = configItems.find(itemName);
00291 if (i != configItems.end())
00292 {
00293 return i->second;
00294 }
00295 else
00296 {
00297 return defRetVal;
00298 }
00299 }
00300 }
00301
00303 LogAppenderRef
00304 LogAppender::createLogAppender(
00305 const String& name,
00306 const StringArray& components,
00307 const StringArray& categories,
00308 const String& messageFormat,
00309 const String& type,
00310 const LoggerConfigMap& configItems)
00311 {
00312 LogAppenderRef appender;
00313 if (type.empty() || type.equalsIgnoreCase(TYPE_NULL))
00314 {
00315 appender = new NullAppender(components, categories, messageFormat);
00316 }
00317 #ifndef BLOCXX_WIN32
00318 else if ( type == TYPE_SYSLOG )
00319 {
00320 String identity = getConfigItem(configItems, Format(LogConfigOptions::LOG_1_SYSLOG_IDENTITY_opt, name), BLOCXX_DEFAULT_LOG_1_SYSLOG_IDENTITY);
00321 String facility = getConfigItem(configItems, Format(LogConfigOptions::LOG_1_SYSLOG_FACILITY_opt, name), BLOCXX_DEFAULT_LOG_1_SYSLOG_FACILITY);
00322
00323 appender = new SyslogAppender(components, categories, messageFormat, identity, facility);
00324 }
00325 #endif
00326 else if (type == TYPE_STDERR || type == "cerr")
00327 {
00328 appender = new CerrAppender(components, categories, messageFormat);
00329 }
00330 else if (type == TYPE_FILE || type == TYPE_MPFILE)
00331 {
00332 String configItem = Format(LogConfigOptions::LOG_1_LOCATION_opt, name);
00333 String filename = getConfigItem(configItems, configItem);
00334
00335 UInt64 maxFileSize(0);
00336 try
00337 {
00338 maxFileSize = getConfigItem(configItems, Format(LogConfigOptions::LOG_1_MAX_FILE_SIZE_opt, name),
00339 BLOCXX_DEFAULT_LOG_1_MAX_FILE_SIZE).toUInt64();
00340 }
00341 catch (StringConversionException& e)
00342 {
00343 BLOCXX_THROW_ERR_SUBEX(LoggerException,
00344 Format("%1: Invalid config value: %2", LogConfigOptions::LOG_1_MAX_FILE_SIZE_opt, e.getMessage()).c_str(),
00345 Logger::E_INVALID_MAX_FILE_SIZE, e);
00346 }
00347
00348 unsigned int maxBackupIndex(0);
00349 try
00350 {
00351 maxBackupIndex = getConfigItem(configItems, Format(LogConfigOptions::LOG_1_MAX_BACKUP_INDEX_opt, name),
00352 BLOCXX_DEFAULT_LOG_1_MAX_BACKUP_INDEX).toUnsignedInt();
00353 }
00354 catch (StringConversionException& e)
00355 {
00356 BLOCXX_THROW_ERR_SUBEX(LoggerException,
00357 Format("%1: Invalid config value: %2", LogConfigOptions::LOG_1_MAX_BACKUP_INDEX_opt, e.getMessage()).c_str(),
00358 Logger::E_INVALID_MAX_BACKUP_INDEX, e);
00359 }
00360
00361 if (type == TYPE_FILE)
00362 {
00363 bool flushLog =
00364 getConfigItem(
00365 configItems,
00366 Format(LogConfigOptions::LOG_1_FLUSH_opt, name),
00367 BLOCXX_DEFAULT_LOG_1_FLUSH
00368 ).equalsIgnoreCase("true");
00369 appender = new FileAppender(
00370 components, categories, filename.c_str(), messageFormat,
00371 maxFileSize, maxBackupIndex, flushLog
00372 );
00373 }
00374 else
00375 {
00376 appender = new MultiProcessFileAppender(
00377 components, categories, filename, messageFormat,
00378 maxFileSize, maxBackupIndex
00379 );
00380 }
00381 }
00382 else
00383 {
00384 BLOCXX_THROW_ERR(LoggerException, Format("Unknown log type: %1", type).c_str(), Logger::E_UNKNOWN_LOG_APPENDER_TYPE);
00385 }
00386
00387 return appender;
00388 }
00389
00391 const GlobalStringArray LogAppender::ALL_COMPONENTS = BLOCXX_GLOBAL_STRING_INIT("*");
00392 const GlobalStringArray LogAppender::ALL_CATEGORIES = BLOCXX_GLOBAL_STRING_INIT("*");
00393 const GlobalString LogAppender::STR_TTCC_MESSAGE_FORMAT = BLOCXX_GLOBAL_STRING_INIT("%r [%t] %-5p %c - %m");
00394 const GlobalString LogAppender::TYPE_SYSLOG = BLOCXX_GLOBAL_STRING_INIT("syslog");
00395 const GlobalString LogAppender::TYPE_STDERR = BLOCXX_GLOBAL_STRING_INIT("stderr");
00396 const GlobalString LogAppender::TYPE_FILE = BLOCXX_GLOBAL_STRING_INIT("file");
00397 const GlobalString LogAppender::TYPE_MPFILE = BLOCXX_GLOBAL_STRING_INIT("mpfile");
00398 const GlobalString LogAppender::TYPE_NULL = BLOCXX_GLOBAL_STRING_INIT("null");
00399
00401 LogAppender::LogAppender(const StringArray& components, const StringArray& categories, const String& pattern)
00402 : m_components(components.begin(), components.end())
00403 , m_categories(categories.begin(), categories.end())
00404 , m_formatter(pattern)
00405 , m_logLevel(E_NONE_LEVEL)
00406 {
00407 m_allComponents = m_components.count("*") > 0;
00408 m_allCategories = m_categories.count("*") > 0;
00409
00410
00411 size_t numCategories = m_categories.size();
00412 size_t debug3Count = m_categories.count(Logger::STR_DEBUG3_CATEGORY);
00413 size_t debug2Count = m_categories.count(Logger::STR_DEBUG2_CATEGORY);
00414 size_t debugCount = m_categories.count(Logger::STR_DEBUG_CATEGORY);
00415 size_t infoCount = m_categories.count(Logger::STR_INFO_CATEGORY);
00416 size_t warningCount = m_categories.count(Logger::STR_WARNING_CATEGORY);
00417 size_t errorCount = m_categories.count(Logger::STR_ERROR_CATEGORY);
00418 size_t fatalCount = m_categories.count(Logger::STR_FATAL_CATEGORY);
00419 int nonLevelCategoryCount = numCategories - debug3Count - debug2Count - debugCount - infoCount - warningCount - errorCount - fatalCount;
00420
00421 if (numCategories == 0)
00422 {
00423 m_logLevel = E_NONE_LEVEL;
00424 }
00425 else if (m_allCategories || nonLevelCategoryCount > 0)
00426 {
00427 m_logLevel = E_ALL_LEVEL;
00428 }
00429 else if (debug3Count > 0)
00430 {
00431 m_logLevel = E_DEBUG3_LEVEL;
00432 }
00433 else if (debug2Count > 0)
00434 {
00435 m_logLevel = E_DEBUG2_LEVEL;
00436 }
00437 else if (debugCount > 0)
00438 {
00439 m_logLevel = E_DEBUG_LEVEL;
00440 }
00441 else if (infoCount > 0)
00442 {
00443 m_logLevel = E_INFO_LEVEL;
00444 }
00445 else if (warningCount > 0)
00446 {
00447 m_logLevel = E_WARNING_LEVEL;
00448 }
00449 else if (errorCount > 0)
00450 {
00451 m_logLevel = E_ERROR_LEVEL;
00452 }
00453 else if (fatalCount > 0)
00454 {
00455 m_logLevel = E_FATAL_ERROR_LEVEL;
00456 }
00457 else
00458 {
00459 BLOCXX_ASSERTMSG(0, "Internal error. LogAppender unable to determine log level!");
00460 }
00461 }
00462
00463
00464
00465 }
00466
00467