Add server side ncurses terminal
[oweals/minetest.git] / src / log.h
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #ifndef LOG_HEADER
21 #define LOG_HEADER
22
23 #include <map>
24 #include <queue>
25 #include <string>
26 #include <fstream>
27 #include "threads.h"
28 #include "irrlichttypes.h"
29
30 class ILogOutput;
31
32 enum LogLevel {
33         LL_NONE, // Special level that is always printed
34         LL_ERROR,
35         LL_WARNING,
36         LL_ACTION,  // In-game actions
37         LL_INFO,
38         LL_VERBOSE,
39         LL_MAX,
40 };
41
42 typedef u8 LogLevelMask;
43 #define LOGLEVEL_TO_MASKLEVEL(x) (1 << x)
44
45 class Logger {
46 public:
47         void addOutput(ILogOutput *out);
48         void addOutput(ILogOutput *out, LogLevel lev);
49         void addOutputMasked(ILogOutput *out, LogLevelMask mask);
50         void addOutputMaxLevel(ILogOutput *out, LogLevel lev);
51         LogLevelMask removeOutput(ILogOutput *out);
52         void setLevelSilenced(LogLevel lev, bool silenced);
53
54         void registerThread(const std::string &name);
55         void deregisterThread();
56
57         void log(LogLevel lev, const std::string &text);
58         // Logs without a prefix
59         void logRaw(LogLevel lev, const std::string &text);
60
61         void setTraceEnabled(bool enable) { m_trace_enabled = enable; }
62         bool getTraceEnabled() { return m_trace_enabled; }
63
64         static LogLevel stringToLevel(const std::string &name);
65         static const std::string getLevelLabel(LogLevel lev);
66
67 private:
68         void logToOutputsRaw(LogLevel, const std::string &line);
69         void logToOutputs(LogLevel, const std::string &combined,
70                 const std::string &time, const std::string &thread_name,
71                 const std::string &payload_text);
72
73         const std::string getThreadName();
74
75         std::vector<ILogOutput *> m_outputs[LL_MAX];
76
77         // Should implement atomic loads and stores (even though it's only
78         // written to when one thread has access currently).
79         // Works on all known architectures (x86, ARM, MIPS).
80         volatile bool m_silenced_levels[LL_MAX];
81         std::map<threadid_t, std::string> m_thread_names;
82         mutable Mutex m_mutex;
83         bool m_trace_enabled;
84 };
85
86 class ILogOutput {
87 public:
88         virtual void logRaw(LogLevel, const std::string &line) = 0;
89         virtual void log(LogLevel, const std::string &combined,
90                 const std::string &time, const std::string &thread_name,
91                 const std::string &payload_text) = 0;
92 };
93
94 class ICombinedLogOutput : public ILogOutput {
95 public:
96         void log(LogLevel lev, const std::string &combined,
97                 const std::string &time, const std::string &thread_name,
98                 const std::string &payload_text)
99         {
100                 logRaw(lev, combined);
101         }
102 };
103
104 class StreamLogOutput : public ICombinedLogOutput {
105 public:
106         StreamLogOutput(std::ostream &stream) :
107                 m_stream(stream)
108         {
109         }
110
111         void logRaw(LogLevel lev, const std::string &line)
112         {
113                 m_stream << line << std::endl;
114         }
115
116 private:
117         std::ostream &m_stream;
118 };
119
120 class FileLogOutput : public ICombinedLogOutput {
121 public:
122         void open(const std::string &filename);
123
124         void logRaw(LogLevel lev, const std::string &line)
125         {
126                 m_stream << line << std::endl;
127         }
128
129 private:
130         std::ofstream m_stream;
131 };
132
133 class LogOutputBuffer : public ICombinedLogOutput {
134 public:
135         LogOutputBuffer(Logger &logger, LogLevel lev) :
136                 m_logger(logger)
137         {
138                 m_logger.addOutput(this, lev);
139         }
140
141         ~LogOutputBuffer()
142         {
143                 m_logger.removeOutput(this);
144         }
145
146         void logRaw(LogLevel lev, const std::string &line)
147         {
148                 m_buffer.push(line);
149         }
150
151         bool empty()
152         {
153                 return m_buffer.empty();
154         }
155
156         std::string get()
157         {
158                 if (empty())
159                         return "";
160                 std::string s = m_buffer.front();
161                 m_buffer.pop();
162                 return s;
163         }
164
165 private:
166         std::queue<std::string> m_buffer;
167         Logger &m_logger;
168 };
169
170
171 extern StreamLogOutput stdout_output;
172 extern StreamLogOutput stderr_output;
173 extern std::ostream null_stream;
174
175 extern std::ostream *dout_con_ptr;
176 extern std::ostream *derr_con_ptr;
177 extern std::ostream *dout_server_ptr;
178 extern std::ostream *derr_server_ptr;
179
180 #ifndef SERVER
181 extern std::ostream *dout_client_ptr;
182 extern std::ostream *derr_client_ptr;
183 #endif
184
185 extern Logger g_logger;
186
187 // Writes directly to all LL_NONE log outputs for g_logger with no prefix.
188 extern std::ostream rawstream;
189
190 extern std::ostream errorstream;
191 extern std::ostream warningstream;
192 extern std::ostream actionstream;
193 extern std::ostream infostream;
194 extern std::ostream verbosestream;
195 extern std::ostream dstream;
196
197 #define TRACEDO(x) do {               \
198         if (g_logger.getTraceEnabled()) { \
199                 x;                            \
200         }                                 \
201 } while (0)
202
203 #define TRACESTREAM(x) TRACEDO(verbosestream x)
204
205 #define dout_con (*dout_con_ptr)
206 #define derr_con (*derr_con_ptr)
207 #define dout_server (*dout_server_ptr)
208 #define derr_server (*derr_server_ptr)
209
210 #ifndef SERVER
211         #define dout_client (*dout_client_ptr)
212         #define derr_client (*derr_client_ptr)
213 #endif
214
215
216 #endif