Merge pull request #25959 from neo1973/TagLib_deprecation_warnings
[xbmc.git] / lib / libUPnP / Neptune / Source / Core / NptLogging.cpp
blob51d20e7429af85d877531f23bec10cfe9c44b5c7
1 /*****************************************************************
3 | Neptune - Logging Support
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
6 | All rights reserved.
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 ****************************************************************/
31 /** @file
32 * Implementation file for logging
35 /*----------------------------------------------------------------------
36 | includes
37 +---------------------------------------------------------------------*/
38 #include <stdarg.h>
40 #include "NptLogging.h"
41 #include "NptList.h"
42 #include "NptStreams.h"
43 #include "NptSockets.h"
44 #include "NptUtils.h"
45 #include "NptFile.h"
46 #include "NptSystem.h"
47 #include "NptConsole.h"
48 #include "NptDebug.h"
50 /*----------------------------------------------------------------------
51 | logging
52 +---------------------------------------------------------------------*/
53 //NPT_SET_LOCAL_LOGGER("neptune.logging")
55 /*----------------------------------------------------------------------
56 | types
57 +---------------------------------------------------------------------*/
58 class NPT_LogConsoleHandler : public NPT_LogHandler {
59 public:
60 // enums
61 enum {
62 OUTPUT_TO_CONSOLE = 1,
63 OUTPUT_TO_DEBUG = 2
66 // class methods
67 static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler);
69 // methods
70 void Log(const NPT_LogRecord& record) override;
72 private:
73 // members
74 NPT_UInt32 m_Outputs;
75 bool m_UseColors;
76 NPT_Flags m_FormatFilter;
79 class NPT_LogFileHandler : public NPT_LogHandler {
80 public:
81 // class methods
82 static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler);
84 // methods
85 void Log(const NPT_LogRecord& record) override;
87 private:
88 NPT_Result Open(bool append = true);
90 private:
91 // members
92 bool m_Flush;
93 bool m_Append;
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 {
101 public:
102 // class methods
103 static void FormatRecord(const NPT_LogRecord& record, NPT_String& msg);
104 static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler);
106 // methods
107 void Log(const NPT_LogRecord& record) override;
109 private:
110 // constructor
111 NPT_LogTcpHandler() : m_Port(0) {}
113 // methods
114 NPT_Result Connect();
116 // members
117 NPT_String m_Host;
118 NPT_UInt16 m_Port;
119 NPT_OutputStreamReference m_Stream;
122 class NPT_LogUdpHandler : public NPT_LogHandler {
123 public:
124 // class methods
125 static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler);
127 // methods
128 void Log(const NPT_LogRecord& record) override;
130 private:
131 // members
132 NPT_UdpSocket m_Socket;
133 NPT_SocketAddress m_Target;
136 class NPT_LogNullHandler : public NPT_LogHandler {
137 public:
138 // class methods
139 static NPT_Result Create(NPT_LogHandler*& handler);
141 // methods
142 void Log(const NPT_LogRecord& record) override;
145 class NPT_LogCustomHandler : public NPT_LogHandler {
146 public:
147 // class methods
148 static NPT_Result SetCustomHandlerFunction(CustomHandlerExternalFunction function);
149 static NPT_Result Create(NPT_LogHandler*& handler);
151 // methods
152 void Log(const NPT_LogRecord& record) override;
154 private:
155 static CustomHandlerExternalFunction s_ExternalFunction;
158 /*----------------------------------------------------------------------
159 | constants
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"
167 #endif
169 #if !defined(NPT_CONFIG_DEFAULT_LOG_CONFIG_SOURCE)
170 #define NPT_CONFIG_DEFAULT_LOG_CONFIG_SOURCE "file:neptune-logging.properties"
171 #endif
173 #if !defined(NPT_CONFIG_DEFAULT_LOG_LEVEL)
174 #define NPT_CONFIG_DEFAULT_LOG_LEVEL NPT_LOG_LEVEL_OFF
175 #endif
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"
179 #endif
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
188 #else
189 #define NPT_LOG_CONSOLE_HANDLER_DEFAULT_COLOR_MODE true
190 #endif
192 #ifndef NPT_CONFIG_DEFAULT_LOG_CONSOLE_HANDLER_OUTPUTS
193 #define NPT_CONFIG_DEFAULT_LOG_CONSOLE_HANDLER_OUTPUTS OUTPUT_TO_DEBUG
194 #endif
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 /*----------------------------------------------------------------------
206 | globals
207 +---------------------------------------------------------------------*/
208 static NPT_LogManager LogManager;
210 /*----------------------------------------------------------------------
211 | NPT_LogManagerAutoDisabler
212 +---------------------------------------------------------------------*/
213 class NPT_LogManagerAutoDisabler
215 public:
216 NPT_LogManagerAutoDisabler() : m_WasEnabled(LogManager.IsEnabled()) {
217 LogManager.SetEnabled(false);
219 ~NPT_LogManagerAutoDisabler() {
220 LogManager.SetEnabled(m_WasEnabled);
222 private:
223 bool m_WasEnabled;
226 /*----------------------------------------------------------------------
227 | NPT_LogManagerAutoLocker
228 +---------------------------------------------------------------------*/
229 class NPT_LogManagerAutoLocker
231 public:
232 // methods
233 NPT_LogManagerAutoLocker(NPT_LogManager &manager) : m_Manager(manager) {
234 m_Manager.Lock();
236 ~NPT_LogManagerAutoLocker() {
237 m_Manager.Unlock();
240 private:
241 // members
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;
253 #endif
255 /*----------------------------------------------------------------------
256 | NPT_LogHandler::Create
257 +---------------------------------------------------------------------*/
258 NPT_Result
259 NPT_LogHandler::Create(const char* logger_name,
260 const char* handler_name,
261 NPT_LogHandler*& handler)
263 handler = NULL;
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 +---------------------------------------------------------------------*/
285 NPT_Result
286 NPT_LogHandler::SetCustomHandlerFunction(CustomHandlerExternalFunction function)
288 return NPT_LogCustomHandler::SetCustomHandlerFunction(function);
291 /*----------------------------------------------------------------------
292 | NPT_Log::GetLogLevel
293 +---------------------------------------------------------------------*/
294 int
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;
315 } else {
316 return -1;
320 /*----------------------------------------------------------------------
321 | NPT_Log::GetLogLevelName
322 +---------------------------------------------------------------------*/
323 const char*
324 NPT_Log::GetLogLevelName(int level)
326 switch (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";
335 default: return "";
339 /*----------------------------------------------------------------------
340 | NPT_Log::GetLogLevelAnsiColor
341 +---------------------------------------------------------------------*/
342 const char*
343 NPT_Log::GetLogLevelAnsiColor(int level)
345 switch (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 +---------------------------------------------------------------------*/
360 void
361 NPT_Log::FormatRecordToStream(const NPT_LogRecord& record,
362 NPT_OutputStream& stream,
363 bool use_colors,
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);
379 start;
380 --start) {
381 if (record.m_SourceFile[start-1] == '\\' ||
382 record.m_SourceFile[start-1] == '/') {
383 break;
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;
417 if (use_colors) {
418 ansi_color = GetLogLevelAnsiColor(record.m_Level);
419 if (ansi_color) {
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() :
438 m_LockOwner(0),
439 m_LockRecursion(0),
440 m_Enabled(true),
441 m_Configured(false),
442 m_Root(NULL)
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();
454 ++i) {
455 NPT_Logger* logger = *i;
456 delete logger;
459 /* destroy the root logger */
460 delete m_Root;
463 /*----------------------------------------------------------------------
464 | NPT_LogManager::GetDefault
465 +---------------------------------------------------------------------*/
466 NPT_LogManager&
467 NPT_LogManager::GetDefault()
469 return LogManager;
472 /*----------------------------------------------------------------------
473 | NPT_LogManager::Lock
474 +---------------------------------------------------------------------*/
475 void
476 NPT_LogManager::Lock()
478 NPT_Thread::ThreadId me = NPT_Thread::GetCurrentThreadId();
479 if (m_LockOwner != me) {
480 m_Lock.Lock();
481 m_LockOwner = me;
483 ++m_LockRecursion;
486 /*----------------------------------------------------------------------
487 | NPT_LogManager::Unlock
488 +---------------------------------------------------------------------*/
489 void
490 NPT_LogManager::Unlock()
492 if (--m_LockRecursion == 0) {
493 m_LockOwner = (NPT_Thread::ThreadId)0;
494 m_Lock.Unlock();
498 /*----------------------------------------------------------------------
499 | NPT_LogManager::Configure
500 +---------------------------------------------------------------------*/
501 NPT_Result
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;
534 for (;;) {
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;
544 cursor++;
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
554 m_Configured = true;
556 return NPT_SUCCESS;
559 /*----------------------------------------------------------------------
560 | NPT_LogManager::ConfigValueIsBooleanTrue
561 +---------------------------------------------------------------------*/
562 bool
563 NPT_LogManager::ConfigValueIsBooleanTrue(NPT_String& value)
565 return
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 +---------------------------------------------------------------------*/
575 bool
576 NPT_LogManager::ConfigValueIsBooleanFalse(NPT_String& value)
578 return
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 +---------------------------------------------------------------------*/
588 NPT_String*
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();
596 ++i) {
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;
605 // not found
606 return NULL;
609 /*----------------------------------------------------------------------
610 | NPT_LogManager::SetConfigValue
611 +---------------------------------------------------------------------*/
612 NPT_Result
613 NPT_LogManager::SetConfigValue(const char* key, const char* value)
615 NPT_String* value_string = GetConfigValue(key, NULL);
616 if (value_string) {
617 /* the key already exists, replace the value */
618 *value_string = value;
619 } else {
620 /* the value does not already exist, create a new one */
621 NPT_CHECK(LogManager.m_Config.Add(NPT_LogConfigEntry(key, value)));
624 return NPT_SUCCESS;
627 /*----------------------------------------------------------------------
628 | NPT_LogManager::ParseConfig
629 +---------------------------------------------------------------------*/
630 NPT_Result
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;
637 NPT_String key;
638 NPT_String value;
640 /* parse all entries */
641 while (cursor <= config+config_size) {
642 /* separators are newlines, ';' or end of buffer */
643 if ( cursor == config+config_size ||
644 *cursor == '\n' ||
645 *cursor == '\r' ||
646 *cursor == ';') {
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)));
652 key.Trim(" \t");
653 value.Trim(" \t");
655 SetConfigValue((const char*)key, (const char*)value);
657 line = cursor+1;
658 separator = NULL;
659 } else if (*cursor == '=' && separator == NULL) {
660 separator = cursor;
662 cursor++;
665 return NPT_SUCCESS;
668 /*----------------------------------------------------------------------
669 | NPT_LogManager::ParseConfigFile
670 +---------------------------------------------------------------------*/
671 NPT_Result
672 NPT_LogManager::ParseConfigFile(const char* filename)
674 NPT_Result result;
676 /* load the file */
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 +---------------------------------------------------------------------*/
688 NPT_Result
689 NPT_LogManager::ParseConfigSource(NPT_String& source)
691 if (source.StartsWith("file:")) {
692 /* file source */
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);
703 } else {
704 return NPT_ERROR_INVALID_SYNTAX;
707 return NPT_SUCCESS;
710 /*----------------------------------------------------------------------
711 | NPT_LogManager::HaveLoggerConfig
712 +---------------------------------------------------------------------*/
713 bool
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();
719 ++i) {
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")) {
726 return true;
731 /* no config found */
732 return false;
735 /*----------------------------------------------------------------------
736 | NPT_LogManager::ConfigureLogger
737 +---------------------------------------------------------------------*/
738 NPT_Result
739 NPT_LogManager::ConfigureLogger(NPT_Logger* logger)
741 /* configure the level */
742 NPT_String* level_value = GetConfigValue(logger->m_Name,".level");
743 if (level_value) {
744 NPT_Int32 value;
745 /* try a symbolic name */
746 value = NPT_Log::GetLogLevel(*level_value);
747 if (value < 0) {
748 /* try a numeric value */
749 if (NPT_FAILED(level_value->ToInteger(value, false))) {
750 value = -1;
753 if (value >= 0) {
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");
764 if (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;
770 for (;;) {
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 */
777 if (NPT_SUCCEEDED(
778 NPT_LogHandler::Create(logger->m_Name, handler_name, handler))) {
779 logger->AddHandler(handler);
783 if (*cursor == '\0') break;
784 name_start = cursor+1;
786 ++cursor;
790 /* configure the forwarding */
791 NPT_String* forward = GetConfigValue(logger->m_Name,".forward");
792 if (forward && !ConfigValueIsBooleanTrue(*forward)) {
793 logger->m_ForwardToParent = false;
796 return NPT_SUCCESS;
799 /*----------------------------------------------------------------------
800 | NPT_LogManager::FindLogger
801 +---------------------------------------------------------------------*/
802 NPT_Logger*
803 NPT_LogManager::FindLogger(const char* name)
805 for (NPT_List<NPT_Logger*>::Iterator i = LogManager.m_Loggers.GetFirstItem();
807 ++i) {
808 NPT_Logger* logger = *i;
809 if (logger->m_Name == name) {
810 return logger;
814 return NULL;
817 /*----------------------------------------------------------------------
818 | NPT_LogManager::GetLogger
819 +---------------------------------------------------------------------*/
820 NPT_Logger*
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;
850 for (;;) {
851 NPT_Logger* candidate_parent;
853 /* find the last dot */
854 int dot = parent_name.ReverseFind('.');
855 if (dot < 0) break;
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;
862 break;
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);
868 break;
872 /* attach to the parent */
873 logger->SetParent(parent);
875 /* add this logger to the list */
876 LogManager.m_Loggers.Add(logger);
878 return logger;
881 /*----------------------------------------------------------------------
882 | NPT_Logger::NPT_Logger
883 +---------------------------------------------------------------------*/
884 NPT_Logger::NPT_Logger(const char* name, NPT_LogManager& manager) :
885 m_Manager(manager),
886 m_Name(name),
887 m_Level(NPT_LOG_LEVEL_OFF),
888 m_LevelIsInherited(true),
889 m_ForwardToParent(true),
890 m_Parent(NULL)
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 +---------------------------------------------------------------------*/
909 NPT_Result
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>());
918 m_Handlers.Clear();
921 return NPT_SUCCESS;
924 /*----------------------------------------------------------------------
925 | NPT_Logger::Log
926 +---------------------------------------------------------------------*/
927 void
928 NPT_Logger::Log(int level,
929 const char* source_file,
930 unsigned int source_line,
931 const char* source_function,
932 const char* msg,
933 ...)
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;
945 int result;
946 va_list args;
947 for(;;) {
948 /* try to format the message (it might not fit) */
949 va_start(args, msg);
950 result = NPT_FormatStringVN(message, buffer_size-1, msg, args);
951 va_end(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 */
979 m_Manager.Lock();
980 m_Manager.SetEnabled(false); // prevent recursion
981 while (logger) {
982 /* call all handlers for the current logger */
983 for (NPT_List<NPT_LogHandler*>::Iterator i = logger->m_Handlers.GetFirstItem();
985 ++i) {
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;
993 } else {
994 break;
997 m_Manager.SetEnabled(true);
998 m_Manager.Unlock();
1000 /* free anything we may have allocated */
1001 if (message != buffer) delete[] message;
1004 /*----------------------------------------------------------------------
1005 | NPT_Logger::AddHandler
1006 +---------------------------------------------------------------------*/
1007 NPT_Result
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 +---------------------------------------------------------------------*/
1022 NPT_Result
1023 NPT_Logger::SetParent(NPT_Logger* parent)
1025 /* set our new parent */
1026 m_Parent = 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;
1035 return NPT_SUCCESS;
1038 /*----------------------------------------------------------------------
1039 | NPT_LogNullHandler::Create
1040 +---------------------------------------------------------------------*/
1041 NPT_Result
1042 NPT_LogNullHandler::Create(NPT_LogHandler*& handler)
1044 handler = new NPT_LogNullHandler();
1045 return NPT_SUCCESS;
1048 /*----------------------------------------------------------------------
1049 | NPT_LogNullHandler::Log
1050 +---------------------------------------------------------------------*/
1051 void
1052 NPT_LogNullHandler::Log(const NPT_LogRecord& /*record*/)
1057 NPT_LogHandler::CustomHandlerExternalFunction NPT_LogCustomHandler::s_ExternalFunction = NULL;
1058 /*----------------------------------------------------------------------
1059 | NPT_LogCustomHandler::SetCustomHandlerFunction
1060 +---------------------------------------------------------------------*/
1061 NPT_Result
1062 NPT_LogCustomHandler::SetCustomHandlerFunction(CustomHandlerExternalFunction function)
1064 s_ExternalFunction = function;
1065 return NPT_SUCCESS;
1068 /*----------------------------------------------------------------------
1069 | NPT_LogCustomHandler::Create
1070 +---------------------------------------------------------------------*/
1071 NPT_Result
1072 NPT_LogCustomHandler::Create(NPT_LogHandler*& handler)
1074 /* allocate a new object */
1075 NPT_LogCustomHandler* instance = new NPT_LogCustomHandler();
1076 handler = instance;
1077 return NPT_SUCCESS;
1080 /*----------------------------------------------------------------------
1081 | NPT_LogCustomHandler::Log
1082 +---------------------------------------------------------------------*/
1083 void
1084 NPT_LogCustomHandler::Log(const NPT_LogRecord& record)
1086 if (s_ExternalFunction) {
1087 (*s_ExternalFunction)(&record);
1091 /*----------------------------------------------------------------------
1092 | NPT_LogConsoleHandler::Create
1093 +---------------------------------------------------------------------*/
1094 NPT_Result
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();
1104 handler = instance;
1106 /* configure the object */
1107 NPT_String* colors;
1108 instance->m_UseColors = NPT_LOG_CONSOLE_HANDLER_DEFAULT_COLOR_MODE;
1109 colors = LogManager.GetConfigValue(logger_prefix,".colors");
1110 if (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");
1121 if (outputs) {
1122 outputs->ToInteger(instance->m_Outputs, true);
1125 NPT_String* filter;
1126 instance->m_FormatFilter = 0;
1127 filter = LogManager.GetConfigValue(logger_prefix,".filter");
1128 if (filter) {
1129 filter->ToInteger(instance->m_FormatFilter, true);
1132 return NPT_SUCCESS;
1135 /*----------------------------------------------------------------------
1136 | NPT_LogConsoleHandler::Log
1137 +---------------------------------------------------------------------*/
1138 void
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 +---------------------------------------------------------------------*/
1156 void
1157 NPT_LogFileHandler::Log(const NPT_LogRecord& record)
1159 if (m_MaxFilesize > 0) {
1160 /* get current file size */
1161 NPT_LargeSize 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 */
1168 m_Stream = NULL;
1170 /* rename file using current time */
1171 NPT_TimeStamp now;
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) +
1178 "-" +
1179 suffix +
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()) {
1189 Open(m_Append);
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 +---------------------------------------------------------------------*/
1201 NPT_Result
1202 NPT_LogFileHandler::Open(bool append /* = true */)
1204 /* reset stream just in case */
1205 m_Stream = NULL;
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));
1216 /* seek to end */
1217 if (append) {
1218 NPT_LargeSize size;
1219 NPT_CHECK(NPT_File::GetSize(m_Filename, size));
1220 NPT_CHECK(m_Stream->Seek(size));
1222 return NPT_SUCCESS;
1225 /*----------------------------------------------------------------------
1226 | NPT_LogFileHandler::Create
1227 +---------------------------------------------------------------------*/
1228 NPT_Result
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();
1238 handler = instance;
1240 /* filename */
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;
1248 } else {
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;
1257 } else {
1258 instance->m_Flush = false;
1261 /* append mode */
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;
1268 /* filter */
1269 NPT_String* filter;
1270 instance->m_FormatFilter = 0;
1271 filter = LogManager.GetConfigValue(logger_prefix,".filter");
1272 if (filter) {
1273 filter->ToInteger(instance->m_FormatFilter, true);
1276 /* recycle */
1277 NPT_String* recycle;
1278 instance->m_MaxFilesize = 0;
1279 recycle = LogManager.GetConfigValue(logger_prefix,".recycle");
1280 if (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 +---------------------------------------------------------------------*/
1294 NPT_Result
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();
1303 handler = instance;
1305 /* configure the object */
1306 const NPT_String* hostname = LogManager.GetConfigValue(logger_prefix, ".hostname");
1307 if (hostname) {
1308 instance->m_Host = *hostname;
1309 } else {
1310 /* default hostname */
1311 instance->m_Host = "localhost";
1313 const NPT_String* port = LogManager.GetConfigValue(logger_prefix, ".port");
1314 if (port) {
1315 NPT_UInt32 port_int;
1316 if (NPT_SUCCEEDED(port->ToInteger(port_int, true))) {
1317 instance->m_Port = (NPT_UInt16)port_int;
1318 } else {
1319 instance->m_Port = NPT_LOG_TCP_HANDLER_DEFAULT_PORT;
1321 } else {
1322 /* default port */
1323 instance->m_Port = NPT_LOG_TCP_HANDLER_DEFAULT_PORT;
1326 return NPT_SUCCESS;
1329 /*----------------------------------------------------------------------
1330 | NPT_LogTcpHandler::Connect
1331 +---------------------------------------------------------------------*/
1332 NPT_Result
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)) {
1344 return result;
1347 /* get the stream */
1348 return tcp_socket.GetOutputStream(m_Stream);
1351 /*----------------------------------------------------------------------
1352 | NPT_LogTcpHandler::Log
1353 +---------------------------------------------------------------------*/
1354 void
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;
1366 msg.Reserve(2048);
1367 msg += "Logger: ";
1368 msg += record.m_LoggerName;
1369 msg += "\r\nLevel: ";
1370 msg += level_name;
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));
1385 msg += "\r\n\r\n";
1386 msg += record.m_Message;
1389 /*----------------------------------------------------------------------
1390 | NPT_LogTcpHandler::Log
1391 +---------------------------------------------------------------------*/
1392 void
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
1401 NPT_String msg;
1402 FormatRecord(record, msg);
1404 // log, and disconnect if this fails
1405 if (NPT_FAILED(m_Stream->WriteString(msg))) {
1406 m_Stream = NULL;
1410 /*----------------------------------------------------------------------
1411 | NPT_LogUdpHandler::Create
1412 +---------------------------------------------------------------------*/
1413 NPT_Result
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();
1422 handler = instance;
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");
1432 if (port_prop) {
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);
1444 return NPT_SUCCESS;
1447 /*----------------------------------------------------------------------
1448 | NPT_LogUdpHandler::Log
1449 +---------------------------------------------------------------------*/
1450 void
1451 NPT_LogUdpHandler::Log(const NPT_LogRecord& record)
1453 // format the record
1454 NPT_String msg;
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
1482 // cleanup
1483 delete m_Server;
1486 /*----------------------------------------------------------------------
1487 | NPT_HttpLoggerConfigurator::SetupResponse
1488 +---------------------------------------------------------------------*/
1489 NPT_Result
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
1498 NPT_String msg;
1500 msg = "<ul>";
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);
1505 msg += "<li>";
1506 msg += entry.m_Key;
1507 msg += "=";
1508 msg += entry.m_Value;
1509 msg += "</li>";
1511 msg += "</ul>";
1513 msg += "<ul>";
1514 NPT_List<NPT_Logger*>& loggers = LogManager.GetLoggers();
1515 NPT_List<NPT_Logger*>::Iterator lit = loggers.GetFirstItem();
1516 for (;lit;++lit) {
1517 NPT_Logger* logger = (*lit);
1518 msg += "<li>";
1519 msg += logger->GetName();
1520 msg += ", level=";
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=";
1526 for (;hit;++hit) {
1527 NPT_LogHandler* handler = (*hit);
1528 msg += handler->ToString();
1530 msg += "</li>";
1532 msg += "</ul>";
1534 // setup the response body
1535 NPT_HttpEntity* entity = response.GetEntity();
1536 entity->SetContentType("text/html");
1537 entity->SetInputStream(msg);
1539 return NPT_SUCCESS;
1542 /*----------------------------------------------------------------------
1543 | NPT_HttpLoggerConfigurator::Run
1544 +---------------------------------------------------------------------*/
1545 void
1546 NPT_HttpLoggerConfigurator::Run()
1548 for (;;) {
1549 NPT_Result result;
1550 result = m_Server->Loop();
1551 if (NPT_FAILED(result)) {
1552 break;