X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flog.cpp;h=54442c39b1669561a5fa9b6a686395d9416d4c0a;hb=79414aa3e5591fdaffa0956a08610a2228042941;hp=4f77101f932efde992e09d2c433ef6e8d9a3854f;hpb=2139d7d45fb1a8ed250ad96c9975c581f02f72a9;p=minetest.git diff --git a/src/log.cpp b/src/log.cpp index 4f77101f9..54442c39b 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "debug.h" #include "gettime.h" #include "porting.h" +#include "settings.h" #include "config.h" #include "exceptions.h" #include "util/numeric.h" @@ -34,9 +35,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include +const int BUFFER_LENGTH = 256; + class StringBuffer : public std::streambuf { public: - StringBuffer() {} + StringBuffer() { + buffer_index = 0; + } int overflow(int c); virtual void flush(const std::string &buf) = 0; @@ -44,7 +49,8 @@ class StringBuffer : public std::streambuf { void push_back(char c); private: - std::string buffer; + char buffer[BUFFER_LENGTH]; + int buffer_index; }; @@ -68,21 +74,6 @@ class RawLogBuffer : public StringBuffer { 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 //// @@ -124,6 +115,42 @@ 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 /////////////////////////////////////////////////////////////////////////////// @@ -152,7 +179,7 @@ LogLevel Logger::stringToLevel(const std::string &name) void Logger::addOutput(ILogOutput *out) { - addOutputMaxLevel(out, LL_MAX); + addOutputMaxLevel(out, (LogLevel)(LL_MAX - 1)); } void Logger::addOutput(ILogOutput *out, LogLevel lev) @@ -160,21 +187,34 @@ void Logger::addOutput(ILogOutput *out, LogLevel lev) m_outputs[lev].push_back(out); } +void Logger::addOutputMasked(ILogOutput *out, LogLevelMask mask) +{ + for (size_t i = 0; i < LL_MAX; i++) { + if (mask & LOGLEVEL_TO_MASKLEVEL(i)) + m_outputs[i].push_back(out); + } +} + void Logger::addOutputMaxLevel(ILogOutput *out, LogLevel lev) { + assert(lev < LL_MAX); for (size_t i = 0; i <= lev; i++) m_outputs[i].push_back(out); } -void Logger::removeOutput(ILogOutput *out) +LogLevelMask Logger::removeOutput(ILogOutput *out) { + 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()) + if (it != m_outputs[i].end()) { + ret_mask |= LOGLEVEL_TO_MASKLEVEL(i); m_outputs[i].erase(it); + } } + return ret_mask; } void Logger::setLevelSilenced(LogLevel lev, bool silenced) @@ -184,14 +224,14 @@ void Logger::setLevelSilenced(LogLevel lev, bool silenced) void Logger::registerThread(const std::string &name) { - threadid_t id = get_current_thread_id(); + std::thread::id id = std::this_thread::get_id(); MutexAutoLock lock(m_mutex); m_thread_names[id] = name; } void Logger::deregisterThread() { - threadid_t id = get_current_thread_id(); + std::thread::id id = std::this_thread::get_id(); MutexAutoLock lock(m_mutex); m_thread_names.erase(id); } @@ -207,15 +247,18 @@ const std::string Logger::getLevelLabel(LogLevel lev) "VERBOSE", }; assert(lev < LL_MAX && lev >= 0); - assert(ARRLEN(names) == LL_MAX); + STATIC_ASSERT(ARRLEN(names) == LL_MAX, + mismatch_between_loglevel_names_and_enum); return names[lev]; } +LogColor Logger::color_mode = LOG_COLOR_AUTO; + const std::string Logger::getThreadName() { - std::map::const_iterator it; + std::map::const_iterator it; - threadid_t id = get_current_thread_id(); + std::thread::id id = std::this_thread::get_id(); it = m_thread_names.find(id); if (it != m_thread_names.end()) return it->second; @@ -232,11 +275,11 @@ void Logger::log(LogLevel lev, const std::string &text) 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 << getTimestamp() << ": " << label << "[" << thread_name << "]: " << text; + os << timestamp << ": " << label << "[" << thread_name << "]: " << text; - logToSystem(lev, text); - logToOutputs(lev, os.str()); + logToOutputs(lev, os.str(), timestamp, thread_name, text); } void Logger::logRaw(LogLevel lev, const std::string &text) @@ -244,24 +287,23 @@ void Logger::logRaw(LogLevel lev, const std::string &text) if (m_silenced_levels[lev]) return; - logToSystem(lev, text); - logToOutputs(lev, text); + logToOutputsRaw(lev, text); } -void Logger::logToSystem(LogLevel lev, const std::string &text) +void Logger::logToOutputsRaw(LogLevel lev, const std::string &line) { -#ifdef __ANDROID__ - assert(ARRLEN(level_to_android) == LL_MAX); - __android_log_print(level_to_android[lev], - PROJECT_NAME_C, "%s", text.c_str()); -#endif + MutexAutoLock lock(m_mutex); + for (size_t i = 0; i != m_outputs[lev].size(); i++) + m_outputs[lev][i]->logRaw(lev, line); } -void Logger::logToOutputs(LogLevel lev, const std::string &text) +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(text); + m_outputs[lev][i]->log(lev, combined, time, thread_name, payload_text); } @@ -269,19 +311,108 @@ void Logger::logToOutputs(LogLevel lev, const std::string &text) //// *LogOutput methods //// -void FileLogOutput::open(const std::string &filename) +void FileLogOutput::setFile(const std::string &filename, s64 file_size_max) { - stream.open(filename.c_str(), std::ios::app | std::ios::ate); - if (!stream.good()) + // Only move debug.txt if there is a valid maximum file size + bool is_too_large = false; + if (file_size_max > 0) { + std::ifstream ifile(filename, std::ios::binary | std::ios::ate); + is_too_large = ifile.tellg() > file_size_max; + ifile.close(); + } + + if (is_too_large) { + std::string filename_secondary = filename + ".1"; + actionstream << "The log file grew too big; it is moved to " << + filename_secondary << std::endl; + remove(filename_secondary.c_str()); + rename(filename.c_str(), filename_secondary.c_str()); + } + m_stream.open(filename, std::ios::app | std::ios::ate); + + if (!m_stream.good()) throw FileNotGoodException("Failed to open log file " + filename + ": " + strerror(errno)); - stream << "\n\n" - "-------------" << std::endl - << " Separator" << std::endl - << "-------------\n" << std::endl; + m_stream << "\n\n" + "-------------" << std::endl << + " Separator" << std::endl << + "-------------\n" << std::endl; } +void StreamLogOutput::logRaw(LogLevel lev, const std::string &line) +{ + bool colored_message = (Logger::color_mode == LOG_COLOR_ALWAYS) || + (Logger::color_mode == LOG_COLOR_AUTO && is_tty); + if (colored_message) { + switch (lev) { + case LL_ERROR: + // error is red + m_stream << "\033[91m"; + break; + case LL_WARNING: + // warning is yellow + m_stream << "\033[93m"; + break; + case LL_INFO: + // info is a bit dark + m_stream << "\033[37m"; + break; + case LL_VERBOSE: + // verbose is darker than info + m_stream << "\033[2m"; + break; + default: + // action is white + colored_message = false; + } + } + m_stream << line << std::endl; + + if (colored_message) { + // reset to white color + m_stream << "\033[0m"; + } +} + +void LogOutputBuffer::updateLogLevel() +{ + const std::string &conf_loglev = g_settings->get("chat_log_level"); + LogLevel log_level = Logger::stringToLevel(conf_loglev); + if (log_level == LL_MAX) { + warningstream << "Supplied unrecognized chat_log_level; " + "showing none." << std::endl; + log_level = LL_NONE; + } + + m_logger.removeOutput(this); + m_logger.addOutputMaxLevel(this, log_level); +} + +void LogOutputBuffer::logRaw(LogLevel lev, const std::string &line) +{ + std::string color; + + if (!g_settings->getBool("disable_escape_sequences")) { + switch (lev) { + case LL_ERROR: // red + color = "\x1b(c@#F00)"; + break; + case LL_WARNING: // yellow + color = "\x1b(c@#EE0)"; + break; + case LL_INFO: // grey + color = "\x1b(c@#BBB)"; + break; + case LL_VERBOSE: // dark grey + color = "\x1b(c@#888)"; + break; + default: break; + } + } + + m_buffer.push(color.append(line)); +} //// //// *Buffer methods @@ -304,17 +435,19 @@ std::streamsize StringBuffer::xsputn(const char *s, std::streamsize n) void StringBuffer::push_back(char c) { if (c == '\n' || c == '\r') { - if (!buffer.empty()) - flush(buffer); - buffer.clear(); + if (buffer_index) + flush(std::string(buffer, buffer_index)); + buffer_index = 0; } else { - buffer.push_back(c); + buffer[buffer_index++] = c; + if (buffer_index >= BUFFER_LENGTH) { + flush(std::string(buffer, buffer_index)); + buffer_index = 0; + } } } - - void LogBuffer::flush(const std::string &buffer) { logger.log(level, buffer);