Line data Source code
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 "jthread/jmutexautolock.h"
28 : #include "debug.h"
29 : #include "gettime.h"
30 : #include "porting.h"
31 : #include "config.h"
32 :
33 : // Connection
34 : std::ostream *dout_con_ptr = &dummyout;
35 : std::ostream *derr_con_ptr = &verbosestream;
36 :
37 : // Server
38 : std::ostream *dout_server_ptr = &infostream;
39 : std::ostream *derr_server_ptr = &errorstream;
40 :
41 : #ifndef SERVER
42 : // Client
43 : std::ostream *dout_client_ptr = &infostream;
44 : std::ostream *derr_client_ptr = &errorstream;
45 : #endif
46 :
47 : #ifdef __ANDROID__
48 : unsigned int android_log_level_mapping[] = {
49 : /* LMT_ERROR */ ANDROID_LOG_ERROR,
50 : /* LMT_ACTION */ ANDROID_LOG_WARN,
51 : /* LMT_INFO */ ANDROID_LOG_INFO,
52 : /* LMT_VERBOSE */ ANDROID_LOG_VERBOSE
53 : };
54 : #endif
55 :
56 2 : std::vector<ILogOutput*> log_outputs[LMT_NUM_VALUES];
57 1 : std::map<threadid_t, std::string> log_threadnames;
58 1 : JMutex log_threadnamemutex;
59 :
60 1 : void log_add_output(ILogOutput *out, enum LogMessageLevel lev)
61 : {
62 1 : log_outputs[lev].push_back(out);
63 1 : }
64 :
65 2 : void log_add_output_maxlev(ILogOutput *out, enum LogMessageLevel lev)
66 : {
67 6 : for(int i=0; i<=lev; i++)
68 4 : log_outputs[i].push_back(out);
69 2 : }
70 :
71 1 : void log_add_output_all_levs(ILogOutput *out)
72 : {
73 5 : for(int i=0; i<LMT_NUM_VALUES; i++)
74 4 : log_outputs[i].push_back(out);
75 1 : }
76 :
77 2 : void log_remove_output(ILogOutput *out)
78 : {
79 10 : for(int i=0; i<LMT_NUM_VALUES; i++){
80 : std::vector<ILogOutput*>::iterator it =
81 8 : std::find(log_outputs[i].begin(), log_outputs[i].end(), out);
82 8 : if(it != log_outputs[i].end())
83 5 : log_outputs[i].erase(it);
84 : }
85 2 : }
86 :
87 0 : void log_set_lev_silence(enum LogMessageLevel lev, bool silence)
88 : {
89 0 : JMutexAutoLock lock(log_threadnamemutex);
90 :
91 0 : for (std::vector<ILogOutput *>::iterator it = log_outputs[lev].begin();
92 0 : it != log_outputs[lev].end(); ++it) {
93 0 : ILogOutput *out = *it;
94 0 : out->silence = silence;
95 : }
96 0 : }
97 :
98 9 : void log_register_thread(const std::string &name)
99 : {
100 9 : threadid_t id = get_current_thread_id();
101 18 : JMutexAutoLock lock(log_threadnamemutex);
102 :
103 9 : log_threadnames[id] = name;
104 9 : }
105 :
106 4 : void log_deregister_thread()
107 : {
108 4 : threadid_t id = get_current_thread_id();
109 8 : JMutexAutoLock lock(log_threadnamemutex);
110 :
111 4 : log_threadnames.erase(id);
112 4 : }
113 :
114 47502 : static std::string get_lev_string(enum LogMessageLevel lev)
115 : {
116 47502 : switch(lev){
117 : case LMT_ERROR:
118 0 : return "ERROR";
119 : case LMT_ACTION:
120 0 : return "ACTION";
121 : case LMT_INFO:
122 29410 : return "INFO";
123 : case LMT_VERBOSE:
124 18092 : return "VERBOSE";
125 : case LMT_NUM_VALUES:
126 0 : break;
127 : }
128 0 : return "(unknown level)";
129 : }
130 :
131 47502 : void log_printline(enum LogMessageLevel lev, const std::string &text)
132 : {
133 95004 : JMutexAutoLock lock(log_threadnamemutex);
134 95004 : std::string threadname = "(unknown thread)";
135 47502 : std::map<threadid_t, std::string>::const_iterator i;
136 47502 : i = log_threadnames.find(get_current_thread_id());
137 47502 : if(i != log_threadnames.end())
138 47502 : threadname = i->second;
139 95004 : std::string levelname = get_lev_string(lev);
140 95004 : std::ostringstream os(std::ios_base::binary);
141 47502 : os << getTimestamp() << ": " << levelname << "["<<threadname<<"]: " << text;
142 :
143 142524 : for(std::vector<ILogOutput*>::iterator i = log_outputs[lev].begin();
144 95016 : i != log_outputs[lev].end(); i++) {
145 6 : ILogOutput *out = *i;
146 6 : if (out->silence)
147 0 : continue;
148 :
149 6 : out->printLog(os.str());
150 6 : out->printLog(os.str(), lev);
151 6 : out->printLog(lev, text);
152 : }
153 47502 : }
154 :
155 : class Logbuf : public std::streambuf
156 : {
157 : public:
158 4 : Logbuf(enum LogMessageLevel lev):
159 4 : m_lev(lev)
160 : {
161 4 : }
162 :
163 4 : ~Logbuf()
164 4 : {
165 4 : }
166 :
167 47498 : int overflow(int c)
168 : {
169 47498 : bufchar(c);
170 47498 : return c;
171 : }
172 186287 : std::streamsize xsputn(const char *s, std::streamsize n)
173 : {
174 3899554 : for(int i=0; i<n; i++)
175 3713267 : bufchar(s[i]);
176 186287 : return n;
177 : }
178 :
179 47498 : void printbuf()
180 : {
181 47498 : log_printline(m_lev, m_buf);
182 : #ifdef __ANDROID__
183 : __android_log_print(android_log_level_mapping[m_lev], PROJECT_NAME, "%s", m_buf.c_str());
184 : #endif
185 47498 : }
186 :
187 3760765 : void bufchar(char c)
188 : {
189 3760765 : if(c == '\n' || c == '\r'){
190 47498 : if(m_buf != "")
191 47498 : printbuf();
192 47498 : m_buf = "";
193 47498 : return;
194 : }
195 3713267 : m_buf += c;
196 : }
197 :
198 : private:
199 : enum LogMessageLevel m_lev;
200 : std::string m_buf;
201 : };
202 :
203 1 : Logbuf errorbuf(LMT_ERROR);
204 1 : Logbuf actionbuf(LMT_ACTION);
205 1 : Logbuf infobuf(LMT_INFO);
206 1 : Logbuf verbosebuf(LMT_VERBOSE);
207 1 : std::ostream errorstream(&errorbuf);
208 1 : std::ostream actionstream(&actionbuf);
209 1 : std::ostream infostream(&infobuf);
210 1 : std::ostream verbosestream(&verbosebuf);
211 :
212 3 : bool log_trace_level_enabled = false;
213 :
|