1 /* Logger.cpp */
2
3 /* Copyright (C) 2011-2020 Michael Lugmair (Lucio Carreras)
4 *
5 * This file is part of sayonara player
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "Utils/Utils.h"
22 #include "Utils/Settings/Settings.h"
23 #include "Utils/Logger/Logger.h"
24 #include "Utils/Logger/LogListener.h"
25
26
27 #include <QString>
28 #include <QStringList>
29 #include <QByteArray>
30 #include <QPoint>
31 #include <QDateTime>
32 #include <QSize>
33 #include <QMargins>
34 #include <QRect>
35 #include <QRegion>
36
37 #include "LoggerUtils.h"
38
39 #include <ostream>
40 #include <iostream>
41 #include <fstream>
42 #include <sstream>
43 #include <iomanip>
44
45 #ifdef Q_OS_UNIX
46 #define LOG_RED "\x1B[31m"
47 #define LOG_GREEN "\x1B[32m"
48 #define LOG_BLUE "\x1B[34m"
49 #define LOG_YELLOW "\x1B[33m"
50 #define LOG_COL_END "\x1B[0m"
51 #else
52 #define LOG_RED ""
53 #define LOG_GREEN ""
54 #define LOG_BLUE ""
55 #define LOG_YELLOW ""
56 #define LOG_COL_END ""
57 #endif
58
59 #ifdef SAYONARA_HAS_CXX_ABI
60 #include "cxxabi.h"
61 #endif
62
63 using LogListeners=QList<LogListener*>;
64 Q_GLOBAL_STATIC(LogListeners, log_listeners)
65
66 using LogEntries=QList<LogEntry>;
67 Q_GLOBAL_STATIC(LogEntries, log_buffer)
68
69 struct Logger::Private
70 {
71 QString class_name;
72 std::stringstream msg;
73 Log type;
74
PrivateLogger::Private75 Private() {}
76
~PrivateLogger::Private77 ~Private()
78 {
79 QString type_str;
80 std::string color;
81
82 bool ignore=false;
83
84 Settings* s = Settings::instance();
85 int logger_level = 0;
86
87 if(s->checkSettings()){
88 logger_level = GetSetting(Set::Logger_Level);
89 }
90
91 switch(type)
92 {
93 case Log::Info:
94 color = LOG_GREEN;
95 type_str = "Info";
96 break;
97 case Log::Warning:
98 color = LOG_RED;
99 type_str = "Warning";
100 break;
101 case Log::Error:
102 color = LOG_RED;
103 type_str = "Error";
104 break;
105 case Log::Debug:
106 color = LOG_YELLOW;
107 type_str = "Debug";
108 if(logger_level < 1) {
109 ignore = true;
110 }
111 break;
112 case Log::Develop:
113 color = LOG_YELLOW;
114 type_str = "Dev";
115 if(logger_level < 2){
116 ignore = true;
117 }
118 break;
119 case Log::Crazy:
120 color = LOG_YELLOW;
121 type_str = "CrazyLog";
122 if(logger_level < 3){
123 ignore = true;
124 }
125
126 break;
127 case Log::Always:
128 [[fallthrough]];
129 default:
130 color = LOG_YELLOW;
131 type_str = "";
132 break;
133 }
134
135 if(!ignore)
136 {
137 QString date_time = QDateTime::currentDateTime().toString("hh:mm:ss");
138
139 std::string str(msg.str());
140 std::clog
141 << "[" << date_time.toStdString() << "] "
142 << color
143 << type_str.toStdString() << ": "
144 << LOG_COL_END;
145
146 if(!class_name.isEmpty()) {
147 std::clog << LOG_BLUE << class_name.toStdString() << ": " << LOG_COL_END;
148 }
149
150 std::clog << str;
151 std::clog << std::endl;
152
153 LogEntry le;
154 le.className = class_name;
155 le.message = QString::fromStdString(str);
156 le.type = type;
157
158 log_buffer->push_back(le);
159
160 for(auto it=log_listeners->begin(); it != log_listeners->end(); it++)
161 {
162 LogListener* log_listener = *it;
163 if(log_listener)
164 {
165 log_listener->addLogLine(le);
166 }
167 }
168 }
169
170 msg.clear();
171 }
172 };
173
174
Logger(const Log & type,const QString & class_name)175 Logger::Logger(const Log& type, const QString& class_name)
176 {
177 m = new Logger::Private();
178
179 m->type = type;
180 m->class_name = class_name;
181 }
182
~Logger()183 Logger::~Logger()
184 {
185 delete m;
186 m = nullptr;
187 }
188
189 //static
registerLogListener(LogListener * log_listener)190 void Logger::registerLogListener(LogListener* log_listener)
191 {
192 for(auto it=log_buffer->begin(); it != log_buffer->end(); it++)
193 {
194 log_listener->addLogLine(*it);
195 }
196
197 log_listeners->push_back(log_listener);
198 }
199
200
operator <<(const QString & msg)201 Logger& Logger::operator << (const QString& msg)
202 {
203 (*this) << msg.toLocal8Bit().constData();
204 return *this;
205 }
206
operator <<(const QStringList & lst)207 Logger& Logger::operator << (const QStringList& lst)
208 {
209 (*this) << lst.join(",");
210
211 return *this;
212 }
213
operator <<(const QChar & c)214 Logger& Logger::operator << (const QChar& c)
215 {
216 (*this) << c.toLatin1();
217
218 return *this;
219 }
220
operator <<(const QPoint & point)221 Logger& Logger::operator << (const QPoint& point)
222 {
223 (*this) << "Point(" << point.x() << "," << point.y() << ")";
224 return *this;
225 }
226
operator <<(const QSize & size)227 Logger& Logger::operator <<(const QSize& size)
228 {
229 (*this) << "Size(" << size.width() << "," << size.height() << ")";
230 return *this;
231 }
232
operator <<(const QRect & r)233 Logger& Logger::operator <<(const QRect& r)
234 {
235 (*this) << "Rect("
236 << "left:" << r.left()
237 << ", right:" << r.right()
238 << ", top:" << r.top()
239 << ", bottom:" << r.bottom()
240 << ", width:" << r.width()
241 << ", heigh:" << r.height();
242 return *this;
243 }
244
245
operator <<(const QByteArray & arr)246 Logger& Logger::operator << (const QByteArray& arr)
247 {
248 m->msg << std::endl;
249
250 QString line_str;
251
252 for(int i=0; i<arr.size(); i++)
253 {
254 char c = arr[i];
255
256 QChar qc = QChar(c);
257
258 if(qc.isPrint()){
259 line_str += qc;
260 }
261
262 else{
263 line_str += ".";
264 }
265
266 m->msg << std::hex << (unsigned int) (c & (0xff)) << " ";
267
268 if(i % 8 == 7)
269 {
270 m->msg << "\t";
271 m->msg << line_str.toLocal8Bit().constData() << std::endl;
272
273 line_str.clear();
274 }
275 }
276
277 if(!line_str.isEmpty())
278 {
279 for(int i=0; i<8-line_str.size(); i++)
280 {
281 m->msg << " ";
282 }
283
284 m->msg << "\t" << line_str.toLocal8Bit().constData() << std::endl;
285 }
286
287 return *this;
288 }
289
operator <<(const char * str)290 Logger& Logger::operator << (const char* str)
291 {
292 m->msg << str;
293
294 return *this;
295 }
296
operator <<(const std::string & str)297 Logger& Logger::operator << (const std::string& str)
298 {
299 (*this) << str.c_str();
300 return *this;
301 }
302
303
304 /*************************
305 * Static Log functions
306 * ***********************/
spLog(const Log & type,const std::string & data)307 Logger spLog(const Log& type, const std::string& data)
308 {
309 QString class_name;
310 if(!data.empty())
311 {
312 #ifdef SAYONARA_HAS_CXX_ABI
313 int status;
314 char* content = abi::__cxa_demangle(data.c_str(), nullptr, nullptr, &status);
315 if(content && strnlen(content, 3) > 1){
316 class_name = QString(content);
317 free(content);
318 }
319 else {
320 class_name = QString::fromStdString(data);
321 }
322
323 #else
324 class_name = QString::fromStdString(data);
325 #endif
326 }
327
328 return Logger(type, class_name);
329 }
330
spLog(const Log & type,const char * data)331 Logger spLog(const Log& type, const char* data)
332 {
333 return spLog(type, std::string(data));
334 }
335