diff options
Diffstat (limited to 'common/log.cpp')
-rw-r--r-- | common/log.cpp | 165 |
1 files changed, 133 insertions, 32 deletions
diff --git a/common/log.cpp b/common/log.cpp index 45bbec1..96c6f82 100644 --- a/common/log.cpp +++ b/common/log.cpp | |||
@@ -3,11 +3,19 @@ | |||
3 | #include <QString> | 3 | #include <QString> |
4 | #include <QIODevice> | 4 | #include <QIODevice> |
5 | #include <QCoreApplication> | 5 | #include <QCoreApplication> |
6 | #include <QSettings> | ||
7 | #include <QStandardPaths> | ||
8 | #include <QSharedPointer> | ||
6 | #include <iostream> | 9 | #include <iostream> |
7 | #include <unistd.h> | 10 | #include <unistd.h> |
8 | 11 | ||
9 | using namespace Sink::Log; | 12 | using namespace Sink::Log; |
10 | 13 | ||
14 | static QSharedPointer<QSettings> config() | ||
15 | { | ||
16 | return QSharedPointer<QSettings>::create(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/sink/log.ini", QSettings::IniFormat); | ||
17 | } | ||
18 | |||
11 | class DebugStream: public QIODevice | 19 | class DebugStream: public QIODevice |
12 | { | 20 | { |
13 | public: | 21 | public: |
@@ -17,24 +25,24 @@ public: | |||
17 | { | 25 | { |
18 | open(WriteOnly); | 26 | open(WriteOnly); |
19 | } | 27 | } |
20 | virtual ~DebugStream(){}; | 28 | virtual ~DebugStream(); |
21 | 29 | ||
22 | bool isSequential() const { return true; } | 30 | bool isSequential() const { return true; } |
23 | qint64 readData(char *, qint64) { return 0; /* eof */ } | 31 | qint64 readData(char *, qint64) { return 0; /* eof */ } |
24 | qint64 readLineData(char *, qint64) { return 0; /* eof */ } | 32 | qint64 readLineData(char *, qint64) { return 0; /* eof */ } |
25 | qint64 writeData(const char *data, qint64 len) | 33 | qint64 writeData(const char *data, qint64 len) |
26 | { | 34 | { |
27 | const QByteArray buf = QByteArray::fromRawData(data, len); | 35 | std::cout << data << std::endl; |
28 | // if (!qgetenv("IMAP_TRACE").isEmpty()) { | ||
29 | // qt_message_output(QtDebugMsg, buf.trimmed().constData()); | ||
30 | std::cout << buf.trimmed().constData() << std::endl; | ||
31 | // } | ||
32 | return len; | 36 | return len; |
33 | } | 37 | } |
34 | private: | 38 | private: |
35 | Q_DISABLE_COPY(DebugStream) | 39 | Q_DISABLE_COPY(DebugStream) |
36 | }; | 40 | }; |
37 | 41 | ||
42 | //Virtual method anchor | ||
43 | DebugStream::~DebugStream() | ||
44 | {} | ||
45 | |||
38 | class NullStream: public QIODevice | 46 | class NullStream: public QIODevice |
39 | { | 47 | { |
40 | public: | 48 | public: |
@@ -43,7 +51,7 @@ public: | |||
43 | { | 51 | { |
44 | open(WriteOnly); | 52 | open(WriteOnly); |
45 | } | 53 | } |
46 | virtual ~NullStream(){}; | 54 | virtual ~NullStream(); |
47 | 55 | ||
48 | bool isSequential() const { return true; } | 56 | bool isSequential() const { return true; } |
49 | qint64 readData(char *, qint64) { return 0; /* eof */ } | 57 | qint64 readData(char *, qint64) { return 0; /* eof */ } |
@@ -56,6 +64,10 @@ private: | |||
56 | Q_DISABLE_COPY(NullStream) | 64 | Q_DISABLE_COPY(NullStream) |
57 | }; | 65 | }; |
58 | 66 | ||
67 | //Virtual method anchor | ||
68 | NullStream::~NullStream() | ||
69 | {} | ||
70 | |||
59 | /* | 71 | /* |
60 | * ANSI color codes: | 72 | * ANSI color codes: |
61 | * 0: reset colors/style | 73 | * 0: reset colors/style |
@@ -130,31 +142,95 @@ DebugLevel Sink::Log::debugLevelFromName(const QByteArray &name) | |||
130 | 142 | ||
131 | void Sink::Log::setDebugOutputLevel(DebugLevel debugLevel) | 143 | void Sink::Log::setDebugOutputLevel(DebugLevel debugLevel) |
132 | { | 144 | { |
133 | qputenv("SINKDEBUGLEVEL", debugLevelName(debugLevel)); | 145 | config()->setValue("level", debugLevel); |
134 | } | 146 | } |
135 | 147 | ||
136 | Sink::Log::DebugLevel Sink::Log::debugOutputLevel() | 148 | Sink::Log::DebugLevel Sink::Log::debugOutputLevel() |
137 | { | 149 | { |
138 | return debugLevelFromName(qgetenv("SINKDEBUGLEVEL")); | 150 | return static_cast<Sink::Log::DebugLevel>(config()->value("level", Sink::Log::Log).toInt()); |
151 | } | ||
152 | |||
153 | void Sink::Log::setDebugOutputFilter(FilterType type, const QByteArrayList &filter) | ||
154 | { | ||
155 | switch (type) { | ||
156 | case ApplicationName: | ||
157 | config()->setValue("applicationfilter", QVariant::fromValue(filter)); | ||
158 | break; | ||
159 | case Area: | ||
160 | config()->setValue("areafilter", QVariant::fromValue(filter)); | ||
161 | break; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | QByteArrayList Sink::Log::debugOutputFilter(FilterType type) | ||
166 | { | ||
167 | switch (type) { | ||
168 | case ApplicationName: | ||
169 | return config()->value("applicationfilter").value<QByteArrayList>(); | ||
170 | case Area: | ||
171 | return config()->value("areafilter").value<QByteArrayList>(); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | void Sink::Log::setDebugOutputFields(const QByteArrayList &output) | ||
176 | { | ||
177 | config()->setValue("outputfields", QVariant::fromValue(output)); | ||
178 | } | ||
179 | |||
180 | QByteArrayList Sink::Log::debugOutputFields() | ||
181 | { | ||
182 | return config()->value("outputfields").value<QByteArrayList>(); | ||
183 | } | ||
184 | |||
185 | static QByteArray getProgramName() | ||
186 | { | ||
187 | if (QCoreApplication::instance()) { | ||
188 | return QCoreApplication::instance()->applicationName().toLocal8Bit(); | ||
189 | } else { | ||
190 | return "<unknown program name>"; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | static bool containsItemStartingWith(const QByteArray &pattern, const QByteArrayList &list) | ||
195 | { | ||
196 | for (const auto &item : list) { | ||
197 | if (pattern.startsWith(item)) { | ||
198 | return true; | ||
199 | } | ||
200 | } | ||
201 | return false; | ||
202 | } | ||
203 | |||
204 | static bool caseInsensitiveContains(const QByteArray &pattern, const QByteArrayList &list) | ||
205 | { | ||
206 | for (const auto &item : list) { | ||
207 | if (item.toLower() == pattern) { | ||
208 | return true; | ||
209 | } | ||
210 | } | ||
211 | return false; | ||
139 | } | 212 | } |
140 | 213 | ||
141 | QDebug Sink::Log::debugStream(DebugLevel debugLevel, int line, const char* file, const char* function, const char* debugArea) | 214 | QDebug Sink::Log::debugStream(DebugLevel debugLevel, int line, const char* file, const char* function, const char* debugArea) |
142 | { | 215 | { |
143 | DebugLevel debugOutputLevel = debugLevelFromName(qgetenv("SINKDEBUGLEVEL")); | 216 | static NullStream nullstream; |
144 | if (debugLevel < debugOutputLevel) { | 217 | if (debugLevel < debugOutputLevel()) { |
145 | static NullStream stream; | 218 | return QDebug(&nullstream); |
146 | return QDebug(&stream); | ||
147 | } | 219 | } |
148 | 220 | ||
149 | static DebugStream stream; | 221 | auto areas = debugOutputFilter(Sink::Log::Area); |
150 | QDebug debug(&stream); | 222 | if (debugArea && !areas.isEmpty()) { |
223 | if (!containsItemStartingWith(debugArea, areas)) { | ||
224 | return QDebug(&nullstream); | ||
225 | } | ||
226 | } | ||
227 | static QByteArray programName = getProgramName(); | ||
151 | 228 | ||
152 | static QByteArray programName; | 229 | auto filter = debugOutputFilter(Sink::Log::ApplicationName); |
153 | if (programName.isEmpty()) { | 230 | if (!filter.isEmpty() && !filter.contains(programName)) { |
154 | if (QCoreApplication::instance()) | 231 | if (!containsItemStartingWith(programName, filter)) { |
155 | programName = QCoreApplication::instance()->applicationName().toLocal8Bit(); | 232 | return QDebug(&nullstream); |
156 | else | 233 | } |
157 | programName = "<unknown program name>"; | ||
158 | } | 234 | } |
159 | 235 | ||
160 | QString prefix; | 236 | QString prefix; |
@@ -175,29 +251,54 @@ QDebug Sink::Log::debugStream(DebugLevel debugLevel, int line, const char* file, | |||
175 | prefix = "Error: "; | 251 | prefix = "Error: "; |
176 | prefixColorCode = ANSI_Colors::Red; | 252 | prefixColorCode = ANSI_Colors::Red; |
177 | break; | 253 | break; |
178 | default: | ||
179 | break; | ||
180 | }; | 254 | }; |
181 | 255 | ||
182 | bool showLocation = false; | 256 | auto debugOutput = debugOutputFields(); |
183 | bool showProgram = true; | 257 | |
258 | bool showLocation = debugOutput.isEmpty() ? false : caseInsensitiveContains("location", debugOutput); | ||
259 | bool showFunction = debugOutput.isEmpty() ? false : caseInsensitiveContains("function", debugOutput); | ||
260 | bool showProgram = debugOutput.isEmpty() ? false : caseInsensitiveContains("application", debugOutput); | ||
261 | bool useColor = true; | ||
262 | bool multiline = false; | ||
184 | 263 | ||
185 | const QString resetColor = colorCommand(ANSI_Colors::Reset); | 264 | const QString resetColor = colorCommand(ANSI_Colors::Reset); |
186 | QString output; | 265 | QString output; |
187 | output += colorCommand(QList<int>() << ANSI_Colors::Bold << prefixColorCode) + prefix + resetColor; | 266 | if (useColor) { |
267 | output += colorCommand(QList<int>() << ANSI_Colors::Bold << prefixColorCode); | ||
268 | } | ||
269 | output += prefix; | ||
270 | if (useColor) { | ||
271 | output += resetColor; | ||
272 | } | ||
188 | if (showProgram) { | 273 | if (showProgram) { |
189 | output += QString(" %1(%2)").arg(QString::fromLatin1(programName)).arg(unsigned(getpid())); | 274 | int width = 10; |
275 | output += QString(" %1(%2)").arg(QString::fromLatin1(programName).leftJustified(width, ' ', true)).arg(unsigned(getpid())).rightJustified(width + 8, ' '); | ||
190 | } | 276 | } |
191 | if (debugArea) { | 277 | if (debugArea) { |
192 | output += colorCommand(QList<int>() << ANSI_Colors::Bold << prefixColorCode) + QString(" %1 ").arg(QString::fromLatin1(debugArea)) + resetColor; | 278 | if (useColor) { |
279 | output += colorCommand(QList<int>() << ANSI_Colors::Bold << prefixColorCode); | ||
280 | } | ||
281 | output += QString(" %1 ").arg(QString::fromLatin1(debugArea).leftJustified(25, ' ', true)); | ||
282 | if (useColor) { | ||
283 | output += resetColor; | ||
284 | } | ||
285 | } | ||
286 | if (showFunction) { | ||
287 | output += QString(" %3").arg(QString::fromLatin1(function).leftJustified(25, ' ', true)); | ||
193 | } | 288 | } |
194 | if (showLocation) { | 289 | if (showLocation) { |
195 | output += QString(" %3").arg(function); | 290 | const auto filename = QString::fromLatin1(file).split('/').last(); |
196 | output += QString("%1:%2").arg(file).arg(line); | 291 | output += QString(" %1:%2").arg(filename.right(25)).arg(QString::number(line).leftJustified(4, ' ')).leftJustified(30, ' ', true); |
292 | } | ||
293 | if (multiline) { | ||
294 | output += "\n "; | ||
197 | } | 295 | } |
198 | output += ":"; | 296 | output += ":"; |
199 | 297 | ||
200 | debug << output; | 298 | static DebugStream stream; |
299 | QDebug debug(&stream); | ||
300 | |||
301 | debug.noquote().nospace() << output; | ||
201 | 302 | ||
202 | return debug; | 303 | return debug.space().quote(); |
203 | } | 304 | } |