blocxx
LogAppender.cpp
Go to the documentation of this file.
1/*******************************************************************************
2* Copyright (C) 2005, Quest Software, Inc. All rights reserved.
3* Copyright (C) 2006, Novell, Inc. All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7*
8* * Redistributions of source code must retain the above copyright notice,
9* this list of conditions and the following disclaimer.
10* * Redistributions in binary form must reproduce the above copyright
11* notice, this list of conditions and the following disclaimer in the
12* documentation and/or other materials provided with the distribution.
13* * Neither the name of
14* Quest Software, Inc.,
15* nor Novell, Inc.,
16* nor the names of its contributors or employees may be used to
17* endorse or promote products derived from this software without
18* specific prior written permission.
19*
20* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30* POSSIBILITY OF SUCH DAMAGE.
31*******************************************************************************/
32
33
38
39#include "blocxx/BLOCXX_config.h"
41#include "blocxx/String.hpp"
42#include "blocxx/Array.hpp"
43#include "blocxx/LogMessage.hpp"
44#include "blocxx/Logger.hpp"
45#include "blocxx/Assertion.hpp"
48#ifndef BLOCXX_WIN32
50#endif
54#include "blocxx/Format.hpp"
58#include "blocxx/ThreadOnce.hpp"
59#include "blocxx/NullLogger.hpp"
60#include "blocxx/GlobalPtr.hpp"
61
62
63namespace BLOCXX_NAMESPACE
64{
65
66#ifdef BLOCXX_WIN32
67DWORD dwTlsIndex = 0;
68#endif
69
70char const LOG_1_LOCATION_opt[] = "log.%1.location";
71char const LOG_1_MAX_FILE_SIZE_opt[] = "log.%1.max_file_size";
72char const LOG_1_MAX_BACKUP_INDEX_opt[] = "log.%1.max_backup_index";
73char const LOG_1_FLUSH_opt[] = "log.%1.flush";
74char const LOG_1_SYSLOG_IDENTITY_opt[] = "log.%1.identity";
75char const LOG_1_SYSLOG_FACILITY_opt[] = "log.%1.facility";
76
77
82
84// we're passing a pointer to this to pthreads, it has to have C linkage.
85extern "C"
86{
87static void freeThreadLogAppender(void *ptr)
88{
89 delete static_cast<LogAppenderRef *>(ptr);
90}
91} // end extern "C"
92
94namespace
95{
96
97OnceFlag g_onceGuard = BLOCXX_ONCE_INIT;
98NonRecursiveMutex* g_mutexGuard = NULL;
99
100struct NullAppenderFactory
101{
102 static LogAppenderRef* create()
103 {
104 return new LogAppenderRef(new NullAppender());
105 }
106};
107::BLOCXX_NAMESPACE::GlobalPtr<LogAppenderRef,NullAppenderFactory> g_defaultLogAppender = BLOCXX_GLOBAL_PTR_INIT;
108
109
111void initGuardAndKey()
112{
113 g_mutexGuard = new NonRecursiveMutex();
114#ifdef BLOCXX_WIN32
115 LPVOID thread_data = NULL;
116 BOOL ret = TlsSetValue(dwTlsIndex, thread_data)
117 BLOCXX_ASSERTMSG(ret, "failed create a thread specific key");
118#elif BLOCXX_NCR
119 int ret = pthread_keycreate(&g_loggerKey, freeThreadLogAppender);
120 BLOCXX_ASSERTMSG(ret == 0, "failed create a thread specific key");
121#else
122 int ret = pthread_key_create(&g_loggerKey, freeThreadLogAppender);
123 BLOCXX_ASSERTMSG(ret == 0, "failed create a thread specific key");
124#endif
125}
126
127
128} // end unnamed namespace
129
131// STATIC
134{
135 LogAppenderRef threadLogAppender = getThreadLogAppender();
136 if(threadLogAppender)
137 {
138 return threadLogAppender;
139 }
140 else
141 {
142 return getDefaultLogAppender();
143 }
144}
145
147// STATIC
150{
151 callOnce(g_onceGuard, initGuardAndKey);
152 NonRecursiveMutexLock lock(*g_mutexGuard);
153
154 // This looks unsafe, but the get() method (called indirectly by operator*),
155 // if it has never been previously called, will allocate a new
156 // LogAppenderRef wich will have a NullAppender inside it.
157 return *g_defaultLogAppender;
158}
159
160
162// STATIC
163bool
165{
166 if (ref)
167 {
168 callOnce(g_onceGuard, initGuardAndKey);
169 NonRecursiveMutexLock lock(*g_mutexGuard);
170
171 LogAppenderRef(ref).swap(*g_defaultLogAppender);
172 return true;
173 }
174 return false;
175}
176
177
179// STATIC
182{
183 callOnce(g_onceGuard, initGuardAndKey);
184 LogAppenderRef *ptr = NULL;
185
186#ifdef BLOCXX_WIN32
187 ptr = static_cast<LogAppenderRef *>(TlsGetValue(dwTlsIndex));
188#elif BLOCXX_NCR
189 pthread_addr_t addr_ptr = NULL;
190 int ret = pthread_getspecific(g_loggerKey, &addr_ptr);
191 if (ret == 0)
192 {
193 ptr = static_cast<LogAppenderRef *>(addr_ptr);
194 }
195#else
196 ptr = static_cast<LogAppenderRef *>(pthread_getspecific(g_loggerKey));
197#endif
198
199 if(ptr)
200 {
201 return *ptr;
202 }
203 else
204 {
205 return LogAppenderRef();
206 }
207}
208
210// STATIC
211bool
213{
214 callOnce(g_onceGuard, initGuardAndKey);
215 LogAppenderRef *ptr = 0;
216 if (ref)
217 {
218 ptr = new LogAppenderRef(ref);
219 }
220#ifdef BLOCXX_WIN32
221 LogAppenderRef *ptr_old = static_cast<LogAppenderRef *>(TlsGetValue(dwTlsIndex));
222 if (ptr_old)
223 {
224 delete ptr_old;
225 }
226
227 BOOL ret = FALSE;
228 if (!(ret = TlsSetValue(dwTlsIndex, ptr)))
229 {
230 if (ptr)
231 {
232 delete ptr;
233 }
234 }
235 BLOCXX_ASSERTMSG(ret, "failed to set a thread specific logger");
236#elif BLOCXX_NCR
237 pthread_addr_t addr_ptr = NULL;
238 pthread_getspecific(g_loggerKey, &addr_ptr);
239 freeThreadLogAppender(addr_ptr);
240 int ret = pthread_setspecific(g_loggerKey, ptr);
241 BLOCXX_ASSERTMSG(ret == 0, "failed to set a thread specific logger");
242#else
243 freeThreadLogAppender(pthread_getspecific(g_loggerKey));
244
245 int ret = pthread_setspecific(g_loggerKey, ptr);
246 if (ret != 0)
247 {
248 delete ptr;
249 }
250 BLOCXX_ASSERTMSG(ret == 0, "failed to set a thread specific logger");
251#endif
252
253 return (ref != 0);
254}
255
256
258void
260{
262 {
263 StringBuffer buf;
264 m_formatter.formatMessage(message, buf);
265 doProcessLogMessage(buf.releaseString(), message);
266 }
267}
268
270bool
272{
273 return m_allCategories || m_categories.count(category) > 0;
274}
275
277bool
278LogAppender::componentAndCategoryAreEnabled(const String& component, const String& category) const
279{
280 return (m_allComponents || m_components.count(component) > 0) &&
281 categoryIsEnabled(category);
282}
283
285namespace
286{
287 String
288 getConfigItem(const LoggerConfigMap& configItems, const String &itemName, const String& defRetVal = "")
289 {
290 LoggerConfigMap::const_iterator i = configItems.find(itemName);
291 if (i != configItems.end())
292 {
293 return i->second;
294 }
295 else
296 {
297 return defRetVal;
298 }
299 }
300}
301
305 const String& name,
306 const StringArray& components,
307 const StringArray& categories,
308 const String& messageFormat,
309 const String& type,
310 const LoggerConfigMap& configItems)
311{
312 LogAppenderRef appender;
313 if (type.empty() || type.equalsIgnoreCase(TYPE_NULL))
314 {
315 appender = new NullAppender(components, categories, messageFormat);
316 }
317#ifndef BLOCXX_WIN32
318 else if ( type == TYPE_SYSLOG )
319 {
322
323 appender = new SyslogAppender(components, categories, messageFormat, identity, facility);
324 }
325#endif
326 else if (type == TYPE_STDERR || type == "cerr")
327 {
328 appender = new CerrAppender(components, categories, messageFormat);
329 }
330 else if (type == TYPE_FILE || type == TYPE_MPFILE)
331 {
333 String filename = getConfigItem(configItems, configItem);
334
335 UInt64 maxFileSize(0);
336 try
337 {
338 maxFileSize = getConfigItem(configItems, Format(LogConfigOptions::LOG_1_MAX_FILE_SIZE_opt, name),
340 }
342 {
344 Format("%1: Invalid config value: %2", LogConfigOptions::LOG_1_MAX_FILE_SIZE_opt, e.getMessage()).c_str(),
346 }
347
348 unsigned int maxBackupIndex(0);
349 try
350 {
351 maxBackupIndex = getConfigItem(configItems, Format(LogConfigOptions::LOG_1_MAX_BACKUP_INDEX_opt, name),
353 }
355 {
357 Format("%1: Invalid config value: %2", LogConfigOptions::LOG_1_MAX_BACKUP_INDEX_opt, e.getMessage()).c_str(),
359 }
360
361 if (type == TYPE_FILE)
362 {
363 bool flushLog =
364 getConfigItem(
365 configItems,
368 ).equalsIgnoreCase("true");
369 appender = new FileAppender(
370 components, categories, filename.c_str(), messageFormat,
371 maxFileSize, maxBackupIndex, flushLog
372 );
373 }
374 else // type == TYPE_MPFILE
375 {
376 appender = new MultiProcessFileAppender(
377 components, categories, filename, messageFormat,
378 maxFileSize, maxBackupIndex
379 );
380 }
381 }
382 else
383 {
384 BLOCXX_THROW_ERR(LoggerException, Format("Unknown log type: %1", type).c_str(), Logger::E_UNKNOWN_LOG_APPENDER_TYPE);
385 }
386
387 return appender;
388}
389
399
401LogAppender::LogAppender(const StringArray& components, const StringArray& categories, const String& pattern)
402 : m_components(components.begin(), components.end())
403 , m_categories(categories.begin(), categories.end())
404 , m_formatter(pattern)
406{
407 m_allComponents = m_components.count("*") > 0;
408 m_allCategories = m_categories.count("*") > 0;
409
410 // set up the log level
411 size_t numCategories = m_categories.size();
412 size_t debug3Count = m_categories.count(Logger::STR_DEBUG3_CATEGORY);
413 size_t debug2Count = m_categories.count(Logger::STR_DEBUG2_CATEGORY);
414 size_t debugCount = m_categories.count(Logger::STR_DEBUG_CATEGORY);
415 size_t infoCount = m_categories.count(Logger::STR_INFO_CATEGORY);
416 size_t warningCount = m_categories.count(Logger::STR_WARNING_CATEGORY);
417 size_t errorCount = m_categories.count(Logger::STR_ERROR_CATEGORY);
418 size_t fatalCount = m_categories.count(Logger::STR_FATAL_CATEGORY);
419 int nonLevelCategoryCount = numCategories - debug3Count - debug2Count - debugCount - infoCount - warningCount - errorCount - fatalCount;
420
421 if (numCategories == 0)
422 {
424 }
425 else if (m_allCategories || nonLevelCategoryCount > 0)
426 {
428 }
429 else if (debug3Count > 0)
430 {
432 }
433 else if (debug2Count > 0)
434 {
436 }
437 else if (debugCount > 0)
438 {
440 }
441 else if (infoCount > 0)
442 {
444 }
445 else if (warningCount > 0)
446 {
448 }
449 else if (errorCount > 0)
450 {
452 }
453 else if (fatalCount > 0)
454 {
456 }
457 else
458 {
459 BLOCXX_ASSERTMSG(0, "Internal error. LogAppender unable to determine log level!");
460 }
461}
462
463
464
465} // end namespace BLOCXX_NAMESPACE
466
467
#define BLOCXX_ASSERTMSG(CON, MSG)
BLOCXX_ASSERTMSG works the same as BLOCXX_ASSERT, but with a second string parameter that will be add...
Definition Assertion.hpp:71
#define BLOCXX_THROW_ERR_SUBEX(exType, msg, err, subex)
Throw an exception using FILE and LINE.
#define BLOCXX_THROW_ERR(exType, msg, err)
Throw an exception using FILE and LINE.
#define BLOCXX_GLOBAL_PTR_INIT
This macro is provided to abstract the details of GlobalPtr.
#define BLOCXX_GLOBAL_STRING_INIT(str)
#define BLOCXX_DEFAULT_LOG_1_SYSLOG_IDENTITY
Definition LogConfig.hpp:69
#define BLOCXX_DEFAULT_LOG_1_FLUSH
Definition LogConfig.hpp:65
#define BLOCXX_DEFAULT_LOG_1_MAX_FILE_SIZE
Definition LogConfig.hpp:57
#define BLOCXX_DEFAULT_LOG_1_MAX_BACKUP_INDEX
Definition LogConfig.hpp:61
#define BLOCXX_DEFAULT_LOG_1_SYSLOG_FACILITY
Definition LogConfig.hpp:73
The CerrAppender is a LogAppender derivative that sends log message to stderr.
virtual const char * getMessage() const
Returns the message.
This class sends log messges to a file.
const char * c_str() const
Definition Format.cpp:55
static const GlobalStringArray ALL_CATEGORIES
Pass to createLogAppender to indicate all categories.
static LogAppenderRef getDefaultLogAppender()
Returns a copy of default LogAppenderRef.
static const GlobalString TYPE_MPFILE
String of the type of the multi-process file log appender.
static const GlobalString TYPE_FILE
String of the type of the file log appender.
bool componentAndCategoryAreEnabled(const String &component, const String &category) const
LogAppender(const StringArray &components=ALL_COMPONENTS, const StringArray &categories=ALL_CATEGORIES, const String &pattern=STR_TTCC_MESSAGE_FORMAT)
static const GlobalString TYPE_SYSLOG
String of the type of the syslog log appender.
static bool setDefaultLogAppender(const LogAppenderRef &ref)
Set the default global LogAppenderRef.
SortedVectorSet< String > m_categories
SortedVectorSet< String > m_components
static LogAppenderRef getThreadLogAppender()
Returns a copy of the thread LogAppenderRef.
static LogAppenderRef createLogAppender(const String &name, const StringArray &components, const StringArray &categories, const String &messageFormat, const String &type, const LoggerConfigMap &configItems)
Create a concrete log appender depending on the type string passed in.
bool categoryIsEnabled(const String &category) const
static const GlobalStringArray ALL_COMPONENTS
Pass to createLogAppender to indicate all components.
static LogAppenderRef getCurrentLogAppender()
Get a copy of the per thread LogAppenderRef or if not set, the default one.
virtual void doProcessLogMessage(const String &formattedMessage, const LogMessage &message) const =0
static const GlobalString STR_TTCC_MESSAGE_FORMAT
The Log4j TTCC message format - TTCC is acronym for Time Thread Category Component.
static const GlobalString TYPE_NULL
String of the type of the null log appender.
void logMessage(const LogMessage &message) const
Log a message using the specified component and category.
static const GlobalString TYPE_STDERR
String of the type of the stderr log appender.
LogMessagePatternFormatter m_formatter
static bool setThreadLogAppender(const LogAppenderRef &ref)
Set a per thread LogAppenderRef that overrides the default one.
static const GlobalString STR_DEBUG2_CATEGORY
Definition Logger.hpp:96
static const GlobalString STR_WARNING_CATEGORY
Definition Logger.hpp:93
static const GlobalString STR_DEBUG3_CATEGORY
Definition Logger.hpp:97
static const GlobalString STR_DEBUG_CATEGORY
Definition Logger.hpp:95
static const GlobalString STR_FATAL_CATEGORY
Definition Logger.hpp:91
static const GlobalString STR_ERROR_CATEGORY
Definition Logger.hpp:92
static const GlobalString STR_INFO_CATEGORY
Definition Logger.hpp:94
This class sends log messges to a file, for use when there may be multiple processes logging to the s...
Note that descriptions of what exceptions may be thrown assumes that object is used correctly,...
Note that descriptions of what exceptions may be thrown assumes that object is used correctly,...
This class sends log messges to the bit bucket.
const_iterator find(const key_type &x) const
This String class is an abstract data type that represents as NULL terminated string of characters.
Definition String.hpp:67
bool equalsIgnoreCase(const String &arg) const
Determine if another String object is equal to this String object, ignoring case in the comparision.
Definition String.cpp:529
const char * c_str() const
Definition String.cpp:905
This class sends log messges to syslog.
const char *const LOG_1_SYSLOG_FACILITY_opt
Definition LogConfig.cpp:48
const char *const LOG_1_SYSLOG_IDENTITY_opt
Definition LogConfig.cpp:47
const char *const LOG_1_MAX_FILE_SIZE_opt
Definition LogConfig.cpp:44
const char *const LOG_1_LOCATION_opt
Definition LogConfig.cpp:43
const char *const LOG_1_MAX_BACKUP_INDEX_opt
Definition LogConfig.cpp:45
Taken from RFC 1321.
LazyGlobal< StringArray, const char *const, StringArrayConstructorFactory > GlobalStringArray
char const LOG_1_LOCATION_opt[]
void BLOCXX_COMMON_API callOnce(OnceFlag &flag, FuncT F)
The first time callOnce is called with a given onceFlag argument, it calls func with no argument and ...
LazyGlobal< String, char const *const > GlobalString
char const LOG_1_MAX_FILE_SIZE_opt[]
char const LOG_1_SYSLOG_FACILITY_opt[]
char const LOG_1_FLUSH_opt[]
Array< String > StringArray
Definition CommonFwd.hpp:73
static void freeThreadLogAppender(void *ptr)
char const LOG_1_MAX_BACKUP_INDEX_opt[]
IntrusiveReference< LogAppender > LogAppenderRef
Definition CommonFwd.hpp:67
SortedVectorMap< String, String > LoggerConfigMap
Definition LogConfig.hpp:53
char const LOG_1_SYSLOG_IDENTITY_opt[]