summaryrefslogtreecommitdiffstats
path: root/lib/libUPnP/Neptune/Source/Core/NptLogging.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libUPnP/Neptune/Source/Core/NptLogging.cpp')
-rw-r--r--lib/libUPnP/Neptune/Source/Core/NptLogging.cpp1555
1 files changed, 1555 insertions, 0 deletions
diff --git a/lib/libUPnP/Neptune/Source/Core/NptLogging.cpp b/lib/libUPnP/Neptune/Source/Core/NptLogging.cpp
new file mode 100644
index 0000000..51d20e7
--- /dev/null
+++ b/lib/libUPnP/Neptune/Source/Core/NptLogging.cpp
@@ -0,0 +1,1555 @@
+/*****************************************************************
+|
+| Neptune - Logging Support
+|
+| Copyright (c) 2002-2008, Axiomatic Systems, LLC.
+| All rights reserved.
+|
+| Redistribution and use in source and binary forms, with or without
+| modification, are permitted provided that the following conditions are met:
+| * Redistributions of source code must retain the above copyright
+| notice, this list of conditions and the following disclaimer.
+| * Redistributions in binary form must reproduce the above copyright
+| notice, this list of conditions and the following disclaimer in the
+| documentation and/or other materials provided with the distribution.
+| * Neither the name of Axiomatic Systems nor the
+| names of its contributors may be used to endorse or promote products
+| derived from this software without specific prior written permission.
+|
+| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY
+| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY
+| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+|
+****************************************************************/
+/** @file
+* Implementation file for logging
+*/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include <stdarg.h>
+
+#include "NptLogging.h"
+#include "NptList.h"
+#include "NptStreams.h"
+#include "NptSockets.h"
+#include "NptUtils.h"
+#include "NptFile.h"
+#include "NptSystem.h"
+#include "NptConsole.h"
+#include "NptDebug.h"
+
+/*----------------------------------------------------------------------
+| logging
++---------------------------------------------------------------------*/
+//NPT_SET_LOCAL_LOGGER("neptune.logging")
+
+/*----------------------------------------------------------------------
+| types
++---------------------------------------------------------------------*/
+class NPT_LogConsoleHandler : public NPT_LogHandler {
+public:
+ // enums
+ enum {
+ OUTPUT_TO_CONSOLE = 1,
+ OUTPUT_TO_DEBUG = 2
+ };
+
+ // class methods
+ static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler);
+
+ // methods
+ void Log(const NPT_LogRecord& record) override;
+
+private:
+ // members
+ NPT_UInt32 m_Outputs;
+ bool m_UseColors;
+ NPT_Flags m_FormatFilter;
+};
+
+class NPT_LogFileHandler : public NPT_LogHandler {
+public:
+ // class methods
+ static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler);
+
+ // methods
+ void Log(const NPT_LogRecord& record) override;
+
+private:
+ NPT_Result Open(bool append = true);
+
+private:
+ // members
+ bool m_Flush;
+ bool m_Append;
+ NPT_String m_Filename;
+ NPT_Flags m_FormatFilter;
+ NPT_LargeSize m_MaxFilesize;
+ NPT_OutputStreamReference m_Stream;
+};
+
+class NPT_LogTcpHandler : public NPT_LogHandler {
+public:
+ // class methods
+ static void FormatRecord(const NPT_LogRecord& record, NPT_String& msg);
+ static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler);
+
+ // methods
+ void Log(const NPT_LogRecord& record) override;
+
+private:
+ // constructor
+ NPT_LogTcpHandler() : m_Port(0) {}
+
+ // methods
+ NPT_Result Connect();
+
+ // members
+ NPT_String m_Host;
+ NPT_UInt16 m_Port;
+ NPT_OutputStreamReference m_Stream;
+};
+
+class NPT_LogUdpHandler : public NPT_LogHandler {
+public:
+ // class methods
+ static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler);
+
+ // methods
+ void Log(const NPT_LogRecord& record) override;
+
+private:
+ // members
+ NPT_UdpSocket m_Socket;
+ NPT_SocketAddress m_Target;
+};
+
+class NPT_LogNullHandler : public NPT_LogHandler {
+public:
+ // class methods
+ static NPT_Result Create(NPT_LogHandler*& handler);
+
+ // methods
+ void Log(const NPT_LogRecord& record) override;
+};
+
+class NPT_LogCustomHandler : public NPT_LogHandler {
+public:
+ // class methods
+ static NPT_Result SetCustomHandlerFunction(CustomHandlerExternalFunction function);
+ static NPT_Result Create(NPT_LogHandler*& handler);
+
+ // methods
+ void Log(const NPT_LogRecord& record) override;
+
+private:
+ static CustomHandlerExternalFunction s_ExternalFunction;
+};
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+#define NPT_LOG_HEAP_BUFFER_INCREMENT 4096
+#define NPT_LOG_STACK_BUFFER_MAX_SIZE 512
+#define NPT_LOG_HEAP_BUFFER_MAX_SIZE 65536
+
+#if !defined(NPT_CONFIG_LOG_CONFIG_ENV)
+#define NPT_CONFIG_LOG_CONFIG_ENV "NEPTUNE_LOG_CONFIG"
+#endif
+
+#if !defined(NPT_CONFIG_DEFAULT_LOG_CONFIG_SOURCE)
+#define NPT_CONFIG_DEFAULT_LOG_CONFIG_SOURCE "file:neptune-logging.properties"
+#endif
+
+#if !defined(NPT_CONFIG_DEFAULT_LOG_LEVEL)
+#define NPT_CONFIG_DEFAULT_LOG_LEVEL NPT_LOG_LEVEL_OFF
+#endif
+#define NPT_LOG_ROOT_DEFAULT_HANDLER "ConsoleHandler"
+#if !defined(NPT_CONFIG_DEFAULT_FILE_HANDLER_FILENAME)
+#define NPT_CONFIG_DEFAULT_LOG_FILE_HANDLER_FILENAME "_neptune.log"
+#endif
+
+#define NPT_LOG_TCP_HANDLER_DEFAULT_PORT 7723
+#define NPT_LOG_TCP_HANDLER_DEFAULT_CONNECT_TIMEOUT 5000 /* 5 seconds */
+
+#define NPT_LOG_UDP_HANDLER_DEFAULT_PORT 7724
+
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__APPLE__)
+#define NPT_LOG_CONSOLE_HANDLER_DEFAULT_COLOR_MODE false
+#else
+#define NPT_LOG_CONSOLE_HANDLER_DEFAULT_COLOR_MODE true
+#endif
+
+#ifndef NPT_CONFIG_DEFAULT_LOG_CONSOLE_HANDLER_OUTPUTS
+#define NPT_CONFIG_DEFAULT_LOG_CONSOLE_HANDLER_OUTPUTS OUTPUT_TO_DEBUG
+#endif
+
+#define NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE 1000000
+
+#define NPT_LOG_FORMAT_FILTER_NO_SOURCE 1
+#define NPT_LOG_FORMAT_FILTER_NO_TIMESTAMP 2
+#define NPT_LOG_FORMAT_FILTER_NO_FUNCTION_NAME 4
+#define NPT_LOG_FORMAT_FILTER_NO_LOGGER_NAME 8
+#define NPT_LOG_FORMAT_FILTER_NO_SOURCEPATH 16
+#define NPT_LOG_FORMAT_FILTER_NO_THREAD_ID 32
+
+/*----------------------------------------------------------------------
+| globals
++---------------------------------------------------------------------*/
+static NPT_LogManager LogManager;
+
+/*----------------------------------------------------------------------
+| NPT_LogManagerAutoDisabler
++---------------------------------------------------------------------*/
+class NPT_LogManagerAutoDisabler
+{
+public:
+ NPT_LogManagerAutoDisabler() : m_WasEnabled(LogManager.IsEnabled()) {
+ LogManager.SetEnabled(false);
+ }
+ ~NPT_LogManagerAutoDisabler() {
+ LogManager.SetEnabled(m_WasEnabled);
+ }
+private:
+ bool m_WasEnabled;
+};
+
+/*----------------------------------------------------------------------
+| NPT_LogManagerAutoLocker
++---------------------------------------------------------------------*/
+class NPT_LogManagerAutoLocker
+{
+ public:
+ // methods
+ NPT_LogManagerAutoLocker(NPT_LogManager &manager) : m_Manager(manager) {
+ m_Manager.Lock();
+ }
+ ~NPT_LogManagerAutoLocker() {
+ m_Manager.Unlock();
+ }
+
+ private:
+ // members
+ NPT_LogManager& m_Manager;
+};
+
+/*----------------------------------------------------------------------
+| NPT_GetSystemLogConfig
++---------------------------------------------------------------------*/
+#if !defined(NPT_CONFIG_HAVE_SYSTEM_LOG_CONFIG)
+NPT_Result NPT_GetSystemLogConfig(NPT_String& /*config*/)
+{
+ return NPT_ERROR_NOT_SUPPORTED;
+}
+#endif
+
+/*----------------------------------------------------------------------
+| NPT_LogHandler::Create
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogHandler::Create(const char* logger_name,
+ const char* handler_name,
+ NPT_LogHandler*& handler)
+{
+ handler = NULL;
+
+ if (NPT_StringsEqual(handler_name, "NullHandler")) {
+ return NPT_LogNullHandler::Create(handler);
+ } else if (NPT_StringsEqual(handler_name, "FileHandler")) {
+ return NPT_LogFileHandler::Create(logger_name, handler);
+ } else if (NPT_StringsEqual(handler_name, "ConsoleHandler")) {
+ return NPT_LogConsoleHandler::Create(logger_name, handler);
+ } else if (NPT_StringsEqual(handler_name, "TcpHandler")) {
+ return NPT_LogTcpHandler::Create(logger_name, handler);
+ } else if (NPT_StringsEqual(handler_name, "UdpHandler")) {
+ return NPT_LogUdpHandler::Create(logger_name, handler);
+ } else if (NPT_StringsEqual(handler_name, "CustomHandler")) {
+ return NPT_LogCustomHandler::Create(handler);
+ }
+
+ return NPT_ERROR_NO_SUCH_CLASS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogHandler::SetCustomHandlerFunction
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogHandler::SetCustomHandlerFunction(CustomHandlerExternalFunction function)
+{
+ return NPT_LogCustomHandler::SetCustomHandlerFunction(function);
+}
+
+/*----------------------------------------------------------------------
+| NPT_Log::GetLogLevel
++---------------------------------------------------------------------*/
+int
+NPT_Log::GetLogLevel(const char* name)
+{
+ if ( NPT_StringsEqual(name, "FATAL")) {
+ return NPT_LOG_LEVEL_FATAL;
+ } else if (NPT_StringsEqual(name, "SEVERE")) {
+ return NPT_LOG_LEVEL_SEVERE;
+ } else if (NPT_StringsEqual(name, "WARNING")) {
+ return NPT_LOG_LEVEL_WARNING;
+ } else if (NPT_StringsEqual(name, "INFO")) {
+ return NPT_LOG_LEVEL_INFO;
+ } else if (NPT_StringsEqual(name, "FINE")) {
+ return NPT_LOG_LEVEL_FINE;
+ } else if (NPT_StringsEqual(name, "FINER")) {
+ return NPT_LOG_LEVEL_FINER;
+ } else if (NPT_StringsEqual(name, "FINEST")) {
+ return NPT_LOG_LEVEL_FINEST;
+ } else if (NPT_StringsEqual(name, "ALL")) {
+ return NPT_LOG_LEVEL_ALL;
+ } else if (NPT_StringsEqual(name, "OFF")) {
+ return NPT_LOG_LEVEL_OFF;
+ } else {
+ return -1;
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_Log::GetLogLevelName
++---------------------------------------------------------------------*/
+const char*
+NPT_Log::GetLogLevelName(int level)
+{
+ switch (level) {
+ case NPT_LOG_LEVEL_FATAL: return "FATAL";
+ case NPT_LOG_LEVEL_SEVERE: return "SEVERE";
+ case NPT_LOG_LEVEL_WARNING: return "WARNING";
+ case NPT_LOG_LEVEL_INFO: return "INFO";
+ case NPT_LOG_LEVEL_FINE: return "FINE";
+ case NPT_LOG_LEVEL_FINER: return "FINER";
+ case NPT_LOG_LEVEL_FINEST: return "FINEST";
+ case NPT_LOG_LEVEL_OFF: return "OFF";
+ default: return "";
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_Log::GetLogLevelAnsiColor
++---------------------------------------------------------------------*/
+const char*
+NPT_Log::GetLogLevelAnsiColor(int level)
+{
+ switch (level) {
+ case NPT_LOG_LEVEL_FATAL: return "31";
+ case NPT_LOG_LEVEL_SEVERE: return "31";
+ case NPT_LOG_LEVEL_WARNING: return "33";
+ case NPT_LOG_LEVEL_INFO: return "32";
+ case NPT_LOG_LEVEL_FINE: return "34";
+ case NPT_LOG_LEVEL_FINER: return "35";
+ case NPT_LOG_LEVEL_FINEST: return "36";
+ default: return NULL;
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_Log::FormatRecordToStream
++---------------------------------------------------------------------*/
+void
+NPT_Log::FormatRecordToStream(const NPT_LogRecord& record,
+ NPT_OutputStream& stream,
+ bool use_colors,
+ NPT_Flags format_filter)
+{
+ const char* level_name = GetLogLevelName(record.m_Level);
+ NPT_String level_string;
+
+ /* format and emit the record */
+ if (level_name[0] == '\0') {
+ level_string = NPT_String::FromInteger(record.m_Level);
+ level_name = level_string;
+ }
+ if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_SOURCE) == 0) {
+ unsigned int start = 0;
+ /* remove source file path if requested */
+ if (format_filter & NPT_LOG_FORMAT_FILTER_NO_SOURCEPATH) {
+ for (start = NPT_StringLength(record.m_SourceFile);
+ start;
+ --start) {
+ if (record.m_SourceFile[start-1] == '\\' ||
+ record.m_SourceFile[start-1] == '/') {
+ break;
+ }
+ }
+ }
+ stream.WriteString(record.m_SourceFile + start);
+ stream.Write("(", 1, NULL);
+ stream.WriteString(NPT_String::FromIntegerU(record.m_SourceLine));
+ stream.Write("): ", 3, NULL);
+ }
+ if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_LOGGER_NAME) == 0) {
+ stream.Write("[", 1, NULL);
+ stream.WriteString(record.m_LoggerName);
+ stream.Write("] ", 2, NULL);
+ }
+ if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_TIMESTAMP) == 0) {
+ NPT_String ts = NPT_DateTime(record.m_TimeStamp, true).ToString(NPT_DateTime::FORMAT_W3C,
+ NPT_DateTime::FLAG_EMIT_FRACTION |
+ NPT_DateTime::FLAG_EXTENDED_PRECISION);
+ stream.WriteString(ts.GetChars());
+ stream.Write(" ", 1);
+ }
+ if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_FUNCTION_NAME) == 0) {
+ stream.WriteFully("[",1);
+ if (record.m_SourceFunction) {
+ stream.WriteString(record.m_SourceFunction);
+ }
+ stream.WriteFully("] ",2);
+ }
+ if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_THREAD_ID) == 0) {
+ stream.Write("(", 1, NULL);
+ stream.WriteString(NPT_String::FromIntegerU(record.m_ThreadId));
+ stream.Write(") ", 2, NULL);
+ }
+ const char* ansi_color = NULL;
+ if (use_colors) {
+ ansi_color = GetLogLevelAnsiColor(record.m_Level);
+ if (ansi_color) {
+ stream.Write("\033[", 2, NULL);
+ stream.WriteString(ansi_color);
+ stream.Write(";1m", 3, NULL);
+ }
+ }
+ stream.WriteString(level_name);
+ if (use_colors && ansi_color) {
+ stream.Write("\033[0m", 4, NULL);
+ }
+ stream.Write(": ", 2, NULL);
+ stream.WriteString(record.m_Message);
+ stream.Write("\r\n", 2, NULL);
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::NPT_LogManager
++---------------------------------------------------------------------*/
+NPT_LogManager::NPT_LogManager() :
+ m_LockOwner(0),
+ m_LockRecursion(0),
+ m_Enabled(true),
+ m_Configured(false),
+ m_Root(NULL)
+{
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::~NPT_LogManager
++---------------------------------------------------------------------*/
+NPT_LogManager::~NPT_LogManager()
+{
+ /* destroy everything we've created */
+ for (NPT_List<NPT_Logger*>::Iterator i = m_Loggers.GetFirstItem();
+ i;
+ ++i) {
+ NPT_Logger* logger = *i;
+ delete logger;
+ }
+
+ /* destroy the root logger */
+ delete m_Root;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::GetDefault
++---------------------------------------------------------------------*/
+NPT_LogManager&
+NPT_LogManager::GetDefault()
+{
+ return LogManager;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::Lock
++---------------------------------------------------------------------*/
+void
+NPT_LogManager::Lock()
+{
+ NPT_Thread::ThreadId me = NPT_Thread::GetCurrentThreadId();
+ if (m_LockOwner != me) {
+ m_Lock.Lock();
+ m_LockOwner = me;
+ }
+ ++m_LockRecursion;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::Unlock
++---------------------------------------------------------------------*/
+void
+NPT_LogManager::Unlock()
+{
+ if (--m_LockRecursion == 0) {
+ m_LockOwner = (NPT_Thread::ThreadId)0;
+ m_Lock.Unlock();
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::Configure
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogManager::Configure(const char* config_sources)
+{
+ // exit if we're already initialized
+ if (m_Configured) return NPT_SUCCESS;
+
+ // prevent multiple threads from configuring at the same time
+ NPT_LogManagerAutoLocker lock(*this);
+ if (m_Configured) return NPT_SUCCESS;
+
+ // we need to be disabled while we configure ourselves
+ NPT_LogManagerAutoDisabler autodisabler;
+
+ // set some default config values
+ SetConfigValue(".handlers", NPT_LOG_ROOT_DEFAULT_HANDLER);
+
+ // see if the config sources have been set to non-default values
+ if (config_sources == NULL) {
+ config_sources = NPT_CONFIG_DEFAULT_LOG_CONFIG_SOURCE;
+ }
+ NPT_String config_sources_system;
+ if (NPT_SUCCEEDED(NPT_GetSystemLogConfig(config_sources_system))) {
+ config_sources = config_sources_system;
+ }
+ NPT_String config_sources_env;
+ if (NPT_SUCCEEDED(NPT_Environment::Get(NPT_CONFIG_LOG_CONFIG_ENV, config_sources_env))) {
+ config_sources = config_sources_env;
+ }
+
+ /* load all configs */
+ NPT_String config_source;
+ const char* cursor = config_sources;
+ const char* source = config_sources;
+ for (;;) {
+ if (*cursor == '\0' || *cursor == '|') {
+ if (cursor != source) {
+ config_source.Assign(source, (NPT_Size)(cursor-source));
+ config_source.Trim(" \t");
+ ParseConfigSource(config_source);
+ if (*cursor == '|') source = cursor+1;
+ }
+ if (*cursor == '\0') break;
+ }
+ cursor++;
+ }
+
+ /* create the root logger */
+ LogManager.m_Root = new NPT_Logger("", *this);
+ LogManager.m_Root->m_Level = NPT_CONFIG_DEFAULT_LOG_LEVEL;
+ LogManager.m_Root->m_LevelIsInherited = false;
+ ConfigureLogger(LogManager.m_Root);
+
+ // we're initialized now
+ m_Configured = true;
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::ConfigValueIsBooleanTrue
++---------------------------------------------------------------------*/
+bool
+NPT_LogManager::ConfigValueIsBooleanTrue(NPT_String& value)
+{
+ return
+ value.Compare("true", true) == 0 ||
+ value.Compare("yes", true) == 0 ||
+ value.Compare("on", true) == 0 ||
+ value.Compare("1", true) == 0;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::ConfigValueIsBooleanFalse
++---------------------------------------------------------------------*/
+bool
+NPT_LogManager::ConfigValueIsBooleanFalse(NPT_String& value)
+{
+ return
+ value.Compare("false", true) == 0 ||
+ value.Compare("no", true) == 0 ||
+ value.Compare("off", true) == 0 ||
+ value.Compare("0", true) == 0;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::GetConfigValue
++---------------------------------------------------------------------*/
+NPT_String*
+NPT_LogManager::GetConfigValue(const char* prefix, const char* suffix)
+{
+ NPT_Size prefix_length = prefix?NPT_StringLength(prefix):0;
+ NPT_Size suffix_length = suffix?NPT_StringLength(suffix):0;
+ NPT_Size key_length = prefix_length+suffix_length;
+ for (NPT_List<NPT_LogConfigEntry>::Iterator i = LogManager.m_Config.GetFirstItem();
+ i;
+ ++i) {
+ NPT_LogConfigEntry& entry = *i;
+ if ((entry.m_Key.GetLength() == key_length) &&
+ (prefix == NULL || entry.m_Key.StartsWith(prefix)) &&
+ (suffix == NULL || entry.m_Key.EndsWith(suffix )) ) {
+ return &entry.m_Value;
+ }
+ }
+
+ // not found
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::SetConfigValue
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogManager::SetConfigValue(const char* key, const char* value)
+{
+ NPT_String* value_string = GetConfigValue(key, NULL);
+ if (value_string) {
+ /* the key already exists, replace the value */
+ *value_string = value;
+ } else {
+ /* the value does not already exist, create a new one */
+ NPT_CHECK(LogManager.m_Config.Add(NPT_LogConfigEntry(key, value)));
+ }
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::ParseConfig
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogManager::ParseConfig(const char* config,
+ NPT_Size config_size)
+{
+ const char* cursor = config;
+ const char* line = config;
+ const char* separator = NULL;
+ NPT_String key;
+ NPT_String value;
+
+ /* parse all entries */
+ while (cursor <= config+config_size) {
+ /* separators are newlines, ';' or end of buffer */
+ if ( cursor == config+config_size ||
+ *cursor == '\n' ||
+ *cursor == '\r' ||
+ *cursor == ';') {
+ /* newline or end of buffer */
+ if (separator && line[0] != '#') {
+ /* we have a property */
+ key.Assign(line, (NPT_Size)(separator-line));
+ value.Assign(line+(separator+1-line), (NPT_Size)(cursor-(separator+1)));
+ key.Trim(" \t");
+ value.Trim(" \t");
+
+ SetConfigValue((const char*)key, (const char*)value);
+ }
+ line = cursor+1;
+ separator = NULL;
+ } else if (*cursor == '=' && separator == NULL) {
+ separator = cursor;
+ }
+ cursor++;
+ }
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::ParseConfigFile
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogManager::ParseConfigFile(const char* filename)
+{
+ NPT_Result result;
+
+ /* load the file */
+ NPT_DataBuffer buffer;
+ result = NPT_File::Load(filename, buffer);
+ if (NPT_FAILED(result)) return result;
+
+ /* parse the config */
+ return ParseConfig((const char*)buffer.GetData(), buffer.GetDataSize());
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::ParseConfigSource
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogManager::ParseConfigSource(NPT_String& source)
+{
+ if (source.StartsWith("file:")) {
+ /* file source */
+ ParseConfigFile(source.GetChars()+5);
+ } else if (source.StartsWith("plist:")) {
+ /* property list source */
+ ParseConfig(source.GetChars()+6, source.GetLength()-6);
+ } else if (source.StartsWith("http:port=")) {
+ /* http configurator */
+ unsigned int port = 0;
+ NPT_Result result = NPT_ParseInteger(source.GetChars()+10, port, true);
+ if (NPT_FAILED(result)) return result;
+ new NPT_HttpLoggerConfigurator(port);
+ } else {
+ return NPT_ERROR_INVALID_SYNTAX;
+ }
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::HaveLoggerConfig
++---------------------------------------------------------------------*/
+bool
+NPT_LogManager::HaveLoggerConfig(const char* name)
+{
+ NPT_Size name_length = NPT_StringLength(name);
+ for (NPT_List<NPT_LogConfigEntry>::Iterator i = m_Config.GetFirstItem();
+ i;
+ ++i) {
+ NPT_LogConfigEntry& entry = *i;
+ if (entry.m_Key.StartsWith(name)) {
+ const char* suffix = entry.m_Key.GetChars()+name_length;
+ if (NPT_StringsEqual(suffix, ".level") ||
+ NPT_StringsEqual(suffix, ".handlers") ||
+ NPT_StringsEqual(suffix, ".forward")) {
+ return true;
+ }
+ }
+ }
+
+ /* no config found */
+ return false;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::ConfigureLogger
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogManager::ConfigureLogger(NPT_Logger* logger)
+{
+ /* configure the level */
+ NPT_String* level_value = GetConfigValue(logger->m_Name,".level");
+ if (level_value) {
+ NPT_Int32 value;
+ /* try a symbolic name */
+ value = NPT_Log::GetLogLevel(*level_value);
+ if (value < 0) {
+ /* try a numeric value */
+ if (NPT_FAILED(level_value->ToInteger(value, false))) {
+ value = -1;
+ }
+ }
+ if (value >= 0) {
+ logger->m_Level = value;
+ logger->m_LevelIsInherited = false;
+ }
+ }
+
+ /* remove any existing handlers */
+ logger->DeleteHandlers();
+
+ /* configure the handlers */
+ NPT_String* handlers = GetConfigValue(logger->m_Name,".handlers");
+ if (handlers) {
+ const char* handlers_list = handlers->GetChars();
+ const char* cursor = handlers_list;
+ const char* name_start = handlers_list;
+ NPT_String handler_name;
+ NPT_LogHandler* handler;
+ for (;;) {
+ if (*cursor == '\0' || *cursor == ',') {
+ if (cursor != name_start) {
+ handler_name.Assign(name_start, (NPT_Size)(cursor-name_start));
+ handler_name.Trim(" \t");
+
+ /* create a handler */
+ if (NPT_SUCCEEDED(
+ NPT_LogHandler::Create(logger->m_Name, handler_name, handler))) {
+ logger->AddHandler(handler);
+ }
+
+ }
+ if (*cursor == '\0') break;
+ name_start = cursor+1;
+ }
+ ++cursor;
+ }
+ }
+
+ /* configure the forwarding */
+ NPT_String* forward = GetConfigValue(logger->m_Name,".forward");
+ if (forward && !ConfigValueIsBooleanTrue(*forward)) {
+ logger->m_ForwardToParent = false;
+ }
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::FindLogger
++---------------------------------------------------------------------*/
+NPT_Logger*
+NPT_LogManager::FindLogger(const char* name)
+{
+ for (NPT_List<NPT_Logger*>::Iterator i = LogManager.m_Loggers.GetFirstItem();
+ i;
+ ++i) {
+ NPT_Logger* logger = *i;
+ if (logger->m_Name == name) {
+ return logger;
+ }
+ }
+
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogManager::GetLogger
++---------------------------------------------------------------------*/
+NPT_Logger*
+NPT_LogManager::GetLogger(const char* name)
+{
+ // exit now if the log manager is disabled
+ if (!LogManager.m_Enabled) return NULL;
+
+ /* check that the manager is initialized */
+ if (!LogManager.m_Configured) {
+ /* init the manager */
+ LogManager.Configure();
+ NPT_ASSERT(LogManager.m_Configured);
+ }
+
+ // auto lock until we return from this method
+ NPT_LogManagerAutoLocker lock(LogManager);
+
+ /* check if this logger is already configured */
+ NPT_Logger* logger = LogManager.FindLogger(name);
+ if (logger) return logger;
+
+ /* create a new logger */
+ logger = new NPT_Logger(name, LogManager);
+ if (logger == NULL) return NULL;
+
+ /* configure the logger */
+ LogManager.ConfigureLogger(logger);
+
+ /* find which parent to attach to */
+ NPT_Logger* parent = LogManager.m_Root;
+ NPT_String parent_name = name;
+ for (;;) {
+ NPT_Logger* candidate_parent;
+
+ /* find the last dot */
+ int dot = parent_name.ReverseFind('.');
+ if (dot < 0) break;
+ parent_name.SetLength(dot);
+
+ /* see if the parent exists */
+ candidate_parent = LogManager.FindLogger(parent_name);
+ if (candidate_parent) {
+ parent = candidate_parent;
+ break;
+ }
+
+ /* this parent name does not exist, see if we need to create it */
+ if (LogManager.HaveLoggerConfig(parent_name)) {
+ parent = GetLogger(parent_name);
+ break;
+ }
+ }
+
+ /* attach to the parent */
+ logger->SetParent(parent);
+
+ /* add this logger to the list */
+ LogManager.m_Loggers.Add(logger);
+
+ return logger;
+}
+
+/*----------------------------------------------------------------------
+| NPT_Logger::NPT_Logger
++---------------------------------------------------------------------*/
+NPT_Logger::NPT_Logger(const char* name, NPT_LogManager& manager) :
+ m_Manager(manager),
+ m_Name(name),
+ m_Level(NPT_LOG_LEVEL_OFF),
+ m_LevelIsInherited(true),
+ m_ForwardToParent(true),
+ m_Parent(NULL)
+{
+}
+
+/*----------------------------------------------------------------------
+| NPT_Logger::~NPT_Logger
++---------------------------------------------------------------------*/
+NPT_Logger::~NPT_Logger()
+{
+ /* remove external handlers before cleaning up */
+ m_Handlers.Remove(m_ExternalHandlers, true);
+
+ /* delete all handlers */
+ m_Handlers.Apply(NPT_ObjectDeleter<NPT_LogHandler>());
+}
+
+/*----------------------------------------------------------------------
+| NPT_Logger::DeleteHandlers
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Logger::DeleteHandlers()
+{
+ /* remove external handlers before cleaning up */
+ m_Handlers.Remove(m_ExternalHandlers, true);
+
+ /* delete all handlers and empty the list */
+ if (m_Handlers.GetItemCount()) {
+ m_Handlers.Apply(NPT_ObjectDeleter<NPT_LogHandler>());
+ m_Handlers.Clear();
+ }
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_Logger::Log
++---------------------------------------------------------------------*/
+void
+NPT_Logger::Log(int level,
+ const char* source_file,
+ unsigned int source_line,
+ const char* source_function,
+ const char* msg,
+ ...)
+{
+ // this is a no-op if the log manager is disabled
+ if (!LogManager.IsEnabled()) return;
+
+ /* check the log level (in case filtering has not already been done) */
+ if (level < m_Level) return;
+
+ /* format the message */
+ char buffer[NPT_LOG_STACK_BUFFER_MAX_SIZE];
+ NPT_Size buffer_size = sizeof(buffer);
+ char* message = buffer;
+ int result;
+ va_list args;
+ for(;;) {
+ /* try to format the message (it might not fit) */
+ va_start(args, msg);
+ result = NPT_FormatStringVN(message, buffer_size-1, msg, args);
+ va_end(args);
+ if (result >= (int)(buffer_size-1)) result = -1;
+ message[buffer_size-1] = 0; /* force a NULL termination */
+ if (result >= 0) break;
+
+ /* the buffer was too small, try something bigger */
+ buffer_size = (buffer_size+NPT_LOG_HEAP_BUFFER_INCREMENT)*2;
+ if (buffer_size > NPT_LOG_HEAP_BUFFER_MAX_SIZE) break;
+ if (message != buffer) delete[] message;
+ message = new char[buffer_size];
+ if (message == NULL) return;
+ }
+
+ /* the message is formatted, publish it to the handlers */
+ NPT_LogRecord record;
+ NPT_Logger* logger = this;
+
+ /* setup the log record */
+ record.m_LoggerName = logger->m_Name,
+ record.m_Level = level;
+ record.m_Message = message;
+ record.m_SourceFile = source_file;
+ record.m_SourceLine = source_line;
+ record.m_SourceFunction = source_function;
+ NPT_System::GetCurrentTimeStamp(record.m_TimeStamp);
+ record.m_ThreadId = (NPT_UInt64)NPT_Thread::GetCurrentThreadId();
+
+ /* call all handlers for this logger and parents */
+ m_Manager.Lock();
+ m_Manager.SetEnabled(false); // prevent recursion
+ while (logger) {
+ /* call all handlers for the current logger */
+ for (NPT_List<NPT_LogHandler*>::Iterator i = logger->m_Handlers.GetFirstItem();
+ i;
+ ++i) {
+ NPT_LogHandler* handler = *i;
+ handler->Log(record);
+ }
+
+ /* forward to the parent unless this logger does not forward */
+ if (logger->m_ForwardToParent) {
+ logger = logger->m_Parent;
+ } else {
+ break;
+ }
+ }
+ m_Manager.SetEnabled(true);
+ m_Manager.Unlock();
+
+ /* free anything we may have allocated */
+ if (message != buffer) delete[] message;
+}
+
+/*----------------------------------------------------------------------
+| NPT_Logger::AddHandler
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Logger::AddHandler(NPT_LogHandler* handler, bool transfer_ownership /* = true */)
+{
+ /* check parameters */
+ if (handler == NULL) return NPT_ERROR_INVALID_PARAMETERS;
+
+ /* keep track of what handlers we won't cleanup */
+ if (!transfer_ownership) m_ExternalHandlers.Add(handler);
+
+ return m_Handlers.Add(handler);
+}
+
+/*----------------------------------------------------------------------
+| NPT_Logger::SetParent
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Logger::SetParent(NPT_Logger* parent)
+{
+ /* set our new parent */
+ m_Parent = parent;
+
+ /* find the first ancestor with its own log level */
+ NPT_Logger* logger = this;
+ while (logger->m_LevelIsInherited && logger->m_Parent) {
+ logger = logger->m_Parent;
+ }
+ if (logger != this) m_Level = logger->m_Level;
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogNullHandler::Create
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogNullHandler::Create(NPT_LogHandler*& handler)
+{
+ handler = new NPT_LogNullHandler();
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogNullHandler::Log
++---------------------------------------------------------------------*/
+void
+NPT_LogNullHandler::Log(const NPT_LogRecord& /*record*/)
+{
+}
+
+
+NPT_LogHandler::CustomHandlerExternalFunction NPT_LogCustomHandler::s_ExternalFunction = NULL;
+/*----------------------------------------------------------------------
+| NPT_LogCustomHandler::SetCustomHandlerFunction
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogCustomHandler::SetCustomHandlerFunction(CustomHandlerExternalFunction function)
+{
+ s_ExternalFunction = function;
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogCustomHandler::Create
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogCustomHandler::Create(NPT_LogHandler*& handler)
+{
+ /* allocate a new object */
+ NPT_LogCustomHandler* instance = new NPT_LogCustomHandler();
+ handler = instance;
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogCustomHandler::Log
++---------------------------------------------------------------------*/
+void
+NPT_LogCustomHandler::Log(const NPT_LogRecord& record)
+{
+ if (s_ExternalFunction) {
+ (*s_ExternalFunction)(&record);
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogConsoleHandler::Create
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogConsoleHandler::Create(const char* logger_name,
+ NPT_LogHandler*& handler)
+{
+ /* compute a prefix for the configuration of this handler */
+ NPT_String logger_prefix = logger_name;
+ logger_prefix += ".ConsoleHandler";
+
+ /* allocate a new object */
+ NPT_LogConsoleHandler* instance = new NPT_LogConsoleHandler();
+ handler = instance;
+
+ /* configure the object */
+ NPT_String* colors;
+ instance->m_UseColors = NPT_LOG_CONSOLE_HANDLER_DEFAULT_COLOR_MODE;
+ colors = LogManager.GetConfigValue(logger_prefix,".colors");
+ if (colors) {
+ if (NPT_LogManager::ConfigValueIsBooleanTrue(*colors)) {
+ instance->m_UseColors = true;
+ } else if (NPT_LogManager::ConfigValueIsBooleanFalse(*colors)) {
+ instance->m_UseColors = false;
+ }
+ }
+
+ NPT_String* outputs;
+ instance->m_Outputs = NPT_CONFIG_DEFAULT_LOG_CONSOLE_HANDLER_OUTPUTS;
+ outputs = LogManager.GetConfigValue(logger_prefix,".outputs");
+ if (outputs) {
+ outputs->ToInteger(instance->m_Outputs, true);
+ }
+
+ NPT_String* filter;
+ instance->m_FormatFilter = 0;
+ filter = LogManager.GetConfigValue(logger_prefix,".filter");
+ if (filter) {
+ filter->ToInteger(instance->m_FormatFilter, true);
+ }
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogConsoleHandler::Log
++---------------------------------------------------------------------*/
+void
+NPT_LogConsoleHandler::Log(const NPT_LogRecord& record)
+{
+ NPT_MemoryStream memory_stream(4096);
+
+ NPT_Log::FormatRecordToStream(record, memory_stream, m_UseColors, m_FormatFilter);
+ memory_stream.Write("\0", 1);
+ if (m_Outputs & OUTPUT_TO_CONSOLE) {
+ NPT_Console::Output((const char*)memory_stream.GetData());
+ }
+ if (m_Outputs & OUTPUT_TO_DEBUG) {
+ NPT_DebugOutput((const char*)memory_stream.GetData());
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogFileHandler::Log
++---------------------------------------------------------------------*/
+void
+NPT_LogFileHandler::Log(const NPT_LogRecord& record)
+{
+ if (m_MaxFilesize > 0) {
+ /* get current file size */
+ NPT_LargeSize size;
+ NPT_File::GetSize(m_Filename, size);
+
+ /* time to recycle ? */
+ if (size > m_MaxFilesize) {
+ /* release stream to force a reopen later
+ and to be able to rename file */
+ m_Stream = NULL;
+
+ /* rename file using current time */
+ NPT_TimeStamp now;
+ NPT_System::GetCurrentTimeStamp(now);
+ NPT_String suffix = NPT_DateTime(now, true).ToString(NPT_DateTime::FORMAT_W3C);
+ suffix.Replace(':', '_');
+ NPT_String new_name = NPT_FilePath::Create(
+ NPT_FilePath::DirName(m_Filename),
+ NPT_FilePath::BaseName(m_Filename, false) +
+ "-" +
+ suffix +
+ NPT_FilePath::FileExtension(m_Filename));
+
+ NPT_File::Rename(m_Filename, new_name);
+ }
+ }
+
+ /* try to reopen the file if it failed to open
+ previously or if we rotated it */
+ if (m_Stream.IsNull()) {
+ Open(m_Append);
+ }
+
+ if (m_Stream.AsPointer()) {
+ NPT_Log::FormatRecordToStream(record, *m_Stream, false, m_FormatFilter);
+ if (m_Flush) m_Stream->Flush();
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogFileHandler::Open
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogFileHandler::Open(bool append /* = true */)
+{
+ /* reset stream just in case */
+ m_Stream = NULL;
+
+ /* open the log file */
+ NPT_File file(m_Filename);
+ NPT_Result result = file.Open(NPT_FILE_OPEN_MODE_CREATE |
+ NPT_FILE_OPEN_MODE_READ |
+ NPT_FILE_OPEN_MODE_WRITE |
+ (append?NPT_FILE_OPEN_MODE_APPEND:NPT_FILE_OPEN_MODE_TRUNCATE));
+ if (NPT_FAILED(result)) return result;
+
+ NPT_CHECK(file.GetOutputStream(m_Stream));
+ /* seek to end */
+ if (append) {
+ NPT_LargeSize size;
+ NPT_CHECK(NPT_File::GetSize(m_Filename, size));
+ NPT_CHECK(m_Stream->Seek(size));
+ }
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogFileHandler::Create
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogFileHandler::Create(const char* logger_name,
+ NPT_LogHandler*& handler)
+{
+ /* compute a prefix for the configuration of this handler */
+ NPT_String logger_prefix = logger_name;
+ logger_prefix += ".FileHandler";
+
+ /* allocate a new object */
+ NPT_LogFileHandler* instance = new NPT_LogFileHandler();
+ handler = instance;
+
+ /* filename */
+ NPT_String* filename_conf = LogManager.GetConfigValue(logger_prefix, ".filename");
+ if (filename_conf) {
+ instance->m_Filename = *filename_conf;
+ } else if (logger_name[0]) {
+ NPT_String filename_synth = logger_name;
+ filename_synth += ".log";
+ instance->m_Filename = filename_synth;
+ } else {
+ /* default name for the root logger */
+ instance->m_Filename = NPT_CONFIG_DEFAULT_LOG_FILE_HANDLER_FILENAME;
+ }
+
+ /* always flush flag */
+ NPT_String* flush = LogManager.GetConfigValue(logger_prefix, ".flush");
+ if (flush && NPT_LogManager::ConfigValueIsBooleanTrue(*flush)) {
+ instance->m_Flush = true;
+ } else {
+ instance->m_Flush = false;
+ }
+
+ /* append mode */
+ instance->m_Append = true;
+ NPT_String* append_mode = LogManager.GetConfigValue(logger_prefix, ".append");
+ if (append_mode && NPT_LogManager::ConfigValueIsBooleanFalse(*append_mode)) {
+ instance->m_Append = false;
+ }
+
+ /* filter */
+ NPT_String* filter;
+ instance->m_FormatFilter = 0;
+ filter = LogManager.GetConfigValue(logger_prefix,".filter");
+ if (filter) {
+ filter->ToInteger(instance->m_FormatFilter, true);
+ }
+
+ /* recycle */
+ NPT_String* recycle;
+ instance->m_MaxFilesize = 0;
+ recycle = LogManager.GetConfigValue(logger_prefix,".recycle");
+ if (recycle) {
+ NPT_ParseInteger64(*recycle, instance->m_MaxFilesize, true);
+ if (instance->m_MaxFilesize < NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE) {
+ instance->m_MaxFilesize = NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE;
+ }
+ }
+
+ /* open the log file */
+ return instance->Open(instance->m_Append);
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogTcpHandler::Create
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogTcpHandler::Create(const char* logger_name, NPT_LogHandler*& handler)
+{
+ /* compute a prefix for the configuration of this handler */
+ NPT_String logger_prefix = logger_name;
+ logger_prefix += ".TcpHandler";
+
+ /* allocate a new object */
+ NPT_LogTcpHandler* instance = new NPT_LogTcpHandler();
+ handler = instance;
+
+ /* configure the object */
+ const NPT_String* hostname = LogManager.GetConfigValue(logger_prefix, ".hostname");
+ if (hostname) {
+ instance->m_Host = *hostname;
+ } else {
+ /* default hostname */
+ instance->m_Host = "localhost";
+ }
+ const NPT_String* port = LogManager.GetConfigValue(logger_prefix, ".port");
+ if (port) {
+ NPT_UInt32 port_int;
+ if (NPT_SUCCEEDED(port->ToInteger(port_int, true))) {
+ instance->m_Port = (NPT_UInt16)port_int;
+ } else {
+ instance->m_Port = NPT_LOG_TCP_HANDLER_DEFAULT_PORT;
+ }
+ } else {
+ /* default port */
+ instance->m_Port = NPT_LOG_TCP_HANDLER_DEFAULT_PORT;
+ }
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogTcpHandler::Connect
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogTcpHandler::Connect()
+{
+ /* create a socket */
+ NPT_TcpClientSocket tcp_socket;
+
+ /* connect to the host */
+ NPT_IpAddress ip_address;
+ NPT_CHECK(ip_address.ResolveName(m_Host));
+ NPT_Result result = tcp_socket.Connect(NPT_SocketAddress(ip_address, m_Port),
+ NPT_LOG_TCP_HANDLER_DEFAULT_CONNECT_TIMEOUT);
+ if (NPT_FAILED(result)) {
+ return result;
+ }
+
+ /* get the stream */
+ return tcp_socket.GetOutputStream(m_Stream);
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogTcpHandler::Log
++---------------------------------------------------------------------*/
+void
+NPT_LogTcpHandler::FormatRecord(const NPT_LogRecord& record, NPT_String& msg)
+{
+ /* format the record */
+ const char* level_name = NPT_Log::GetLogLevelName(record.m_Level);
+ NPT_String level_string;
+
+ /* format and emit the record */
+ if (level_name[0] == '\0') {
+ level_string = NPT_String::FromIntegerU(record.m_Level);
+ level_name = level_string;
+ }
+ msg.Reserve(2048);
+ msg += "Logger: ";
+ msg += record.m_LoggerName;
+ msg += "\r\nLevel: ";
+ msg += level_name;
+ msg += "\r\nSource-File: ";
+ msg += record.m_SourceFile;
+ msg += "\r\nSource-Function: ";
+ msg += record.m_SourceFunction;
+ msg += "\r\nSource-Line: ";
+ msg += NPT_String::FromIntegerU(record.m_SourceLine);
+ msg += "\r\nThread-Id: ";
+ msg += NPT_String::FromIntegerU(record.m_ThreadId);
+ msg += "\r\nTimeStamp: ";
+ msg += NPT_DateTime(record.m_TimeStamp, true).ToString(NPT_DateTime::FORMAT_W3C,
+ NPT_DateTime::FLAG_EMIT_FRACTION |
+ NPT_DateTime::FLAG_EXTENDED_PRECISION);
+ msg += "\r\nContent-Length: ";
+ msg += NPT_String::FromIntegerU(NPT_StringLength(record.m_Message));
+ msg += "\r\n\r\n";
+ msg += record.m_Message;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogTcpHandler::Log
++---------------------------------------------------------------------*/
+void
+NPT_LogTcpHandler::Log(const NPT_LogRecord& record)
+{
+ // ensure we're connected
+ if (m_Stream.IsNull()) {
+ if (NPT_FAILED(Connect())) return;
+ }
+
+ // format the record
+ NPT_String msg;
+ FormatRecord(record, msg);
+
+ // log, and disconnect if this fails
+ if (NPT_FAILED(m_Stream->WriteString(msg))) {
+ m_Stream = NULL;
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogUdpHandler::Create
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_LogUdpHandler::Create(const char* logger_name, NPT_LogHandler*& handler)
+{
+ /* compute a prefix for the configuration of this handler */
+ NPT_String logger_prefix = logger_name;
+ logger_prefix += ".UdpHandler";
+
+ /* allocate a new object */
+ NPT_LogUdpHandler* instance = new NPT_LogUdpHandler();
+ handler = instance;
+
+ /* configure the object */
+ const char* hostname = "localhost";
+ const NPT_String* hostname_prop = LogManager.GetConfigValue(logger_prefix, ".hostname");
+ if (hostname_prop) {
+ hostname = hostname_prop->GetChars();
+ }
+ NPT_UInt32 port = NPT_LOG_UDP_HANDLER_DEFAULT_PORT;
+ const NPT_String* port_prop = LogManager.GetConfigValue(logger_prefix, ".port");
+ if (port_prop) {
+ if (NPT_FAILED(port_prop->ToInteger(port, true))) {
+ port = NPT_LOG_UDP_HANDLER_DEFAULT_PORT;
+ }
+ }
+
+ // resolve the target hostname
+ NPT_IpAddress target_ip;
+ target_ip.ResolveName(hostname);
+ instance->m_Target.SetIpAddress(target_ip);
+ instance->m_Target.SetPort(port);
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_LogUdpHandler::Log
++---------------------------------------------------------------------*/
+void
+NPT_LogUdpHandler::Log(const NPT_LogRecord& record)
+{
+ // format the record
+ NPT_String msg;
+ NPT_LogTcpHandler::FormatRecord(record, msg);
+
+ // send it in a datagram
+ NPT_DataBuffer buffer(msg.GetChars(), msg.GetLength()+1, false);
+ m_Socket.Send(buffer, &m_Target);
+}
+
+/*----------------------------------------------------------------------
+| NPT_HttpLoggerConfigurator::NPT_HttpLoggerConfigurator
++---------------------------------------------------------------------*/
+NPT_HttpLoggerConfigurator::NPT_HttpLoggerConfigurator(NPT_UInt16 port, bool detached) :
+ NPT_Thread(detached)
+{
+ // create the server
+ m_Server = new NPT_HttpServer(port);
+
+ // attach a handler to response to the requests
+ m_Server->AddRequestHandler(this, "/", true);
+}
+
+/*----------------------------------------------------------------------
+| NPT_HttpLoggerConfigurator::~NPT_HttpLoggerConfigurator
++---------------------------------------------------------------------*/
+NPT_HttpLoggerConfigurator::~NPT_HttpLoggerConfigurator()
+{
+ // TODO: send a command to the server to tell it to abort
+
+ // cleanup
+ delete m_Server;
+}
+
+/*----------------------------------------------------------------------
+| NPT_HttpLoggerConfigurator::SetupResponse
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_HttpLoggerConfigurator::SetupResponse(NPT_HttpRequest& request,
+ const NPT_HttpRequestContext& /*context*/,
+ NPT_HttpResponse& response)
+{
+ // we only support GET here
+ if (request.GetMethod() != NPT_HTTP_METHOD_GET) return NPT_ERROR_HTTP_METHOD_NOT_SUPPORTED;
+
+ // construct the response message
+ NPT_String msg;
+
+ msg = "<ul>";
+ NPT_List<NPT_LogConfigEntry>& config = LogManager.GetConfig();
+ NPT_List<NPT_LogConfigEntry>::Iterator cit = config.GetFirstItem();
+ for (; cit; ++cit) {
+ NPT_LogConfigEntry& entry = (*cit);
+ msg += "<li>";
+ msg += entry.m_Key;
+ msg += "=";
+ msg += entry.m_Value;
+ msg += "</li>";
+ }
+ msg += "</ul>";
+
+ msg += "<ul>";
+ NPT_List<NPT_Logger*>& loggers = LogManager.GetLoggers();
+ NPT_List<NPT_Logger*>::Iterator lit = loggers.GetFirstItem();
+ for (;lit;++lit) {
+ NPT_Logger* logger = (*lit);
+ msg += "<li>";
+ msg += logger->GetName();
+ msg += ", level=";
+ msg += NPT_String::FromInteger(logger->GetLevel());
+
+ NPT_List<NPT_LogHandler*>& handlers = logger->GetHandlers();
+ NPT_List<NPT_LogHandler*>::Iterator hit = handlers.GetFirstItem();
+ msg += ", handlers=";
+ for (;hit;++hit) {
+ NPT_LogHandler* handler = (*hit);
+ msg += handler->ToString();
+ }
+ msg += "</li>";
+ }
+ msg += "</ul>";
+
+ // setup the response body
+ NPT_HttpEntity* entity = response.GetEntity();
+ entity->SetContentType("text/html");
+ entity->SetInputStream(msg);
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_HttpLoggerConfigurator::Run
++---------------------------------------------------------------------*/
+void
+NPT_HttpLoggerConfigurator::Run()
+{
+ for (;;) {
+ NPT_Result result;
+ result = m_Server->Loop();
+ if (NPT_FAILED(result)) {
+ break;
+ }
+ }
+}