c017d127e6c21d9305c3c545b728117fa3e8d3ed
[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 <mutex>
28 #include "threads.h"
29 #include "irrlichttypes.h"
30
31 class ILogOutput;
32
33 enum LogLevel {
34         LL_NONE, // Special level that is always printed
35         LL_ERROR,
36         LL_WARNING,
37         LL_ACTION,  // In-game actions
38         LL_INFO,
39         LL_VERBOSE,
40         LL_MAX,
41 };
42
43 typedef u8 LogLevelMask;
44 #define LOGLEVEL_TO_MASKLEVEL(x) (1 << x)
45
46 class Logger {
47 public:
48         void addOutput(ILogOutput *out);
49         void addOutput(ILogOutput *out, LogLevel lev);
50         void addOutputMasked(ILogOutput *out, LogLevelMask mask);
51         void addOutputMaxLevel(ILogOutput *out, LogLevel lev);
52         LogLevelMask removeOutput(ILogOutput *out);
53         void setLevelSilenced(LogLevel lev, bool silenced);
54
55         void registerThread(const std::string &name);
56         void deregisterThread();
57
58         void log(LogLevel lev, const std::string &text);
59         // Logs without a prefix
60         void logRaw(LogLevel lev, const std::string &text);
61
62         void setTraceEnabled(bool enable) { m_trace_enabled = enable; }
63         bool getTraceEnabled() { return m_trace_enabled; }
64
65         static LogLevel stringToLevel(const std::string &name);
66         static const std::string getLevelLabel(LogLevel lev);
67
68 private:
69         void logToOutputsRaw(LogLevel, const std::string &line);
70         void logToOutputs(LogLevel, const std::string &combined,
71                 const std::string &time, const std::string &thread_name,
72                 const std::string &payload_text);
73
74         const std::string getThreadName();
75
76         std::vector<ILogOutput *> m_outputs[LL_MAX];
77
78         // Should implement atomic loads and stores (even though it's only
79         // written to when one thread has access currently).
80         // Works on all known architectures (x86, ARM, MIPS).
81         volatile bool m_silenced_levels[LL_MAX];
82         std::map<threadid_t, std::string> m_thread_names;
83         mutable std::mutex m_mutex;
84         bool m_trace_enabled;
85 };
86
87 class ILogOutput {
88 public:
89         virtual void logRaw(LogLevel, const std::string &line) = 0;
90         virtual void log(LogLevel, const std::string &combined,
91                 const std::string &time, const std::string &thread_name,
92                 const std::string &payload_text) = 0;
93 };
94
95 class ICombinedLogOutput : public ILogOutput {
96 public:
97         void log(LogLevel lev, const std::string &combined,
98                 const std::string &time, const std::string &thread_name,
99                 const std::string &payload_text)
100         {
101                 logRaw(lev, combined);
102         }
103 };
104
105 class StreamLogOutput : public ICombinedLogOutput {
106 public:
107         StreamLogOutput(std::ostream &stream) :
108                 m_stream(stream)
109         {
110         }
111
112         void logRaw(LogLevel lev, const std::string &line)
113         {
114                 m_stream << line << std::endl;
115         }
116
117 private:
118         std::ostream &m_stream;
119 };
120
121 class FileLogOutput : public ICombinedLogOutput {
122 public:
123         void open(const std::string &filename);
124
125         void logRaw(LogLevel lev, const std::string &line)
126         {
127                 m_stream << line << std::endl;
128         }
129
130 private:
131         std::ofstream m_stream;
132 };
133
134 class LogOutputBuffer : public ICombinedLogOutput {
135 public:
136         LogOutputBuffer(Logger &logger, LogLevel lev) :
137                 m_logger(logger)
138         {
139                 m_logger.addOutput(this, lev);
140         }
141
142         ~LogOutputBuffer()
143         {
144                 m_logger.removeOutput(this);
145         }
146
147         void logRaw(LogLevel lev, const std::string &line)
148         {
149                 m_buffer.push(line);
150         }
151
152         bool empty()
153         {
154                 return m_buffer.empty();
155         }
156
157         std::string get()
158         {
159                 if (empty())
160                         return "";
161                 std::string s = m_buffer.front();
162                 m_buffer.pop();
163                 return s;
164         }
165
166 private:
167         std::queue<std::string> m_buffer;
168         Logger &m_logger;
169 };
170
171
172 extern StreamLogOutput stdout_output;
173 extern StreamLogOutput stderr_output;
174 extern std::ostream null_stream;
175
176 extern std::ostream *dout_con_ptr;
177 extern std::ostream *derr_con_ptr;
178 extern std::ostream *dout_server_ptr;
179 extern std::ostream *derr_server_ptr;
180
181 #ifndef SERVER
182 extern std::ostream *dout_client_ptr;
183 extern std::ostream *derr_client_ptr;
184 #endif
185
186 extern Logger g_logger;
187
188 // Writes directly to all LL_NONE log outputs for g_logger with no prefix.
189 extern std::ostream rawstream;
190
191 extern std::ostream errorstream;
192 extern std::ostream warningstream;
193 extern std::ostream actionstream;
194 extern std::ostream infostream;
195 extern std::ostream verbosestream;
196 extern std::ostream dstream;
197
198 #define TRACEDO(x) do {               \
199         if (g_logger.getTraceEnabled()) { \
200                 x;                            \
201         }                                 \
202 } while (0)
203
204 #define TRACESTREAM(x) TRACEDO(verbosestream x)
205
206 #define dout_con (*dout_con_ptr)
207 #define derr_con (*derr_con_ptr)
208 #define dout_server (*dout_server_ptr)
209 #define derr_server (*derr_server_ptr)
210
211 #ifndef SERVER
212         #define dout_client (*dout_client_ptr)
213         #define derr_client (*derr_client_ptr)
214 #endif
215
216
217 #endif