1#include "QLogger.h"
2
3#include "QLoggerWriter.h"
4
5#include <QDateTime>
6#include <QDir>
7
8Q_DECLARE_METATYPE(QLogger::LogLevel);
9Q_DECLARE_METATYPE(QLogger::LogMode);
10Q_DECLARE_METATYPE(QLogger::LogFileDisplay);
11Q_DECLARE_METATYPE(QLogger::LogMessageDisplay);
12
13namespace QLogger
14{
15
16void QLog_(const QString &module, LogLevel level, const QString &message, const QString &function, const QString &file,
17 int line)
18{
19 QLoggerManager::getInstance()->enqueueMessage(module, level, message, function, file, line);
20}
21
22static const int QUEUE_LIMIT = 100;
23
24QLoggerManager *QLoggerManager::getInstance()
25{
26 static QLoggerManager INSTANCE;
27
28 return &INSTANCE;
29}
30
31bool QLoggerManager::addDestination(const QString &fileDest, const QString &module, LogLevel level,
32 const QString &fileFolderDestination, LogMode mode, LogFileDisplay fileSuffixIfFull,
33 LogMessageDisplays messageOptions, bool notify)
34{
35 QMutexLocker lock(&mMutex);
36
37 if (!mModuleDest.contains(module))
38 {
39 const auto log = createWriter(fileDest, level, fileFolderDestination, mode, fileSuffixIfFull, messageOptions);
40
41 mModuleDest.insert(module, log);
42
43 startWriter(module, log, mode, notify);
44
45 return true;
46 }
47
48 return false;
49}
50
51bool QLoggerManager::addDestination(const QString &fileDest, const QStringList &modules, LogLevel level,
52 const QString &fileFolderDestination, LogMode mode, LogFileDisplay fileSuffixIfFull,
53 LogMessageDisplays messageOptions, bool notify)
54{
55 QMutexLocker lock(&mMutex);
56 bool allAdded = false;
57
58 for (const auto &module : modules)
59 {
60 if (!mModuleDest.contains(module))
61 {
62 const auto log = createWriter(fileDest, level, fileFolderDestination, mode, fileSuffixIfFull, messageOptions);
63
64 mModuleDest.insert(module, log);
65
66 startWriter(module, log, mode, notify);
67
68 allAdded = true;
69 }
70 }
71
72 return allAdded;
73}
74
75QLoggerWriter *QLoggerManager::createWriter(const QString &fileDest, LogLevel level,
76 const QString &fileFolderDestination, LogMode mode,
77 LogFileDisplay fileSuffixIfFull, LogMessageDisplays messageOptions) const
78{
79 const auto lFileDest = fileDest.isEmpty() ? mDefaultFileDestination : fileDest;
80 const auto lLevel = level == LogLevel::Warning ? mDefaultLevel : level;
81 const auto lFileFolderDestination = fileFolderDestination.isEmpty()
82 ? mDefaultFileDestinationFolder
83 : QDir::fromNativeSeparators(fileFolderDestination);
84 const auto lMode = mode == LogMode::OnlyFile ? mDefaultMode : mode;
85 const auto lFileSuffixIfFull
86 = fileSuffixIfFull == LogFileDisplay::DateTime ? mDefaultFileSuffixIfFull : fileSuffixIfFull;
87 const auto lMessageOptions
88 = messageOptions.testFlag(LogMessageDisplay::Default) ? mDefaultMessageOptions : messageOptions;
89
90 const auto log
91 = new QLoggerWriter(lFileDest, lLevel, lFileFolderDestination, lMode, lFileSuffixIfFull, lMessageOptions);
92
93 log->setMaxFileSize(mDefaultMaxFileSize);
94 log->stop(mIsStop);
95
96 return log;
97}
98
99void QLoggerManager::startWriter(const QString &module, QLoggerWriter *log, LogMode mode, bool notify)
100{
101 if (notify)
102 {
103 const auto threadId = QString("%1").arg((quintptr)QThread::currentThread(), QT_POINTER_SIZE * 2, 16, QChar('0'));
104 log->enqueue(QDateTime::currentDateTime(), threadId, module, LogLevel::Info, "", "", -1, "Adding destination!");
105 }
106
107 if (mode != LogMode::Disabled)
108 log->start();
109}
110
111void QLoggerManager::clearFileDestinationFolder(const QString &fileFolderDestination, int days)
112{
113 QDir dir(fileFolderDestination + QStringLiteral("/logs"));
114
115 if (!dir.exists())
116 return;
117
118 dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
119
120 const auto list = dir.entryInfoList();
121 const auto now = QDateTime::currentDateTime();
122
123 for (const auto &fileInfoIter : list)
124 {
125 if (fileInfoIter.lastModified().daysTo(now) >= days)
126 {
127 // remove file
128 dir.remove(fileInfoIter.fileName());
129 }
130 }
131}
132
133void QLoggerManager::setDefaultFileDestinationFolder(const QString &fileDestinationFolder)
134{
135 mDefaultFileDestinationFolder = QDir::fromNativeSeparators(fileDestinationFolder);
136}
137
138void QLoggerManager::writeAndDequeueMessages(const QString &module)
139{
140 QMutexLocker lock(&mMutex);
141
142 const auto logWriter = mModuleDest.value(module, nullptr);
143
144 if (logWriter && !logWriter->isStop())
145 {
146 const auto values = mNonWriterQueue.values(module);
147
148 for (const auto &values : values)
149 {
150 const auto level = qvariant_cast<LogLevel>(values.at(2).toInt());
151
152 if (logWriter->getLevel() <= level)
153 {
154 const auto datetime = values.at(0).toDateTime();
155 const auto threadId = values.at(1).toString();
156 const auto function = values.at(3).toString();
157 const auto file = values.at(4).toString();
158 const auto line = values.at(5).toInt();
159 const auto message = values.at(6).toString();
160
161 logWriter->enqueue(datetime, threadId, module, level, function, file, line, message);
162 }
163 }
164
165 mNonWriterQueue.remove(module);
166 }
167}
168
169void QLoggerManager::enqueueMessage(const QString &module, LogLevel level, const QString &message,
170 const QString &function, const QString &file, int line)
171{
172 QMutexLocker lock(&mMutex);
173 const auto logWriter = mModuleDest.value(module, nullptr);
174 const auto isLogEnabled = logWriter && logWriter->getMode() != LogMode::Disabled && !logWriter->isStop();
175
176 if (isLogEnabled && logWriter->getLevel() <= level)
177 {
178 const auto threadId = QString("%1").arg((quintptr)QThread::currentThread(), QT_POINTER_SIZE * 2, 16, QChar('0'));
179 const auto fileName = file.mid(file.lastIndexOf('/') + 1);
180
181 writeAndDequeueMessages(module);
182
183 logWriter->enqueue(QDateTime::currentDateTime(), threadId, module, level, function, fileName, line, message);
184 }
185 else if (!logWriter && mNonWriterQueue.count(module) < QUEUE_LIMIT)
186 {
187 const auto threadId = QString("%1").arg((quintptr)QThread::currentThread(), QT_POINTER_SIZE * 2, 16, QChar('0'));
188 const auto fileName = file.mid(file.lastIndexOf('/') + 1);
189
190 mNonWriterQueue.insert(module,
191 { QDateTime::currentDateTime(), threadId, QVariant::fromValue<LogLevel>(level), function,
192 fileName, line, message });
193 }
194}
195
196void QLoggerManager::pause()
197{
198 QMutexLocker lock(&mMutex);
199
200 mIsStop = true;
201
202 for (auto &logWriter : mModuleDest)
203 logWriter->stop(mIsStop);
204}
205
206void QLoggerManager::resume()
207{
208 QMutexLocker lock(&mMutex);
209
210 mIsStop = false;
211
212 for (auto &logWriter : mModuleDest)
213 logWriter->stop(mIsStop);
214}
215
216void QLoggerManager::overwriteLogMode(LogMode mode)
217{
218 QMutexLocker lock(&mMutex);
219
220 setDefaultMode(mode);
221
222 for (auto &logWriter : mModuleDest)
223 logWriter->setLogMode(mode);
224}
225
226void QLoggerManager::overwriteLogLevel(LogLevel level)
227{
228 QMutexLocker lock(&mMutex);
229
230 setDefaultLevel(level);
231
232 for (auto &logWriter : mModuleDest)
233 logWriter->setLogLevel(level);
234}
235
236void QLoggerManager::overwriteMaxFileSize(int maxSize)
237{
238 QMutexLocker lock(&mMutex);
239
240 setDefaultMaxFileSize(maxSize);
241
242 for (auto &logWriter : mModuleDest)
243 logWriter->setMaxFileSize(maxSize);
244}
245
246QLoggerManager::~QLoggerManager()
247{
248 QMutexLocker locker(&mMutex);
249
250 for (const auto &dest : mModuleDest.toStdMap())
251 writeAndDequeueMessages(dest.first);
252
253 for (auto dest : qAsConst(mModuleDest))
254 {
255 dest->closeDestination();
256 dest->wait();
257 }
258
259 for (auto dest : qAsConst(mModuleDest))
260 delete dest;
261
262 mModuleDest.clear();
263}
264
265}
266