summaryrefslogtreecommitdiffstats
path: root/common/log.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'common/log.cpp')
-rw-r--r--common/log.cpp165
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
9using namespace Sink::Log; 12using namespace Sink::Log;
10 13
14static QSharedPointer<QSettings> config()
15{
16 return QSharedPointer<QSettings>::create(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/sink/log.ini", QSettings::IniFormat);
17}
18
11class DebugStream: public QIODevice 19class DebugStream: public QIODevice
12{ 20{
13public: 21public:
@@ -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 }
34private: 38private:
35 Q_DISABLE_COPY(DebugStream) 39 Q_DISABLE_COPY(DebugStream)
36}; 40};
37 41
42//Virtual method anchor
43DebugStream::~DebugStream()
44{}
45
38class NullStream: public QIODevice 46class NullStream: public QIODevice
39{ 47{
40public: 48public:
@@ -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
68NullStream::~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
131void Sink::Log::setDebugOutputLevel(DebugLevel debugLevel) 143void Sink::Log::setDebugOutputLevel(DebugLevel debugLevel)
132{ 144{
133 qputenv("SINKDEBUGLEVEL", debugLevelName(debugLevel)); 145 config()->setValue("level", debugLevel);
134} 146}
135 147
136Sink::Log::DebugLevel Sink::Log::debugOutputLevel() 148Sink::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
153void 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
165QByteArrayList 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
175void Sink::Log::setDebugOutputFields(const QByteArrayList &output)
176{
177 config()->setValue("outputfields", QVariant::fromValue(output));
178}
179
180QByteArrayList Sink::Log::debugOutputFields()
181{
182 return config()->value("outputfields").value<QByteArrayList>();
183}
184
185static QByteArray getProgramName()
186{
187 if (QCoreApplication::instance()) {
188 return QCoreApplication::instance()->applicationName().toLocal8Bit();
189 } else {
190 return "<unknown program name>";
191 }
192}
193
194static 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
204static 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
141QDebug Sink::Log::debugStream(DebugLevel debugLevel, int line, const char* file, const char* function, const char* debugArea) 214QDebug 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}