Mercurial > projects > hoofbaby
view deps/Platinum/ThirdParty/Neptune/Source/Core/NptLogging.cpp @ 0:3425707ddbf6
Initial import (hopefully this mercurial stuff works...)
author | fraserofthenight |
---|---|
date | Mon, 06 Jul 2009 08:06:28 -0700 |
parents | |
children |
line wrap: on
line source
/***************************************************************** | | 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 "NptThreads.h" //#include "NptDirectory.h" /*---------------------------------------------------------------------- | types +---------------------------------------------------------------------*/ class NPT_LogConsoleHandler : public NPT_LogHandler { public: // class methods static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler); // methods void Log(const NPT_LogRecord& record); private: // members 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); private: NPT_Result Open(bool append = true); private: // members NPT_String m_Filename; NPT_Flags m_FormatFilter; NPT_Mutex m_RecycleLock; NPT_LargeSize m_Recycle; NPT_InputStreamReference m_InputStream; NPT_OutputStreamReference m_OutputStream; }; class NPT_LogTcpHandler : public NPT_LogHandler { public: // class methods static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler); // methods void Log(const NPT_LogRecord& record); private: // methods NPT_Result Connect(); // members NPT_String m_Host; NPT_UInt16 m_Port; NPT_OutputStreamReference m_Stream; }; class NPT_LogNullHandler : public NPT_LogHandler { public: // class methods static NPT_Result Create(NPT_LogHandler*& handler); // methods void Log(const NPT_LogRecord& record); }; /*---------------------------------------------------------------------- | 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_LOG_CONFIG_ENV) #define NPT_LOG_CONFIG_ENV "NEPTUNE_LOG_CONFIG" #endif #if !defined(NPT_LOG_DEFAULT_CONFIG_SOURCE) #define NPT_LOG_DEFAULT_CONFIG_SOURCE "file:neptune-logging.properties" #endif #define NPT_LOG_ROOT_DEFAULT_LOG_LEVEL NPT_LOG_LEVEL_INFO #define NPT_LOG_ROOT_DEFAULT_HANDLER "ConsoleHandler" #if !defined(NPT_LOG_ROOT_DEFAULT_FILE_HANDLER_FILENAME) #define NPT_LOG_ROOT_DEFAULT_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 */ #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 #define NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE 20000000 #define NPT_LOG_FORMAT_FILTER_NO_SOURCE 1 #define NPT_LOG_FORMAT_FILTER_NO_TIMESTAMP 2 #define NPT_LOG_FORMAT_FILTER_NO_LOGGER_NAME 4 #define NPT_LOG_FORMAT_FILTER_NO_FUNCTION_NAME 8 #define NPT_LOG_FORMAT_FILTER_NO_SOURCEPATH 16 /*---------------------------------------------------------------------- | globals +---------------------------------------------------------------------*/ static NPT_LogManager LogManager; const char* LogManagerConfig = NULL; bool LogManagerEnabled = true; /*---------------------------------------------------------------------- | 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); } return NPT_ERROR_NO_SUCH_CLASS; } /*---------------------------------------------------------------------- | NPT_Log::GetLogLevel +---------------------------------------------------------------------*/ int NPT_Log::GetLogLevel(const char* name) { if ( NPT_StringsEqual(name, "FATAL")) { return NPT_LOG_LEVEL_SEVERE; } else if (NPT_StringsEqual(name, "SEVERE")) { return NPT_LOG_LEVEL_WARNING; } 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) { 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) { stream.WriteString(NPT_String::FromIntegerU(record.m_TimeStamp.m_Seconds)); stream.WriteString(":"); NPT_String ms = NPT_String::FromIntegerU(record.m_TimeStamp.m_NanoSeconds/1000000L); if (ms.GetLength() < 3) stream.Write("0", 1); if (ms.GetLength() < 2) stream.Write("0", 1); stream.WriteString(ms); 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); } 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("\n", 1, NULL); } /*---------------------------------------------------------------------- | NPT_LogManager::NPT_LogManager +---------------------------------------------------------------------*/ NPT_LogManager::NPT_LogManager() : m_Configured(false), m_Configuring(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::EnableLogging +---------------------------------------------------------------------*/ void NPT_LogManager::EnableLogging(bool value) { LogManagerEnabled = value; } /*---------------------------------------------------------------------- | NPT_LogManager::SetConfig +---------------------------------------------------------------------*/ void NPT_LogManager::SetConfig(const char* config) { LogManagerConfig = config; } /*---------------------------------------------------------------------- | NPT_LogManager::Configure +---------------------------------------------------------------------*/ NPT_Result NPT_LogManager::Configure() { NPT_String config_sources_env; const char* config_sources = NPT_LOG_DEFAULT_CONFIG_SOURCE; // exit if we're already initialized if (m_Configured) return NPT_SUCCESS; // we're starting to configure ourselves m_Configuring = true; /* set some default config values */ SetConfigValue(".handlers", NPT_LOG_ROOT_DEFAULT_HANDLER); if (!LogManagerConfig) { /* see if the config sources have been set to non-default values */ if (NPT_SUCCEEDED(NPT_GetEnvironment(NPT_LOG_CONFIG_ENV, config_sources_env))) { config_sources = config_sources_env; } } else { config_sources = LogManagerConfig; } /* 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 == '\0') break; } cursor++; } /* create the root logger */ LogManager.m_Root = new NPT_Logger(""); LogManager.m_Root->m_Level = NPT_LOG_ROOT_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 { 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; } } /* 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) { NPT_Logger* logger; /* check that LogManager was not turned off */ if (!LogManagerEnabled) return NULL; /* check that the manager is initialized */ if (!LogManager.m_Configured) { /* check that we're not in the middle of configuration */ if (LogManager.m_Configuring) return NULL; /* init the manager */ LogManager.Configure(); NPT_ASSERT(LogManager.m_Configured); } /* check if this logger is already configured */ logger = LogManager.FindLogger(name); if (logger) return logger; /* create a new logger */ logger = new NPT_Logger(name); 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) : 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() { /* destroy all handlers */ for (NPT_List<NPT_LogHandler*>::Iterator i = m_Handlers.GetFirstItem(); i; ++i) { NPT_LogHandler* handler = *i; delete handler; } } /*---------------------------------------------------------------------- | NPT_Logger::Log +---------------------------------------------------------------------*/ void NPT_Logger::Log(int level, const char* source_file, unsigned int source_line, const char* source_function, const char* msg, ...) { char buffer[NPT_LOG_STACK_BUFFER_MAX_SIZE]; NPT_Size buffer_size = sizeof(buffer); char* message = buffer; int result; va_list args; va_start(args, msg); /* check the log level (in case filtering has not already been done) */ if (level < m_Level) return; for(;;) { /* try to format the message (it might not fit) */ result = NPT_FormatStringVN(message, buffer_size-1, msg, 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); /* call all handlers for this logger and parents */ 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; } } /* free anything we may have allocated */ if (message != buffer) delete[] message; va_end(args); } /*---------------------------------------------------------------------- | NPT_Logger::AddHandler +---------------------------------------------------------------------*/ NPT_Result NPT_Logger::AddHandler(NPT_LogHandler* handler) { /* check parameters */ if (handler == NULL) return NPT_ERROR_INVALID_PARAMETERS; 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_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* filter; instance->m_FormatFilter = 30; // default to nothing filter = LogManager.GetConfigValue(logger_prefix,".filter"); if (filter) { NPT_Int32 flags = 0; filter->ToInteger(flags, true); instance->m_FormatFilter = flags; } 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); NPT_Console::Output((const char*)memory_stream.GetData()); } /*---------------------------------------------------------------------- | NPT_LogFileHandler::Log +---------------------------------------------------------------------*/ void NPT_LogFileHandler::Log(const NPT_LogRecord& record) { if (m_Recycle > 0) { m_RecycleLock.Lock(); /* get log size */ NPT_LargeSize size; if (!m_InputStream.IsNull()) m_InputStream->GetSize(size); /* time to recycle ? */ if (size > m_Recycle) { /* release streams to force a reopen later */ m_OutputStream = NULL; m_InputStream = NULL; /* move file */ NPT_TimeStamp now; NPT_System::GetCurrentTimeStamp(now); NPT_String new_name = NPT_FilePath::Create( NPT_FilePath::DirectoryName(m_Filename), NPT_FilePath::BaseName(m_Filename) + "-" + NPT_String::FromIntegerU(now.m_Seconds) + ".log"); NPT_File::Rename(m_Filename, new_name); } } /* try to reopen the file if it failed to open previously or if we recycled it */ if (m_InputStream.IsNull() || m_OutputStream.IsNull()) { Open(); } if (m_InputStream.AsPointer() && m_OutputStream.AsPointer()) { /* seek output stream to end of file */ NPT_LargeSize size; m_InputStream->GetSize(size); m_OutputStream->Seek(size); NPT_Debug("NPT_LogFileHandler told to seek to position %d\n", size); NPT_Log::FormatRecordToStream(record, *m_OutputStream, false, m_FormatFilter); /* force flushing */ m_OutputStream->Flush(); } if (m_Recycle > 0) m_RecycleLock.Unlock(); } /*---------------------------------------------------------------------- | NPT_LogFileHandler::Open +---------------------------------------------------------------------*/ NPT_Result NPT_LogFileHandler::Open(bool append /* = true */) { /* reset streams just in case */ m_OutputStream = NULL; m_InputStream = 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)) { NPT_Debug("NPT_LogFileHandler::Open - cannot open log file '%s' (%d)\n", m_Filename.GetChars(), result); return result; } NPT_CHECK(file.GetInputStream(m_InputStream)); NPT_CHECK(file.GetOutputStream(m_OutputStream)); 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_LOG_ROOT_DEFAULT_FILE_HANDLER_FILENAME; } /* append mode */ bool append = true; NPT_String* append_mode = LogManager.GetConfigValue(logger_prefix, ".append"); if (append_mode && NPT_LogManager::ConfigValueIsBooleanFalse(*append_mode)) { append = false; } /* filter */ NPT_String* filter; instance->m_FormatFilter = 0; filter = LogManager.GetConfigValue(logger_prefix,".filter"); if (filter) { NPT_Int32 flags = 0; filter->ToInteger(flags, true); instance->m_FormatFilter = flags; } /* recycle */ NPT_String* recycle; instance->m_Recycle = 0; recycle = LogManager.GetConfigValue(logger_prefix,".recycle"); if (recycle) { NPT_Int32 size = 0; recycle->ToInteger(size, true); if (size > NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE) { instance->m_Recycle = size; } else { instance->m_Recycle = NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE; } } /* open the log file */ return instance->Open(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_Int32 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_Socket tcp_socket = new NPT_TcpClientSocket(); /* 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::Log(const NPT_LogRecord& record) { /* ensure we're connected */ if (m_Stream.IsNull()) { if (NPT_FAILED(Connect())) return; } /* format the record */ NPT_String msg; 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-Line: "; msg += NPT_String::FromIntegerU(record.m_SourceLine); msg += "\r\nTimeStamp: "; msg += NPT_String::FromIntegerU(record.m_TimeStamp.m_Seconds); msg += ":"; msg += NPT_String::FromIntegerU(record.m_TimeStamp.m_NanoSeconds/1000000L); msg += "\r\nContent-Length: "; msg += NPT_String::FromIntegerU(NPT_StringLength(record.m_Message)); msg += "\r\n\r\n"; msg += record.m_Message; /* emit the formatted record */ if (NPT_FAILED(m_Stream->WriteString(msg))) { m_Stream = NULL; } }