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