diff options
author | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2020-06-08 21:13:11 +0200 |
---|---|---|
committer | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2020-08-08 10:01:42 +0200 |
commit | 48d2927ecca77ec7f0876960bff624d5d39a4e0f (patch) | |
tree | 26a739aed7a63fa1a3cc611f77ef100509ed2138 | |
parent | c425d4627ea7a0df3db12600d832de276c691e8b (diff) | |
download | rockbox-48d2927ecca77ec7f0876960bff624d5d39a4e0f.tar.gz rockbox-48d2927ecca77ec7f0876960bff624d5d39a4e0f.zip |
rbutil: Update CuteLogger to most recent upstream.
Update to the most recent git version.
This changes the folder structure and renames some classes to follow
upstream.
Restore MSVC static link fix, and fix wrong variable in qmake project file.
Change-Id: I874bb9ed60e37af09a841988e771fd341414d145
24 files changed, 2201 insertions, 1242 deletions
diff --git a/rbutil/rbutilqt/logger/AbstractAppender.cpp b/rbutil/rbutilqt/logger/AbstractAppender.cpp deleted file mode 100644 index de86b930d0..0000000000 --- a/rbutil/rbutilqt/logger/AbstractAppender.cpp +++ /dev/null | |||
@@ -1,58 +0,0 @@ | |||
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 "AbstractAppender.h" | ||
16 | |||
17 | // Qt | ||
18 | #include <QMutexLocker> | ||
19 | |||
20 | |||
21 | AbstractAppender::AbstractAppender() | ||
22 | : m_detailsLevel(Logger::Debug) | ||
23 | {} | ||
24 | |||
25 | |||
26 | AbstractAppender::~AbstractAppender() | ||
27 | {} | ||
28 | |||
29 | |||
30 | Logger::LogLevel AbstractAppender::detailsLevel() const | ||
31 | { | ||
32 | QMutexLocker locker(&m_detailsLevelMutex); | ||
33 | return m_detailsLevel; | ||
34 | } | ||
35 | |||
36 | |||
37 | void AbstractAppender::setDetailsLevel(Logger::LogLevel level) | ||
38 | { | ||
39 | QMutexLocker locker(&m_detailsLevelMutex); | ||
40 | m_detailsLevel = level; | ||
41 | } | ||
42 | |||
43 | |||
44 | void AbstractAppender::setDetailsLevel(const QString& level) | ||
45 | { | ||
46 | setDetailsLevel(Logger::levelFromString(level)); | ||
47 | } | ||
48 | |||
49 | |||
50 | void AbstractAppender::write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | ||
51 | const char* function, const QString& message) | ||
52 | { | ||
53 | if (logLevel >= detailsLevel()) | ||
54 | { | ||
55 | QMutexLocker locker(&m_writeMutex); | ||
56 | append(timeStamp, logLevel, file, line, function, message); | ||
57 | } | ||
58 | } | ||
diff --git a/rbutil/rbutilqt/logger/AbstractAppender.h b/rbutil/rbutilqt/logger/AbstractAppender.h deleted file mode 100644 index df1df4957c..0000000000 --- a/rbutil/rbutilqt/logger/AbstractAppender.h +++ /dev/null | |||
@@ -1,125 +0,0 @@ | |||
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 | #ifndef ABSTRACTAPPENDER_H | ||
15 | #define ABSTRACTAPPENDER_H | ||
16 | |||
17 | // Local | ||
18 | #include "CuteLogger_global.h" | ||
19 | #include <Logger.h> | ||
20 | |||
21 | // Qt | ||
22 | #include <QMutex> | ||
23 | |||
24 | //! The AbstractAppender class provides an abstract base class for writing a log entries. | ||
25 | /** | ||
26 | * The AbstractAppender class is the base interface class for all log appenders that could be used with Logger. | ||
27 | * | ||
28 | * AbstractAppender provides a common implementation for the thread safe, mutex-protected logging of application | ||
29 | * messages, such as ConsoleAppender, FileAppender or something else. AbstractAppender is abstract and can not be | ||
30 | * instantiated, but you can use any of its subclasses or create a custom log appender at your choice. | ||
31 | * | ||
32 | * Appenders are the logical devices that is aimed to be attached to Logger object by calling | ||
33 | * Logger::registerAppender(). On each log record call from the application Logger object sequentially calls write() | ||
34 | * function on all the appenders registered in it. | ||
35 | * | ||
36 | * You can subclass AbstractAppender to implement a logging target of any kind you like. It may be the external logging | ||
37 | * subsystem (for example, syslog in *nix), XML file, SQL database entries, D-Bus messages or anything else you can | ||
38 | * imagine. | ||
39 | * | ||
40 | * For the simple non-structured plain text logging (for example, to a plain text file or to the console output) you may | ||
41 | * like to subclass the AbstractStringAppender instead of AbstractAppender, which will give you a more convinient way to | ||
42 | * control the format of the log output. | ||
43 | * | ||
44 | * \sa AbstractStringAppender | ||
45 | * \sa Logger::registerAppender() | ||
46 | */ | ||
47 | class CUTELOGGERSHARED_EXPORT AbstractAppender | ||
48 | { | ||
49 | public: | ||
50 | //! Constructs a AbstractAppender object. | ||
51 | AbstractAppender(); | ||
52 | |||
53 | //! Destructs the AbstractAppender object. | ||
54 | virtual ~AbstractAppender(); | ||
55 | |||
56 | //! Returns the current details level of appender. | ||
57 | /** | ||
58 | * Log records with a log level lower than a current detailsLevel() will be silently ignored by appender and would not | ||
59 | * be sent to its append() function. | ||
60 | * | ||
61 | * It provides additional logging flexibility, allowing you to set the different severity levels for different types | ||
62 | * of logs. | ||
63 | * | ||
64 | * \note This function is thread safe. | ||
65 | * | ||
66 | * \sa setDetailsLevel() | ||
67 | * \sa Logger::LogLevel | ||
68 | */ | ||
69 | Logger::LogLevel detailsLevel() const; | ||
70 | |||
71 | //! Sets the current details level of appender. | ||
72 | /** | ||
73 | * \note This function is thread safe. | ||
74 | * | ||
75 | * \sa detalsLevel() | ||
76 | * \sa Logger::LogLevel | ||
77 | */ | ||
78 | void setDetailsLevel(Logger::LogLevel level); | ||
79 | |||
80 | //! Sets the current details level of appender | ||
81 | /** | ||
82 | * This function is provided for convinience, it behaves like an above function. | ||
83 | * | ||
84 | * \sa detalsLevel() | ||
85 | * \sa Logger::LogLevel | ||
86 | */ | ||
87 | void setDetailsLevel(const QString& level); | ||
88 | |||
89 | //! Tries to write the log record to this logger | ||
90 | /** | ||
91 | * This is the function called by Logger object to write a log message to the appender. | ||
92 | * | ||
93 | * \note This function is thread safe. | ||
94 | * | ||
95 | * \sa Logger::write() | ||
96 | * \sa detailsLevel() | ||
97 | */ | ||
98 | void write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, const char* function, | ||
99 | const QString& message); | ||
100 | |||
101 | protected: | ||
102 | //! Writes the log record to the logger instance | ||
103 | /** | ||
104 | * This function is called every time when user tries to write a message to this AbstractAppender instance using | ||
105 | * the write() function. Write function works as proxy and transfers only the messages with log level more or equal | ||
106 | * to the current logLevel(). | ||
107 | * | ||
108 | * Overload this function when you are implementing a custom appender. | ||
109 | * | ||
110 | * \note This function is not needed to be thread safe because it is never called directly by Logger object. The | ||
111 | * write() function works as a proxy and protects this function from concurrent access. | ||
112 | * | ||
113 | * \sa Logger::write() | ||
114 | */ | ||
115 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | ||
116 | const char* function, const QString& message) = 0; | ||
117 | |||
118 | private: | ||
119 | QMutex m_writeMutex; | ||
120 | |||
121 | Logger::LogLevel m_detailsLevel; | ||
122 | mutable QMutex m_detailsLevelMutex; | ||
123 | }; | ||
124 | |||
125 | #endif // ABSTRACTAPPENDER_H | ||
diff --git a/rbutil/rbutilqt/logger/AbstractStringAppender.cpp b/rbutil/rbutilqt/logger/AbstractStringAppender.cpp deleted file mode 100644 index 073ecb7782..0000000000 --- a/rbutil/rbutilqt/logger/AbstractStringAppender.cpp +++ /dev/null | |||
@@ -1,161 +0,0 @@ | |||
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 "AbstractStringAppender.h" | ||
16 | |||
17 | // Qt | ||
18 | #include <QReadLocker> | ||
19 | #include <QWriteLocker> | ||
20 | #include <QDateTime> | ||
21 | #include <QRegExp> | ||
22 | |||
23 | const char formattingMarker = '%'; | ||
24 | |||
25 | AbstractStringAppender::AbstractStringAppender() | ||
26 | : m_format(QLatin1String("%t{yyyy-MM-ddTHH:mm:ss.zzz} [%-7l] <%c> %m\n")) | ||
27 | {} | ||
28 | |||
29 | |||
30 | QString AbstractStringAppender::format() const | ||
31 | { | ||
32 | QReadLocker locker(&m_formatLock); | ||
33 | return m_format; | ||
34 | } | ||
35 | |||
36 | |||
37 | void AbstractStringAppender::setFormat(const QString& format) | ||
38 | { | ||
39 | QWriteLocker locker(&m_formatLock); | ||
40 | m_format = format; | ||
41 | } | ||
42 | |||
43 | |||
44 | QString AbstractStringAppender::stripFunctionName(const char* name) | ||
45 | { | ||
46 | QRegExp rx("^.+\\s((?:[\\w\\d]+::)+)?([\\w\\d\\<\\>~]+)(?:\\(.*\\)).*$"); // XXX: SLOW! | ||
47 | return QString::fromLatin1(name).replace(rx, QString(QLatin1String("\\1\\2"))); | ||
48 | } | ||
49 | |||
50 | |||
51 | QString AbstractStringAppender::formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, | ||
52 | int line, const char* function, const QString& message) const | ||
53 | { | ||
54 | QString f = format(); | ||
55 | const int size = f.size(); | ||
56 | |||
57 | QString result; | ||
58 | |||
59 | int i = 0; | ||
60 | while (i < f.size()) | ||
61 | { | ||
62 | QChar c = f.at(i); | ||
63 | |||
64 | // We will silently ignore the broken % marker at the end of string | ||
65 | if (c != QLatin1Char(formattingMarker) || (i + 1) == size) | ||
66 | { | ||
67 | result.append(c); | ||
68 | } | ||
69 | else | ||
70 | { | ||
71 | QChar command = f.at(++i); | ||
72 | |||
73 | // Check for the padding instruction | ||
74 | int fieldWidth = 0; | ||
75 | if (command.isDigit() || command.category() == QChar::Punctuation_Dash) | ||
76 | { | ||
77 | int j = 1; | ||
78 | while ((i + j) < size && f.at(i + j).isDigit()) | ||
79 | j++; | ||
80 | fieldWidth = f.mid(i, j).toInt(); | ||
81 | |||
82 | i += j; | ||
83 | command = f.at(i); | ||
84 | } | ||
85 | |||
86 | // Log record chunk to insert instead of formatting instruction | ||
87 | QString chunk; | ||
88 | |||
89 | // Time stamp | ||
90 | if (command == QLatin1Char('t')) | ||
91 | { | ||
92 | if (f.at(i + 1) == QLatin1Char('{')) | ||
93 | { | ||
94 | int j = 1; | ||
95 | while ((i + 2 + j) < size && f.at(i + 2 + j) != QLatin1Char('}')) | ||
96 | j++; | ||
97 | |||
98 | if ((i + 2 + j) < size) | ||
99 | { | ||
100 | chunk = timeStamp.toString(f.mid(i + 2, j)); | ||
101 | |||
102 | i += j; | ||
103 | i += 2; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | if (chunk.isNull()) | ||
108 | chunk = timeStamp.toString(QLatin1String("HH:mm:ss.zzz")); | ||
109 | } | ||
110 | |||
111 | // Log level | ||
112 | else if (command == QLatin1Char('l')) | ||
113 | chunk = Logger::levelToString(logLevel); | ||
114 | |||
115 | // Uppercased log level | ||
116 | else if (command == QLatin1Char('L')) | ||
117 | chunk = Logger::levelToString(logLevel).toUpper(); | ||
118 | |||
119 | // Filename | ||
120 | else if (command == QLatin1Char('F')) | ||
121 | chunk = QLatin1String(file); | ||
122 | |||
123 | // Filename without a path | ||
124 | else if (command == QLatin1Char('f')) | ||
125 | chunk = QString(QLatin1String(file)).section('/', -1); | ||
126 | |||
127 | // Source line number | ||
128 | else if (command == QLatin1Char('i')) | ||
129 | chunk = QString::number(line); | ||
130 | |||
131 | // Function name, as returned by Q_FUNC_INFO | ||
132 | else if (command == QLatin1Char('C')) | ||
133 | chunk = QString::fromLatin1(function); | ||
134 | |||
135 | // Stripped function name | ||
136 | else if (command == QLatin1Char('c')) | ||
137 | chunk = stripFunctionName(function); | ||
138 | |||
139 | // Log message | ||
140 | else if (command == QLatin1Char('m')) | ||
141 | chunk = message; | ||
142 | |||
143 | // We simply replace the double formatting marker (%) with one | ||
144 | else if (command == QLatin1Char(formattingMarker)) | ||
145 | chunk = QLatin1Char(formattingMarker); | ||
146 | |||
147 | // Do not process any unknown commands | ||
148 | else | ||
149 | { | ||
150 | chunk = QLatin1Char(formattingMarker); | ||
151 | chunk.append(command); | ||
152 | } | ||
153 | |||
154 | result.append(QString(QLatin1String("%1")).arg(chunk, fieldWidth)); | ||
155 | } | ||
156 | |||
157 | ++i; | ||
158 | } | ||
159 | |||
160 | return result; | ||
161 | } | ||
diff --git a/rbutil/rbutilqt/logger/AbstractStringAppender.h b/rbutil/rbutilqt/logger/AbstractStringAppender.h deleted file mode 100644 index 3cef63bff9..0000000000 --- a/rbutil/rbutilqt/logger/AbstractStringAppender.h +++ /dev/null | |||
@@ -1,116 +0,0 @@ | |||
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 | #ifndef ABSTRACTSTRINGAPPENDER_H | ||
15 | #define ABSTRACTSTRINGAPPENDER_H | ||
16 | |||
17 | // Local | ||
18 | #include "CuteLogger_global.h" | ||
19 | #include <AbstractAppender.h> | ||
20 | |||
21 | // Qt | ||
22 | #include <QReadWriteLock> | ||
23 | |||
24 | |||
25 | //! The AbstractStringAppender class provides a convinient base for appenders working with plain text formatted logs. | ||
26 | /** | ||
27 | * AbstractSringAppender is the simple extension of the AbstractAppender class providing the convinient way to create | ||
28 | * custom log appenders working with a plain text formatted log targets. | ||
29 | * | ||
30 | * It have the formattedString() protected function that formats the logging arguments according to a format set with | ||
31 | * setFormat(). | ||
32 | * | ||
33 | * This class can not be directly instantiated because it contains pure virtual function inherited from AbstractAppender | ||
34 | * class. | ||
35 | * | ||
36 | * For more detailed description of customizing the log output format see the documentation on the setFormat() function. | ||
37 | */ | ||
38 | class CUTELOGGERSHARED_EXPORT AbstractStringAppender : public AbstractAppender | ||
39 | { | ||
40 | public: | ||
41 | //! Constructs a new string appender object | ||
42 | AbstractStringAppender(); | ||
43 | |||
44 | //! Returns the current log format string. | ||
45 | /** | ||
46 | * The default format is set to "%t{yyyy-MM-ddTHH:mm:ss.zzz} [%-7l] <%C> %m\n". You can set a different log record | ||
47 | * format using the setFormat() function. | ||
48 | * | ||
49 | * \sa setFormat(const QString&) | ||
50 | */ | ||
51 | QString format() const; | ||
52 | |||
53 | //! Sets the logging format for writing strings to the log target with this appender. | ||
54 | /** | ||
55 | * The string format seems to be very common to those developers who have used a standart sprintf function. | ||
56 | * | ||
57 | * Log output format is a simple QString with the special markers (starting with % sign) which will be replaced with | ||
58 | * it's internal meaning when writing a log record. | ||
59 | * | ||
60 | * Controlling marker begins with the percent sign (%) which is followed by (optional) field width argument, the | ||
61 | * (necessary) single-letter command (which describes, what will be put to log record instead of marker, and an | ||
62 | * additional formatting argument (in the {} brackets) supported for some of the log commands. | ||
63 | * | ||
64 | * Field width argument works almost identically to the \c QString::arg() \c fieldWidth argument (and uses it | ||
65 | * internally). For example, \c "%-7l" will be replaced with the left padded debug level of the message | ||
66 | * (\c "Debug ") or something. For the more detailed description of it you may consider to look to the Qt | ||
67 | * Reference Documentation. | ||
68 | * | ||
69 | * Supported marker commands are: | ||
70 | * \arg \c %t - timestamp. You may specify your custom timestamp format using the {} brackets after the marker, | ||
71 | * timestamp format here will be similiar to those used in QDateTime::toString() function. For example, | ||
72 | * "%t{dd-MM-yyyy, HH:mm}" may be replaced with "17-12-2010, 20:17" depending on current date and time. | ||
73 | * The default format used here is "HH:mm:ss.zzz". | ||
74 | * \arg \c %l - Log level. Possible log levels are shown in the Logger::LogLevel enumerator. | ||
75 | * \arg \c %L - Uppercased log level. | ||
76 | * \arg \c %F - Full source file name (with path) of the file that requested log recording. Uses the \c __FILE__ | ||
77 | * preprocessor macro. | ||
78 | * \arg \c %f - Short file name (with stripped path). | ||
79 | * \arg \c %i - Line number in the source file. Uses the \c __LINE__ preprocessor macro. | ||
80 | * \arg \c %C - Name of function that called on of the LOG_* macros. Uses the \c Q_FUNC_INFO macro provided with | ||
81 | * Qt. | ||
82 | * \arg \c %c - [EXPERIMENTAL] Similiar to the %C, but the function name is stripped using stripFunctionName | ||
83 | * \arg \c %m - The log message sent by the caller. | ||
84 | * \arg \c %% - Convinient marker that is replaced with the single \c % mark. | ||
85 | * | ||
86 | * \note Format doesn't add \c '\\n' to the end of the format line. Please consider adding it manually. | ||
87 | * | ||
88 | * \sa format() | ||
89 | * \sa stripFunctionName() | ||
90 | * \sa Logger::LogLevel | ||
91 | */ | ||
92 | void setFormat(const QString&); | ||
93 | |||
94 | //! Strips the long function signature (as added by Q_FUNC_INFO macro) | ||
95 | /** | ||
96 | * The string processing drops the returning type, arguments and template parameters of function. It is definitely | ||
97 | * useful for enchancing the log output readability. | ||
98 | * \return stripped function name | ||
99 | */ | ||
100 | static QString stripFunctionName(const char*); | ||
101 | |||
102 | protected: | ||
103 | //! Returns the string to record to the logging target, formatted according to the format(). | ||
104 | /** | ||
105 | * \sa format() | ||
106 | * \sa setFormat(const QString&) | ||
107 | */ | ||
108 | QString formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | ||
109 | const char* function, const QString& message) const; | ||
110 | |||
111 | private: | ||
112 | QString m_format; | ||
113 | mutable QReadWriteLock m_formatLock; | ||
114 | }; | ||
115 | |||
116 | #endif // ABSTRACTSTRINGAPPENDER_H | ||
diff --git a/rbutil/rbutilqt/logger/ConsoleAppender.cpp b/rbutil/rbutilqt/logger/ConsoleAppender.cpp deleted file mode 100644 index da4a43c740..0000000000 --- a/rbutil/rbutilqt/logger/ConsoleAppender.cpp +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
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 "ConsoleAppender.h" | ||
16 | |||
17 | // STL | ||
18 | #include <iostream> | ||
19 | |||
20 | |||
21 | void ConsoleAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | ||
22 | const char* function, const QString& message) | ||
23 | { | ||
24 | std::cerr << qPrintable(formattedString(timeStamp, logLevel, file, line, function, message)); | ||
25 | } | ||
diff --git a/rbutil/rbutilqt/logger/Logger.cpp b/rbutil/rbutilqt/logger/Logger.cpp deleted file mode 100644 index 33ba50ec58..0000000000 --- a/rbutil/rbutilqt/logger/Logger.cpp +++ /dev/null | |||
@@ -1,370 +0,0 @@ | |||
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 | |||
30 | class 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 | ||
75 | static void cleanupLoggerPrivate(); | ||
76 | |||
77 | #if QT_VERSION >= 0x050000 | ||
78 | static void qtLoggerMessageHandler(QtMsgType, const QMessageLogContext& context, const QString& msg); | ||
79 | #else | ||
80 | static 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 | */ | ||
92 | class 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 | ||
230 | LoggerPrivate* LoggerPrivate::m_self = 0; | ||
231 | QReadWriteLock LoggerPrivate::m_selfLock; | ||
232 | |||
233 | |||
234 | static 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 | ||
244 | static 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 | |||
268 | static 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 | |||
289 | QString 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 | |||
311 | Logger::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 | |||
334 | void Logger::registerAppender(AbstractAppender* appender) | ||
335 | { | ||
336 | LoggerPrivate::instance()->registerAppender(appender); | ||
337 | } | ||
338 | |||
339 | |||
340 | void 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 | |||
347 | void 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 | |||
353 | void 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 | |||
361 | QDebug 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 | |||
367 | void Logger::writeAssert(const char* file, int line, const char* function, const char* condition) | ||
368 | { | ||
369 | LoggerPrivate::instance()->writeAssert(file, line, function, condition); | ||
370 | } | ||
diff --git a/rbutil/rbutilqt/logger/Logger.h b/rbutil/rbutilqt/logger/Logger.h deleted file mode 100644 index d056dfc25d..0000000000 --- a/rbutil/rbutilqt/logger/Logger.h +++ /dev/null | |||
@@ -1,319 +0,0 @@ | |||
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 | #ifndef LOGGER_H | ||
15 | #define LOGGER_H | ||
16 | /** | ||
17 | * \file Logger.h | ||
18 | * \brief A file containing the description of Logger class and and additional useful macros for logging | ||
19 | */ | ||
20 | |||
21 | // Qt | ||
22 | #include <QString> | ||
23 | #include <QDebug> | ||
24 | class QDateTime; | ||
25 | |||
26 | // Local | ||
27 | #include "CuteLogger_global.h" | ||
28 | class AbstractAppender; | ||
29 | |||
30 | |||
31 | //! Writes the trace log record | ||
32 | /** | ||
33 | * This macro is the convinient way to call Logger::write(). It uses the common preprocessor macros \c __FILE__, | ||
34 | * \c __LINE__ and the standart Qt \c Q_FUNC_INFO macros to automatically determine the needed parameters to call | ||
35 | * Logger::write(). | ||
36 | * | ||
37 | * \note This and other (LOG_INFO() etc...) macros uses the variadic macro arguments to give convinient usage form for | ||
38 | * the different versions of Logger::write() (using the QString or const char* argument or returning the QDebug class | ||
39 | * instance). Not all compilers will support this. Please, consider reviewing your compiler documentation to ensure | ||
40 | * it support __VA_ARGS__ macro. | ||
41 | * | ||
42 | * It is checked to work with GCC 4.4 or later. | ||
43 | * | ||
44 | * \sa Logger::LogLevel | ||
45 | * \sa Logger::write() | ||
46 | */ | ||
47 | #define LOG_TRACE(...) Logger::write(Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__) | ||
48 | |||
49 | //! Writes the debug log record | ||
50 | /** | ||
51 | * This macro records the info log record using the Logger::write() function. It works identically to the LOG_TRACE() | ||
52 | * macro. | ||
53 | * | ||
54 | * \sa LOG_TRACE() | ||
55 | * \sa Logger::LogLevel | ||
56 | * \sa Logger::write() | ||
57 | */ | ||
58 | #define LOG_DEBUG(...) Logger::write(Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__) | ||
59 | |||
60 | //! Write the info log record | ||
61 | /** | ||
62 | * This macro records the info log record using the Logger::write() function. It works identically to the LOG_TRACE() | ||
63 | * macro. | ||
64 | * | ||
65 | * \sa LOG_TRACE() | ||
66 | * \sa Logger::LogLevel | ||
67 | * \sa Logger::write() | ||
68 | */ | ||
69 | #define LOG_INFO(...) Logger::write(Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__) | ||
70 | |||
71 | //! Write the warning log record | ||
72 | /** | ||
73 | * This macro records the warning log record using the Logger::write() function. It works identically to the LOG_TRACE() | ||
74 | * macro. | ||
75 | * | ||
76 | * \sa LOG_TRACE() | ||
77 | * \sa Logger::LogLevel | ||
78 | * \sa Logger::write() | ||
79 | */ | ||
80 | #define LOG_WARNING(...) Logger::write(Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__) | ||
81 | |||
82 | //! Write the error log record | ||
83 | /** | ||
84 | * This macro records the error log record using the Logger::write() function. It works identically to the LOG_TRACE() | ||
85 | * macro. | ||
86 | * | ||
87 | * \sa LOG_TRACE() | ||
88 | * \sa Logger::LogLevel | ||
89 | * \sa Logger::write() | ||
90 | */ | ||
91 | #define LOG_ERROR(...) Logger::write(Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__) | ||
92 | |||
93 | //! Write the fatal log record | ||
94 | /** | ||
95 | * This macro records the fatal log record using the Logger::write() function. It works identically to the LOG_TRACE() | ||
96 | * macro. | ||
97 | * | ||
98 | * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() | ||
99 | * function, which will interrupt the running of your software and begin the writing of the core dump. | ||
100 | * | ||
101 | * \sa LOG_TRACE() | ||
102 | * \sa Logger::LogLevel | ||
103 | * \sa Logger::write() | ||
104 | */ | ||
105 | #define LOG_FATAL(...) Logger::write(Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__) | ||
106 | |||
107 | //! Check the assertion | ||
108 | /** | ||
109 | * This macro is a convinient and recommended to use way to call Logger::writeAssert() function. It uses the | ||
110 | * preprocessor macros (as the LOG_DEBUG() does) to fill the necessary arguments of the Logger::writeAssert() call. It | ||
111 | * also uses undocumented but rather mature and stable \c qt_noop() function (which does nothing) when the assertion | ||
112 | * is true. | ||
113 | * | ||
114 | * Example: | ||
115 | * \code | ||
116 | * bool b = checkSomething(); | ||
117 | * ... | ||
118 | * LOG_ASSERT(b == true); | ||
119 | * \endcode | ||
120 | * | ||
121 | * \sa Logger::writeAssert() | ||
122 | */ | ||
123 | #define LOG_ASSERT(cond) ((!(cond)) ? Logger::writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, #cond) : qt_noop()) | ||
124 | |||
125 | |||
126 | /** | ||
127 | * \mainpage | ||
128 | * | ||
129 | * Logger is a simple way to write the history of your application lifecycle to any target logging device (which is | ||
130 | * called Appender and may write to any target you will implement with it: console, text file, XML or something - you | ||
131 | * choose) and to map logging message to a class, function, source file and line of code which it is called from. | ||
132 | * | ||
133 | * Some simple appenders (which may be considered an examples) are provided with the logger itself: see ConsoleAppender | ||
134 | * and FileAppender documentation. | ||
135 | * | ||
136 | * It supports using it in a multithreaded applications, so ALL of its functions are thread safe. | ||
137 | * | ||
138 | * Simple usage example: | ||
139 | * \code | ||
140 | * #include <QCoreApplication> | ||
141 | * | ||
142 | * #include <Logger.h> | ||
143 | * #include <ConsoleAppender.h> | ||
144 | * | ||
145 | * int main(int argc, char* argv[]) | ||
146 | * { | ||
147 | * QCoreApplication app(argc, argv); | ||
148 | * ... | ||
149 | * ConsoleAppender* consoleAppender = new ConsoleAppender(); | ||
150 | * consoleAppender->setFormat("[%-7l] <%C> %m\n"); | ||
151 | * Logger::registerAppender(consoleAppender); | ||
152 | * ... | ||
153 | * LOG_INFO("Starting the application"); | ||
154 | * int result = app.exec(); | ||
155 | * ... | ||
156 | * if (result) | ||
157 | * LOG_WARNING() << "Something went wrong." << "Result code is" << result; | ||
158 | * | ||
159 | * return result; | ||
160 | * } | ||
161 | * \endcode | ||
162 | * | ||
163 | * Logger internally uses the lazy-initialized singleton object and needs no definite initialization, but you may | ||
164 | * consider registering a log appender before calling any log recording functions or macros. | ||
165 | * | ||
166 | * The library design of Logger allows you to simply mass-replace all occurrences of qDebug and similiar calls with | ||
167 | * similiar Logger macros (e.g. LOG_DEBUG) | ||
168 | * | ||
169 | * \note Logger uses a singleton class which must live through all the application life cycle and cleans it on the | ||
170 | * destruction of the QCoreApplication (or QApplication) instance. It needs a QCoreApplication instance to be | ||
171 | * created before any of the Logger's functions are called. | ||
172 | * | ||
173 | * \sa AbstractAppender | ||
174 | * \sa LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL | ||
175 | * \sa LOG_ASSERT | ||
176 | */ | ||
177 | |||
178 | //! Very simple but rather powerful component which may be used for logging your application activities. | ||
179 | class CUTELOGGERSHARED_EXPORT Logger | ||
180 | { | ||
181 | public: | ||
182 | //! Describes the possible severity levels of the log records | ||
183 | enum LogLevel | ||
184 | { | ||
185 | Trace, //!< Trace level. Can be used for mostly unneeded records used for internal code tracing. | ||
186 | Debug, //!< Debug level. Useful for non-necessary records used for the debugging of the software. | ||
187 | Info, //!< Info level. Can be used for informational records, which may be interesting for not only developers. | ||
188 | Warning, //!< Warning. May be used to log some non-fatal warnings detected by your application. | ||
189 | Error, //!< Error. May be used for a big problems making your application work wrong but not crashing. | ||
190 | Fatal //!< Fatal. Used for unrecoverable errors, crashes the application right after the log record is written. | ||
191 | }; | ||
192 | |||
193 | //! Converts the LogLevel enum value to its string representation | ||
194 | /** | ||
195 | * \param logLevel Log level to convert | ||
196 | * | ||
197 | * \sa LogLevel | ||
198 | * \sa levelFromString() | ||
199 | */ | ||
200 | static QString levelToString(LogLevel logLevel); | ||
201 | |||
202 | //! Converts the LogLevel string representation to enum value | ||
203 | /** | ||
204 | * Comparation of the strings is case independent. If the log level string provided cannot be understood | ||
205 | * Logger::Debug is returned. | ||
206 | * | ||
207 | * \param s String to be decoded | ||
208 | * | ||
209 | * \sa LogLevel | ||
210 | * \sa levelToString() | ||
211 | */ | ||
212 | static LogLevel levelFromString(const QString& s); | ||
213 | |||
214 | //! Registers the appender to write the log records to | ||
215 | /** | ||
216 | * On the log writing call (using one of the macros or the write() function) Logger traverses through the list of | ||
217 | * the appenders and writes a log records to the each of them. Please, look through the AbstractAppender | ||
218 | * documentation to understand the concept of appenders. | ||
219 | * | ||
220 | * If no appenders was added to Logger, it falls back to logging into the \c std::cerr STL stream. | ||
221 | * | ||
222 | * \param appender Appender to register in the Logger | ||
223 | * | ||
224 | * \note Logger takes ownership on the appender and it will delete it on the application exit. According to this, | ||
225 | * appenders must be created on heap to prevent double destruction of the appender. | ||
226 | * | ||
227 | * \sa AbstractAppender | ||
228 | */ | ||
229 | static void registerAppender(AbstractAppender* appender); | ||
230 | |||
231 | //! Writes the log record | ||
232 | /** | ||
233 | * Writes the log records with the supplied arguments to all the registered appenders. | ||
234 | * | ||
235 | * \note It is not recommended to call this function directly. Instead of this you can just call one of the macros | ||
236 | * (LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL) that will supply all the needed | ||
237 | * information to this function. | ||
238 | * | ||
239 | * \param timeStamp - the time stamp of the record | ||
240 | * \param logLevel - the log level of the record | ||
241 | * \param file - the name of the source file that requested the log record | ||
242 | * \param line - the line of the code of source file that requested the log record | ||
243 | * \param function - name of the function that requested the log record | ||
244 | * \param message - log message | ||
245 | * | ||
246 | * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() | ||
247 | * function, which will interrupt the running of your software and begin the writing of the core dump. | ||
248 | * | ||
249 | * \sa LogLevel | ||
250 | * \sa LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL | ||
251 | * \sa AbstractAppender | ||
252 | */ | ||
253 | static void write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, | ||
254 | const QString& message); | ||
255 | |||
256 | /** | ||
257 | * This is the overloaded function provided for the convinience. It behaves identically to the above function. | ||
258 | * | ||
259 | * This function uses the current timestamp obtained with \c QDateTime::currentDateTime(). | ||
260 | * | ||
261 | * \sa write() | ||
262 | */ | ||
263 | static void write(LogLevel logLevel, const char* file, int line, const char* function, const QString& message); | ||
264 | |||
265 | /** | ||
266 | * This is the overloaded function provided for the convinience. It behaves identically to the above function. | ||
267 | * | ||
268 | * This function uses the current timestamp obtained with \c QDateTime::currentDateTime(). Also it supports writing | ||
269 | * <tt>const char*</tt> instead of \c QString and converts it internally using the \c QString::fromAscii(). If you | ||
270 | * want this function to support the non-ascii strings, you will need to setup the codec using the | ||
271 | * \c QTextCodec::setCodecForCStrings() | ||
272 | * | ||
273 | * \sa write() | ||
274 | */ | ||
275 | static void write(LogLevel logLevel, const char* file, int line, const char* function, const char* message, ...); | ||
276 | |||
277 | /** | ||
278 | * This is the overloaded function provided for the convinience. It behaves identically to the above function. | ||
279 | * | ||
280 | * This function doesn't accept any log message as argument. It returns the \c QDebug object that can be written | ||
281 | * using the stream functions. For example, you may like to write: | ||
282 | * \code | ||
283 | * LOG_DEBUG() << "This is the size" << size << "of the element" << elementName; | ||
284 | * \endcode | ||
285 | * instead of writing | ||
286 | * \code | ||
287 | * LOG_DEBUG(QString(QLatin1String("This is the size %1x%2 of the element %3")) | ||
288 | * .arg(size.x()).arg(size.y()).arg(elementName)); | ||
289 | * \endcode | ||
290 | * | ||
291 | * Please consider reading the Qt Reference Documentation for the description of the QDebug class usage syntax. | ||
292 | * | ||
293 | * \note This overload is definitely more pleasant to use than the first write() overload, but it behaves definitely | ||
294 | * slower than all the above overloads. | ||
295 | * | ||
296 | * \sa write() | ||
297 | */ | ||
298 | static QDebug write(LogLevel logLevel, const char* file, int line, const char* function); | ||
299 | |||
300 | //! Writes the assertion | ||
301 | /** | ||
302 | * This function writes the assertion record using the write() function. | ||
303 | * | ||
304 | * The assertion record is always written using the Logger::Fatal log level which leads to the abortation of the | ||
305 | * program and generation of the core dump (if supported). | ||
306 | * | ||
307 | * The message written to the appenders will be identical to the \c condition argument prefixed with the | ||
308 | * <tt>ASSERT:</tt> notification. | ||
309 | * | ||
310 | * \note It is not recommended to call this function directly. Instead of this you can just call the LOG_ASSERT | ||
311 | * macro that will supply all the needed information to this function. | ||
312 | * | ||
313 | * \sa LOG_ASSERT | ||
314 | * \sa write() | ||
315 | */ | ||
316 | static void writeAssert(const char* file, int line, const char* function, const char* condition); | ||
317 | }; | ||
318 | |||
319 | #endif // LOGGER_H | ||
diff --git a/rbutil/rbutilqt/logger/README.ROCKBOX b/rbutil/rbutilqt/logger/README.ROCKBOX index 08f537fb3f..f501a410dd 100644 --- a/rbutil/rbutilqt/logger/README.ROCKBOX +++ b/rbutil/rbutilqt/logger/README.ROCKBOX | |||
@@ -1,7 +1,7 @@ | |||
1 | This folder contains the cutelogger project for logging functionality. | 1 | This folder contains the cutelogger project for logging functionality. |
2 | These files are distributed under the LGPL v2 or later. | 2 | These files are distributed under the LGPL v2 or later. |
3 | The source files have been last synced with the projects at | 3 | The source files have been last synced with the projects at |
4 | https://gitorious.org/cutelogger to commit | 4 | https://github.com/dept2/CuteLogger/ to commit |
5 | e3c2745c6c5f38896f87472e01ea2caf2d9e211b. | 5 | 5ae6b9ac13e0cc2821d236e3542a83990b63c95c |
6 | 6 | on Aug 7, 2020. | |
7 | 7 | ||
diff --git a/rbutil/rbutilqt/logger/include/AbstractAppender.h b/rbutil/rbutilqt/logger/include/AbstractAppender.h new file mode 100644 index 0000000000..e029b045aa --- /dev/null +++ b/rbutil/rbutilqt/logger/include/AbstractAppender.h | |||
@@ -0,0 +1,49 @@ | |||
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 | #ifndef ABSTRACTAPPENDER_H | ||
15 | #define ABSTRACTAPPENDER_H | ||
16 | |||
17 | // Local | ||
18 | #include "CuteLogger_global.h" | ||
19 | #include <Logger.h> | ||
20 | |||
21 | // Qt | ||
22 | #include <QMutex> | ||
23 | |||
24 | |||
25 | class CUTELOGGERSHARED_EXPORT AbstractAppender | ||
26 | { | ||
27 | public: | ||
28 | AbstractAppender(); | ||
29 | virtual ~AbstractAppender(); | ||
30 | |||
31 | Logger::LogLevel detailsLevel() const; | ||
32 | void setDetailsLevel(Logger::LogLevel level); | ||
33 | void setDetailsLevel(const QString& level); | ||
34 | |||
35 | void write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, const char* function, | ||
36 | const QString& category, const QString& message); | ||
37 | |||
38 | protected: | ||
39 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | ||
40 | const char* function, const QString& category, const QString& message) = 0; | ||
41 | |||
42 | private: | ||
43 | QMutex m_writeMutex; | ||
44 | |||
45 | Logger::LogLevel m_detailsLevel; | ||
46 | mutable QMutex m_detailsLevelMutex; | ||
47 | }; | ||
48 | |||
49 | #endif // ABSTRACTAPPENDER_H | ||
diff --git a/rbutil/rbutilqt/logger/include/AbstractStringAppender.h b/rbutil/rbutilqt/logger/include/AbstractStringAppender.h new file mode 100644 index 0000000000..78df9e6176 --- /dev/null +++ b/rbutil/rbutilqt/logger/include/AbstractStringAppender.h | |||
@@ -0,0 +1,46 @@ | |||
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 | #ifndef ABSTRACTSTRINGAPPENDER_H | ||
15 | #define ABSTRACTSTRINGAPPENDER_H | ||
16 | |||
17 | // Local | ||
18 | #include "CuteLogger_global.h" | ||
19 | #include <AbstractAppender.h> | ||
20 | |||
21 | // Qt | ||
22 | #include <QReadWriteLock> | ||
23 | |||
24 | |||
25 | class CUTELOGGERSHARED_EXPORT AbstractStringAppender : public AbstractAppender | ||
26 | { | ||
27 | public: | ||
28 | AbstractStringAppender(); | ||
29 | |||
30 | virtual QString format() const; | ||
31 | void setFormat(const QString&); | ||
32 | |||
33 | static QString stripFunctionName(const char*); | ||
34 | |||
35 | protected: | ||
36 | QString formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | ||
37 | const char* function, const QString& category, const QString& message) const; | ||
38 | |||
39 | private: | ||
40 | static QByteArray qCleanupFuncinfo(const char*); | ||
41 | |||
42 | QString m_format; | ||
43 | mutable QReadWriteLock m_formatLock; | ||
44 | }; | ||
45 | |||
46 | #endif // ABSTRACTSTRINGAPPENDER_H | ||
diff --git a/rbutil/rbutilqt/logger/ConsoleAppender.h b/rbutil/rbutilqt/logger/include/ConsoleAppender.h index fa685b5e82..64ef2e7a19 100644 --- a/rbutil/rbutilqt/logger/ConsoleAppender.h +++ b/rbutil/rbutilqt/logger/include/ConsoleAppender.h | |||
@@ -16,17 +16,21 @@ | |||
16 | 16 | ||
17 | #include "CuteLogger_global.h" | 17 | #include "CuteLogger_global.h" |
18 | #include <AbstractStringAppender.h> | 18 | #include <AbstractStringAppender.h> |
19 | 19 | ||
20 | //! ConsoleAppender is the simple appender that writes the log records to the std::cerr output stream. | 20 | |
21 | class CUTELOGGERSHARED_EXPORT ConsoleAppender : public AbstractStringAppender | 21 | class CUTELOGGERSHARED_EXPORT ConsoleAppender : public AbstractStringAppender |
22 | { | 22 | { |
23 | public: | ||
24 | ConsoleAppender(); | ||
25 | virtual QString format() const; | ||
26 | void ignoreEnvironmentPattern(bool ignore); | ||
27 | |||
23 | protected: | 28 | protected: |
24 | //! Writes the log record to the std::cerr stream. | ||
25 | /** | ||
26 | * \sa AbstractStringAppender::format() | ||
27 | */ | ||
28 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | 29 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, |
29 | const char* function, const QString& message); | 30 | const char* function, const QString& category, const QString& message); |
31 | |||
32 | private: | ||
33 | bool m_ignoreEnvPattern; | ||
30 | }; | 34 | }; |
31 | 35 | ||
32 | #endif // CONSOLEAPPENDER_H | 36 | #endif // CONSOLEAPPENDER_H |
diff --git a/rbutil/rbutilqt/logger/CuteLogger_global.h b/rbutil/rbutilqt/logger/include/CuteLogger_global.h index c5e7680845..c5e7680845 100644 --- a/rbutil/rbutilqt/logger/CuteLogger_global.h +++ b/rbutil/rbutilqt/logger/include/CuteLogger_global.h | |||
diff --git a/rbutil/rbutilqt/logger/FileAppender.h b/rbutil/rbutilqt/logger/include/FileAppender.h index 70a70c3e43..ab9e12a91d 100644 --- a/rbutil/rbutilqt/logger/FileAppender.h +++ b/rbutil/rbutilqt/logger/include/FileAppender.h | |||
@@ -23,34 +23,20 @@ | |||
23 | #include <QTextStream> | 23 | #include <QTextStream> |
24 | 24 | ||
25 | 25 | ||
26 | //! File is the simple appender that writes the log records to the plain text file. | ||
27 | class CUTELOGGERSHARED_EXPORT FileAppender : public AbstractStringAppender | 26 | class CUTELOGGERSHARED_EXPORT FileAppender : public AbstractStringAppender |
28 | { | 27 | { |
29 | public: | 28 | public: |
30 | //! Constructs the new file appender assigned to file with the given name. | ||
31 | FileAppender(const QString& fileName = QString()); | 29 | FileAppender(const QString& fileName = QString()); |
32 | ~FileAppender(); | 30 | ~FileAppender(); |
33 | 31 | ||
34 | //! Returns the name set by setFileName() or to the FileAppender constructor. | ||
35 | /** | ||
36 | * \sa setFileName() | ||
37 | */ | ||
38 | QString fileName() const; | 32 | QString fileName() const; |
39 | |||
40 | //! Sets the name of the file. The name can have no path, a relative path, or an absolute path. | ||
41 | /** | ||
42 | * \sa fileName() | ||
43 | */ | ||
44 | void setFileName(const QString&); | 33 | void setFileName(const QString&); |
45 | 34 | ||
35 | bool reopenFile(); | ||
36 | |||
46 | protected: | 37 | protected: |
47 | //! Write the log record to the file. | ||
48 | /** | ||
49 | * \sa fileName() | ||
50 | * \sa AbstractStringAppender::format() | ||
51 | */ | ||
52 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | 38 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, |
53 | const char* function, const QString& message); | 39 | const char* function, const QString& category, const QString& message); |
54 | bool openFile(); | 40 | bool openFile(); |
55 | void closeFile(); | 41 | void closeFile(); |
56 | 42 | ||
diff --git a/rbutil/rbutilqt/logger/include/Logger.h b/rbutil/rbutilqt/logger/include/Logger.h new file mode 100644 index 0000000000..509bc5f435 --- /dev/null +++ b/rbutil/rbutilqt/logger/include/Logger.h | |||
@@ -0,0 +1,237 @@ | |||
1 | /* | ||
2 | Copyright (c) 2012 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 | #ifndef LOGGER_H | ||
15 | #define LOGGER_H | ||
16 | |||
17 | // Qt | ||
18 | #include <QString> | ||
19 | #include <QDebug> | ||
20 | #include <QDateTime> | ||
21 | |||
22 | // Local | ||
23 | #include "CuteLogger_global.h" | ||
24 | class AbstractAppender; | ||
25 | |||
26 | |||
27 | class Logger; | ||
28 | CUTELOGGERSHARED_EXPORT Logger* cuteLoggerInstance(); | ||
29 | #define cuteLogger cuteLoggerInstance() | ||
30 | |||
31 | |||
32 | #define LOG_TRACE CuteMessageLogger(cuteLoggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO).write | ||
33 | #define LOG_DEBUG CuteMessageLogger(cuteLoggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO).write | ||
34 | #define LOG_INFO CuteMessageLogger(cuteLoggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO).write | ||
35 | #define LOG_WARNING CuteMessageLogger(cuteLoggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO).write | ||
36 | #define LOG_ERROR CuteMessageLogger(cuteLoggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO).write | ||
37 | #define LOG_FATAL CuteMessageLogger(cuteLoggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO).write | ||
38 | |||
39 | #define LOG_CTRACE(category) CuteMessageLogger(cuteLoggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | ||
40 | #define LOG_CDEBUG(category) CuteMessageLogger(cuteLoggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | ||
41 | #define LOG_CINFO(category) CuteMessageLogger(cuteLoggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | ||
42 | #define LOG_CWARNING(category) CuteMessageLogger(cuteLoggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | ||
43 | #define LOG_CERROR(category) CuteMessageLogger(cuteLoggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | ||
44 | #define LOG_CFATAL(category) CuteMessageLogger(cuteLoggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | ||
45 | |||
46 | #define LOG_TRACE_TIME LoggerTimingHelper loggerTimingHelper(cuteLoggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start | ||
47 | #define LOG_DEBUG_TIME LoggerTimingHelper loggerTimingHelper(cuteLoggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start | ||
48 | #define LOG_INFO_TIME LoggerTimingHelper loggerTimingHelper(cuteLoggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start | ||
49 | |||
50 | #define LOG_ASSERT(cond) ((!(cond)) ? cuteLoggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, #cond) : qt_noop()) | ||
51 | #define LOG_ASSERT_X(cond, msg) ((!(cond)) ? cuteLoggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, msg) : qt_noop()) | ||
52 | |||
53 | #if (__cplusplus >= 201103L) | ||
54 | #include <functional> | ||
55 | |||
56 | #define LOG_CATEGORY(category) \ | ||
57 | Logger customCuteLoggerInstance{category};\ | ||
58 | std::function<Logger*()> cuteLoggerInstance = [&customCuteLoggerInstance]() {\ | ||
59 | return &customCuteLoggerInstance;\ | ||
60 | };\ | ||
61 | |||
62 | #define LOG_GLOBAL_CATEGORY(category) \ | ||
63 | Logger customCuteLoggerInstance{category, true};\ | ||
64 | std::function<Logger*()> cuteLoggerInstance = [&customCuteLoggerInstance]() {\ | ||
65 | return &customCuteLoggerInstance;\ | ||
66 | };\ | ||
67 | |||
68 | #else | ||
69 | |||
70 | #define LOG_CATEGORY(category) \ | ||
71 | Logger* cuteLoggerInstance()\ | ||
72 | {\ | ||
73 | static Logger customCuteLoggerInstance(category);\ | ||
74 | return &customCuteLoggerInstance;\ | ||
75 | }\ | ||
76 | |||
77 | #define LOG_GLOBAL_CATEGORY(category) \ | ||
78 | Logger* cuteLoggerInstance()\ | ||
79 | {\ | ||
80 | static Logger customCuteLoggerInstance(category);\ | ||
81 | customCuteLoggerInstance.logToGlobalInstance(category, true);\ | ||
82 | return &customCuteLoggerInstance;\ | ||
83 | }\ | ||
84 | |||
85 | #endif | ||
86 | |||
87 | |||
88 | class LoggerPrivate; | ||
89 | class CUTELOGGERSHARED_EXPORT Logger | ||
90 | { | ||
91 | Q_DISABLE_COPY(Logger) | ||
92 | |||
93 | public: | ||
94 | Logger(); | ||
95 | Logger(const QString& defaultCategory, bool writeToGlobalInstance = false); | ||
96 | ~Logger(); | ||
97 | |||
98 | //! Describes the possible severity levels of the log records | ||
99 | enum LogLevel | ||
100 | { | ||
101 | Trace, //!< Trace level. Can be used for mostly unneeded records used for internal code tracing. | ||
102 | Debug, //!< Debug level. Useful for non-necessary records used for the debugging of the software. | ||
103 | Info, //!< Info level. Can be used for informational records, which may be interesting for not only developers. | ||
104 | Warning, //!< Warning. May be used to log some non-fatal warnings detected by your application. | ||
105 | Error, //!< Error. May be used for a big problems making your application work wrong but not crashing. | ||
106 | Fatal //!< Fatal. Used for unrecoverable errors, crashes the application right after the log record is written. | ||
107 | }; | ||
108 | |||
109 | //! Sets the timing display mode for the LOG_TRACE_TIME, LOG_DEBUG_TIME and LOG_INFO_TIME macros | ||
110 | enum TimingMode | ||
111 | { | ||
112 | TimingAuto, //!< Show time in seconds, if it exceeds 10s (default) | ||
113 | TimingMs //!< Always use milliseconds to display | ||
114 | }; | ||
115 | |||
116 | static QString levelToString(LogLevel logLevel); | ||
117 | static LogLevel levelFromString(const QString& s); | ||
118 | |||
119 | static Logger* globalInstance(); | ||
120 | |||
121 | void registerAppender(AbstractAppender* appender); | ||
122 | void registerCategoryAppender(const QString& category, AbstractAppender* appender); | ||
123 | |||
124 | void removeAppender(AbstractAppender* appender); | ||
125 | |||
126 | void logToGlobalInstance(const QString& category, bool logToGlobal = false); | ||
127 | |||
128 | void setDefaultCategory(const QString& category); | ||
129 | QString defaultCategory() const; | ||
130 | |||
131 | void write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category, | ||
132 | const QString& message); | ||
133 | void write(LogLevel logLevel, const char* file, int line, const char* function, const char* category, const QString& message); | ||
134 | |||
135 | void writeAssert(const char* file, int line, const char* function, const char* condition); | ||
136 | |||
137 | private: | ||
138 | void write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category, | ||
139 | const QString& message, bool fromLocalInstance); | ||
140 | Q_DECLARE_PRIVATE(Logger) | ||
141 | LoggerPrivate* d_ptr; | ||
142 | }; | ||
143 | |||
144 | |||
145 | class CUTELOGGERSHARED_EXPORT CuteMessageLogger | ||
146 | { | ||
147 | Q_DISABLE_COPY(CuteMessageLogger) | ||
148 | |||
149 | public: | ||
150 | CuteMessageLogger(Logger* l, Logger::LogLevel level, const char* file, int line, const char* function) | ||
151 | : m_l(l), | ||
152 | m_level(level), | ||
153 | m_file(file), | ||
154 | m_line(line), | ||
155 | m_function(function), | ||
156 | m_category(nullptr) | ||
157 | {} | ||
158 | |||
159 | CuteMessageLogger(Logger* l, Logger::LogLevel level, const char* file, int line, const char* function, const char* category) | ||
160 | : m_l(l), | ||
161 | m_level(level), | ||
162 | m_file(file), | ||
163 | m_line(line), | ||
164 | m_function(function), | ||
165 | m_category(category) | ||
166 | {} | ||
167 | |||
168 | ~CuteMessageLogger(); | ||
169 | |||
170 | void write(const char* msg, ...) | ||
171 | #if defined(Q_CC_GNU) && !defined(__INSURE__) | ||
172 | # if defined(Q_CC_MINGW) && !defined(Q_CC_CLANG) | ||
173 | __attribute__ ((format (gnu_printf, 2, 3))) | ||
174 | # else | ||
175 | __attribute__ ((format (printf, 2, 3))) | ||
176 | # endif | ||
177 | #endif | ||
178 | ; | ||
179 | |||
180 | void write(const QString& msg); | ||
181 | |||
182 | QDebug write(); | ||
183 | |||
184 | private: | ||
185 | Logger* m_l; | ||
186 | Logger::LogLevel m_level; | ||
187 | const char* m_file; | ||
188 | int m_line; | ||
189 | const char* m_function; | ||
190 | const char* m_category; | ||
191 | QString m_message; | ||
192 | }; | ||
193 | |||
194 | |||
195 | class CUTELOGGERSHARED_EXPORT LoggerTimingHelper | ||
196 | { | ||
197 | Q_DISABLE_COPY(LoggerTimingHelper) | ||
198 | |||
199 | public: | ||
200 | inline explicit LoggerTimingHelper(Logger* l, Logger::LogLevel logLevel, const char* file, int line, | ||
201 | const char* function) | ||
202 | : m_logger(l), | ||
203 | m_logLevel(logLevel), | ||
204 | m_timingMode(Logger::TimingAuto), | ||
205 | m_file(file), | ||
206 | m_line(line), | ||
207 | m_function(function) | ||
208 | {} | ||
209 | |||
210 | void start(const char* msg, ...) | ||
211 | #if defined(Q_CC_GNU) && !defined(__INSURE__) | ||
212 | # if defined(Q_CC_MINGW) && !defined(Q_CC_CLANG) | ||
213 | __attribute__ ((format (gnu_printf, 2, 3))) | ||
214 | # else | ||
215 | __attribute__ ((format (printf, 2, 3))) | ||
216 | # endif | ||
217 | #endif | ||
218 | ; | ||
219 | |||
220 | void start(const QString& msg = QString()); | ||
221 | void start(Logger::TimingMode mode, const QString& msg); | ||
222 | |||
223 | ~LoggerTimingHelper(); | ||
224 | |||
225 | private: | ||
226 | Logger* m_logger; | ||
227 | QTime m_time; | ||
228 | Logger::LogLevel m_logLevel; | ||
229 | Logger::TimingMode m_timingMode; | ||
230 | const char* m_file; | ||
231 | int m_line; | ||
232 | const char* m_function; | ||
233 | QString m_block; | ||
234 | }; | ||
235 | |||
236 | |||
237 | #endif // LOGGER_H | ||
diff --git a/rbutil/rbutilqt/logger/OutputDebugAppender.h b/rbutil/rbutilqt/logger/include/OutputDebugAppender.h index f5a5b8c588..dd7ad4deb7 100644 --- a/rbutil/rbutilqt/logger/OutputDebugAppender.h +++ b/rbutil/rbutilqt/logger/include/OutputDebugAppender.h | |||
@@ -18,16 +18,12 @@ | |||
18 | #include "CuteLogger_global.h" | 18 | #include "CuteLogger_global.h" |
19 | #include <AbstractStringAppender.h> | 19 | #include <AbstractStringAppender.h> |
20 | 20 | ||
21 | //! OutputDebugAppender is the appender that writes the log records to the Microsoft Debug Log | 21 | |
22 | class CUTELOGGERSHARED_EXPORT OutputDebugAppender : public AbstractStringAppender | 22 | class CUTELOGGERSHARED_EXPORT OutputDebugAppender : public AbstractStringAppender |
23 | { | 23 | { |
24 | protected: | 24 | protected: |
25 | //! Writes the log record to the windows debug log. | ||
26 | /** | ||
27 | * \sa AbstractStringAppender::format() | ||
28 | */ | ||
29 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | 25 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, |
30 | const char* function, const QString& message); | 26 | const char* function, const QString& category, const QString& message); |
31 | }; | 27 | }; |
32 | 28 | ||
33 | #endif // OUTPUTDEBUGAPPENDER_H | 29 | #endif // OUTPUTDEBUGAPPENDER_H |
diff --git a/rbutil/rbutilqt/logger/logger.pri b/rbutil/rbutilqt/logger/logger.pri index ec8d68b399..e34bccb3cf 100644 --- a/rbutil/rbutilqt/logger/logger.pri +++ b/rbutil/rbutilqt/logger/logger.pri | |||
@@ -1,19 +1,22 @@ | |||
1 | 1 | ||
2 | SOURCES += \ | 2 | SOURCES += \ |
3 | $$PWD/AbstractAppender.cpp \ | 3 | $$PWD/src/AbstractAppender.cpp \ |
4 | $$PWD/AbstractStringAppender.cpp \ | 4 | $$PWD/src/AbstractStringAppender.cpp \ |
5 | $$PWD/ConsoleAppender.cpp \ | 5 | $$PWD/src/ConsoleAppender.cpp \ |
6 | $$PWD/FileAppender.cpp \ | 6 | $$PWD/src/FileAppender.cpp \ |
7 | $$PWD/Logger.cpp \ | 7 | $$PWD/src/Logger.cpp \ |
8 | 8 | ||
9 | INCLUDES += \ | 9 | HEADERS += \ |
10 | $$PWD/AbstractAppender.h \ | 10 | $$PWD/include/AbstractAppender.h \ |
11 | $$PWD/ConsoleAppender.h \ | 11 | $$PWD/include/ConsoleAppender.h \ |
12 | $$PWD/FileAppender.h \ | 12 | $$PWD/include/FileAppender.h \ |
13 | $$PWD/OutputDebugAppender.h \ | 13 | $$PWD/include/OutputDebugAppender.h \ |
14 | $$PWD/AbstractStringAppender.h \ | 14 | $$PWD/include/AbstractStringAppender.h \ |
15 | $$PWD/CuteLogger_global.h \ | 15 | $$PWD/include/CuteLogger_global.h \ |
16 | $$PWD/Logger.h \ | 16 | $$PWD/include/Logger.h \ |
17 | |||
18 | INCLUDEPATH += $$PWD/include | ||
17 | 19 | ||
18 | DEFINES += \ | 20 | DEFINES += \ |
19 | CUTELOGGER_STATIC | 21 | CUTELOGGER_STATIC |
22 | |||
diff --git a/rbutil/rbutilqt/logger/src/AbstractAppender.cpp b/rbutil/rbutilqt/logger/src/AbstractAppender.cpp new file mode 100644 index 0000000000..778bbddd11 --- /dev/null +++ b/rbutil/rbutilqt/logger/src/AbstractAppender.cpp | |||
@@ -0,0 +1,147 @@ | |||
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 "AbstractAppender.h" | ||
16 | |||
17 | // Qt | ||
18 | #include <QMutexLocker> | ||
19 | |||
20 | |||
21 | /** | ||
22 | * \class AbstractAppender | ||
23 | * | ||
24 | * \brief The AbstractAppender class provides an abstract base class for writing a log entries. | ||
25 | * | ||
26 | * The AbstractAppender class is the base interface class for all log appenders that could be used with Logger. | ||
27 | * | ||
28 | * AbstractAppender provides a common implementation for the thread safe, mutex-protected logging of application | ||
29 | * messages, such as ConsoleAppender, FileAppender or something else. AbstractAppender is abstract and can not be | ||
30 | * instantiated, but you can use any of its subclasses or create a custom log appender at your choice. | ||
31 | * | ||
32 | * Appenders are the logical devices that is aimed to be attached to Logger object by calling | ||
33 | * Logger::registerAppender(). On each log record call from the application Logger object sequentially calls write() | ||
34 | * function on all the appenders registered in it. | ||
35 | * | ||
36 | * You can subclass AbstractAppender to implement a logging target of any kind you like. It may be the external logging | ||
37 | * subsystem (for example, syslog in *nix), XML file, SQL database entries, D-Bus messages or anything else you can | ||
38 | * imagine. | ||
39 | * | ||
40 | * For the simple non-structured plain text logging (for example, to a plain text file or to the console output) you may | ||
41 | * like to subclass the AbstractStringAppender instead of AbstractAppender, which will give you a more convinient way to | ||
42 | * control the format of the log output. | ||
43 | * | ||
44 | * \sa AbstractStringAppender | ||
45 | * \sa Logger::registerAppender() | ||
46 | */ | ||
47 | |||
48 | |||
49 | //! Constructs a AbstractAppender object. | ||
50 | AbstractAppender::AbstractAppender() | ||
51 | : m_detailsLevel(Logger::Debug) | ||
52 | {} | ||
53 | |||
54 | |||
55 | //! Destructs the AbstractAppender object. | ||
56 | AbstractAppender::~AbstractAppender() | ||
57 | {} | ||
58 | |||
59 | |||
60 | //! Returns the current details level of appender. | ||
61 | /** | ||
62 | * Log records with a log level lower than a current detailsLevel() will be silently ignored by appender and would not | ||
63 | * be sent to its append() function. | ||
64 | * | ||
65 | * It provides additional logging flexibility, allowing you to set the different severity levels for different types | ||
66 | * of logs. | ||
67 | * | ||
68 | * \note This function is thread safe. | ||
69 | * | ||
70 | * \sa setDetailsLevel() | ||
71 | * \sa Logger::LogLevel | ||
72 | */ | ||
73 | Logger::LogLevel AbstractAppender::detailsLevel() const | ||
74 | { | ||
75 | QMutexLocker locker(&m_detailsLevelMutex); | ||
76 | return m_detailsLevel; | ||
77 | } | ||
78 | |||
79 | |||
80 | //! Sets the current details level of appender. | ||
81 | /** | ||
82 | * Default details level is Logger::Debug | ||
83 | * | ||
84 | * \note This function is thread safe. | ||
85 | * | ||
86 | * \sa detailsLevel() | ||
87 | * \sa Logger::LogLevel | ||
88 | */ | ||
89 | void AbstractAppender::setDetailsLevel(Logger::LogLevel level) | ||
90 | { | ||
91 | QMutexLocker locker(&m_detailsLevelMutex); | ||
92 | m_detailsLevel = level; | ||
93 | } | ||
94 | |||
95 | |||
96 | |||
97 | //! Sets the current details level of appender | ||
98 | /** | ||
99 | * This function is provided for convenience, it behaves like an above function. | ||
100 | * | ||
101 | * \sa detailsLevel() | ||
102 | * \sa Logger::LogLevel | ||
103 | */ | ||
104 | void AbstractAppender::setDetailsLevel(const QString& level) | ||
105 | { | ||
106 | setDetailsLevel(Logger::levelFromString(level)); | ||
107 | } | ||
108 | |||
109 | |||
110 | //! Tries to write the log record to this logger | ||
111 | /** | ||
112 | * This is the function called by Logger object to write a log message to the appender. | ||
113 | * | ||
114 | * \note This function is thread safe. | ||
115 | * | ||
116 | * \sa Logger::write() | ||
117 | * \sa detailsLevel() | ||
118 | */ | ||
119 | void AbstractAppender::write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | ||
120 | const char* function, const QString& category, const QString& message) | ||
121 | { | ||
122 | if (logLevel >= detailsLevel()) | ||
123 | { | ||
124 | QMutexLocker locker(&m_writeMutex); | ||
125 | append(timeStamp, logLevel, file, line, function, category, message); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | |||
130 | /** | ||
131 | * \fn virtual void AbstractAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, | ||
132 | * int line, const char* function, const QString& message) | ||
133 | * | ||
134 | * \brief Writes the log record to the logger instance | ||
135 | * | ||
136 | * This function is called every time when user tries to write a message to this AbstractAppender instance using | ||
137 | * the write() function. Write function works as proxy and transfers only the messages with log level more or equal | ||
138 | * to the current logLevel(). | ||
139 | * | ||
140 | * Overload this function when you are implementing a custom appender. | ||
141 | * | ||
142 | * \note This function is not needed to be thread safe because it is never called directly by Logger object. The | ||
143 | * write() function works as a proxy and protects this function from concurrent access. | ||
144 | * | ||
145 | * \sa Logger::write() | ||
146 | */ | ||
147 | |||
diff --git a/rbutil/rbutilqt/logger/src/AbstractStringAppender.cpp b/rbutil/rbutilqt/logger/src/AbstractStringAppender.cpp new file mode 100644 index 0000000000..ce64aaeb43 --- /dev/null +++ b/rbutil/rbutilqt/logger/src/AbstractStringAppender.cpp | |||
@@ -0,0 +1,459 @@ | |||
1 | /* | ||
2 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) Nikolay Matyunin (matyunin.n at gmail dot com) | ||
3 | |||
4 | Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). | ||
5 | |||
6 | This program is free software: you can redistribute it and/or modify | ||
7 | it under the terms of the GNU Lesser General Public License version 2.1 | ||
8 | as published by the Free Software Foundation and appearing in the file | ||
9 | LICENSE.LGPL included in the packaging of this file. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU Lesser General Public License for more details. | ||
15 | */ | ||
16 | // Local | ||
17 | #include "AbstractStringAppender.h" | ||
18 | |||
19 | // Qt | ||
20 | #include <QReadLocker> | ||
21 | #include <QWriteLocker> | ||
22 | #include <QDateTime> | ||
23 | #include <QRegExp> | ||
24 | #include <QCoreApplication> | ||
25 | #include <QThread> | ||
26 | |||
27 | |||
28 | /** | ||
29 | * \class AbstractStringAppender | ||
30 | * | ||
31 | * \brief The AbstractStringAppender class provides a convinient base for appenders working with plain text formatted | ||
32 | * logs. | ||
33 | * | ||
34 | * AbstractSringAppender is the simple extension of the AbstractAppender class providing the convinient way to create | ||
35 | * custom log appenders working with a plain text formatted log targets. | ||
36 | * | ||
37 | * It have the formattedString() protected function that formats the logging arguments according to a format set with | ||
38 | * setFormat(). | ||
39 | * | ||
40 | * This class can not be directly instantiated because it contains pure virtual function inherited from AbstractAppender | ||
41 | * class. | ||
42 | * | ||
43 | * For more detailed description of customizing the log output format see the documentation on the setFormat() function. | ||
44 | */ | ||
45 | |||
46 | |||
47 | const char formattingMarker = '%'; | ||
48 | |||
49 | |||
50 | //! Constructs a new string appender object | ||
51 | AbstractStringAppender::AbstractStringAppender() | ||
52 | : m_format(QLatin1String("%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n")) | ||
53 | {} | ||
54 | |||
55 | |||
56 | //! Returns the current log format string. | ||
57 | /** | ||
58 | * The default format is set to "%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n". You can set a different log record | ||
59 | * format using the setFormat() function. | ||
60 | * | ||
61 | * \sa setFormat(const QString&) | ||
62 | */ | ||
63 | QString AbstractStringAppender::format() const | ||
64 | { | ||
65 | QReadLocker locker(&m_formatLock); | ||
66 | return m_format; | ||
67 | } | ||
68 | |||
69 | |||
70 | //! Sets the logging format for writing strings to the log target with this appender. | ||
71 | /** | ||
72 | * The string format seems to be very common to those developers who have used a standart sprintf function. | ||
73 | * | ||
74 | * Log output format is a simple QString with the special markers (starting with % sign) which will be replaced with | ||
75 | * it's internal meaning when writing a log record. | ||
76 | * | ||
77 | * Controlling marker begins with the percent sign (%) which is followed by the command inside {} brackets | ||
78 | * (the command describes, what will be put to log record instead of marker). | ||
79 | * Optional field width argument may be specified right after the command (through the colon symbol before the closing bracket) | ||
80 | * Some commands requires an additional formatting argument (in the second {} brackets). | ||
81 | * | ||
82 | * Field width argument works almost identically to the \c QString::arg() \c fieldWidth argument (and uses it | ||
83 | * internally). For example, \c "%{type:-7}" will be replaced with the left padded debug level of the message | ||
84 | * (\c "Debug ") or something. For the more detailed description of it you may consider to look to the Qt | ||
85 | * Reference Documentation. | ||
86 | * | ||
87 | * Supported marker commands are: | ||
88 | * \arg \c %{time} - timestamp. You may specify your custom timestamp format using the second {} brackets after the marker, | ||
89 | * timestamp format here will be similiar to those used in QDateTime::toString() function. For example, | ||
90 | * "%{time}{dd-MM-yyyy, HH:mm}" may be replaced with "17-12-2010, 20:17" depending on current date and time. | ||
91 | * The default format used here is "HH:mm:ss.zzz". | ||
92 | * \arg \c %{type} - Log level. Possible log levels are shown in the Logger::LogLevel enumerator. | ||
93 | * \arg \c %{Type} - Uppercased log level. | ||
94 | * \arg \c %{typeOne} - One letter log level. | ||
95 | * \arg \c %{TypeOne} - One uppercase letter log level. | ||
96 | * \arg \c %{File} - Full source file name (with path) of the file that requested log recording. Uses the \c __FILE__ | ||
97 | * preprocessor macro. | ||
98 | * \arg \c %{file} - Short file name (with stripped path). | ||
99 | * \arg \c %{line} - Line number in the source file. Uses the \c __LINE__ preprocessor macro. | ||
100 | * \arg \c %{Function} - Name of function that called on of the LOG_* macros. Uses the \c Q_FUNC_INFO macro provided with | ||
101 | * Qt. | ||
102 | * \arg \c %{function} - Similiar to the %{Function}, but the function name is stripped using stripFunctionName | ||
103 | * \arg \c %{message} - The log message sent by the caller. | ||
104 | * \arg \c %{category} - The log category. | ||
105 | * \arg \c %{appname} - Application name (returned by QCoreApplication::applicationName() function). | ||
106 | * \arg \c %{pid} - Application pid (returned by QCoreApplication::applicationPid() function). | ||
107 | * \arg \c %{threadid} - ID of current thread. | ||
108 | * \arg \c %% - Convinient marker that is replaced with the single \c % mark. | ||
109 | * | ||
110 | * \note Format doesn't add \c '\\n' to the end of the format line. Please consider adding it manually. | ||
111 | * | ||
112 | * \sa format() | ||
113 | * \sa stripFunctionName() | ||
114 | * \sa Logger::LogLevel | ||
115 | */ | ||
116 | void AbstractStringAppender::setFormat(const QString& format) | ||
117 | { | ||
118 | QWriteLocker locker(&m_formatLock); | ||
119 | m_format = format; | ||
120 | } | ||
121 | |||
122 | |||
123 | //! Strips the long function signature (as added by Q_FUNC_INFO macro) | ||
124 | /** | ||
125 | * The string processing drops the returning type, arguments and template parameters of function. It is definitely | ||
126 | * useful for enchancing the log output readability. | ||
127 | * \return stripped function name | ||
128 | */ | ||
129 | QString AbstractStringAppender::stripFunctionName(const char* name) | ||
130 | { | ||
131 | return QString::fromLatin1(qCleanupFuncinfo(name)); | ||
132 | } | ||
133 | |||
134 | |||
135 | // The function was backported from Qt5 sources (qlogging.h) | ||
136 | QByteArray AbstractStringAppender::qCleanupFuncinfo(const char* name) | ||
137 | { | ||
138 | QByteArray info(name); | ||
139 | |||
140 | // Strip the function info down to the base function name | ||
141 | // note that this throws away the template definitions, | ||
142 | // the parameter types (overloads) and any const/volatile qualifiers. | ||
143 | if (info.isEmpty()) | ||
144 | return info; | ||
145 | |||
146 | int pos; | ||
147 | |||
148 | // skip trailing [with XXX] for templates (gcc) | ||
149 | pos = info.size() - 1; | ||
150 | if (info.endsWith(']')) { | ||
151 | while (--pos) { | ||
152 | if (info.at(pos) == '[') | ||
153 | info.truncate(pos); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | bool hasLambda = false; | ||
158 | QRegExp lambdaRegex("::<lambda\\(.*\\)>"); | ||
159 | int lambdaIndex = lambdaRegex.indexIn(QString::fromLatin1(info)); | ||
160 | if (lambdaIndex != -1) | ||
161 | { | ||
162 | hasLambda = true; | ||
163 | info.remove(lambdaIndex, lambdaRegex.matchedLength()); | ||
164 | } | ||
165 | |||
166 | // operator names with '(', ')', '<', '>' in it | ||
167 | static const char operator_call[] = "operator()"; | ||
168 | static const char operator_lessThan[] = "operator<"; | ||
169 | static const char operator_greaterThan[] = "operator>"; | ||
170 | static const char operator_lessThanEqual[] = "operator<="; | ||
171 | static const char operator_greaterThanEqual[] = "operator>="; | ||
172 | |||
173 | // canonize operator names | ||
174 | info.replace("operator ", "operator"); | ||
175 | |||
176 | // remove argument list | ||
177 | forever { | ||
178 | int parencount = 0; | ||
179 | pos = info.lastIndexOf(')'); | ||
180 | if (pos == -1) { | ||
181 | // Don't know how to parse this function name | ||
182 | return info; | ||
183 | } | ||
184 | |||
185 | // find the beginning of the argument list | ||
186 | --pos; | ||
187 | ++parencount; | ||
188 | while (pos && parencount) { | ||
189 | if (info.at(pos) == ')') | ||
190 | ++parencount; | ||
191 | else if (info.at(pos) == '(') | ||
192 | --parencount; | ||
193 | --pos; | ||
194 | } | ||
195 | if (parencount != 0) | ||
196 | return info; | ||
197 | |||
198 | info.truncate(++pos); | ||
199 | |||
200 | if (info.at(pos - 1) == ')') { | ||
201 | if (info.indexOf(operator_call) == pos - (int)strlen(operator_call)) | ||
202 | break; | ||
203 | |||
204 | // this function returns a pointer to a function | ||
205 | // and we matched the arguments of the return type's parameter list | ||
206 | // try again | ||
207 | info.remove(0, info.indexOf('(')); | ||
208 | info.chop(1); | ||
209 | continue; | ||
210 | } else { | ||
211 | break; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | if (hasLambda) | ||
216 | info.append("::lambda"); | ||
217 | |||
218 | // find the beginning of the function name | ||
219 | int parencount = 0; | ||
220 | int templatecount = 0; | ||
221 | --pos; | ||
222 | |||
223 | // make sure special characters in operator names are kept | ||
224 | if (pos > -1) { | ||
225 | switch (info.at(pos)) { | ||
226 | case ')': | ||
227 | if (info.indexOf(operator_call) == pos - (int)strlen(operator_call) + 1) | ||
228 | pos -= 2; | ||
229 | break; | ||
230 | case '<': | ||
231 | if (info.indexOf(operator_lessThan) == pos - (int)strlen(operator_lessThan) + 1) | ||
232 | --pos; | ||
233 | break; | ||
234 | case '>': | ||
235 | if (info.indexOf(operator_greaterThan) == pos - (int)strlen(operator_greaterThan) + 1) | ||
236 | --pos; | ||
237 | break; | ||
238 | case '=': { | ||
239 | int operatorLength = (int)strlen(operator_lessThanEqual); | ||
240 | if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1) | ||
241 | pos -= 2; | ||
242 | else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1) | ||
243 | pos -= 2; | ||
244 | break; | ||
245 | } | ||
246 | default: | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | while (pos > -1) { | ||
252 | if (parencount < 0 || templatecount < 0) | ||
253 | return info; | ||
254 | |||
255 | char c = info.at(pos); | ||
256 | if (c == ')') | ||
257 | ++parencount; | ||
258 | else if (c == '(') | ||
259 | --parencount; | ||
260 | else if (c == '>') | ||
261 | ++templatecount; | ||
262 | else if (c == '<') | ||
263 | --templatecount; | ||
264 | else if (c == ' ' && templatecount == 0 && parencount == 0) | ||
265 | break; | ||
266 | |||
267 | --pos; | ||
268 | } | ||
269 | info = info.mid(pos + 1); | ||
270 | |||
271 | // remove trailing '*', '&' that are part of the return argument | ||
272 | while ((info.at(0) == '*') | ||
273 | || (info.at(0) == '&')) | ||
274 | info = info.mid(1); | ||
275 | |||
276 | // we have the full function name now. | ||
277 | // clean up the templates | ||
278 | while ((pos = info.lastIndexOf('>')) != -1) { | ||
279 | if (!info.contains('<')) | ||
280 | break; | ||
281 | |||
282 | // find the matching close | ||
283 | int end = pos; | ||
284 | templatecount = 1; | ||
285 | --pos; | ||
286 | while (pos && templatecount) { | ||
287 | char c = info.at(pos); | ||
288 | if (c == '>') | ||
289 | ++templatecount; | ||
290 | else if (c == '<') | ||
291 | --templatecount; | ||
292 | --pos; | ||
293 | } | ||
294 | ++pos; | ||
295 | info.remove(pos, end - pos + 1); | ||
296 | } | ||
297 | |||
298 | return info; | ||
299 | } | ||
300 | |||
301 | |||
302 | //! Returns the string to record to the logging target, formatted according to the format(). | ||
303 | /** | ||
304 | * \sa format() | ||
305 | * \sa setFormat(const QString&) | ||
306 | */ | ||
307 | QString AbstractStringAppender::formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, | ||
308 | int line, const char* function, const QString& category, const QString& message) const | ||
309 | { | ||
310 | QString f = format(); | ||
311 | const int size = f.size(); | ||
312 | |||
313 | QString result; | ||
314 | |||
315 | int i = 0; | ||
316 | while (i < f.size()) | ||
317 | { | ||
318 | QChar c = f.at(i); | ||
319 | |||
320 | // We will silently ignore the broken % marker at the end of string | ||
321 | if (c != QLatin1Char(formattingMarker) || (i + 2) >= size) | ||
322 | { | ||
323 | result.append(c); | ||
324 | } | ||
325 | else | ||
326 | { | ||
327 | i += 2; | ||
328 | QChar currentChar = f.at(i); | ||
329 | QString command; | ||
330 | int fieldWidth = 0; | ||
331 | |||
332 | if (currentChar.isLetter()) | ||
333 | { | ||
334 | command.append(currentChar); | ||
335 | int j = 1; | ||
336 | while ((i + j) < size && f.at(i + j).isLetter()) | ||
337 | { | ||
338 | command.append(f.at(i+j)); | ||
339 | j++; | ||
340 | } | ||
341 | |||
342 | i+=j; | ||
343 | currentChar = f.at(i); | ||
344 | |||
345 | // Check for the padding instruction | ||
346 | if (currentChar == QLatin1Char(':')) | ||
347 | { | ||
348 | currentChar = f.at(++i); | ||
349 | if (currentChar.isDigit() || currentChar.category() == QChar::Punctuation_Dash) | ||
350 | { | ||
351 | int j = 1; | ||
352 | while ((i + j) < size && f.at(i + j).isDigit()) | ||
353 | j++; | ||
354 | fieldWidth = f.mid(i, j).toInt(); | ||
355 | |||
356 | i += j; | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | |||
361 | // Log record chunk to insert instead of formatting instruction | ||
362 | QString chunk; | ||
363 | |||
364 | // Time stamp | ||
365 | if (command == QLatin1String("time")) | ||
366 | { | ||
367 | if (f.at(i + 1) == QLatin1Char('{')) | ||
368 | { | ||
369 | int j = 1; | ||
370 | while ((i + 2 + j) < size && f.at(i + 2 + j) != QLatin1Char('}')) | ||
371 | j++; | ||
372 | |||
373 | if ((i + 2 + j) < size) | ||
374 | { | ||
375 | chunk = timeStamp.toString(f.mid(i + 2, j)); | ||
376 | |||
377 | i += j; | ||
378 | i += 2; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | if (chunk.isNull()) | ||
383 | chunk = timeStamp.toString(QLatin1String("HH:mm:ss.zzz")); | ||
384 | } | ||
385 | |||
386 | // Log level | ||
387 | else if (command == QLatin1String("type")) | ||
388 | chunk = Logger::levelToString(logLevel); | ||
389 | |||
390 | // Uppercased log level | ||
391 | else if (command == QLatin1String("Type")) | ||
392 | chunk = Logger::levelToString(logLevel).toUpper(); | ||
393 | |||
394 | // One letter log level | ||
395 | else if (command == QLatin1String("typeOne")) | ||
396 | chunk = Logger::levelToString(logLevel).left(1).toLower(); | ||
397 | |||
398 | // One uppercase letter log level | ||
399 | else if (command == QLatin1String("TypeOne")) | ||
400 | chunk = Logger::levelToString(logLevel).left(1).toUpper(); | ||
401 | |||
402 | // Filename | ||
403 | else if (command == QLatin1String("File")) | ||
404 | chunk = QLatin1String(file); | ||
405 | |||
406 | // Filename without a path | ||
407 | else if (command == QLatin1String("file")) | ||
408 | chunk = QString(QLatin1String(file)).section(QRegExp("[/\\\\]"), -1); | ||
409 | |||
410 | // Source line number | ||
411 | else if (command == QLatin1String("line")) | ||
412 | chunk = QString::number(line); | ||
413 | |||
414 | // Function name, as returned by Q_FUNC_INFO | ||
415 | else if (command == QLatin1String("Function")) | ||
416 | chunk = QString::fromLatin1(function); | ||
417 | |||
418 | // Stripped function name | ||
419 | else if (command == QLatin1String("function")) | ||
420 | chunk = stripFunctionName(function); | ||
421 | |||
422 | // Log message | ||
423 | else if (command == QLatin1String("message")) | ||
424 | chunk = message; | ||
425 | |||
426 | else if (command == QLatin1String("category")) | ||
427 | chunk = category; | ||
428 | |||
429 | // Application pid | ||
430 | else if (command == QLatin1String("pid")) | ||
431 | chunk = QString::number(QCoreApplication::applicationPid()); | ||
432 | |||
433 | // Appplication name | ||
434 | else if (command == QLatin1String("appname")) | ||
435 | chunk = QCoreApplication::applicationName(); | ||
436 | |||
437 | // Thread ID (duplicates Qt5 threadid debbuging way) | ||
438 | else if (command == QLatin1String("threadid")) | ||
439 | chunk = QLatin1String("0x") + QString::number(qlonglong(QThread::currentThread()->currentThread()), 16); | ||
440 | |||
441 | // We simply replace the double formatting marker (%) with one | ||
442 | else if (command == QString(formattingMarker)) | ||
443 | chunk = QLatin1Char(formattingMarker); | ||
444 | |||
445 | // Do not process any unknown commands | ||
446 | else | ||
447 | { | ||
448 | chunk = QString(formattingMarker); | ||
449 | chunk.append(command); | ||
450 | } | ||
451 | |||
452 | result.append(QString(QLatin1String("%1")).arg(chunk, fieldWidth)); | ||
453 | } | ||
454 | |||
455 | ++i; | ||
456 | } | ||
457 | |||
458 | return result; | ||
459 | } | ||
diff --git a/rbutil/rbutilqt/logger/src/ConsoleAppender.cpp b/rbutil/rbutilqt/logger/src/ConsoleAppender.cpp new file mode 100644 index 0000000000..932ffab787 --- /dev/null +++ b/rbutil/rbutilqt/logger/src/ConsoleAppender.cpp | |||
@@ -0,0 +1,64 @@ | |||
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 "ConsoleAppender.h" | ||
16 | |||
17 | // STL | ||
18 | #include <iostream> | ||
19 | |||
20 | |||
21 | /** | ||
22 | * \class ConsoleAppender | ||
23 | * | ||
24 | * \brief ConsoleAppender is the simple appender that writes the log records to the std::cerr output stream. | ||
25 | * | ||
26 | * ConsoleAppender uses "[%{type:-7}] <%{function}> %{message}\n" as a default output format. It is similar to the | ||
27 | * AbstractStringAppender but doesn't show a timestamp. | ||
28 | * | ||
29 | * You can modify ConsoleAppender output format without modifying your code by using \c QT_MESSAGE_PATTERN environment | ||
30 | * variable. If you need your application to ignore this environment variable you can call | ||
31 | * ConsoleAppender::ignoreEnvironmentPattern(true) | ||
32 | */ | ||
33 | |||
34 | |||
35 | ConsoleAppender::ConsoleAppender() | ||
36 | : AbstractStringAppender() | ||
37 | , m_ignoreEnvPattern(false) | ||
38 | { | ||
39 | setFormat("[%{type:-7}] <%{function}> %{message}\n"); | ||
40 | } | ||
41 | |||
42 | |||
43 | QString ConsoleAppender::format() const | ||
44 | { | ||
45 | const QString envPattern = QString::fromLocal8Bit(qgetenv("QT_MESSAGE_PATTERN")); | ||
46 | return (m_ignoreEnvPattern || envPattern.isEmpty()) ? AbstractStringAppender::format() : (envPattern + "\n"); | ||
47 | } | ||
48 | |||
49 | |||
50 | void ConsoleAppender::ignoreEnvironmentPattern(bool ignore) | ||
51 | { | ||
52 | m_ignoreEnvPattern = ignore; | ||
53 | } | ||
54 | |||
55 | |||
56 | //! Writes the log record to the std::cerr stream. | ||
57 | /** | ||
58 | * \sa AbstractStringAppender::format() | ||
59 | */ | ||
60 | void ConsoleAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | ||
61 | const char* function, const QString& category, const QString& message) | ||
62 | { | ||
63 | std::cerr << qPrintable(formattedString(timeStamp, logLevel, file, line, function, category, message)); | ||
64 | } | ||
diff --git a/rbutil/rbutilqt/logger/FileAppender.cpp b/rbutil/rbutilqt/logger/src/FileAppender.cpp index 3e4d0e22f9..b9018b0324 100644 --- a/rbutil/rbutilqt/logger/FileAppender.cpp +++ b/rbutil/rbutilqt/logger/src/FileAppender.cpp | |||
@@ -17,7 +17,14 @@ | |||
17 | // STL | 17 | // STL |
18 | #include <iostream> | 18 | #include <iostream> |
19 | 19 | ||
20 | /** | ||
21 | * \class FileAppender | ||
22 | * | ||
23 | * \brief Simple appender that writes the log records to the plain text file. | ||
24 | */ | ||
20 | 25 | ||
26 | |||
27 | //! Constructs the new file appender assigned to file with the given name. | ||
21 | FileAppender::FileAppender(const QString& fileName) | 28 | FileAppender::FileAppender(const QString& fileName) |
22 | { | 29 | { |
23 | setFileName(fileName); | 30 | setFileName(fileName); |
@@ -30,6 +37,10 @@ FileAppender::~FileAppender() | |||
30 | } | 37 | } |
31 | 38 | ||
32 | 39 | ||
40 | //! Returns the name set by setFileName() or to the FileAppender constructor. | ||
41 | /** | ||
42 | * \sa setFileName() | ||
43 | */ | ||
33 | QString FileAppender::fileName() const | 44 | QString FileAppender::fileName() const |
34 | { | 45 | { |
35 | QMutexLocker locker(&m_logFileMutex); | 46 | QMutexLocker locker(&m_logFileMutex); |
@@ -37,8 +48,15 @@ QString FileAppender::fileName() const | |||
37 | } | 48 | } |
38 | 49 | ||
39 | 50 | ||
51 | //! Sets the name of the file. The name can have no path, a relative path, or an absolute path. | ||
52 | /** | ||
53 | * \sa fileName() | ||
54 | */ | ||
40 | void FileAppender::setFileName(const QString& s) | 55 | void FileAppender::setFileName(const QString& s) |
41 | { | 56 | { |
57 | if (s.isEmpty()) | ||
58 | std::cerr << "<FileAppender::FileAppender> File name is empty. The appender will do nothing" << std::endl; | ||
59 | |||
42 | QMutexLocker locker(&m_logFileMutex); | 60 | QMutexLocker locker(&m_logFileMutex); |
43 | if (m_logFile.isOpen()) | 61 | if (m_logFile.isOpen()) |
44 | m_logFile.close(); | 62 | m_logFile.close(); |
@@ -47,37 +65,50 @@ void FileAppender::setFileName(const QString& s) | |||
47 | } | 65 | } |
48 | 66 | ||
49 | 67 | ||
68 | bool FileAppender::reopenFile() | ||
69 | { | ||
70 | closeFile(); | ||
71 | return openFile(); | ||
72 | } | ||
73 | |||
74 | |||
50 | bool FileAppender::openFile() | 75 | bool FileAppender::openFile() |
51 | { | 76 | { |
52 | bool isOpen = false; | 77 | if (m_logFile.fileName().isEmpty()) |
53 | if (!m_logFile.isOpen()) | 78 | return false; |
79 | |||
80 | bool isOpen = m_logFile.isOpen(); | ||
81 | if (!isOpen) | ||
54 | { | 82 | { |
55 | if (m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) | 83 | isOpen = m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text); |
56 | { | 84 | if (isOpen) |
57 | m_logStream.setDevice(&m_logFile); | 85 | m_logStream.setDevice(&m_logFile); |
58 | isOpen = true; | ||
59 | } | ||
60 | else | 86 | else |
61 | { | ||
62 | std::cerr << "<FileAppender::append> Cannot open the log file " << qPrintable(m_logFile.fileName()) << std::endl; | 87 | std::cerr << "<FileAppender::append> Cannot open the log file " << qPrintable(m_logFile.fileName()) << std::endl; |
63 | } | ||
64 | } | 88 | } |
65 | return isOpen; | 89 | return isOpen; |
66 | } | 90 | } |
67 | 91 | ||
68 | 92 | ||
93 | //! Write the log record to the file. | ||
94 | /** | ||
95 | * \sa fileName() | ||
96 | * \sa AbstractStringAppender::format() | ||
97 | */ | ||
69 | void FileAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | 98 | void FileAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, |
70 | const char* function, const QString& message) | 99 | const char* function, const QString& category, const QString& message) |
71 | { | 100 | { |
72 | QMutexLocker locker(&m_logFileMutex); | 101 | QMutexLocker locker(&m_logFileMutex); |
73 | 102 | ||
74 | openFile(); | 103 | if (openFile()) |
75 | 104 | { | |
76 | m_logStream << formattedString(timeStamp, logLevel, file, line, function, message); | 105 | m_logStream << formattedString(timeStamp, logLevel, file, line, function, category, message); |
77 | m_logStream.flush(); | 106 | m_logStream.flush(); |
78 | m_logFile.flush(); | 107 | m_logFile.flush(); |
108 | } | ||
79 | } | 109 | } |
80 | 110 | ||
111 | |||
81 | void FileAppender::closeFile() | 112 | void FileAppender::closeFile() |
82 | { | 113 | { |
83 | QMutexLocker locker(&m_logFileMutex); | 114 | QMutexLocker locker(&m_logFileMutex); |
diff --git a/rbutil/rbutilqt/logger/src/Logger.cpp b/rbutil/rbutilqt/logger/src/Logger.cpp new file mode 100644 index 0000000000..16a18db728 --- /dev/null +++ b/rbutil/rbutilqt/logger/src/Logger.cpp | |||
@@ -0,0 +1,1099 @@ | |||
1 | /* | ||
2 | Copyright (c) 2012 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 | #include "AbstractStringAppender.h" | ||
18 | |||
19 | // Qt | ||
20 | #include <QCoreApplication> | ||
21 | #include <QReadWriteLock> | ||
22 | #include <QSemaphore> | ||
23 | #include <QDateTime> | ||
24 | #include <QIODevice> | ||
25 | #include <QTextCodec> | ||
26 | |||
27 | #if defined(Q_OS_ANDROID) | ||
28 | # include <android/log.h> | ||
29 | # include <AndroidAppender.h> | ||
30 | #endif | ||
31 | |||
32 | // STL | ||
33 | #include <iostream> | ||
34 | |||
35 | |||
36 | /** | ||
37 | * \file Logger.h | ||
38 | * \brief A file containing the description of Logger class and and additional useful macros for logging | ||
39 | */ | ||
40 | |||
41 | |||
42 | /** | ||
43 | * \mainpage | ||
44 | * | ||
45 | * Logger is a simple way to write the history of your application lifecycle to any target logging device (which is | ||
46 | * called Appender and may write to any target you will implement with it: console, text file, XML or something - you | ||
47 | * choose) and to map logging message to a class, function, source file and line of code which it is called from. | ||
48 | * | ||
49 | * Some simple appenders (which may be considered an examples) are provided with the Logger itself: see ConsoleAppender | ||
50 | * and FileAppender documentation. | ||
51 | * | ||
52 | * It supports using it in a multithreaded applications, so all of its functions are thread safe. | ||
53 | * | ||
54 | * Simple usage example: | ||
55 | * \code | ||
56 | * #include <QCoreApplication> | ||
57 | * | ||
58 | * #include <Logger.h> | ||
59 | * #include <ConsoleAppender.h> | ||
60 | * | ||
61 | * int main(int argc, char* argv[]) | ||
62 | * { | ||
63 | * QCoreApplication app(argc, argv); | ||
64 | * ... | ||
65 | * ConsoleAppender* consoleAppender = new ConsoleAppender; | ||
66 | * consoleAppender->setFormat("[%{type:-7}] <%{Function}> %{message}\n"); | ||
67 | * cuteLogger->registerAppender(consoleAppender); | ||
68 | * ... | ||
69 | * LOG_INFO("Starting the application"); | ||
70 | * int result = app.exec(); | ||
71 | * ... | ||
72 | * if (result) | ||
73 | * LOG_WARNING() << "Something went wrong." << "Result code is" << result; | ||
74 | * | ||
75 | * return result; | ||
76 | * } | ||
77 | * \endcode | ||
78 | * | ||
79 | * Logger internally uses the lazy-initialized singleton object and needs no definite initialization, but you may | ||
80 | * consider registering a log appender before calling any log recording functions or macros. | ||
81 | * | ||
82 | * The library design of Logger allows you to simply mass-replace all occurrences of qDebug and similar calls with | ||
83 | * similar Logger macros (e.g. LOG_DEBUG()) | ||
84 | * | ||
85 | * \note Logger uses a singleton global instance which lives through all the application life cycle and self-destroys | ||
86 | * destruction of the QCoreApplication (or QApplication) instance. It needs a QCoreApplication instance to be | ||
87 | * created before any of the Logger's functions are called. | ||
88 | * | ||
89 | * \sa cuteLogger | ||
90 | * \sa LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL | ||
91 | * \sa LOG_CTRACE, LOG_CDEBUG, LOG_CINFO, LOG_CWARNING, LOG_CERROR, LOG_CFATAL | ||
92 | * \sa LOG_ASSERT | ||
93 | * \sa LOG_TRACE_TIME, LOG_DEBUG_TIME, LOG_INFO_TIME | ||
94 | * \sa AbstractAppender | ||
95 | */ | ||
96 | |||
97 | |||
98 | /** | ||
99 | * \def cuteLogger | ||
100 | * | ||
101 | * \brief Macro returning the current instance of Logger object | ||
102 | * | ||
103 | * If you haven't created a local Logger object it returns the same value as the Logger::globalInstance() functions. | ||
104 | * This macro is a recommended way to get an access to the Logger instance used in current class. | ||
105 | * | ||
106 | * Example: | ||
107 | * \code | ||
108 | * ConsoleAppender* consoleAppender = new ConsoleAppender; | ||
109 | * cuteLogger->registerAppender(consoleAppender); | ||
110 | * \endcode | ||
111 | * | ||
112 | * \sa Logger::globalInstance() | ||
113 | */ | ||
114 | |||
115 | |||
116 | /** | ||
117 | * \def LOG_TRACE | ||
118 | * | ||
119 | * \brief Writes the trace log record | ||
120 | * | ||
121 | * This macro is the convinient way to call Logger::write(). It uses the common preprocessor macros \c __FILE__, | ||
122 | * \c __LINE__ and the standart Qt \c Q_FUNC_INFO macros to automatically determine the needed parameters to call | ||
123 | * Logger::write(). | ||
124 | * | ||
125 | * \note This and other (LOG_INFO() etc...) macros uses the variadic macro arguments to give convinient usage form for | ||
126 | * the different versions of Logger::write() (using the QString or const char* argument or returning the QDebug class | ||
127 | * instance). Not all compilers will support this. Please, consider reviewing your compiler documentation to ensure | ||
128 | * it support __VA_ARGS__ macro. | ||
129 | * | ||
130 | * \sa Logger::LogLevel | ||
131 | * \sa Logger::write() | ||
132 | */ | ||
133 | |||
134 | |||
135 | /** | ||
136 | * \def LOG_DEBUG | ||
137 | * | ||
138 | * \brief Writes the debug log record | ||
139 | * | ||
140 | * This macro records the debug log record using the Logger::write() function. It works similar to the LOG_TRACE() | ||
141 | * macro. | ||
142 | * | ||
143 | * \sa LOG_TRACE() | ||
144 | * \sa Logger::LogLevel | ||
145 | * \sa Logger::write() | ||
146 | */ | ||
147 | |||
148 | |||
149 | /** | ||
150 | * \def LOG_INFO | ||
151 | * | ||
152 | * \brief Writes the info log record | ||
153 | * | ||
154 | * This macro records the info log record using the Logger::write() function. It works similar to the LOG_TRACE() | ||
155 | * macro. | ||
156 | * | ||
157 | * \sa LOG_TRACE() | ||
158 | * \sa Logger::LogLevel | ||
159 | * \sa Logger::write() | ||
160 | */ | ||
161 | |||
162 | |||
163 | /** | ||
164 | * \def LOG_WARNING | ||
165 | * | ||
166 | * \brief Write the warning log record | ||
167 | * | ||
168 | * This macro records the warning log record using the Logger::write() function. It works similar to the LOG_TRACE() | ||
169 | * macro. | ||
170 | * | ||
171 | * \sa LOG_TRACE() | ||
172 | * \sa Logger::LogLevel | ||
173 | * \sa Logger::write() | ||
174 | */ | ||
175 | |||
176 | |||
177 | /** | ||
178 | * \def LOG_ERROR | ||
179 | * | ||
180 | * \brief Write the error log record | ||
181 | * This macro records the error log record using the Logger::write() function. It works similar to the LOG_TRACE() | ||
182 | * macro. | ||
183 | * | ||
184 | * \sa LOG_TRACE() | ||
185 | * \sa Logger::LogLevel | ||
186 | * \sa Logger::write() | ||
187 | */ | ||
188 | |||
189 | |||
190 | /** | ||
191 | * \def LOG_FATAL | ||
192 | * | ||
193 | * \brief Write the fatal log record | ||
194 | * | ||
195 | * This macro records the fatal log record using the Logger::write() function. It works similar to the LOG_TRACE() | ||
196 | * macro. | ||
197 | * | ||
198 | * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() | ||
199 | * function, which will interrupt the running of your software and begin the writing of the core dump. | ||
200 | * | ||
201 | * \sa LOG_TRACE() | ||
202 | * \sa Logger::LogLevel | ||
203 | * \sa Logger::write() | ||
204 | */ | ||
205 | |||
206 | |||
207 | /** | ||
208 | * \def LOG_CTRACE(category) | ||
209 | * | ||
210 | * \brief Writes the trace log record to the specific category | ||
211 | * | ||
212 | * This macro is the similar to the LOG_TRACE() macro, but has a category parameter | ||
213 | * to write only to the category appenders (registered using Logger::registerCategoryAppender() method). | ||
214 | * | ||
215 | * \param category category name string | ||
216 | * | ||
217 | * \sa LOG_TRACE() | ||
218 | * \sa Logger::LogLevel | ||
219 | * \sa Logger::registerCategoryAppender() | ||
220 | * \sa Logger::write() | ||
221 | * \sa LOG_CATEGORY(), LOG_GLOBAL_CATEGORY() | ||
222 | */ | ||
223 | |||
224 | |||
225 | /** | ||
226 | * \def LOG_CDEBUG | ||
227 | * | ||
228 | * \brief Writes the debug log record to the specific category | ||
229 | * | ||
230 | * This macro records the debug log record using the Logger::write() function. It works similar to the LOG_CTRACE() | ||
231 | * macro. | ||
232 | * | ||
233 | * \sa LOG_CTRACE() | ||
234 | */ | ||
235 | |||
236 | |||
237 | /** | ||
238 | * \def LOG_CINFO | ||
239 | * | ||
240 | * \brief Writes the info log record to the specific category | ||
241 | * | ||
242 | * This macro records the info log record using the Logger::write() function. It works similar to the LOG_CTRACE() | ||
243 | * macro. | ||
244 | * | ||
245 | * \sa LOG_CTRACE() | ||
246 | */ | ||
247 | |||
248 | |||
249 | /** | ||
250 | * \def LOG_CWARNING | ||
251 | * | ||
252 | * \brief Writes the warning log record to the specific category | ||
253 | * | ||
254 | * This macro records the warning log record using the Logger::write() function. It works similar to the LOG_CTRACE() | ||
255 | * macro. | ||
256 | * | ||
257 | * \sa LOG_CTRACE() | ||
258 | */ | ||
259 | |||
260 | |||
261 | /** | ||
262 | * \def LOG_CERROR | ||
263 | * | ||
264 | * \brief Writes the error log record to the specific category | ||
265 | * | ||
266 | * This macro records the error log record using the Logger::write() function. It works similar to the LOG_CTRACE() | ||
267 | * macro. | ||
268 | * | ||
269 | * \sa LOG_CTRACE() | ||
270 | */ | ||
271 | |||
272 | |||
273 | /** | ||
274 | * \def LOG_CFATAL | ||
275 | * | ||
276 | * \brief Write the fatal log record to the specific category | ||
277 | * | ||
278 | * This macro records the fatal log record using the Logger::write() function. It works similar to the LOG_CTRACE() | ||
279 | * macro. | ||
280 | * | ||
281 | * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() | ||
282 | * function, which will interrupt the running of your software and begin the writing of the core dump. | ||
283 | * | ||
284 | * \sa LOG_CTRACE() | ||
285 | */ | ||
286 | |||
287 | |||
288 | /** | ||
289 | * \def LOG_CATEGORY(category) | ||
290 | * | ||
291 | * \brief Create logger instance inside your custom class to log all messages to the specified category | ||
292 | * | ||
293 | * This macro is used to pass all log messages inside your custom class to the specific category. | ||
294 | * You must include this macro inside your class declaration (similarly to the Q_OBJECT macro). | ||
295 | * Internally, this macro redefines cuteLoggerInstance() function, creates the local Logger object inside your class and | ||
296 | * sets the default category to the specified parameter. | ||
297 | * | ||
298 | * Thus, any call to cuteLoggerInstance() (for example, inside LOG_TRACE() macro) will return the local Logger object, | ||
299 | * so any logging message will be directed to the default category. | ||
300 | * | ||
301 | * \note This macro does not register any appender to the newly created logger instance. You should register | ||
302 | * logger appenders manually, inside your class. | ||
303 | * | ||
304 | * Usage example: | ||
305 | * \code | ||
306 | * class CustomClass : public QObject | ||
307 | * { | ||
308 | * Q_OBJECT | ||
309 | * LOG_CATEGORY("custom_category") | ||
310 | * ... | ||
311 | * }; | ||
312 | * | ||
313 | * CustomClass::CustomClass(QObject* parent) : QObject(parent) | ||
314 | * { | ||
315 | * cuteLogger->registerAppender(new FileAppender("custom_category_log")); | ||
316 | * LOG_TRACE() << "Trace to the custom category log"; | ||
317 | * } | ||
318 | * \endcode | ||
319 | * | ||
320 | * If used compiler supports C++11 standard, LOG_CATEGORY and LOG_GLOBAL_CATEGORY macros would also work when added | ||
321 | * inside of any scope. It could be useful, for example, to log every single run of a method to a different file. | ||
322 | * | ||
323 | * \code | ||
324 | * void foo() | ||
325 | * { | ||
326 | * QString categoryName = QDateTime::currentDateTime().toString("yyyy-MM-ddThh-mm-ss-zzz"); | ||
327 | * LOG_CATEGORY(categoryName); | ||
328 | * cuteLogger->registerAppender(new FileAppender(categoryName + ".log")); | ||
329 | * ... | ||
330 | * } | ||
331 | * \endcode | ||
332 | * | ||
333 | * \sa Logger::write() | ||
334 | * \sa LOG_TRACE | ||
335 | * \sa Logger::registerCategoryAppender() | ||
336 | * \sa Logger::setDefaultCategory() | ||
337 | * \sa LOG_GLOBAL_CATEGORY | ||
338 | */ | ||
339 | |||
340 | |||
341 | /** | ||
342 | * \def LOG_GLOBAL_CATEGORY(category) | ||
343 | * | ||
344 | * \brief Create logger instance inside your custom class to log all messages both to the specified category and to | ||
345 | * the global logger instance. | ||
346 | * | ||
347 | * This macro is similar to LOG_CATEGORY(), but also passes all log messages to the global logger instance appenders. | ||
348 | * It is equal to defining the local category logger using LOG_CATEGORY macro and calling: | ||
349 | * \code cuteLogger->logToGlobalInstance(cuteLogger->defaultCategory(), true); \endcode | ||
350 | * | ||
351 | * \sa LOG_CATEGORY | ||
352 | * \sa Logger::logToGlobalInstance() | ||
353 | * \sa Logger::defaultCategory() | ||
354 | * \sa Logger::registerCategoryAppender() | ||
355 | * \sa Logger::write() | ||
356 | */ | ||
357 | |||
358 | |||
359 | |||
360 | /** | ||
361 | * \def LOG_ASSERT | ||
362 | * | ||
363 | * \brief Check the assertion | ||
364 | * | ||
365 | * This macro is a convinient and recommended to use way to call Logger::writeAssert() function. It uses the | ||
366 | * preprocessor macros (as the LOG_DEBUG() does) to fill the necessary arguments of the Logger::writeAssert() call. It | ||
367 | * also uses undocumented but rather mature and stable \c qt_noop() function (which does nothing) when the assertion | ||
368 | * is true. | ||
369 | * | ||
370 | * Example: | ||
371 | * \code | ||
372 | * bool b = checkSomething(); | ||
373 | * ... | ||
374 | * LOG_ASSERT(b == true); | ||
375 | * \endcode | ||
376 | * | ||
377 | * \sa Logger::writeAssert() | ||
378 | */ | ||
379 | |||
380 | |||
381 | /** | ||
382 | * \def LOG_TRACE_TIME | ||
383 | * | ||
384 | * \brief Logs the processing time of current function / code block | ||
385 | * | ||
386 | * This macro automagically measures the function or code of block execution time and outputs it as a Logger::Trace | ||
387 | * level log record. | ||
388 | * | ||
389 | * Example: | ||
390 | * \code | ||
391 | * int foo() | ||
392 | * { | ||
393 | * LOG_TRACE_TIME(); | ||
394 | * ... // Do some long operations | ||
395 | * return 0; | ||
396 | * } // Outputs: Function foo finished in <time> ms. | ||
397 | * \endcode | ||
398 | * | ||
399 | * If you are measuring a code of block execution time you may also add a name of block to the macro: | ||
400 | * \code | ||
401 | * int bar(bool doFoo) | ||
402 | * { | ||
403 | * LOG_TRACE_TIME(); | ||
404 | * | ||
405 | * if (doFoo) | ||
406 | * { | ||
407 | * LOG_TRACE_TIME("Foo"); | ||
408 | * ... | ||
409 | * } | ||
410 | * | ||
411 | * ... | ||
412 | * } | ||
413 | * // Outputs: | ||
414 | * // "Foo" finished in <time1> ms. | ||
415 | * // Function bar finished in <time2> ms. | ||
416 | * \endcode | ||
417 | * | ||
418 | * \note Macro switches to logging the seconds instead of milliseconds when the execution time reaches 10000 ms. | ||
419 | * \sa LOG_DEBUG_TIME, LOG_INFO_TIME | ||
420 | */ | ||
421 | |||
422 | |||
423 | /** | ||
424 | * \def LOG_DEBUG_TIME | ||
425 | * | ||
426 | * \brief Logs the processing time of current function / code block | ||
427 | * | ||
428 | * This macro automagically measures the function or code of block execution time and outputs it as a Logger::Debug | ||
429 | * level log record. It works similar to LOG_TRACE_TIME() macro. | ||
430 | * | ||
431 | * \sa LOG_TRACE_TIME | ||
432 | */ | ||
433 | |||
434 | |||
435 | /** | ||
436 | * \def LOG_INFO_TIME | ||
437 | * | ||
438 | * \brief Logs the processing time of current function / code block | ||
439 | * | ||
440 | * This macro automagically measures the function or code of block execution time and outputs it as a Logger::Info | ||
441 | * level log record. It works similar to LOG_TRACE_TIME() macro. | ||
442 | * | ||
443 | * \sa LOG_TRACE_TIME | ||
444 | */ | ||
445 | |||
446 | |||
447 | /** | ||
448 | * \class Logger | ||
449 | * | ||
450 | * \brief Very simple but rather powerful component which may be used for logging your application activities. | ||
451 | * | ||
452 | * Global logger instance created on a first access to it (e.g. registering appenders, calling a LOG_DEBUG() macro | ||
453 | * etc.) registers itself as a Qt default message handler and captures all the qDebug/qWarning/qCritical output. | ||
454 | * | ||
455 | * \note Qt 4 qDebug set of macro doesn't support capturing source function name, file name or line number so we | ||
456 | * recommend to use LOG_DEBUG() and other Logger macros instead. | ||
457 | * | ||
458 | * \sa cuteLogger | ||
459 | * \sa [CuteLogger Documentation](index.html) | ||
460 | */ | ||
461 | |||
462 | // Forward declarations | ||
463 | static void cleanupLoggerGlobalInstance(); | ||
464 | |||
465 | #if QT_VERSION >= 0x050000 | ||
466 | static void qtLoggerMessageHandler(QtMsgType, const QMessageLogContext& context, const QString& msg); | ||
467 | #else | ||
468 | static void qtLoggerMessageHandler(QtMsgType type, const char* msg); | ||
469 | #endif | ||
470 | |||
471 | /** | ||
472 | * \internal | ||
473 | * | ||
474 | * LoggerPrivate class implements the Singleton pattern in a thread-safe way. It contains a static pointer to the | ||
475 | * global logger instance protected by QReadWriteLock | ||
476 | */ | ||
477 | class LoggerPrivate | ||
478 | { | ||
479 | public: | ||
480 | static Logger* globalInstance; | ||
481 | static QReadWriteLock globalInstanceLock; | ||
482 | |||
483 | QList<AbstractAppender*> appenders; | ||
484 | QMutex loggerMutex; | ||
485 | |||
486 | QMap<QString, bool> categories; | ||
487 | QMultiMap<QString, AbstractAppender*> categoryAppenders; | ||
488 | QStringList noAppendersCategories; //<! Categories without appenders that was already warned about | ||
489 | QString defaultCategory; | ||
490 | bool writeDefaultCategoryToGlobalInstance; | ||
491 | }; | ||
492 | |||
493 | |||
494 | // Static fields initialization | ||
495 | Logger* LoggerPrivate::globalInstance = nullptr; | ||
496 | QReadWriteLock LoggerPrivate::globalInstanceLock; | ||
497 | |||
498 | |||
499 | static void cleanupLoggerGlobalInstance() | ||
500 | { | ||
501 | QWriteLocker locker(&LoggerPrivate::globalInstanceLock); | ||
502 | |||
503 | delete LoggerPrivate::globalInstance; | ||
504 | LoggerPrivate::globalInstance = nullptr; | ||
505 | } | ||
506 | |||
507 | |||
508 | #if QT_VERSION >= 0x050000 | ||
509 | static void qtLoggerMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) | ||
510 | { | ||
511 | Logger::LogLevel level = Logger::Debug; | ||
512 | switch (type) | ||
513 | { | ||
514 | case QtDebugMsg: | ||
515 | level = Logger::Debug; | ||
516 | break; | ||
517 | #if QT_VERSION >= 0x050500 | ||
518 | case QtInfoMsg: | ||
519 | level = Logger::Info; | ||
520 | break; | ||
521 | #endif | ||
522 | case QtWarningMsg: | ||
523 | level = Logger::Warning; | ||
524 | break; | ||
525 | case QtCriticalMsg: | ||
526 | level = Logger::Error; | ||
527 | break; | ||
528 | case QtFatalMsg: | ||
529 | level = Logger::Fatal; | ||
530 | break; | ||
531 | } | ||
532 | |||
533 | bool isDefaultCategory = QString::fromLatin1(context.category) == "default"; | ||
534 | Logger::globalInstance()->write(level, context.file, context.line, context.function, isDefaultCategory ? nullptr : context.category, msg); | ||
535 | } | ||
536 | |||
537 | #else | ||
538 | |||
539 | static void qtLoggerMessageHandler(QtMsgType type, const char* msg) | ||
540 | { | ||
541 | switch (type) | ||
542 | { | ||
543 | case QtDebugMsg: | ||
544 | cuteLoggerInstance()->write(Logger::Debug, "", 0, "qDebug", 0, msg); | ||
545 | break; | ||
546 | case QtWarningMsg: | ||
547 | cuteLoggerInstance()->write(Logger::Warning, "", 0, "qDebug", 0, msg); | ||
548 | break; | ||
549 | case QtCriticalMsg: | ||
550 | cuteLoggerInstance()->write(Logger::Error, "", 0, "qDebug", 0, msg); | ||
551 | break; | ||
552 | case QtFatalMsg: | ||
553 | cuteLoggerInstance()->write(Logger::Fatal, "", 0, "qDebug", 0, msg); | ||
554 | break; | ||
555 | } | ||
556 | } | ||
557 | #endif | ||
558 | |||
559 | |||
560 | //! Construct the instance of Logger | ||
561 | /** | ||
562 | * If you're only using one global instance of logger you wouldn't probably need to use this constructor manually. | ||
563 | * Consider using [cuteLogger](@ref cuteLogger) macro instead to access the logger instance | ||
564 | */ | ||
565 | Logger::Logger() | ||
566 | : d_ptr(new LoggerPrivate) | ||
567 | { | ||
568 | Q_D(Logger); | ||
569 | d->writeDefaultCategoryToGlobalInstance = false; | ||
570 | } | ||
571 | |||
572 | |||
573 | //! Construct the instance of Logger and set logger default category | ||
574 | /** | ||
575 | * If you're only using one global instance of logger you wouldn't probably need to use this constructor manually. | ||
576 | * Consider using [cuteLogger](@ref cuteLogger) macro instead to access the logger instance and call | ||
577 | * [setDefaultCategory](@ref setDefaultCategory) method. | ||
578 | * | ||
579 | * \sa Logger() | ||
580 | * \sa setDefaultCategory() | ||
581 | */ | ||
582 | Logger::Logger(const QString& defaultCategory, bool writeToGlobalInstance) | ||
583 | : d_ptr(new LoggerPrivate) | ||
584 | { | ||
585 | Q_D(Logger); | ||
586 | d->writeDefaultCategoryToGlobalInstance = writeToGlobalInstance; | ||
587 | |||
588 | setDefaultCategory(defaultCategory); | ||
589 | } | ||
590 | |||
591 | |||
592 | //! Destroy the instance of Logger | ||
593 | /** | ||
594 | * You probably wouldn't need to use this function directly. Global instance of logger will be destroyed automatically | ||
595 | * at the end of your QCoreApplication execution | ||
596 | */ | ||
597 | Logger::~Logger() | ||
598 | { | ||
599 | Q_D(Logger); | ||
600 | |||
601 | // Cleanup appenders | ||
602 | QMutexLocker appendersLocker(&d->loggerMutex); | ||
603 | QSet<AbstractAppender*> deleteList(QSet<AbstractAppender*>::fromList(d->appenders)); | ||
604 | deleteList.unite(QSet<AbstractAppender*>::fromList(d->categoryAppenders.values())); | ||
605 | qDeleteAll(deleteList); | ||
606 | |||
607 | appendersLocker.unlock(); | ||
608 | |||
609 | delete d_ptr; | ||
610 | } | ||
611 | |||
612 | |||
613 | //! Converts the LogLevel enum value to its string representation | ||
614 | /** | ||
615 | * \param logLevel Log level to convert | ||
616 | * | ||
617 | * \sa LogLevel | ||
618 | * \sa levelFromString() | ||
619 | */ | ||
620 | QString Logger::levelToString(Logger::LogLevel logLevel) | ||
621 | { | ||
622 | switch (logLevel) | ||
623 | { | ||
624 | case Trace: | ||
625 | return QLatin1String("Trace"); | ||
626 | case Debug: | ||
627 | return QLatin1String("Debug"); | ||
628 | case Info: | ||
629 | return QLatin1String("Info"); | ||
630 | case Warning: | ||
631 | return QLatin1String("Warning"); | ||
632 | case Error: | ||
633 | return QLatin1String("Error"); | ||
634 | case Fatal: | ||
635 | return QLatin1String("Fatal"); | ||
636 | } | ||
637 | |||
638 | return QString(); | ||
639 | } | ||
640 | |||
641 | |||
642 | //! Converts the LogLevel string representation to enum value | ||
643 | /** | ||
644 | * Comparation of the strings is case independent. If the log level string provided cannot be understood | ||
645 | * Logger::Debug is returned. | ||
646 | * | ||
647 | * \param s String to be decoded | ||
648 | * | ||
649 | * \sa LogLevel | ||
650 | * \sa levelToString() | ||
651 | */ | ||
652 | Logger::LogLevel Logger::levelFromString(const QString& s) | ||
653 | { | ||
654 | QString str = s.trimmed().toLower(); | ||
655 | |||
656 | LogLevel result = Debug; | ||
657 | |||
658 | if (str == QLatin1String("trace")) | ||
659 | result = Trace; | ||
660 | else if (str == QLatin1String("debug")) | ||
661 | result = Debug; | ||
662 | else if (str == QLatin1String("info")) | ||
663 | result = Info; | ||
664 | else if (str == QLatin1String("warning")) | ||
665 | result = Warning; | ||
666 | else if (str == QLatin1String("error")) | ||
667 | result = Error; | ||
668 | else if (str == QLatin1String("fatal")) | ||
669 | result = Fatal; | ||
670 | |||
671 | return result; | ||
672 | } | ||
673 | |||
674 | |||
675 | //! Returns the global instance of Logger | ||
676 | /** | ||
677 | * In a most cases you shouldn't use this function directly. Consider using [cuteLogger](@ref cuteLogger) macro instead. | ||
678 | * | ||
679 | * \sa cuteLogger | ||
680 | */ | ||
681 | Logger* Logger::globalInstance() | ||
682 | { | ||
683 | Logger* result = nullptr; | ||
684 | { | ||
685 | QReadLocker locker(&LoggerPrivate::globalInstanceLock); | ||
686 | result = LoggerPrivate::globalInstance; | ||
687 | } | ||
688 | |||
689 | if (!result) | ||
690 | { | ||
691 | QWriteLocker locker(&LoggerPrivate::globalInstanceLock); | ||
692 | LoggerPrivate::globalInstance = new Logger; | ||
693 | |||
694 | #if QT_VERSION >= 0x050000 | ||
695 | qInstallMessageHandler(qtLoggerMessageHandler); | ||
696 | #else | ||
697 | qInstallMsgHandler(qtLoggerMessageHandler); | ||
698 | #endif | ||
699 | qAddPostRoutine(cleanupLoggerGlobalInstance); | ||
700 | result = LoggerPrivate::globalInstance; | ||
701 | } | ||
702 | |||
703 | return result; | ||
704 | } | ||
705 | |||
706 | |||
707 | //! Registers the appender to write the log records to | ||
708 | /** | ||
709 | * On the log writing call (using one of the macros or the write() function) Logger traverses through the list of | ||
710 | * the appenders and writes a log records to the each of them. Please, look through the AbstractAppender | ||
711 | * documentation to understand the concept of appenders. | ||
712 | * | ||
713 | * If no appenders was added to Logger, it falls back to logging into the \c std::cerr STL stream. | ||
714 | * | ||
715 | * \param appender Appender to register in the Logger | ||
716 | * | ||
717 | * \note Logger takes ownership on the appender and it will delete it on the application exit. According to this, | ||
718 | * appenders must be created on heap to prevent double destruction of the appender. | ||
719 | * | ||
720 | * \sa registerCategoryAppender | ||
721 | * \sa AbstractAppender | ||
722 | */ | ||
723 | void Logger::registerAppender(AbstractAppender* appender) | ||
724 | { | ||
725 | Q_D(Logger); | ||
726 | |||
727 | QMutexLocker locker(&d->loggerMutex); | ||
728 | |||
729 | if (!d->appenders.contains(appender)) | ||
730 | d->appenders.append(appender); | ||
731 | else | ||
732 | std::cerr << "Trying to register appender that was already registered" << std::endl; | ||
733 | } | ||
734 | |||
735 | //! Registers the appender to write the log records to the specific category | ||
736 | /** | ||
737 | * Calling this method, you can link some appender with the named category. | ||
738 | * On the log writing call to the specific category (calling write() with category parameter directly, | ||
739 | * writing to the default category, or using special LOG_CDEBUG(), LOG_CWARNING() etc. macros), | ||
740 | * Logger writes the log message only to the list of registered category appenders. | ||
741 | * | ||
742 | * You can call logToGlobalInstance() to pass all category log messages to the global logger instance appenders | ||
743 | * (registered using registerAppender()). | ||
744 | * If no category appenders with specific name was registered to the Logger, | ||
745 | * it falls back to logging into the \c std::cerr STL stream, both with simple warning message. | ||
746 | * | ||
747 | * \param category Category name | ||
748 | * \param appender Appender to register in the Logger | ||
749 | * | ||
750 | * \note Logger takes ownership on the appender and it will delete it on the application exit. According to this, | ||
751 | * appenders must be created on heap to prevent double destruction of the appender. | ||
752 | * | ||
753 | * \sa registerAppender | ||
754 | * \sa LOG_CTRACE(), LOG_CDEBUG(), LOG_CINFO(), LOG_CWARNING(), LOG_CERROR(), LOG_CFATAL() | ||
755 | * \sa LOG_CATEGORY(), LOG_GLOBAL_CATEGORY() | ||
756 | * \sa logToGlobalInstance | ||
757 | * \sa setDefaultCategory | ||
758 | */ | ||
759 | void Logger::registerCategoryAppender(const QString& category, AbstractAppender* appender) | ||
760 | { | ||
761 | Q_D(Logger); | ||
762 | |||
763 | QMutexLocker locker(&d->loggerMutex); | ||
764 | |||
765 | if (!d->categoryAppenders.values().contains(appender)) | ||
766 | d->categoryAppenders.insert(category, appender); | ||
767 | else | ||
768 | std::cerr << "Trying to register appender that was already registered" << std::endl; | ||
769 | } | ||
770 | |||
771 | |||
772 | //! Removes the registered appender from logger | ||
773 | /** | ||
774 | * After calling this function logger stops writing any of the records to the appender. | ||
775 | * | ||
776 | * \param appender Pointer to appender to remove from logger | ||
777 | * \note Removed appender will not be deleted on the application shutdown and you will need to destroy the object | ||
778 | * yourself. | ||
779 | * \sa registerAppender | ||
780 | */ | ||
781 | void Logger::removeAppender(AbstractAppender* appender) | ||
782 | { | ||
783 | Q_D(Logger); | ||
784 | |||
785 | QMutexLocker locker(&d->loggerMutex); | ||
786 | |||
787 | d->appenders.removeAll(appender); | ||
788 | for (QMultiMap<QString,AbstractAppender*>::iterator it = d->categoryAppenders.begin(); it != d->categoryAppenders.end();) | ||
789 | { | ||
790 | if (it.value() == appender) | ||
791 | it = d->categoryAppenders.erase(it); | ||
792 | else | ||
793 | ++it; | ||
794 | } | ||
795 | } | ||
796 | |||
797 | |||
798 | //! Sets default logging category | ||
799 | /** | ||
800 | * All log messages to this category appenders will also be written to general logger instance appenders (registered | ||
801 | * using [registerAppender](@ref registerAppender) method), and vice versa. | ||
802 | * In particular, any calls to the LOG_DEBUG() macro will be treated as category logging, | ||
803 | * so you needn't to specify category name using LOG_CDEBUG() macro. | ||
804 | * | ||
805 | * To unset the default category, pass a null string as a parameter. | ||
806 | * | ||
807 | * \param category Category name | ||
808 | * | ||
809 | * \note "category" format marker will be set to the category name for all of these messages | ||
810 | * (see [AbstractStringAppender::setFormat](@ref AbstractStringAppender::setFormat)). | ||
811 | * | ||
812 | * \sa defaultCategory() | ||
813 | * \sa registerCategoryAppender() | ||
814 | * \sa logToGlobalInstance() | ||
815 | */ | ||
816 | void Logger::setDefaultCategory(const QString& category) | ||
817 | { | ||
818 | Q_D(Logger); | ||
819 | |||
820 | QMutexLocker locker(&d->loggerMutex); | ||
821 | |||
822 | d->defaultCategory = category; | ||
823 | } | ||
824 | |||
825 | //! Returns default logging category name | ||
826 | /** | ||
827 | * \sa setDefaultCategory | ||
828 | */ | ||
829 | QString Logger::defaultCategory() const | ||
830 | { | ||
831 | Q_D(const Logger); | ||
832 | return d->defaultCategory; | ||
833 | } | ||
834 | |||
835 | //! Links some logging category with the global logger instance appenders. | ||
836 | /** | ||
837 | * If set to true, all log messages to the specified category appenders will also be written to the global logger instance appenders, | ||
838 | * registered using registerAppender(). | ||
839 | * | ||
840 | * By default, all messages to the specific category are written only to the specific category appenders | ||
841 | * (registered using registerCategoryAppender()). | ||
842 | * | ||
843 | * \param category Category name | ||
844 | * \param logToGlobal Link or onlink the category from global logger instance appender | ||
845 | * | ||
846 | * \sa globalInstance | ||
847 | * \sa registerAppender | ||
848 | * \sa registerCategoryAppender | ||
849 | */ | ||
850 | void Logger::logToGlobalInstance(const QString& category, bool logToGlobal) | ||
851 | { | ||
852 | Q_D(Logger); | ||
853 | |||
854 | if (this == globalInstance()) | ||
855 | { | ||
856 | QMutexLocker locker(&d->loggerMutex); | ||
857 | d->categories.insert(category, logToGlobal); | ||
858 | } | ||
859 | else | ||
860 | { | ||
861 | globalInstance()->logToGlobalInstance(category, logToGlobal); | ||
862 | } | ||
863 | } | ||
864 | |||
865 | |||
866 | void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category, | ||
867 | const QString& message, bool fromLocalInstance) | ||
868 | { | ||
869 | Q_D(Logger); | ||
870 | |||
871 | QMutexLocker locker(&d->loggerMutex); | ||
872 | |||
873 | QString logCategory = QString::fromLatin1(category); | ||
874 | if (logCategory.isNull() && !d->defaultCategory.isNull()) | ||
875 | logCategory = d->defaultCategory; | ||
876 | |||
877 | bool wasWritten = false; | ||
878 | bool isGlobalInstance = this == globalInstance(); | ||
879 | bool linkedToGlobal = isGlobalInstance && d->categories.value(logCategory, false); | ||
880 | |||
881 | if (!logCategory.isNull()) | ||
882 | { | ||
883 | QList<AbstractAppender*> appenders = d->categoryAppenders.values(logCategory); | ||
884 | if (appenders.length() == 0) | ||
885 | { | ||
886 | if (logCategory != d->defaultCategory && !linkedToGlobal && !fromLocalInstance && !d->noAppendersCategories.contains(logCategory)) | ||
887 | { | ||
888 | std::cerr << "No appenders associated with category " << qPrintable(logCategory) << std::endl; | ||
889 | d->noAppendersCategories.append(logCategory); | ||
890 | } | ||
891 | } | ||
892 | else | ||
893 | { | ||
894 | foreach (AbstractAppender* appender, appenders) | ||
895 | appender->write(timeStamp, logLevel, file, line, function, logCategory, message); | ||
896 | wasWritten = true; | ||
897 | } | ||
898 | } | ||
899 | |||
900 | // the default category is linked to the main logger appenders | ||
901 | // global logger instance also writes all linked categories to the main appenders | ||
902 | if (logCategory.isNull() || logCategory == d->defaultCategory || linkedToGlobal) | ||
903 | { | ||
904 | if (!d->appenders.isEmpty()) | ||
905 | { | ||
906 | foreach (AbstractAppender* appender, d->appenders) | ||
907 | appender->write(timeStamp, logLevel, file, line, function, logCategory, message); | ||
908 | wasWritten = true; | ||
909 | } | ||
910 | else | ||
911 | { | ||
912 | static bool noAppendersWarningShown = false; | ||
913 | if (!noAppendersWarningShown) | ||
914 | { | ||
915 | #if defined(Q_OS_ANDROID) | ||
916 | __android_log_write(ANDROID_LOG_WARN, "Logger", "No appenders registered with logger"); | ||
917 | #else | ||
918 | std::cerr << "No appenders registered with logger" << std::endl; | ||
919 | #endif | ||
920 | noAppendersWarningShown = true; | ||
921 | } | ||
922 | } | ||
923 | } | ||
924 | |||
925 | // local logger instances send category messages to the global instance | ||
926 | if (!isGlobalInstance) | ||
927 | { | ||
928 | if (!logCategory.isNull()) | ||
929 | { | ||
930 | globalInstance()->write(timeStamp, logLevel, file, line, function, logCategory.toLatin1(), message, true); | ||
931 | wasWritten = true; | ||
932 | } | ||
933 | |||
934 | if (d->writeDefaultCategoryToGlobalInstance && logCategory == d->defaultCategory) | ||
935 | { | ||
936 | globalInstance()->write(timeStamp, logLevel, file, line, function, nullptr, message, true); | ||
937 | wasWritten = true; | ||
938 | } | ||
939 | } | ||
940 | |||
941 | if (!wasWritten && !fromLocalInstance) | ||
942 | { | ||
943 | // Fallback | ||
944 | #if defined(Q_OS_ANDROID) | ||
945 | QString result = QString(QLatin1String("<%2> %3")).arg(AbstractStringAppender::stripFunctionName(function)).arg(message); | ||
946 | __android_log_write(AndroidAppender::androidLogPriority(logLevel), "Logger", qPrintable(result)); | ||
947 | #else | ||
948 | QString result = QString(QLatin1String("[%1] <%2> %3")).arg(levelToString(logLevel), -7) | ||
949 | .arg(AbstractStringAppender::stripFunctionName(function)).arg(message); | ||
950 | std::cerr << qPrintable(result) << std::endl; | ||
951 | #endif | ||
952 | } | ||
953 | |||
954 | if (logLevel == Logger::Fatal) | ||
955 | abort(); | ||
956 | } | ||
957 | |||
958 | |||
959 | //! Writes the log record | ||
960 | /** | ||
961 | * Writes the log records with the supplied arguments to all the registered appenders. | ||
962 | * | ||
963 | * \note It is not recommended to call this function directly. Instead of this you can just call one of the macros | ||
964 | * (LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL) that will supply all the needed | ||
965 | * information to this function. | ||
966 | * | ||
967 | * \param timeStamp - the time stamp of the record | ||
968 | * \param logLevel - the log level of the record | ||
969 | * \param file - the name of the source file that requested the log record | ||
970 | * \param line - the line of the code of source file that requested the log record | ||
971 | * \param function - name of the function that requested the log record | ||
972 | * \param category - logging category (0 for default category) | ||
973 | * \param message - log message | ||
974 | * | ||
975 | * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() | ||
976 | * function, which will interrupt the running of your software and begin the writing of the core dump. | ||
977 | * | ||
978 | * \sa LogLevel | ||
979 | * \sa LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL | ||
980 | * \sa AbstractAppender | ||
981 | */ | ||
982 | void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category, | ||
983 | const QString& message) | ||
984 | { | ||
985 | write(timeStamp, logLevel, file, line, function, category, message, /* fromLocalInstance = */ false); | ||
986 | } | ||
987 | |||
988 | /** | ||
989 | * This is the overloaded function provided for the convinience. It behaves similar to the above function. | ||
990 | * | ||
991 | * This function uses the current timestamp obtained with \c QDateTime::currentDateTime(). | ||
992 | * | ||
993 | * \sa write() | ||
994 | */ | ||
995 | void Logger::write(LogLevel logLevel, const char* file, int line, const char* function, const char* category, | ||
996 | const QString& message) | ||
997 | { | ||
998 | write(QDateTime::currentDateTime(), logLevel, file, line, function, category, message); | ||
999 | } | ||
1000 | |||
1001 | |||
1002 | //! Writes the assertion | ||
1003 | /** | ||
1004 | * This function writes the assertion record using the write() function. | ||
1005 | * | ||
1006 | * The assertion record is always written using the Logger::Fatal log level which leads to the abortation of the | ||
1007 | * program and generation of the core dump (if supported). | ||
1008 | * | ||
1009 | * The message written to the appenders will be identical to the \c condition argument prefixed with the | ||
1010 | * <tt>ASSERT:</tt> notification. | ||
1011 | * | ||
1012 | * \note It is not recommended to call this function directly. Instead of this you can just call the LOG_ASSERT | ||
1013 | * macro that will supply all the needed information to this function. | ||
1014 | * | ||
1015 | * \sa LOG_ASSERT | ||
1016 | * \sa write() | ||
1017 | */ | ||
1018 | void Logger::writeAssert(const char* file, int line, const char* function, const char* condition) | ||
1019 | { | ||
1020 | write(Logger::Fatal, file, line, function, nullptr, QString("ASSERT: \"%1\"").arg(condition)); | ||
1021 | } | ||
1022 | |||
1023 | |||
1024 | Logger* cuteLoggerInstance() | ||
1025 | { | ||
1026 | return Logger::globalInstance(); | ||
1027 | } | ||
1028 | |||
1029 | |||
1030 | |||
1031 | void LoggerTimingHelper::start(const char* msg, ...) | ||
1032 | { | ||
1033 | va_list va; | ||
1034 | va_start(va, msg); | ||
1035 | m_block = QString().vsprintf(msg, va); | ||
1036 | va_end(va); | ||
1037 | |||
1038 | m_time.start(); | ||
1039 | } | ||
1040 | |||
1041 | |||
1042 | void LoggerTimingHelper::start(const QString& block) | ||
1043 | { | ||
1044 | m_block = block; | ||
1045 | m_time.start(); | ||
1046 | } | ||
1047 | |||
1048 | |||
1049 | void LoggerTimingHelper::start(Logger::TimingMode mode, const QString& block) | ||
1050 | { | ||
1051 | m_timingMode = mode; | ||
1052 | m_block = block; | ||
1053 | m_time.start(); | ||
1054 | } | ||
1055 | |||
1056 | |||
1057 | LoggerTimingHelper::~LoggerTimingHelper() | ||
1058 | { | ||
1059 | QString message; | ||
1060 | if (m_block.isEmpty()) | ||
1061 | message = QString(QLatin1String("Function %1 finished in ")).arg(AbstractStringAppender::stripFunctionName(m_function)); | ||
1062 | else | ||
1063 | message = QString(QLatin1String("\"%1\" finished in ")).arg(m_block); | ||
1064 | |||
1065 | int elapsed = m_time.elapsed(); | ||
1066 | if (elapsed >= 10000 && m_timingMode == Logger::TimingAuto) | ||
1067 | message += QString(QLatin1String("%1 s.")).arg(elapsed / 1000); | ||
1068 | else | ||
1069 | message += QString(QLatin1String("%1 ms.")).arg(elapsed); | ||
1070 | |||
1071 | m_logger->write(m_logLevel, m_file, m_line, m_function, nullptr, message); | ||
1072 | } | ||
1073 | |||
1074 | |||
1075 | CuteMessageLogger::~CuteMessageLogger() | ||
1076 | { | ||
1077 | m_l->write(m_level, m_file, m_line, m_function, m_category, m_message); | ||
1078 | } | ||
1079 | |||
1080 | void CuteMessageLogger::write(const char* msg, ...) | ||
1081 | { | ||
1082 | va_list va; | ||
1083 | va_start(va, msg); | ||
1084 | m_message = QString::vasprintf(msg, va); | ||
1085 | va_end(va); | ||
1086 | } | ||
1087 | |||
1088 | |||
1089 | void CuteMessageLogger::write(const QString& msg) | ||
1090 | { | ||
1091 | m_message = msg; | ||
1092 | } | ||
1093 | |||
1094 | |||
1095 | QDebug CuteMessageLogger::write() | ||
1096 | { | ||
1097 | QDebug d(&m_message); | ||
1098 | return d; | ||
1099 | } | ||
diff --git a/rbutil/rbutilqt/logger/OutputDebugAppender.cpp b/rbutil/rbutilqt/logger/src/OutputDebugAppender.cpp index 2d7facbd98..44d640512f 100644 --- a/rbutil/rbutilqt/logger/OutputDebugAppender.cpp +++ b/rbutil/rbutilqt/logger/src/OutputDebugAppender.cpp | |||
@@ -18,14 +18,26 @@ | |||
18 | #include <windows.h> | 18 | #include <windows.h> |
19 | 19 | ||
20 | 20 | ||
21 | /** | ||
22 | * \class OutputDebugAppender | ||
23 | * | ||
24 | * \brief Appender that writes the log records to the Microsoft Debug Log | ||
25 | */ | ||
26 | |||
27 | |||
28 | //! Writes the log record to the windows debug log. | ||
29 | /** | ||
30 | * \sa AbstractStringAppender::format() | ||
31 | */ | ||
21 | void OutputDebugAppender::append(const QDateTime& timeStamp, | 32 | void OutputDebugAppender::append(const QDateTime& timeStamp, |
22 | Logger::LogLevel logLevel, | 33 | Logger::LogLevel logLevel, |
23 | const char* file, | 34 | const char* file, |
24 | int line, | 35 | int line, |
25 | const char* function, | 36 | const char* function, |
37 | const QString& category, | ||
26 | const QString& message) | 38 | const QString& message) |
27 | { | 39 | { |
28 | QString s = formattedString(timeStamp, logLevel, file, line, function, message); | 40 | QString s = formattedString(timeStamp, logLevel, file, line, function, category, message); |
29 | OutputDebugStringW((LPCWSTR) s.utf16()); | 41 | OutputDebugStringW((LPCWSTR) s.utf16()); |
30 | } | 42 | } |
31 | 43 | ||
diff --git a/rbutil/rbutilqt/main.cpp b/rbutil/rbutilqt/main.cpp index cac93395fe..160a31ba0e 100644 --- a/rbutil/rbutilqt/main.cpp +++ b/rbutil/rbutilqt/main.cpp | |||
@@ -40,14 +40,14 @@ Q_IMPORT_PLUGIN(AccessibleFactory) | |||
40 | int main( int argc, char ** argv ) { | 40 | int main( int argc, char ** argv ) { |
41 | QApplication app( argc, argv ); | 41 | QApplication app( argc, argv ); |
42 | ConsoleAppender* consoleAppender = new ConsoleAppender(); | 42 | ConsoleAppender* consoleAppender = new ConsoleAppender(); |
43 | consoleAppender->setFormat("[%f:%i %L] %m\n"); | 43 | consoleAppender->setFormat("[%{file}:%{line} %{type}] %{message}\n"); |
44 | Logger::registerAppender(consoleAppender); | 44 | cuteLoggerInstance()->registerAppender(consoleAppender); |
45 | SysTrace::rotateTrace(); | 45 | SysTrace::rotateTrace(); |
46 | QString tracefile = QDir::tempPath() + "/rbutil-trace.log"; | 46 | QString tracefile = QDir::tempPath() + "/rbutil-trace.log"; |
47 | FileAppender* fileAppender = new FileAppender(); | 47 | FileAppender* fileAppender = new FileAppender(); |
48 | fileAppender->setFormat("[%f:%i %L] %m\n"); | 48 | fileAppender->setFormat("[%{file}:%{line} %{type}] %{message}\n"); |
49 | fileAppender->setFileName(tracefile); | 49 | fileAppender->setFileName(tracefile); |
50 | Logger::registerAppender(fileAppender); | 50 | cuteLoggerInstance()->registerAppender(fileAppender); |
51 | LOG_INFO() << "Starting trace at" << QDateTime::currentDateTime().toString(Qt::ISODate); | 51 | LOG_INFO() << "Starting trace at" << QDateTime::currentDateTime().toString(Qt::ISODate); |
52 | 52 | ||
53 | #if defined(Q_OS_MAC) | 53 | #if defined(Q_OS_MAC) |
diff --git a/rbutil/rbutilqt/systrace.cpp b/rbutil/rbutilqt/systrace.cpp index 83f70b3da5..5f3450eae8 100644 --- a/rbutil/rbutilqt/systrace.cpp +++ b/rbutil/rbutilqt/systrace.cpp | |||
@@ -50,11 +50,11 @@ void SysTrace::refresh(void) | |||
50 | QString color; | 50 | QString color; |
51 | while(!c.atEnd()) { | 51 | while(!c.atEnd()) { |
52 | line = c.readLine(); | 52 | line = c.readLine(); |
53 | if(line.contains("WARNING")) | 53 | if(line.contains("Warning")) |
54 | color = "orange"; | 54 | color = "orange"; |
55 | else if(line.contains("ERROR")) | 55 | else if(line.contains("Error")) |
56 | color = "red"; | 56 | color = "red"; |
57 | else if(line.contains("DEBUG")) | 57 | else if(line.contains("Debug")) |
58 | color = "blue"; | 58 | color = "blue"; |
59 | #if 0 | 59 | #if 0 |
60 | else if(line.contains("INFO")) | 60 | else if(line.contains("INFO")) |