]> git.lizzy.rs Git - minetest.git/blob - src/log.cpp
Fixes #1687 by extra semaphore retval handle code for OSX
[minetest.git] / src / log.cpp
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 #include "log.h"
21
22 #include <map>
23 #include <list>
24 #include <sstream>
25 #include <algorithm>
26 #include "threads.h"
27 #include "debug.h"
28 #include "gettime.h"
29 #include "porting.h"
30 #include "config.h"
31
32 std::list<ILogOutput*> log_outputs[LMT_NUM_VALUES];
33 std::map<threadid_t, std::string> log_threadnames;
34 JMutex                            log_threadnamemutex;
35
36 void log_add_output(ILogOutput *out, enum LogMessageLevel lev)
37 {
38         log_outputs[lev].push_back(out);
39 }
40
41 void log_add_output_maxlev(ILogOutput *out, enum LogMessageLevel lev)
42 {
43         for(int i=0; i<=lev; i++)
44                 log_outputs[i].push_back(out);
45 }
46
47 void log_add_output_all_levs(ILogOutput *out)
48 {
49         for(int i=0; i<LMT_NUM_VALUES; i++)
50                 log_outputs[i].push_back(out);
51 }
52
53 void log_remove_output(ILogOutput *out)
54 {
55         for(int i=0; i<LMT_NUM_VALUES; i++){
56                 std::list<ILogOutput*>::iterator it =
57                                 std::find(log_outputs[i].begin(), log_outputs[i].end(), out);
58                 if(it != log_outputs[i].end())
59                         log_outputs[i].erase(it);
60         }
61 }
62
63 void log_set_lev_silence(enum LogMessageLevel lev, bool silence)
64 {
65         log_threadnamemutex.Lock();
66
67         for (std::list<ILogOutput *>::iterator
68                         it = log_outputs[lev].begin();
69                         it != log_outputs[lev].end();
70                         ++it) {
71                 ILogOutput *out = *it;
72                 out->silence = silence;
73         }
74
75         log_threadnamemutex.Unlock();
76 }
77
78 void log_register_thread(const std::string &name)
79 {
80         threadid_t id = get_current_thread_id();
81         log_threadnamemutex.Lock();
82         log_threadnames[id] = name;
83         log_threadnamemutex.Unlock();
84 }
85
86 void log_deregister_thread()
87 {
88         threadid_t id = get_current_thread_id();
89         log_threadnamemutex.Lock();
90         log_threadnames.erase(id);
91         log_threadnamemutex.Unlock();
92 }
93
94 static std::string get_lev_string(enum LogMessageLevel lev)
95 {
96         switch(lev){
97         case LMT_ERROR:
98                 return "ERROR";
99         case LMT_ACTION:
100                 return "ACTION";
101         case LMT_INFO:
102                 return "INFO";
103         case LMT_VERBOSE:
104                 return "VERBOSE";
105         case LMT_NUM_VALUES:
106                 break;
107         }
108         return "(unknown level)";
109 }
110
111 void log_printline(enum LogMessageLevel lev, const std::string &text)
112 {
113         log_threadnamemutex.Lock();
114         std::string threadname = "(unknown thread)";
115         std::map<threadid_t, std::string>::const_iterator i;
116         i = log_threadnames.find(get_current_thread_id());
117         if(i != log_threadnames.end())
118                 threadname = i->second;
119         std::string levelname = get_lev_string(lev);
120         std::ostringstream os(std::ios_base::binary);
121         os<<getTimestamp()<<": "<<levelname<<"["<<threadname<<"]: "<<text;
122         for(std::list<ILogOutput*>::iterator i = log_outputs[lev].begin();
123                         i != log_outputs[lev].end(); i++){
124                 ILogOutput *out = *i;
125                 if (out->silence)
126                         continue;
127
128                 out->printLog(os.str());
129                 out->printLog(os.str(), lev);
130                 out->printLog(lev, text);
131         }
132         log_threadnamemutex.Unlock();
133 }
134
135 class Logbuf : public std::streambuf
136 {
137 public:
138         Logbuf(enum LogMessageLevel lev):
139                 m_lev(lev)
140         {
141         }
142
143         ~Logbuf()
144         {
145         }
146
147         int overflow(int c)
148         {
149                 bufchar(c);
150                 return c;
151         }
152         std::streamsize xsputn(const char *s, std::streamsize n)
153         {
154                 for(int i=0; i<n; i++)
155                         bufchar(s[i]);
156                 return n;
157         }
158
159         void printbuf()
160         {
161                 log_printline(m_lev, m_buf);
162 #ifdef __ANDROID__
163                 __android_log_print(ANDROID_LOG_ERROR, PROJECT_NAME, "%s", m_buf.c_str());
164 #endif
165         }
166
167         void bufchar(char c)
168         {
169                 if(c == '\n' || c == '\r'){
170                         if(m_buf != "")
171                                 printbuf();
172                         m_buf = "";
173                         return;
174                 }
175                 m_buf += c;
176         }
177
178 private:
179         enum LogMessageLevel m_lev;
180         std::string m_buf;
181 };
182
183 Logbuf errorbuf(LMT_ERROR);
184 Logbuf actionbuf(LMT_ACTION);
185 Logbuf infobuf(LMT_INFO);
186 Logbuf verbosebuf(LMT_VERBOSE);
187 std::ostream errorstream(&errorbuf);
188 std::ostream actionstream(&actionbuf);
189 std::ostream infostream(&infobuf);
190 std::ostream verbosestream(&verbosebuf);
191
192 bool log_trace_level_enabled = false;
193