From 2139d7d45fb1a8ed250ad96c9975c581f02f72a9 Mon Sep 17 00:00:00 2001 From: ShadowNinja Date: Tue, 13 Oct 2015 03:57:44 -0400 Subject: Refactor logging - Add warning log level - Change debug_log_level setting to enumeration string - Map Irrlicht log events to MT log events - Encapsulate log_* functions and global variables into a class, Logger - Unify dstream with standard logging mechanism - Unify core.debug() with standard core.log() script API --- src/log.cpp | 365 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 239 insertions(+), 126 deletions(-) (limited to 'src/log.cpp') diff --git a/src/log.cpp b/src/log.cpp index c584d126a..4f77101f9 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -19,19 +19,91 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" -#include -#include -#include -#include -#include "threads.h" #include "threading/mutex_auto_lock.h" #include "debug.h" #include "gettime.h" #include "porting.h" #include "config.h" +#include "exceptions.h" +#include "util/numeric.h" +#include "log.h" + +#include +#include +#include +#include +#include + +class StringBuffer : public std::streambuf { +public: + StringBuffer() {} + + int overflow(int c); + virtual void flush(const std::string &buf) = 0; + std::streamsize xsputn(const char *s, std::streamsize n); + void push_back(char c); + +private: + std::string buffer; +}; + + +class LogBuffer : public StringBuffer { +public: + LogBuffer(Logger &logger, LogLevel lev) : + logger(logger), + level(lev) + {} + + void flush(const std::string &buffer); + +private: + Logger &logger; + LogLevel level; +}; + + +class RawLogBuffer : public StringBuffer { +public: + void flush(const std::string &buffer); +}; + + +#ifdef __ANDROID__ +static unsigned int level_to_android[] = { + ANDROID_LOG_INFO, // LL_NONE + //ANDROID_LOG_FATAL, + ANDROID_LOG_ERROR, // LL_ERROR + ANDROID_LOG_WARN, // LL_WARNING + ANDROID_LOG_WARN, // LL_ACTION + //ANDROID_LOG_INFO, + ANDROID_LOG_DEBUG, // LL_INFO + ANDROID_LOG_VERBOSE, // LL_VERBOSE + +}; +#endif + +//// +//// Globals +//// + +Logger g_logger; + +StreamLogOutput stdout_output(std::cout); +StreamLogOutput stderr_output(std::cerr); +std::ostream null_stream(NULL); + +RawLogBuffer raw_buf; + +LogBuffer none_buf(g_logger, LL_NONE); +LogBuffer error_buf(g_logger, LL_ERROR); +LogBuffer warning_buf(g_logger, LL_WARNING); +LogBuffer action_buf(g_logger, LL_ACTION); +LogBuffer info_buf(g_logger, LL_INFO); +LogBuffer verbose_buf(g_logger, LL_VERBOSE); // Connection -std::ostream *dout_con_ptr = &dummyout; +std::ostream *dout_con_ptr = &null_stream; std::ostream *derr_con_ptr = &verbosestream; // Server @@ -44,170 +116,211 @@ std::ostream *dout_client_ptr = &infostream; std::ostream *derr_client_ptr = &errorstream; #endif -#ifdef __ANDROID__ -unsigned int android_log_level_mapping[] = { - /* LMT_ERROR */ ANDROID_LOG_ERROR, - /* LMT_ACTION */ ANDROID_LOG_WARN, - /* LMT_INFO */ ANDROID_LOG_INFO, - /* LMT_VERBOSE */ ANDROID_LOG_VERBOSE - }; -#endif +std::ostream rawstream(&raw_buf); +std::ostream dstream(&none_buf); +std::ostream errorstream(&error_buf); +std::ostream warningstream(&warning_buf); +std::ostream actionstream(&action_buf); +std::ostream infostream(&info_buf); +std::ostream verbosestream(&verbose_buf); + -std::vector log_outputs[LMT_NUM_VALUES]; -std::map log_thread_names; -Mutex log_thread_name_mutex; +/////////////////////////////////////////////////////////////////////////////// -void log_add_output(ILogOutput *out, enum LogMessageLevel lev) + +//// +//// Logger +//// + +LogLevel Logger::stringToLevel(const std::string &name) { - log_outputs[lev].push_back(out); + if (name == "none") + return LL_NONE; + else if (name == "error") + return LL_ERROR; + else if (name == "warning") + return LL_WARNING; + else if (name == "action") + return LL_ACTION; + else if (name == "info") + return LL_INFO; + else if (name == "verbose") + return LL_VERBOSE; + else + return LL_MAX; } -void log_add_output_maxlev(ILogOutput *out, enum LogMessageLevel lev) +void Logger::addOutput(ILogOutput *out) { - for(int i=0; i<=lev; i++) - log_outputs[i].push_back(out); + addOutputMaxLevel(out, LL_MAX); } -void log_add_output_all_levs(ILogOutput *out) +void Logger::addOutput(ILogOutput *out, LogLevel lev) { - for(int i=0; i::iterator it = - std::find(log_outputs[i].begin(), log_outputs[i].end(), out); - if(it != log_outputs[i].end()) - log_outputs[i].erase(it); - } + for (size_t i = 0; i <= lev; i++) + m_outputs[i].push_back(out); } -void log_set_lev_silence(enum LogMessageLevel lev, bool silence) +void Logger::removeOutput(ILogOutput *out) { - MutexAutoLock lock(log_thread_name_mutex); + for (size_t i = 0; i < LL_MAX; i++) { + std::vector::iterator it; - for (std::vector::iterator it = log_outputs[lev].begin(); - it != log_outputs[lev].end(); ++it) { - ILogOutput *out = *it; - out->silence = silence; + it = std::find(m_outputs[i].begin(), m_outputs[i].end(), out); + if (it != m_outputs[i].end()) + m_outputs[i].erase(it); } } -void log_register_thread(const std::string &name) +void Logger::setLevelSilenced(LogLevel lev, bool silenced) { - threadid_t id = get_current_thread_id(); - MutexAutoLock lock(log_thread_name_mutex); - - log_thread_names[id] = name; + m_silenced_levels[lev] = silenced; } -void log_deregister_thread() +void Logger::registerThread(const std::string &name) { threadid_t id = get_current_thread_id(); - MutexAutoLock lock(log_thread_name_mutex); + MutexAutoLock lock(m_mutex); + m_thread_names[id] = name; +} - log_thread_names.erase(id); +void Logger::deregisterThread() +{ + threadid_t id = get_current_thread_id(); + MutexAutoLock lock(m_mutex); + m_thread_names.erase(id); } -static std::string get_lev_string(enum LogMessageLevel lev) +const std::string Logger::getLevelLabel(LogLevel lev) { - switch(lev){ - case LMT_ERROR: - return "ERROR"; - case LMT_ACTION: - return "ACTION"; - case LMT_INFO: - return "INFO"; - case LMT_VERBOSE: - return "VERBOSE"; - case LMT_NUM_VALUES: - break; - } - return "(unknown level)"; + static const std::string names[] = { + "", + "ERROR", + "WARNING", + "ACTION", + "INFO", + "VERBOSE", + }; + assert(lev < LL_MAX && lev >= 0); + assert(ARRLEN(names) == LL_MAX); + return names[lev]; } -void log_printline(enum LogMessageLevel lev, const std::string &text) +const std::string Logger::getThreadName() { - MutexAutoLock lock(log_thread_name_mutex); - std::string threadname = "(unknown thread)"; - std::map::const_iterator i; - i = log_thread_names.find(get_current_thread_id()); - if(i != log_thread_names.end()) - threadname = i->second; - std::string levelname = get_lev_string(lev); - std::ostringstream os(std::ios_base::binary); - os << getTimestamp() << ": " << levelname << "["<::const_iterator it; - for(std::vector::iterator i = log_outputs[lev].begin(); - i != log_outputs[lev].end(); ++i) { - ILogOutput *out = *i; - if (out->silence) - continue; + threadid_t id = get_current_thread_id(); + it = m_thread_names.find(id); + if (it != m_thread_names.end()) + return it->second; - out->printLog(os.str()); - out->printLog(os.str(), lev); - out->printLog(lev, text); - } + std::ostringstream os; + os << "#0x" << std::hex << id; + return os.str(); } -class Logbuf : public std::streambuf +void Logger::log(LogLevel lev, const std::string &text) { -public: - Logbuf(enum LogMessageLevel lev): - m_lev(lev) - { - } + if (m_silenced_levels[lev]) + return; - ~Logbuf() - { - } + const std::string thread_name = getThreadName(); + const std::string label = getLevelLabel(lev); + std::ostringstream os(std::ios_base::binary); + os << getTimestamp() << ": " << label << "[" << thread_name << "]: " << text; - int overflow(int c) - { - bufchar(c); - return c; - } - std::streamsize xsputn(const char *s, std::streamsize n) - { - for(int i=0; ilog(text); +} + - void bufchar(char c) - { - if(c == '\n' || c == '\r'){ - if(m_buf != "") - printbuf(); - m_buf = ""; - return; - } - m_buf += c; +//// +//// *LogOutput methods +//// + +void FileLogOutput::open(const std::string &filename) +{ + stream.open(filename.c_str(), std::ios::app | std::ios::ate); + if (!stream.good()) + throw FileNotGoodException("Failed to open log file " + + filename + ": " + strerror(errno)); + stream << "\n\n" + "-------------" << std::endl + << " Separator" << std::endl + << "-------------\n" << std::endl; +} + + + +//// +//// *Buffer methods +//// + +int StringBuffer::overflow(int c) +{ + push_back(c); + return c; +} + + +std::streamsize StringBuffer::xsputn(const char *s, std::streamsize n) +{ + for (int i = 0; i < n; ++i) + push_back(s[i]); + return n; +} + +void StringBuffer::push_back(char c) +{ + if (c == '\n' || c == '\r') { + if (!buffer.empty()) + flush(buffer); + buffer.clear(); + } else { + buffer.push_back(c); } +} -private: - enum LogMessageLevel m_lev; - std::string m_buf; -}; -Logbuf errorbuf(LMT_ERROR); -Logbuf actionbuf(LMT_ACTION); -Logbuf infobuf(LMT_INFO); -Logbuf verbosebuf(LMT_VERBOSE); -std::ostream errorstream(&errorbuf); -std::ostream actionstream(&actionbuf); -std::ostream infostream(&infobuf); -std::ostream verbosestream(&verbosebuf); -bool log_trace_level_enabled = false; +void LogBuffer::flush(const std::string &buffer) +{ + logger.log(level, buffer); +} + +void RawLogBuffer::flush(const std::string &buffer) +{ + g_logger.logRaw(LL_NONE, buffer); +} -- cgit v1.2.3