1 /*****************************************************************
3 | Neptune - Logging Support
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions are met:
10 | * Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 | * Neither the name of Axiomatic Systems nor the
16 | names of its contributors may be used to endorse or promote products
17 | derived from this software without specific prior written permission.
19 | THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY
23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 ****************************************************************/
32 * Implementation file for logging
35 /*----------------------------------------------------------------------
37 +---------------------------------------------------------------------*/
40 #include "NptLogging.h"
42 #include "NptStreams.h"
43 #include "NptSockets.h"
46 #include "NptSystem.h"
47 #include "NptConsole.h"
50 /*----------------------------------------------------------------------
52 +---------------------------------------------------------------------*/
53 //NPT_SET_LOCAL_LOGGER("neptune.logging")
55 /*----------------------------------------------------------------------
57 +---------------------------------------------------------------------*/
58 class NPT_LogConsoleHandler
: public NPT_LogHandler
{
62 OUTPUT_TO_CONSOLE
= 1,
67 static NPT_Result
Create(const char* logger_name
, NPT_LogHandler
*& handler
);
70 void Log(const NPT_LogRecord
& record
) override
;
76 NPT_Flags m_FormatFilter
;
79 class NPT_LogFileHandler
: public NPT_LogHandler
{
82 static NPT_Result
Create(const char* logger_name
, NPT_LogHandler
*& handler
);
85 void Log(const NPT_LogRecord
& record
) override
;
88 NPT_Result
Open(bool append
= true);
94 NPT_String m_Filename
;
95 NPT_Flags m_FormatFilter
;
96 NPT_LargeSize m_MaxFilesize
;
97 NPT_OutputStreamReference m_Stream
;
100 class NPT_LogTcpHandler
: public NPT_LogHandler
{
103 static void FormatRecord(const NPT_LogRecord
& record
, NPT_String
& msg
);
104 static NPT_Result
Create(const char* logger_name
, NPT_LogHandler
*& handler
);
107 void Log(const NPT_LogRecord
& record
) override
;
111 NPT_LogTcpHandler() : m_Port(0) {}
114 NPT_Result
Connect();
119 NPT_OutputStreamReference m_Stream
;
122 class NPT_LogUdpHandler
: public NPT_LogHandler
{
125 static NPT_Result
Create(const char* logger_name
, NPT_LogHandler
*& handler
);
128 void Log(const NPT_LogRecord
& record
) override
;
132 NPT_UdpSocket m_Socket
;
133 NPT_SocketAddress m_Target
;
136 class NPT_LogNullHandler
: public NPT_LogHandler
{
139 static NPT_Result
Create(NPT_LogHandler
*& handler
);
142 void Log(const NPT_LogRecord
& record
) override
;
145 class NPT_LogCustomHandler
: public NPT_LogHandler
{
148 static NPT_Result
SetCustomHandlerFunction(CustomHandlerExternalFunction function
);
149 static NPT_Result
Create(NPT_LogHandler
*& handler
);
152 void Log(const NPT_LogRecord
& record
) override
;
155 static CustomHandlerExternalFunction s_ExternalFunction
;
158 /*----------------------------------------------------------------------
160 +---------------------------------------------------------------------*/
161 #define NPT_LOG_HEAP_BUFFER_INCREMENT 4096
162 #define NPT_LOG_STACK_BUFFER_MAX_SIZE 512
163 #define NPT_LOG_HEAP_BUFFER_MAX_SIZE 65536
165 #if !defined(NPT_CONFIG_LOG_CONFIG_ENV)
166 #define NPT_CONFIG_LOG_CONFIG_ENV "NEPTUNE_LOG_CONFIG"
169 #if !defined(NPT_CONFIG_DEFAULT_LOG_CONFIG_SOURCE)
170 #define NPT_CONFIG_DEFAULT_LOG_CONFIG_SOURCE "file:neptune-logging.properties"
173 #if !defined(NPT_CONFIG_DEFAULT_LOG_LEVEL)
174 #define NPT_CONFIG_DEFAULT_LOG_LEVEL NPT_LOG_LEVEL_OFF
176 #define NPT_LOG_ROOT_DEFAULT_HANDLER "ConsoleHandler"
177 #if !defined(NPT_CONFIG_DEFAULT_FILE_HANDLER_FILENAME)
178 #define NPT_CONFIG_DEFAULT_LOG_FILE_HANDLER_FILENAME "_neptune.log"
181 #define NPT_LOG_TCP_HANDLER_DEFAULT_PORT 7723
182 #define NPT_LOG_TCP_HANDLER_DEFAULT_CONNECT_TIMEOUT 5000 /* 5 seconds */
184 #define NPT_LOG_UDP_HANDLER_DEFAULT_PORT 7724
186 #if defined(_WIN32) || defined(_WIN32_WCE) || defined(__APPLE__)
187 #define NPT_LOG_CONSOLE_HANDLER_DEFAULT_COLOR_MODE false
189 #define NPT_LOG_CONSOLE_HANDLER_DEFAULT_COLOR_MODE true
192 #ifndef NPT_CONFIG_DEFAULT_LOG_CONSOLE_HANDLER_OUTPUTS
193 #define NPT_CONFIG_DEFAULT_LOG_CONSOLE_HANDLER_OUTPUTS OUTPUT_TO_DEBUG
196 #define NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE 1000000
198 #define NPT_LOG_FORMAT_FILTER_NO_SOURCE 1
199 #define NPT_LOG_FORMAT_FILTER_NO_TIMESTAMP 2
200 #define NPT_LOG_FORMAT_FILTER_NO_FUNCTION_NAME 4
201 #define NPT_LOG_FORMAT_FILTER_NO_LOGGER_NAME 8
202 #define NPT_LOG_FORMAT_FILTER_NO_SOURCEPATH 16
203 #define NPT_LOG_FORMAT_FILTER_NO_THREAD_ID 32
205 /*----------------------------------------------------------------------
207 +---------------------------------------------------------------------*/
208 static NPT_LogManager LogManager
;
210 /*----------------------------------------------------------------------
211 | NPT_LogManagerAutoDisabler
212 +---------------------------------------------------------------------*/
213 class NPT_LogManagerAutoDisabler
216 NPT_LogManagerAutoDisabler() : m_WasEnabled(LogManager
.IsEnabled()) {
217 LogManager
.SetEnabled(false);
219 ~NPT_LogManagerAutoDisabler() {
220 LogManager
.SetEnabled(m_WasEnabled
);
226 /*----------------------------------------------------------------------
227 | NPT_LogManagerAutoLocker
228 +---------------------------------------------------------------------*/
229 class NPT_LogManagerAutoLocker
233 NPT_LogManagerAutoLocker(NPT_LogManager
&manager
) : m_Manager(manager
) {
236 ~NPT_LogManagerAutoLocker() {
242 NPT_LogManager
& m_Manager
;
245 /*----------------------------------------------------------------------
246 | NPT_GetSystemLogConfig
247 +---------------------------------------------------------------------*/
248 #if !defined(NPT_CONFIG_HAVE_SYSTEM_LOG_CONFIG)
249 NPT_Result
NPT_GetSystemLogConfig(NPT_String
& /*config*/)
251 return NPT_ERROR_NOT_SUPPORTED
;
255 /*----------------------------------------------------------------------
256 | NPT_LogHandler::Create
257 +---------------------------------------------------------------------*/
259 NPT_LogHandler::Create(const char* logger_name
,
260 const char* handler_name
,
261 NPT_LogHandler
*& handler
)
265 if (NPT_StringsEqual(handler_name
, "NullHandler")) {
266 return NPT_LogNullHandler::Create(handler
);
267 } else if (NPT_StringsEqual(handler_name
, "FileHandler")) {
268 return NPT_LogFileHandler::Create(logger_name
, handler
);
269 } else if (NPT_StringsEqual(handler_name
, "ConsoleHandler")) {
270 return NPT_LogConsoleHandler::Create(logger_name
, handler
);
271 } else if (NPT_StringsEqual(handler_name
, "TcpHandler")) {
272 return NPT_LogTcpHandler::Create(logger_name
, handler
);
273 } else if (NPT_StringsEqual(handler_name
, "UdpHandler")) {
274 return NPT_LogUdpHandler::Create(logger_name
, handler
);
275 } else if (NPT_StringsEqual(handler_name
, "CustomHandler")) {
276 return NPT_LogCustomHandler::Create(handler
);
279 return NPT_ERROR_NO_SUCH_CLASS
;
282 /*----------------------------------------------------------------------
283 | NPT_LogHandler::SetCustomHandlerFunction
284 +---------------------------------------------------------------------*/
286 NPT_LogHandler::SetCustomHandlerFunction(CustomHandlerExternalFunction function
)
288 return NPT_LogCustomHandler::SetCustomHandlerFunction(function
);
291 /*----------------------------------------------------------------------
292 | NPT_Log::GetLogLevel
293 +---------------------------------------------------------------------*/
295 NPT_Log::GetLogLevel(const char* name
)
297 if ( NPT_StringsEqual(name
, "FATAL")) {
298 return NPT_LOG_LEVEL_FATAL
;
299 } else if (NPT_StringsEqual(name
, "SEVERE")) {
300 return NPT_LOG_LEVEL_SEVERE
;
301 } else if (NPT_StringsEqual(name
, "WARNING")) {
302 return NPT_LOG_LEVEL_WARNING
;
303 } else if (NPT_StringsEqual(name
, "INFO")) {
304 return NPT_LOG_LEVEL_INFO
;
305 } else if (NPT_StringsEqual(name
, "FINE")) {
306 return NPT_LOG_LEVEL_FINE
;
307 } else if (NPT_StringsEqual(name
, "FINER")) {
308 return NPT_LOG_LEVEL_FINER
;
309 } else if (NPT_StringsEqual(name
, "FINEST")) {
310 return NPT_LOG_LEVEL_FINEST
;
311 } else if (NPT_StringsEqual(name
, "ALL")) {
312 return NPT_LOG_LEVEL_ALL
;
313 } else if (NPT_StringsEqual(name
, "OFF")) {
314 return NPT_LOG_LEVEL_OFF
;
320 /*----------------------------------------------------------------------
321 | NPT_Log::GetLogLevelName
322 +---------------------------------------------------------------------*/
324 NPT_Log::GetLogLevelName(int level
)
327 case NPT_LOG_LEVEL_FATAL
: return "FATAL";
328 case NPT_LOG_LEVEL_SEVERE
: return "SEVERE";
329 case NPT_LOG_LEVEL_WARNING
: return "WARNING";
330 case NPT_LOG_LEVEL_INFO
: return "INFO";
331 case NPT_LOG_LEVEL_FINE
: return "FINE";
332 case NPT_LOG_LEVEL_FINER
: return "FINER";
333 case NPT_LOG_LEVEL_FINEST
: return "FINEST";
334 case NPT_LOG_LEVEL_OFF
: return "OFF";
339 /*----------------------------------------------------------------------
340 | NPT_Log::GetLogLevelAnsiColor
341 +---------------------------------------------------------------------*/
343 NPT_Log::GetLogLevelAnsiColor(int level
)
346 case NPT_LOG_LEVEL_FATAL
: return "31";
347 case NPT_LOG_LEVEL_SEVERE
: return "31";
348 case NPT_LOG_LEVEL_WARNING
: return "33";
349 case NPT_LOG_LEVEL_INFO
: return "32";
350 case NPT_LOG_LEVEL_FINE
: return "34";
351 case NPT_LOG_LEVEL_FINER
: return "35";
352 case NPT_LOG_LEVEL_FINEST
: return "36";
353 default: return NULL
;
357 /*----------------------------------------------------------------------
358 | NPT_Log::FormatRecordToStream
359 +---------------------------------------------------------------------*/
361 NPT_Log::FormatRecordToStream(const NPT_LogRecord
& record
,
362 NPT_OutputStream
& stream
,
364 NPT_Flags format_filter
)
366 const char* level_name
= GetLogLevelName(record
.m_Level
);
367 NPT_String level_string
;
369 /* format and emit the record */
370 if (level_name
[0] == '\0') {
371 level_string
= NPT_String::FromInteger(record
.m_Level
);
372 level_name
= level_string
;
374 if ((format_filter
& NPT_LOG_FORMAT_FILTER_NO_SOURCE
) == 0) {
375 unsigned int start
= 0;
376 /* remove source file path if requested */
377 if (format_filter
& NPT_LOG_FORMAT_FILTER_NO_SOURCEPATH
) {
378 for (start
= NPT_StringLength(record
.m_SourceFile
);
381 if (record
.m_SourceFile
[start
-1] == '\\' ||
382 record
.m_SourceFile
[start
-1] == '/') {
387 stream
.WriteString(record
.m_SourceFile
+ start
);
388 stream
.Write("(", 1, NULL
);
389 stream
.WriteString(NPT_String::FromIntegerU(record
.m_SourceLine
));
390 stream
.Write("): ", 3, NULL
);
392 if ((format_filter
& NPT_LOG_FORMAT_FILTER_NO_LOGGER_NAME
) == 0) {
393 stream
.Write("[", 1, NULL
);
394 stream
.WriteString(record
.m_LoggerName
);
395 stream
.Write("] ", 2, NULL
);
397 if ((format_filter
& NPT_LOG_FORMAT_FILTER_NO_TIMESTAMP
) == 0) {
398 NPT_String ts
= NPT_DateTime(record
.m_TimeStamp
, true).ToString(NPT_DateTime::FORMAT_W3C
,
399 NPT_DateTime::FLAG_EMIT_FRACTION
|
400 NPT_DateTime::FLAG_EXTENDED_PRECISION
);
401 stream
.WriteString(ts
.GetChars());
402 stream
.Write(" ", 1);
404 if ((format_filter
& NPT_LOG_FORMAT_FILTER_NO_FUNCTION_NAME
) == 0) {
405 stream
.WriteFully("[",1);
406 if (record
.m_SourceFunction
) {
407 stream
.WriteString(record
.m_SourceFunction
);
409 stream
.WriteFully("] ",2);
411 if ((format_filter
& NPT_LOG_FORMAT_FILTER_NO_THREAD_ID
) == 0) {
412 stream
.Write("(", 1, NULL
);
413 stream
.WriteString(NPT_String::FromIntegerU(record
.m_ThreadId
));
414 stream
.Write(") ", 2, NULL
);
416 const char* ansi_color
= NULL
;
418 ansi_color
= GetLogLevelAnsiColor(record
.m_Level
);
420 stream
.Write("\033[", 2, NULL
);
421 stream
.WriteString(ansi_color
);
422 stream
.Write(";1m", 3, NULL
);
425 stream
.WriteString(level_name
);
426 if (use_colors
&& ansi_color
) {
427 stream
.Write("\033[0m", 4, NULL
);
429 stream
.Write(": ", 2, NULL
);
430 stream
.WriteString(record
.m_Message
);
431 stream
.Write("\r\n", 2, NULL
);
434 /*----------------------------------------------------------------------
435 | NPT_LogManager::NPT_LogManager
436 +---------------------------------------------------------------------*/
437 NPT_LogManager::NPT_LogManager() :
446 /*----------------------------------------------------------------------
447 | NPT_LogManager::~NPT_LogManager
448 +---------------------------------------------------------------------*/
449 NPT_LogManager::~NPT_LogManager()
451 /* destroy everything we've created */
452 for (NPT_List
<NPT_Logger
*>::Iterator i
= m_Loggers
.GetFirstItem();
455 NPT_Logger
* logger
= *i
;
459 /* destroy the root logger */
463 /*----------------------------------------------------------------------
464 | NPT_LogManager::GetDefault
465 +---------------------------------------------------------------------*/
467 NPT_LogManager::GetDefault()
472 /*----------------------------------------------------------------------
473 | NPT_LogManager::Lock
474 +---------------------------------------------------------------------*/
476 NPT_LogManager::Lock()
478 NPT_Thread::ThreadId me
= NPT_Thread::GetCurrentThreadId();
479 if (m_LockOwner
!= me
) {
486 /*----------------------------------------------------------------------
487 | NPT_LogManager::Unlock
488 +---------------------------------------------------------------------*/
490 NPT_LogManager::Unlock()
492 if (--m_LockRecursion
== 0) {
493 m_LockOwner
= (NPT_Thread::ThreadId
)0;
498 /*----------------------------------------------------------------------
499 | NPT_LogManager::Configure
500 +---------------------------------------------------------------------*/
502 NPT_LogManager::Configure(const char* config_sources
)
504 // exit if we're already initialized
505 if (m_Configured
) return NPT_SUCCESS
;
507 // prevent multiple threads from configuring at the same time
508 NPT_LogManagerAutoLocker
lock(*this);
509 if (m_Configured
) return NPT_SUCCESS
;
511 // we need to be disabled while we configure ourselves
512 NPT_LogManagerAutoDisabler autodisabler
;
514 // set some default config values
515 SetConfigValue(".handlers", NPT_LOG_ROOT_DEFAULT_HANDLER
);
517 // see if the config sources have been set to non-default values
518 if (config_sources
== NULL
) {
519 config_sources
= NPT_CONFIG_DEFAULT_LOG_CONFIG_SOURCE
;
521 NPT_String config_sources_system
;
522 if (NPT_SUCCEEDED(NPT_GetSystemLogConfig(config_sources_system
))) {
523 config_sources
= config_sources_system
;
525 NPT_String config_sources_env
;
526 if (NPT_SUCCEEDED(NPT_Environment::Get(NPT_CONFIG_LOG_CONFIG_ENV
, config_sources_env
))) {
527 config_sources
= config_sources_env
;
530 /* load all configs */
531 NPT_String config_source
;
532 const char* cursor
= config_sources
;
533 const char* source
= config_sources
;
535 if (*cursor
== '\0' || *cursor
== '|') {
536 if (cursor
!= source
) {
537 config_source
.Assign(source
, (NPT_Size
)(cursor
-source
));
538 config_source
.Trim(" \t");
539 ParseConfigSource(config_source
);
540 if (*cursor
== '|') source
= cursor
+1;
542 if (*cursor
== '\0') break;
547 /* create the root logger */
548 LogManager
.m_Root
= new NPT_Logger("", *this);
549 LogManager
.m_Root
->m_Level
= NPT_CONFIG_DEFAULT_LOG_LEVEL
;
550 LogManager
.m_Root
->m_LevelIsInherited
= false;
551 ConfigureLogger(LogManager
.m_Root
);
553 // we're initialized now
559 /*----------------------------------------------------------------------
560 | NPT_LogManager::ConfigValueIsBooleanTrue
561 +---------------------------------------------------------------------*/
563 NPT_LogManager::ConfigValueIsBooleanTrue(NPT_String
& value
)
566 value
.Compare("true", true) == 0 ||
567 value
.Compare("yes", true) == 0 ||
568 value
.Compare("on", true) == 0 ||
569 value
.Compare("1", true) == 0;
572 /*----------------------------------------------------------------------
573 | NPT_LogManager::ConfigValueIsBooleanFalse
574 +---------------------------------------------------------------------*/
576 NPT_LogManager::ConfigValueIsBooleanFalse(NPT_String
& value
)
579 value
.Compare("false", true) == 0 ||
580 value
.Compare("no", true) == 0 ||
581 value
.Compare("off", true) == 0 ||
582 value
.Compare("0", true) == 0;
585 /*----------------------------------------------------------------------
586 | NPT_LogManager::GetConfigValue
587 +---------------------------------------------------------------------*/
589 NPT_LogManager::GetConfigValue(const char* prefix
, const char* suffix
)
591 NPT_Size prefix_length
= prefix
?NPT_StringLength(prefix
):0;
592 NPT_Size suffix_length
= suffix
?NPT_StringLength(suffix
):0;
593 NPT_Size key_length
= prefix_length
+suffix_length
;
594 for (NPT_List
<NPT_LogConfigEntry
>::Iterator i
= LogManager
.m_Config
.GetFirstItem();
597 NPT_LogConfigEntry
& entry
= *i
;
598 if ((entry
.m_Key
.GetLength() == key_length
) &&
599 (prefix
== NULL
|| entry
.m_Key
.StartsWith(prefix
)) &&
600 (suffix
== NULL
|| entry
.m_Key
.EndsWith(suffix
)) ) {
601 return &entry
.m_Value
;
609 /*----------------------------------------------------------------------
610 | NPT_LogManager::SetConfigValue
611 +---------------------------------------------------------------------*/
613 NPT_LogManager::SetConfigValue(const char* key
, const char* value
)
615 NPT_String
* value_string
= GetConfigValue(key
, NULL
);
617 /* the key already exists, replace the value */
618 *value_string
= value
;
620 /* the value does not already exist, create a new one */
621 NPT_CHECK(LogManager
.m_Config
.Add(NPT_LogConfigEntry(key
, value
)));
627 /*----------------------------------------------------------------------
628 | NPT_LogManager::ParseConfig
629 +---------------------------------------------------------------------*/
631 NPT_LogManager::ParseConfig(const char* config
,
632 NPT_Size config_size
)
634 const char* cursor
= config
;
635 const char* line
= config
;
636 const char* separator
= NULL
;
640 /* parse all entries */
641 while (cursor
<= config
+config_size
) {
642 /* separators are newlines, ';' or end of buffer */
643 if ( cursor
== config
+config_size
||
647 /* newline or end of buffer */
648 if (separator
&& line
[0] != '#') {
649 /* we have a property */
650 key
.Assign(line
, (NPT_Size
)(separator
-line
));
651 value
.Assign(line
+(separator
+1-line
), (NPT_Size
)(cursor
-(separator
+1)));
655 SetConfigValue((const char*)key
, (const char*)value
);
659 } else if (*cursor
== '=' && separator
== NULL
) {
668 /*----------------------------------------------------------------------
669 | NPT_LogManager::ParseConfigFile
670 +---------------------------------------------------------------------*/
672 NPT_LogManager::ParseConfigFile(const char* filename
)
677 NPT_DataBuffer buffer
;
678 result
= NPT_File::Load(filename
, buffer
);
679 if (NPT_FAILED(result
)) return result
;
681 /* parse the config */
682 return ParseConfig((const char*)buffer
.GetData(), buffer
.GetDataSize());
685 /*----------------------------------------------------------------------
686 | NPT_LogManager::ParseConfigSource
687 +---------------------------------------------------------------------*/
689 NPT_LogManager::ParseConfigSource(NPT_String
& source
)
691 if (source
.StartsWith("file:")) {
693 ParseConfigFile(source
.GetChars()+5);
694 } else if (source
.StartsWith("plist:")) {
695 /* property list source */
696 ParseConfig(source
.GetChars()+6, source
.GetLength()-6);
697 } else if (source
.StartsWith("http:port=")) {
698 /* http configurator */
699 unsigned int port
= 0;
700 NPT_Result result
= NPT_ParseInteger(source
.GetChars()+10, port
, true);
701 if (NPT_FAILED(result
)) return result
;
702 new NPT_HttpLoggerConfigurator(port
);
704 return NPT_ERROR_INVALID_SYNTAX
;
710 /*----------------------------------------------------------------------
711 | NPT_LogManager::HaveLoggerConfig
712 +---------------------------------------------------------------------*/
714 NPT_LogManager::HaveLoggerConfig(const char* name
)
716 NPT_Size name_length
= NPT_StringLength(name
);
717 for (NPT_List
<NPT_LogConfigEntry
>::Iterator i
= m_Config
.GetFirstItem();
720 NPT_LogConfigEntry
& entry
= *i
;
721 if (entry
.m_Key
.StartsWith(name
)) {
722 const char* suffix
= entry
.m_Key
.GetChars()+name_length
;
723 if (NPT_StringsEqual(suffix
, ".level") ||
724 NPT_StringsEqual(suffix
, ".handlers") ||
725 NPT_StringsEqual(suffix
, ".forward")) {
731 /* no config found */
735 /*----------------------------------------------------------------------
736 | NPT_LogManager::ConfigureLogger
737 +---------------------------------------------------------------------*/
739 NPT_LogManager::ConfigureLogger(NPT_Logger
* logger
)
741 /* configure the level */
742 NPT_String
* level_value
= GetConfigValue(logger
->m_Name
,".level");
745 /* try a symbolic name */
746 value
= NPT_Log::GetLogLevel(*level_value
);
748 /* try a numeric value */
749 if (NPT_FAILED(level_value
->ToInteger(value
, false))) {
754 logger
->m_Level
= value
;
755 logger
->m_LevelIsInherited
= false;
759 /* remove any existing handlers */
760 logger
->DeleteHandlers();
762 /* configure the handlers */
763 NPT_String
* handlers
= GetConfigValue(logger
->m_Name
,".handlers");
765 const char* handlers_list
= handlers
->GetChars();
766 const char* cursor
= handlers_list
;
767 const char* name_start
= handlers_list
;
768 NPT_String handler_name
;
769 NPT_LogHandler
* handler
;
771 if (*cursor
== '\0' || *cursor
== ',') {
772 if (cursor
!= name_start
) {
773 handler_name
.Assign(name_start
, (NPT_Size
)(cursor
-name_start
));
774 handler_name
.Trim(" \t");
776 /* create a handler */
778 NPT_LogHandler::Create(logger
->m_Name
, handler_name
, handler
))) {
779 logger
->AddHandler(handler
);
783 if (*cursor
== '\0') break;
784 name_start
= cursor
+1;
790 /* configure the forwarding */
791 NPT_String
* forward
= GetConfigValue(logger
->m_Name
,".forward");
792 if (forward
&& !ConfigValueIsBooleanTrue(*forward
)) {
793 logger
->m_ForwardToParent
= false;
799 /*----------------------------------------------------------------------
800 | NPT_LogManager::FindLogger
801 +---------------------------------------------------------------------*/
803 NPT_LogManager::FindLogger(const char* name
)
805 for (NPT_List
<NPT_Logger
*>::Iterator i
= LogManager
.m_Loggers
.GetFirstItem();
808 NPT_Logger
* logger
= *i
;
809 if (logger
->m_Name
== name
) {
817 /*----------------------------------------------------------------------
818 | NPT_LogManager::GetLogger
819 +---------------------------------------------------------------------*/
821 NPT_LogManager::GetLogger(const char* name
)
823 // exit now if the log manager is disabled
824 if (!LogManager
.m_Enabled
) return NULL
;
826 /* check that the manager is initialized */
827 if (!LogManager
.m_Configured
) {
828 /* init the manager */
829 LogManager
.Configure();
830 NPT_ASSERT(LogManager
.m_Configured
);
833 // auto lock until we return from this method
834 NPT_LogManagerAutoLocker
lock(LogManager
);
836 /* check if this logger is already configured */
837 NPT_Logger
* logger
= LogManager
.FindLogger(name
);
838 if (logger
) return logger
;
840 /* create a new logger */
841 logger
= new NPT_Logger(name
, LogManager
);
842 if (logger
== NULL
) return NULL
;
844 /* configure the logger */
845 LogManager
.ConfigureLogger(logger
);
847 /* find which parent to attach to */
848 NPT_Logger
* parent
= LogManager
.m_Root
;
849 NPT_String parent_name
= name
;
851 NPT_Logger
* candidate_parent
;
853 /* find the last dot */
854 int dot
= parent_name
.ReverseFind('.');
856 parent_name
.SetLength(dot
);
858 /* see if the parent exists */
859 candidate_parent
= LogManager
.FindLogger(parent_name
);
860 if (candidate_parent
) {
861 parent
= candidate_parent
;
865 /* this parent name does not exist, see if we need to create it */
866 if (LogManager
.HaveLoggerConfig(parent_name
)) {
867 parent
= GetLogger(parent_name
);
872 /* attach to the parent */
873 logger
->SetParent(parent
);
875 /* add this logger to the list */
876 LogManager
.m_Loggers
.Add(logger
);
881 /*----------------------------------------------------------------------
882 | NPT_Logger::NPT_Logger
883 +---------------------------------------------------------------------*/
884 NPT_Logger::NPT_Logger(const char* name
, NPT_LogManager
& manager
) :
887 m_Level(NPT_LOG_LEVEL_OFF
),
888 m_LevelIsInherited(true),
889 m_ForwardToParent(true),
894 /*----------------------------------------------------------------------
895 | NPT_Logger::~NPT_Logger
896 +---------------------------------------------------------------------*/
897 NPT_Logger::~NPT_Logger()
899 /* remove external handlers before cleaning up */
900 m_Handlers
.Remove(m_ExternalHandlers
, true);
902 /* delete all handlers */
903 m_Handlers
.Apply(NPT_ObjectDeleter
<NPT_LogHandler
>());
906 /*----------------------------------------------------------------------
907 | NPT_Logger::DeleteHandlers
908 +---------------------------------------------------------------------*/
910 NPT_Logger::DeleteHandlers()
912 /* remove external handlers before cleaning up */
913 m_Handlers
.Remove(m_ExternalHandlers
, true);
915 /* delete all handlers and empty the list */
916 if (m_Handlers
.GetItemCount()) {
917 m_Handlers
.Apply(NPT_ObjectDeleter
<NPT_LogHandler
>());
924 /*----------------------------------------------------------------------
926 +---------------------------------------------------------------------*/
928 NPT_Logger::Log(int level
,
929 const char* source_file
,
930 unsigned int source_line
,
931 const char* source_function
,
935 // this is a no-op if the log manager is disabled
936 if (!LogManager
.IsEnabled()) return;
938 /* check the log level (in case filtering has not already been done) */
939 if (level
< m_Level
) return;
941 /* format the message */
942 char buffer
[NPT_LOG_STACK_BUFFER_MAX_SIZE
];
943 NPT_Size buffer_size
= sizeof(buffer
);
944 char* message
= buffer
;
948 /* try to format the message (it might not fit) */
950 result
= NPT_FormatStringVN(message
, buffer_size
-1, msg
, args
);
952 if (result
>= (int)(buffer_size
-1)) result
= -1;
953 message
[buffer_size
-1] = 0; /* force a NULL termination */
954 if (result
>= 0) break;
956 /* the buffer was too small, try something bigger */
957 buffer_size
= (buffer_size
+NPT_LOG_HEAP_BUFFER_INCREMENT
)*2;
958 if (buffer_size
> NPT_LOG_HEAP_BUFFER_MAX_SIZE
) break;
959 if (message
!= buffer
) delete[] message
;
960 message
= new char[buffer_size
];
961 if (message
== NULL
) return;
964 /* the message is formatted, publish it to the handlers */
965 NPT_LogRecord record
;
966 NPT_Logger
* logger
= this;
968 /* setup the log record */
969 record
.m_LoggerName
= logger
->m_Name
,
970 record
.m_Level
= level
;
971 record
.m_Message
= message
;
972 record
.m_SourceFile
= source_file
;
973 record
.m_SourceLine
= source_line
;
974 record
.m_SourceFunction
= source_function
;
975 NPT_System::GetCurrentTimeStamp(record
.m_TimeStamp
);
976 record
.m_ThreadId
= (NPT_UInt64
)NPT_Thread::GetCurrentThreadId();
978 /* call all handlers for this logger and parents */
980 m_Manager
.SetEnabled(false); // prevent recursion
982 /* call all handlers for the current logger */
983 for (NPT_List
<NPT_LogHandler
*>::Iterator i
= logger
->m_Handlers
.GetFirstItem();
986 NPT_LogHandler
* handler
= *i
;
987 handler
->Log(record
);
990 /* forward to the parent unless this logger does not forward */
991 if (logger
->m_ForwardToParent
) {
992 logger
= logger
->m_Parent
;
997 m_Manager
.SetEnabled(true);
1000 /* free anything we may have allocated */
1001 if (message
!= buffer
) delete[] message
;
1004 /*----------------------------------------------------------------------
1005 | NPT_Logger::AddHandler
1006 +---------------------------------------------------------------------*/
1008 NPT_Logger::AddHandler(NPT_LogHandler
* handler
, bool transfer_ownership
/* = true */)
1010 /* check parameters */
1011 if (handler
== NULL
) return NPT_ERROR_INVALID_PARAMETERS
;
1013 /* keep track of what handlers we won't cleanup */
1014 if (!transfer_ownership
) m_ExternalHandlers
.Add(handler
);
1016 return m_Handlers
.Add(handler
);
1019 /*----------------------------------------------------------------------
1020 | NPT_Logger::SetParent
1021 +---------------------------------------------------------------------*/
1023 NPT_Logger::SetParent(NPT_Logger
* parent
)
1025 /* set our new parent */
1028 /* find the first ancestor with its own log level */
1029 NPT_Logger
* logger
= this;
1030 while (logger
->m_LevelIsInherited
&& logger
->m_Parent
) {
1031 logger
= logger
->m_Parent
;
1033 if (logger
!= this) m_Level
= logger
->m_Level
;
1038 /*----------------------------------------------------------------------
1039 | NPT_LogNullHandler::Create
1040 +---------------------------------------------------------------------*/
1042 NPT_LogNullHandler::Create(NPT_LogHandler
*& handler
)
1044 handler
= new NPT_LogNullHandler();
1048 /*----------------------------------------------------------------------
1049 | NPT_LogNullHandler::Log
1050 +---------------------------------------------------------------------*/
1052 NPT_LogNullHandler::Log(const NPT_LogRecord
& /*record*/)
1057 NPT_LogHandler::CustomHandlerExternalFunction
NPT_LogCustomHandler::s_ExternalFunction
= NULL
;
1058 /*----------------------------------------------------------------------
1059 | NPT_LogCustomHandler::SetCustomHandlerFunction
1060 +---------------------------------------------------------------------*/
1062 NPT_LogCustomHandler::SetCustomHandlerFunction(CustomHandlerExternalFunction function
)
1064 s_ExternalFunction
= function
;
1068 /*----------------------------------------------------------------------
1069 | NPT_LogCustomHandler::Create
1070 +---------------------------------------------------------------------*/
1072 NPT_LogCustomHandler::Create(NPT_LogHandler
*& handler
)
1074 /* allocate a new object */
1075 NPT_LogCustomHandler
* instance
= new NPT_LogCustomHandler();
1080 /*----------------------------------------------------------------------
1081 | NPT_LogCustomHandler::Log
1082 +---------------------------------------------------------------------*/
1084 NPT_LogCustomHandler::Log(const NPT_LogRecord
& record
)
1086 if (s_ExternalFunction
) {
1087 (*s_ExternalFunction
)(&record
);
1091 /*----------------------------------------------------------------------
1092 | NPT_LogConsoleHandler::Create
1093 +---------------------------------------------------------------------*/
1095 NPT_LogConsoleHandler::Create(const char* logger_name
,
1096 NPT_LogHandler
*& handler
)
1098 /* compute a prefix for the configuration of this handler */
1099 NPT_String logger_prefix
= logger_name
;
1100 logger_prefix
+= ".ConsoleHandler";
1102 /* allocate a new object */
1103 NPT_LogConsoleHandler
* instance
= new NPT_LogConsoleHandler();
1106 /* configure the object */
1108 instance
->m_UseColors
= NPT_LOG_CONSOLE_HANDLER_DEFAULT_COLOR_MODE
;
1109 colors
= LogManager
.GetConfigValue(logger_prefix
,".colors");
1111 if (NPT_LogManager::ConfigValueIsBooleanTrue(*colors
)) {
1112 instance
->m_UseColors
= true;
1113 } else if (NPT_LogManager::ConfigValueIsBooleanFalse(*colors
)) {
1114 instance
->m_UseColors
= false;
1118 NPT_String
* outputs
;
1119 instance
->m_Outputs
= NPT_CONFIG_DEFAULT_LOG_CONSOLE_HANDLER_OUTPUTS
;
1120 outputs
= LogManager
.GetConfigValue(logger_prefix
,".outputs");
1122 outputs
->ToInteger(instance
->m_Outputs
, true);
1126 instance
->m_FormatFilter
= 0;
1127 filter
= LogManager
.GetConfigValue(logger_prefix
,".filter");
1129 filter
->ToInteger(instance
->m_FormatFilter
, true);
1135 /*----------------------------------------------------------------------
1136 | NPT_LogConsoleHandler::Log
1137 +---------------------------------------------------------------------*/
1139 NPT_LogConsoleHandler::Log(const NPT_LogRecord
& record
)
1141 NPT_MemoryStream
memory_stream(4096);
1143 NPT_Log::FormatRecordToStream(record
, memory_stream
, m_UseColors
, m_FormatFilter
);
1144 memory_stream
.Write("\0", 1);
1145 if (m_Outputs
& OUTPUT_TO_CONSOLE
) {
1146 NPT_Console::Output((const char*)memory_stream
.GetData());
1148 if (m_Outputs
& OUTPUT_TO_DEBUG
) {
1149 NPT_DebugOutput((const char*)memory_stream
.GetData());
1153 /*----------------------------------------------------------------------
1154 | NPT_LogFileHandler::Log
1155 +---------------------------------------------------------------------*/
1157 NPT_LogFileHandler::Log(const NPT_LogRecord
& record
)
1159 if (m_MaxFilesize
> 0) {
1160 /* get current file size */
1162 NPT_File::GetSize(m_Filename
, size
);
1164 /* time to recycle ? */
1165 if (size
> m_MaxFilesize
) {
1166 /* release stream to force a reopen later
1167 and to be able to rename file */
1170 /* rename file using current time */
1172 NPT_System::GetCurrentTimeStamp(now
);
1173 NPT_String suffix
= NPT_DateTime(now
, true).ToString(NPT_DateTime::FORMAT_W3C
);
1174 suffix
.Replace(':', '_');
1175 NPT_String new_name
= NPT_FilePath::Create(
1176 NPT_FilePath::DirName(m_Filename
),
1177 NPT_FilePath::BaseName(m_Filename
, false) +
1180 NPT_FilePath::FileExtension(m_Filename
));
1182 NPT_File::Rename(m_Filename
, new_name
);
1186 /* try to reopen the file if it failed to open
1187 previously or if we rotated it */
1188 if (m_Stream
.IsNull()) {
1192 if (m_Stream
.AsPointer()) {
1193 NPT_Log::FormatRecordToStream(record
, *m_Stream
, false, m_FormatFilter
);
1194 if (m_Flush
) m_Stream
->Flush();
1198 /*----------------------------------------------------------------------
1199 | NPT_LogFileHandler::Open
1200 +---------------------------------------------------------------------*/
1202 NPT_LogFileHandler::Open(bool append
/* = true */)
1204 /* reset stream just in case */
1207 /* open the log file */
1208 NPT_File
file(m_Filename
);
1209 NPT_Result result
= file
.Open(NPT_FILE_OPEN_MODE_CREATE
|
1210 NPT_FILE_OPEN_MODE_READ
|
1211 NPT_FILE_OPEN_MODE_WRITE
|
1212 (append
?NPT_FILE_OPEN_MODE_APPEND
:NPT_FILE_OPEN_MODE_TRUNCATE
));
1213 if (NPT_FAILED(result
)) return result
;
1215 NPT_CHECK(file
.GetOutputStream(m_Stream
));
1219 NPT_CHECK(NPT_File::GetSize(m_Filename
, size
));
1220 NPT_CHECK(m_Stream
->Seek(size
));
1225 /*----------------------------------------------------------------------
1226 | NPT_LogFileHandler::Create
1227 +---------------------------------------------------------------------*/
1229 NPT_LogFileHandler::Create(const char* logger_name
,
1230 NPT_LogHandler
*& handler
)
1232 /* compute a prefix for the configuration of this handler */
1233 NPT_String logger_prefix
= logger_name
;
1234 logger_prefix
+= ".FileHandler";
1236 /* allocate a new object */
1237 NPT_LogFileHandler
* instance
= new NPT_LogFileHandler();
1241 NPT_String
* filename_conf
= LogManager
.GetConfigValue(logger_prefix
, ".filename");
1242 if (filename_conf
) {
1243 instance
->m_Filename
= *filename_conf
;
1244 } else if (logger_name
[0]) {
1245 NPT_String filename_synth
= logger_name
;
1246 filename_synth
+= ".log";
1247 instance
->m_Filename
= filename_synth
;
1249 /* default name for the root logger */
1250 instance
->m_Filename
= NPT_CONFIG_DEFAULT_LOG_FILE_HANDLER_FILENAME
;
1253 /* always flush flag */
1254 NPT_String
* flush
= LogManager
.GetConfigValue(logger_prefix
, ".flush");
1255 if (flush
&& NPT_LogManager::ConfigValueIsBooleanTrue(*flush
)) {
1256 instance
->m_Flush
= true;
1258 instance
->m_Flush
= false;
1262 instance
->m_Append
= true;
1263 NPT_String
* append_mode
= LogManager
.GetConfigValue(logger_prefix
, ".append");
1264 if (append_mode
&& NPT_LogManager::ConfigValueIsBooleanFalse(*append_mode
)) {
1265 instance
->m_Append
= false;
1270 instance
->m_FormatFilter
= 0;
1271 filter
= LogManager
.GetConfigValue(logger_prefix
,".filter");
1273 filter
->ToInteger(instance
->m_FormatFilter
, true);
1277 NPT_String
* recycle
;
1278 instance
->m_MaxFilesize
= 0;
1279 recycle
= LogManager
.GetConfigValue(logger_prefix
,".recycle");
1281 NPT_ParseInteger64(*recycle
, instance
->m_MaxFilesize
, true);
1282 if (instance
->m_MaxFilesize
< NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE
) {
1283 instance
->m_MaxFilesize
= NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE
;
1287 /* open the log file */
1288 return instance
->Open(instance
->m_Append
);
1291 /*----------------------------------------------------------------------
1292 | NPT_LogTcpHandler::Create
1293 +---------------------------------------------------------------------*/
1295 NPT_LogTcpHandler::Create(const char* logger_name
, NPT_LogHandler
*& handler
)
1297 /* compute a prefix for the configuration of this handler */
1298 NPT_String logger_prefix
= logger_name
;
1299 logger_prefix
+= ".TcpHandler";
1301 /* allocate a new object */
1302 NPT_LogTcpHandler
* instance
= new NPT_LogTcpHandler();
1305 /* configure the object */
1306 const NPT_String
* hostname
= LogManager
.GetConfigValue(logger_prefix
, ".hostname");
1308 instance
->m_Host
= *hostname
;
1310 /* default hostname */
1311 instance
->m_Host
= "localhost";
1313 const NPT_String
* port
= LogManager
.GetConfigValue(logger_prefix
, ".port");
1315 NPT_UInt32 port_int
;
1316 if (NPT_SUCCEEDED(port
->ToInteger(port_int
, true))) {
1317 instance
->m_Port
= (NPT_UInt16
)port_int
;
1319 instance
->m_Port
= NPT_LOG_TCP_HANDLER_DEFAULT_PORT
;
1323 instance
->m_Port
= NPT_LOG_TCP_HANDLER_DEFAULT_PORT
;
1329 /*----------------------------------------------------------------------
1330 | NPT_LogTcpHandler::Connect
1331 +---------------------------------------------------------------------*/
1333 NPT_LogTcpHandler::Connect()
1335 /* create a socket */
1336 NPT_TcpClientSocket tcp_socket
;
1338 /* connect to the host */
1339 NPT_IpAddress ip_address
;
1340 NPT_CHECK(ip_address
.ResolveName(m_Host
));
1341 NPT_Result result
= tcp_socket
.Connect(NPT_SocketAddress(ip_address
, m_Port
),
1342 NPT_LOG_TCP_HANDLER_DEFAULT_CONNECT_TIMEOUT
);
1343 if (NPT_FAILED(result
)) {
1347 /* get the stream */
1348 return tcp_socket
.GetOutputStream(m_Stream
);
1351 /*----------------------------------------------------------------------
1352 | NPT_LogTcpHandler::Log
1353 +---------------------------------------------------------------------*/
1355 NPT_LogTcpHandler::FormatRecord(const NPT_LogRecord
& record
, NPT_String
& msg
)
1357 /* format the record */
1358 const char* level_name
= NPT_Log::GetLogLevelName(record
.m_Level
);
1359 NPT_String level_string
;
1361 /* format and emit the record */
1362 if (level_name
[0] == '\0') {
1363 level_string
= NPT_String::FromIntegerU(record
.m_Level
);
1364 level_name
= level_string
;
1368 msg
+= record
.m_LoggerName
;
1369 msg
+= "\r\nLevel: ";
1371 msg
+= "\r\nSource-File: ";
1372 msg
+= record
.m_SourceFile
;
1373 msg
+= "\r\nSource-Function: ";
1374 msg
+= record
.m_SourceFunction
;
1375 msg
+= "\r\nSource-Line: ";
1376 msg
+= NPT_String::FromIntegerU(record
.m_SourceLine
);
1377 msg
+= "\r\nThread-Id: ";
1378 msg
+= NPT_String::FromIntegerU(record
.m_ThreadId
);
1379 msg
+= "\r\nTimeStamp: ";
1380 msg
+= NPT_DateTime(record
.m_TimeStamp
, true).ToString(NPT_DateTime::FORMAT_W3C
,
1381 NPT_DateTime::FLAG_EMIT_FRACTION
|
1382 NPT_DateTime::FLAG_EXTENDED_PRECISION
);
1383 msg
+= "\r\nContent-Length: ";
1384 msg
+= NPT_String::FromIntegerU(NPT_StringLength(record
.m_Message
));
1386 msg
+= record
.m_Message
;
1389 /*----------------------------------------------------------------------
1390 | NPT_LogTcpHandler::Log
1391 +---------------------------------------------------------------------*/
1393 NPT_LogTcpHandler::Log(const NPT_LogRecord
& record
)
1395 // ensure we're connected
1396 if (m_Stream
.IsNull()) {
1397 if (NPT_FAILED(Connect())) return;
1400 // format the record
1402 FormatRecord(record
, msg
);
1404 // log, and disconnect if this fails
1405 if (NPT_FAILED(m_Stream
->WriteString(msg
))) {
1410 /*----------------------------------------------------------------------
1411 | NPT_LogUdpHandler::Create
1412 +---------------------------------------------------------------------*/
1414 NPT_LogUdpHandler::Create(const char* logger_name
, NPT_LogHandler
*& handler
)
1416 /* compute a prefix for the configuration of this handler */
1417 NPT_String logger_prefix
= logger_name
;
1418 logger_prefix
+= ".UdpHandler";
1420 /* allocate a new object */
1421 NPT_LogUdpHandler
* instance
= new NPT_LogUdpHandler();
1424 /* configure the object */
1425 const char* hostname
= "localhost";
1426 const NPT_String
* hostname_prop
= LogManager
.GetConfigValue(logger_prefix
, ".hostname");
1427 if (hostname_prop
) {
1428 hostname
= hostname_prop
->GetChars();
1430 NPT_UInt32 port
= NPT_LOG_UDP_HANDLER_DEFAULT_PORT
;
1431 const NPT_String
* port_prop
= LogManager
.GetConfigValue(logger_prefix
, ".port");
1433 if (NPT_FAILED(port_prop
->ToInteger(port
, true))) {
1434 port
= NPT_LOG_UDP_HANDLER_DEFAULT_PORT
;
1438 // resolve the target hostname
1439 NPT_IpAddress target_ip
;
1440 target_ip
.ResolveName(hostname
);
1441 instance
->m_Target
.SetIpAddress(target_ip
);
1442 instance
->m_Target
.SetPort(port
);
1447 /*----------------------------------------------------------------------
1448 | NPT_LogUdpHandler::Log
1449 +---------------------------------------------------------------------*/
1451 NPT_LogUdpHandler::Log(const NPT_LogRecord
& record
)
1453 // format the record
1455 NPT_LogTcpHandler::FormatRecord(record
, msg
);
1457 // send it in a datagram
1458 NPT_DataBuffer
buffer(msg
.GetChars(), msg
.GetLength()+1, false);
1459 m_Socket
.Send(buffer
, &m_Target
);
1462 /*----------------------------------------------------------------------
1463 | NPT_HttpLoggerConfigurator::NPT_HttpLoggerConfigurator
1464 +---------------------------------------------------------------------*/
1465 NPT_HttpLoggerConfigurator::NPT_HttpLoggerConfigurator(NPT_UInt16 port
, bool detached
) :
1466 NPT_Thread(detached
)
1468 // create the server
1469 m_Server
= new NPT_HttpServer(port
);
1471 // attach a handler to response to the requests
1472 m_Server
->AddRequestHandler(this, "/", true);
1475 /*----------------------------------------------------------------------
1476 | NPT_HttpLoggerConfigurator::~NPT_HttpLoggerConfigurator
1477 +---------------------------------------------------------------------*/
1478 NPT_HttpLoggerConfigurator::~NPT_HttpLoggerConfigurator()
1480 // TODO: send a command to the server to tell it to abort
1486 /*----------------------------------------------------------------------
1487 | NPT_HttpLoggerConfigurator::SetupResponse
1488 +---------------------------------------------------------------------*/
1490 NPT_HttpLoggerConfigurator::SetupResponse(NPT_HttpRequest
& request
,
1491 const NPT_HttpRequestContext
& /*context*/,
1492 NPT_HttpResponse
& response
)
1494 // we only support GET here
1495 if (request
.GetMethod() != NPT_HTTP_METHOD_GET
) return NPT_ERROR_HTTP_METHOD_NOT_SUPPORTED
;
1497 // construct the response message
1501 NPT_List
<NPT_LogConfigEntry
>& config
= LogManager
.GetConfig();
1502 NPT_List
<NPT_LogConfigEntry
>::Iterator cit
= config
.GetFirstItem();
1503 for (; cit
; ++cit
) {
1504 NPT_LogConfigEntry
& entry
= (*cit
);
1508 msg
+= entry
.m_Value
;
1514 NPT_List
<NPT_Logger
*>& loggers
= LogManager
.GetLoggers();
1515 NPT_List
<NPT_Logger
*>::Iterator lit
= loggers
.GetFirstItem();
1517 NPT_Logger
* logger
= (*lit
);
1519 msg
+= logger
->GetName();
1521 msg
+= NPT_String::FromInteger(logger
->GetLevel());
1523 NPT_List
<NPT_LogHandler
*>& handlers
= logger
->GetHandlers();
1524 NPT_List
<NPT_LogHandler
*>::Iterator hit
= handlers
.GetFirstItem();
1525 msg
+= ", handlers=";
1527 NPT_LogHandler
* handler
= (*hit
);
1528 msg
+= handler
->ToString();
1534 // setup the response body
1535 NPT_HttpEntity
* entity
= response
.GetEntity();
1536 entity
->SetContentType("text/html");
1537 entity
->SetInputStream(msg
);
1542 /*----------------------------------------------------------------------
1543 | NPT_HttpLoggerConfigurator::Run
1544 +---------------------------------------------------------------------*/
1546 NPT_HttpLoggerConfigurator::Run()
1550 result
= m_Server
->Loop();
1551 if (NPT_FAILED(result
)) {