X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Flog.h;h=506137739a06a9d6f3b861e8eae075127f679d34;hb=3face01a202040e4feff3b0936b4aa89c051c98d;hp=7d8b60b71845cb32b215f9026d8374d978107eeb;hpb=22e186b4aa88b585e71500c4e9a03bf69b0b6191;p=oweals%2Fminetest.git diff --git a/src/log.h b/src/log.h index 7d8b60b71..506137739 100644 --- a/src/log.h +++ b/src/log.h @@ -17,62 +17,235 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef LOG_HEADER -#define LOG_HEADER +#pragma once +#include +#include #include +#include +#include +#include +#if !defined(_WIN32) // POSIX + #include +#endif +#include "settings.h" +#include "irrlichttypes.h" + +class ILogOutput; + +enum LogLevel { + LL_NONE, // Special level that is always printed + LL_ERROR, + LL_WARNING, + LL_ACTION, // In-game actions + LL_INFO, + LL_VERBOSE, + LL_MAX, +}; -/* - Use this for logging everything. - - If you need to explicitly print something, use dstream or cout or cerr. -*/ +typedef u8 LogLevelMask; +#define LOGLEVEL_TO_MASKLEVEL(x) (1 << x) -enum LogMessageLevel { - LMT_ERROR, /* Something failed ("invalid map data on disk, block (2,2,1)") */ - LMT_ACTION, /* In-game actions ("celeron55 placed block at (12,4,-5)") */ - LMT_INFO, /* More deep info ("saving map on disk (only_modified=true)") */ - LMT_VERBOSE, /* Flood-style ("loaded block (2,2,2) from disk") */ - LMT_NUM_VALUES, +class Logger { +public: + void addOutput(ILogOutput *out); + void addOutput(ILogOutput *out, LogLevel lev); + void addOutputMasked(ILogOutput *out, LogLevelMask mask); + void addOutputMaxLevel(ILogOutput *out, LogLevel lev); + LogLevelMask removeOutput(ILogOutput *out); + void setLevelSilenced(LogLevel lev, bool silenced); + + void registerThread(const std::string &name); + void deregisterThread(); + + void log(LogLevel lev, const std::string &text); + // Logs without a prefix + void logRaw(LogLevel lev, const std::string &text); + + void setTraceEnabled(bool enable) { m_trace_enabled = enable; } + bool getTraceEnabled() { return m_trace_enabled; } + + static LogLevel stringToLevel(const std::string &name); + static const std::string getLevelLabel(LogLevel lev); + +private: + void logToOutputsRaw(LogLevel, const std::string &line); + void logToOutputs(LogLevel, const std::string &combined, + const std::string &time, const std::string &thread_name, + const std::string &payload_text); + + const std::string getThreadName(); + + std::vector m_outputs[LL_MAX]; + + // Should implement atomic loads and stores (even though it's only + // written to when one thread has access currently). + // Works on all known architectures (x86, ARM, MIPS). + volatile bool m_silenced_levels[LL_MAX]; + std::map m_thread_names; + mutable std::mutex m_mutex; + bool m_trace_enabled; }; -class ILogOutput -{ +class ILogOutput { public: - /* line: Full line with timestamp, level and thread */ - virtual void printLog(const std::string &line){}; - /* line: Full line with timestamp, level and thread */ - virtual void printLog(const std::string &line, enum LogMessageLevel lev){}; - /* line: Only actual printed text */ - virtual void printLog(enum LogMessageLevel lev, const std::string &line){}; + virtual void logRaw(LogLevel, const std::string &line) = 0; + virtual void log(LogLevel, const std::string &combined, + const std::string &time, const std::string &thread_name, + const std::string &payload_text) = 0; }; -void log_add_output(ILogOutput *out, enum LogMessageLevel lev); -void log_add_output_maxlev(ILogOutput *out, enum LogMessageLevel lev); -void log_add_output_all_levs(ILogOutput *out); -void log_remove_output(ILogOutput *out); +class ICombinedLogOutput : public ILogOutput { +public: + void log(LogLevel lev, const std::string &combined, + const std::string &time, const std::string &thread_name, + const std::string &payload_text) + { + logRaw(lev, combined); + } +}; -void log_register_thread(const std::string &name); -void log_deregister_thread(); +class StreamLogOutput : public ICombinedLogOutput { +public: + StreamLogOutput(std::ostream &stream) : + m_stream(stream) + { +#if !defined(_WIN32) + is_tty = isatty(fileno(stdout)); +#else + is_tty = false; +#endif + } + + void logRaw(LogLevel lev, const std::string &line) + { + static const std::string use_logcolor = g_settings->get("log_color"); + + bool colored = use_logcolor == "detect" ? is_tty : use_logcolor == "yes"; + if (colored) + 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 = false; + } + + m_stream << line << std::endl; + + if (colored) + // reset to white color + m_stream << "\033[0m"; + } + +private: + std::ostream &m_stream; + bool is_tty; +}; -void log_printline(enum LogMessageLevel lev, const std::string &text); +class FileLogOutput : public ICombinedLogOutput { +public: + void open(const std::string &filename); + + void logRaw(LogLevel lev, const std::string &line) + { + m_stream << line << std::endl; + } -#define LOGLINEF(lev, ...)\ -{\ - char buf[10000];\ - snprintf(buf, 10000, __VA_ARGS__);\ - log_printline(lev, buf);\ -} +private: + std::ofstream m_stream; +}; + +class LogOutputBuffer : public ICombinedLogOutput { +public: + LogOutputBuffer(Logger &logger, LogLevel lev) : + m_logger(logger) + { + m_logger.addOutput(this, lev); + } + + ~LogOutputBuffer() + { + m_logger.removeOutput(this); + } + + void logRaw(LogLevel lev, const std::string &line) + { + m_buffer.push(line); + } + + bool empty() + { + return m_buffer.empty(); + } + + std::string get() + { + if (empty()) + return ""; + std::string s = m_buffer.front(); + m_buffer.pop(); + return s; + } + +private: + std::queue m_buffer; + Logger &m_logger; +}; + + +extern StreamLogOutput stdout_output; +extern StreamLogOutput stderr_output; +extern std::ostream null_stream; + +extern std::ostream *dout_con_ptr; +extern std::ostream *derr_con_ptr; +extern std::ostream *dout_server_ptr; +extern std::ostream *derr_server_ptr; + +#ifndef SERVER +extern std::ostream *dout_client_ptr; +extern std::ostream *derr_client_ptr; +#endif + +extern Logger g_logger; + +// Writes directly to all LL_NONE log outputs for g_logger with no prefix. +extern std::ostream rawstream; extern std::ostream errorstream; +extern std::ostream warningstream; extern std::ostream actionstream; extern std::ostream infostream; extern std::ostream verbosestream; +extern std::ostream dstream; -extern bool log_trace_level_enabled; +#define TRACEDO(x) do { \ + if (g_logger.getTraceEnabled()) { \ + x; \ + } \ +} while (0) -#define TRACESTREAM(x){ if(log_trace_level_enabled) verbosestream x; } -#define TRACEDO(x){ if(log_trace_level_enabled){ x ;} } +#define TRACESTREAM(x) TRACEDO(verbosestream x) -#endif +#define dout_con (*dout_con_ptr) +#define derr_con (*derr_con_ptr) +#define dout_server (*dout_server_ptr) +#ifndef SERVER + #define dout_client (*dout_client_ptr) +#endif