X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flog.cpp;h=589cfd909806ee7ba6be55d720c6f06ba486a6bf;hb=c5968049bbf73ceff08a2b1d35bb34192fa3f315;hp=a963f4c27832b1179cf0842157ada44f29ef1f7c;hpb=1f670fc68844d0a8503d8da04f59c8b662614907;p=dragonfireclient.git diff --git a/src/log.cpp b/src/log.cpp index a963f4c27..589cfd909 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -1,163 +1,370 @@ /* -Minetest-c55 -Copyright (C) 2011 celeron55, Perttu Ahola +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Lesser General Public License for more details. -You should have received a copy of the GNU General Public License along +You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #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 + +const int BUFFER_LENGTH = 256; + +class StringBuffer : public std::streambuf { +public: + StringBuffer() { + buffer_index = 0; + } + + 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: + char buffer[BUFFER_LENGTH]; + int buffer_index; +}; + + +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); +}; + +//// +//// Globals +//// -std::list log_outputs[LMT_NUM_VALUES]; -std::map log_threadnames; +Logger g_logger; -void log_add_output(ILogOutput *out, enum LogMessageLevel lev) +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 = &null_stream; +std::ostream *derr_con_ptr = &verbosestream; + +// Server +std::ostream *dout_server_ptr = &infostream; +std::ostream *derr_server_ptr = &errorstream; + +#ifndef SERVER +// Client +std::ostream *dout_client_ptr = &infostream; +std::ostream *derr_client_ptr = &errorstream; +#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); + +// Android +#ifdef __ANDROID__ + +static unsigned int g_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 +}; + +class AndroidSystemLogOutput : public ICombinedLogOutput { + public: + AndroidSystemLogOutput() + { + g_logger.addOutput(this); + } + ~AndroidSystemLogOutput() + { + g_logger.removeOutput(this); + } + void logRaw(LogLevel lev, const std::string &line) + { + STATIC_ASSERT(ARRLEN(g_level_to_android) == LL_MAX, + mismatch_between_android_and_internal_loglevels); + __android_log_print(g_level_to_android[lev], + PROJECT_NAME_C, "%s", line.c_str()); + } +}; + +AndroidSystemLogOutput g_android_log_output; + +#endif + +/////////////////////////////////////////////////////////////////////////////// + + +//// +//// 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, (LogLevel)(LL_MAX - 1)); } -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 < LL_MAX; i++) { + if (mask & LOGLEVEL_TO_MASKLEVEL(i)) + m_outputs[i].push_back(out); } } -void log_register_thread(const std::string &name) +void Logger::addOutputMaxLevel(ILogOutput *out, LogLevel lev) { - threadid_t id = get_current_thread_id(); - log_threadnames[id] = name; + assert(lev < LL_MAX); + for (size_t i = 0; i <= lev; i++) + m_outputs[i].push_back(out); } -void log_deregister_thread() +LogLevelMask Logger::removeOutput(ILogOutput *out) { - threadid_t id = get_current_thread_id(); - log_threadnames.erase(id); + LogLevelMask ret_mask = 0; + for (size_t i = 0; i < LL_MAX; i++) { + std::vector::iterator it; + + it = std::find(m_outputs[i].begin(), m_outputs[i].end(), out); + if (it != m_outputs[i].end()) { + ret_mask |= LOGLEVEL_TO_MASKLEVEL(i); + m_outputs[i].erase(it); + } + } + return ret_mask; } -static std::string get_lev_string(enum LogMessageLevel lev) +void Logger::setLevelSilenced(LogLevel lev, bool silenced) { - 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)"; + m_silenced_levels[lev] = silenced; } -void log_printline(enum LogMessageLevel lev, const std::string &text) +void Logger::registerThread(const std::string &name) { - std::string threadname = "(unknown thread)"; - std::map::const_iterator i; - i = log_threadnames.find(get_current_thread_id()); - if(i != log_threadnames.end()) - threadname = i->second; - std::string levelname = get_lev_string(lev); + threadid_t id = thr_get_current_thread_id(); + MutexAutoLock lock(m_mutex); + m_thread_names[id] = name; +} + +void Logger::deregisterThread() +{ + threadid_t id = thr_get_current_thread_id(); + MutexAutoLock lock(m_mutex); + m_thread_names.erase(id); +} + +const std::string Logger::getLevelLabel(LogLevel lev) +{ + static const std::string names[] = { + "", + "ERROR", + "WARNING", + "ACTION", + "INFO", + "VERBOSE", + }; + assert(lev < LL_MAX && lev >= 0); + STATIC_ASSERT(ARRLEN(names) == LL_MAX, + mismatch_between_loglevel_names_and_enum); + return names[lev]; +} + +const std::string Logger::getThreadName() +{ + std::map::const_iterator it; + + threadid_t id = thr_get_current_thread_id(); + it = m_thread_names.find(id); + if (it != m_thread_names.end()) + return it->second; + + std::ostringstream os; + os << "#0x" << std::hex << id; + return os.str(); +} + +void Logger::log(LogLevel lev, const std::string &text) +{ + if (m_silenced_levels[lev]) + return; + + const std::string thread_name = getThreadName(); + const std::string label = getLevelLabel(lev); + const std::string timestamp = getTimestamp(); std::ostringstream os(std::ios_base::binary); - os<::iterator i = log_outputs[lev].begin(); - i != log_outputs[lev].end(); i++){ - ILogOutput *out = *i; - out->printLog(os.str()); - out->printLog(os.str(), lev); - out->printLog(lev, text); - } + os << timestamp << ": " << label << "[" << thread_name << "]: " << text; + + logToOutputs(lev, os.str(), timestamp, thread_name, text); } -class Logbuf : public std::streambuf +void Logger::logRaw(LogLevel lev, const std::string &text) { -public: - Logbuf(enum LogMessageLevel lev): - m_lev(lev) - { - } + if (m_silenced_levels[lev]) + return; - ~Logbuf() - { - } + logToOutputsRaw(lev, text); +} - int overflow(int c) - { - bufchar(c); - return c; - } - std::streamsize xsputn(const char *s, std::streamsize n) - { - for(int i=0; ilogRaw(lev, line); +} - void printbuf() - { - log_printline(m_lev, m_buf); - } +void Logger::logToOutputs(LogLevel lev, const std::string &combined, + const std::string &time, const std::string &thread_name, + const std::string &payload_text) +{ + MutexAutoLock lock(m_mutex); + for (size_t i = 0; i != m_outputs[lev].size(); i++) + m_outputs[lev][i]->log(lev, combined, time, thread_name, payload_text); +} + + +//// +//// *LogOutput methods +//// + +void FileLogOutput::open(const std::string &filename) +{ + m_stream.open(filename.c_str(), std::ios::app | std::ios::ate); + if (!m_stream.good()) + throw FileNotGoodException("Failed to open log file " + + filename + ": " + strerror(errno)); + m_stream << "\n\n" + "-------------" << std::endl + << " Separator" << std::endl + << "-------------\n" << std::endl; +} + + + +//// +//// *Buffer methods +//// + +int StringBuffer::overflow(int c) +{ + push_back(c); + return c; +} - void bufchar(char c) - { - if(c == '\n' || c == '\r'){ - if(m_buf != "") - printbuf(); - m_buf = ""; - return; + +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_index) + flush(std::string(buffer, buffer_index)); + buffer_index = 0; + } else { + int index = buffer_index; + buffer[index++] = c; + if (index >= BUFFER_LENGTH) { + flush(std::string(buffer, buffer_index)); + buffer_index = 0; + } else { + buffer_index = index; } - m_buf += 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); +}