1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

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
This commit is contained in:
ShadowNinja 2015-10-13 03:57:44 -04:00 committed by kwolekr
parent e0b57c1140
commit 2139d7d45f
25 changed files with 599 additions and 652 deletions

194
src/log.h
View file

@ -20,83 +20,177 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef LOG_HEADER
#define LOG_HEADER
#include <map>
#include <queue>
#include <string>
#include <fstream>
#include "threads.h"
/*
Use this for logging everything.
class ILogOutput;
If you need to explicitly print something, use dstream or cout or cerr.
*/
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,
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,
};
class ILogOutput
{
class Logger {
public:
ILogOutput() :
silence(false)
{}
void addOutput(ILogOutput *out);
void addOutput(ILogOutput *out, LogLevel lev);
void addOutputMaxLevel(ILogOutput *out, LogLevel lev);
void removeOutput(ILogOutput *out);
void setLevelSilenced(LogLevel lev, bool silenced);
/* 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){};
void registerThread(const std::string &name);
void deregisterThread();
bool silence;
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);
private:
void logToSystem(LogLevel, const std::string &text);
void logToOutputs(LogLevel, const std::string &text);
const std::string getLevelLabel(LogLevel lev);
const std::string getThreadName();
std::vector<ILogOutput *> 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<threadid_t, std::string> m_thread_names;
mutable Mutex m_mutex;
bool m_trace_enabled;
};
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);
void log_set_lev_silence(enum LogMessageLevel lev, bool silence);
class ILogOutput {
public:
virtual void log(const std::string &line) = 0;
};
void log_register_thread(const std::string &name);
void log_deregister_thread();
class StreamLogOutput : public ILogOutput {
public:
StreamLogOutput(std::ostream &stream) :
stream(stream)
{
}
void log_printline(enum LogMessageLevel lev, const std::string &text);
void log(const std::string &line)
{
stream << line << std::endl;
}
#define LOGLINEF(lev, ...)\
{\
char buf[10000];\
snprintf(buf, 10000, __VA_ARGS__);\
log_printline(lev, buf);\
}
private:
std::ostream &stream;
};
extern std::ostream errorstream;
extern std::ostream actionstream;
extern std::ostream infostream;
extern std::ostream verbosestream;
class FileLogOutput : public ILogOutput {
public:
void open(const std::string &filename);
extern bool log_trace_level_enabled;
void log(const std::string &line)
{
stream << line << std::endl;
}
#define TRACESTREAM(x){ if(log_trace_level_enabled) verbosestream x; }
#define TRACEDO(x){ if(log_trace_level_enabled){ x ;} }
private:
std::ofstream stream;
};
class LogOutputBuffer : public ILogOutput {
public:
LogOutputBuffer(Logger &logger, LogLevel lev) :
logger(logger)
{
logger.addOutput(this, lev);
}
~LogOutputBuffer()
{
logger.removeOutput(this);
}
virtual void log(const std::string &line)
{
buffer.push(line);
}
bool empty()
{
return buffer.empty();
}
std::string get()
{
if (empty())
return "";
std::string s = buffer.front();
buffer.pop();
return s;
}
private:
std::queue<std::string> buffer;
Logger &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;
#define TRACEDO(x) do { \
if (g_logger.getTraceEnabled()) { \
x; \
} \
} while (0)
#define TRACESTREAM(x) TRACEDO(verbosestream x)
#define dout_con (*dout_con_ptr)
#define derr_con (*derr_con_ptr)
#define dout_server (*dout_server_ptr)
#define derr_server (*derr_server_ptr)
#ifndef SERVER
extern std::ostream *dout_client_ptr;
extern std::ostream *derr_client_ptr;
#define dout_client (*dout_client_ptr)
#define derr_client (*derr_client_ptr)
#define dout_client (*dout_client_ptr)
#define derr_client (*derr_client_ptr)
#endif
#endif
#endif