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