summaryrefslogtreecommitdiff
path: root/rbutil/rbutilqt/logger/Logger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/rbutilqt/logger/Logger.cpp')
-rw-r--r--rbutil/rbutilqt/logger/Logger.cpp370
1 files changed, 370 insertions, 0 deletions
diff --git a/rbutil/rbutilqt/logger/Logger.cpp b/rbutil/rbutilqt/logger/Logger.cpp
new file mode 100644
index 0000000000..33ba50ec58
--- /dev/null
+++ b/rbutil/rbutilqt/logger/Logger.cpp
@@ -0,0 +1,370 @@
1/*
2 Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com)
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License version 2.1
6 as published by the Free Software Foundation and appearing in the file
7 LICENSE.LGPL included in the packaging of this file.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13*/
14// Local
15#include "Logger.h"
16#include "AbstractAppender.h"
17
18// Qt
19#include <QCoreApplication>
20#include <QReadWriteLock>
21#include <QSemaphore>
22#include <QDateTime>
23#include <QIODevice>
24#include <QTextCodec>
25
26// STL
27#include <iostream>
28
29
30class LogDevice : public QIODevice
31{
32 public:
33 LogDevice()
34 : m_semaphore(1)
35 {}
36
37 void lock(Logger::LogLevel logLevel, const char* file, int line, const char* function)
38 {
39 m_semaphore.acquire();
40
41 if (!isOpen())
42 open(QIODevice::WriteOnly);
43
44 m_logLevel = logLevel;
45 m_file = file;
46 m_line = line;
47 m_function = function;
48 }
49
50 protected:
51 qint64 readData(char*, qint64)
52 {
53 return 0;
54 }
55
56 qint64 writeData(const char* data, qint64 maxSize)
57 {
58 if (maxSize > 0)
59 Logger::write(m_logLevel, m_file, m_line, m_function, QString::fromLocal8Bit(QByteArray(data, maxSize)));
60
61 m_semaphore.release();
62 return maxSize;
63 }
64
65 private:
66 QSemaphore m_semaphore;
67 Logger::LogLevel m_logLevel;
68 const char* m_file;
69 int m_line;
70 const char* m_function;
71};
72
73
74// Forward declarations
75static void cleanupLoggerPrivate();
76
77#if QT_VERSION >= 0x050000
78static void qtLoggerMessageHandler(QtMsgType, const QMessageLogContext& context, const QString& msg);
79#else
80static void qtLoggerMessageHandler(QtMsgType type, const char* msg);
81#endif
82
83/**
84 * \internal
85 *
86 * LoggerPrivate class implements the Singleton pattern in a thread-safe way. It uses a static pointer to itself
87 * protected by QReadWriteLock
88 *
89 * The appender list inside the LoggerPrivate class is also protected by QReadWriteLock so this class could be safely
90 * used in a multi-threaded application.
91 */
92class LoggerPrivate
93{
94 public:
95 static LoggerPrivate* m_self;
96 static QReadWriteLock m_selfLock;
97
98 static LoggerPrivate* instance()
99 {
100 LoggerPrivate* result = 0;
101 {
102 QReadLocker locker(&m_selfLock);
103 result = m_self;
104 }
105
106 if (!result)
107 {
108 QWriteLocker locker(&m_selfLock);
109 m_self = new LoggerPrivate;
110
111#if QT_VERSION >= 0x050000
112 qInstallMessageHandler(qtLoggerMessageHandler);
113#else
114 qInstallMsgHandler(qtLoggerMessageHandler);
115#endif
116 qAddPostRoutine(cleanupLoggerPrivate);
117 result = m_self;
118 }
119
120 return result;
121 }
122
123
124 LoggerPrivate()
125 : m_logDevice(0)
126 {}
127
128
129 ~LoggerPrivate()
130 {
131 // Cleanup appenders
132 QReadLocker appendersLocker(&m_appendersLock);
133 foreach (AbstractAppender* appender, m_appenders)
134 delete appender;
135
136 // Cleanup device
137 QReadLocker deviceLocker(&m_logDeviceLock);
138 delete m_logDevice;
139 }
140
141
142 void registerAppender(AbstractAppender* appender)
143 {
144 QWriteLocker locker(&m_appendersLock);
145
146 if (!m_appenders.contains(appender))
147 m_appenders.append(appender);
148 else
149 std::cerr << "Trying to register appender that was already registered" << std::endl;
150 }
151
152
153 LogDevice* logDevice()
154 {
155 LogDevice* result = 0;
156 {
157 QReadLocker locker(&m_logDeviceLock);
158 result = m_logDevice;
159 }
160
161 if (!result)
162 {
163 QWriteLocker locker(&m_logDeviceLock);
164 m_logDevice = new LogDevice;
165 result = m_logDevice;
166 }
167
168 return result;
169 }
170
171
172 void write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, const char* function,
173 const QString& message)
174 {
175 QReadLocker locker(&m_appendersLock);
176
177 if (!m_appenders.isEmpty())
178 {
179 foreach (AbstractAppender* appender, m_appenders)
180 appender->write(timeStamp, logLevel, file, line, function, message);
181 }
182 else
183 {
184 // Fallback
185 QString result = QString(QLatin1String("[%1] <%2> %3")).arg(Logger::levelToString(logLevel), -7)
186 .arg(function).arg(message);
187
188 std::cerr << qPrintable(result) << std::endl;
189 }
190
191 if (logLevel == Logger::Fatal)
192 abort();
193 }
194
195
196 void write(Logger::LogLevel logLevel, const char* file, int line, const char* function, const QString& message)
197 {
198 write(QDateTime::currentDateTime(), logLevel, file, line, function, message);
199 }
200
201
202 void write(Logger::LogLevel logLevel, const char* file, int line, const char* function, const char* message)
203 {
204 write(logLevel, file, line, function, QString(message));
205 }
206
207
208 QDebug write(Logger::LogLevel logLevel, const char* file, int line, const char* function)
209 {
210 LogDevice* d = logDevice();
211 d->lock(logLevel, file, line, function);
212 return QDebug(d);
213 }
214
215
216 void writeAssert(const char* file, int line, const char* function, const char* condition)
217 {
218 write(Logger::Fatal, file, line, function, QString("ASSERT: \"%1\"").arg(condition));
219 }
220
221 private:
222 QList<AbstractAppender*> m_appenders;
223 QReadWriteLock m_appendersLock;
224
225 LogDevice* m_logDevice;
226 QReadWriteLock m_logDeviceLock;
227};
228
229// Static fields initialization
230LoggerPrivate* LoggerPrivate::m_self = 0;
231QReadWriteLock LoggerPrivate::m_selfLock;
232
233
234static void cleanupLoggerPrivate()
235{
236 QWriteLocker locker(&LoggerPrivate::m_selfLock);
237
238 delete LoggerPrivate::m_self;
239 LoggerPrivate::m_self = 0;
240}
241
242
243#if QT_VERSION >= 0x050000
244static void qtLoggerMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
245{
246 Logger::LogLevel level;
247 switch (type)
248 {
249 case QtDebugMsg:
250 level = Logger::Debug;
251 break;
252 case QtWarningMsg:
253 level = Logger::Warning;
254 break;
255 case QtCriticalMsg:
256 level = Logger::Error;
257 break;
258 case QtFatalMsg:
259 level = Logger::Fatal;
260 break;
261 }
262
263 Logger::write(level, context.file, context.line, context.function, msg);
264}
265
266#else
267
268static void qtLoggerMessageHandler(QtMsgType type, const char* msg)
269{
270 switch (type)
271 {
272 case QtDebugMsg:
273 LOG_DEBUG(msg);
274 break;
275 case QtWarningMsg:
276 LOG_WARNING(msg);
277 break;
278 case QtCriticalMsg:
279 LOG_ERROR(msg);
280 break;
281 case QtFatalMsg:
282 LOG_FATAL(msg);
283 break;
284 }
285}
286#endif
287
288
289QString Logger::levelToString(Logger::LogLevel logLevel)
290{
291 switch (logLevel)
292 {
293 case Trace:
294 return QLatin1String("Trace");
295 case Debug:
296 return QLatin1String("Debug");
297 case Info:
298 return QLatin1String("Info");
299 case Warning:
300 return QLatin1String("Warning");
301 case Error:
302 return QLatin1String("Error");
303 case Fatal:
304 return QLatin1String("Fatal");
305 }
306
307 return QString();
308}
309
310
311Logger::LogLevel Logger::levelFromString(const QString& s)
312{
313 QString str = s.trimmed().toLower();
314
315 LogLevel result = Debug;
316
317 if (str == QLatin1String("trace"))
318 result = Trace;
319 else if (str == QLatin1String("debug"))
320 result = Debug;
321 else if (str == QLatin1String("info"))
322 result = Info;
323 else if (str == QLatin1String("warning"))
324 result = Warning;
325 else if (str == QLatin1String("error"))
326 result = Error;
327 else if (str == QLatin1String("fatal"))
328 result = Fatal;
329
330 return result;
331}
332
333
334void Logger::registerAppender(AbstractAppender* appender)
335{
336 LoggerPrivate::instance()->registerAppender(appender);
337}
338
339
340void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function,
341 const QString& message)
342{
343 LoggerPrivate::instance()->write(timeStamp, logLevel, file, line, function, message);
344}
345
346
347void Logger::write(LogLevel logLevel, const char* file, int line, const char* function, const QString& message)
348{
349 LoggerPrivate::instance()->write(logLevel, file, line, function, message);
350}
351
352
353void Logger::write(LogLevel logLevel, const char* file, int line, const char* function, const char* message, ...)
354{
355 va_list va;
356 va_start(va, message);
357 LoggerPrivate::instance()->write(logLevel, file, line, function, QString().vsprintf(message,va));
358 va_end(va);
359}
360
361QDebug Logger::write(LogLevel logLevel, const char* file, int line, const char* function)
362{
363 return LoggerPrivate::instance()->write(logLevel, file, line, function);
364}
365
366
367void Logger::writeAssert(const char* file, int line, const char* function, const char* condition)
368{
369 LoggerPrivate::instance()->writeAssert(file, line, function, condition);
370}