v2.0.0
Loading...
Searching...
No Matches
mne_logger.cpp
Go to the documentation of this file.
1//=============================================================================================================
18
19//=============================================================================================================
20// INCLUDES
21//=============================================================================================================
22
23#include <iostream>
24#include <string>
25#include "mne_logger.h"
26
27//=============================================================================================================
28// QT INCLUDES
29//=============================================================================================================
30
31#include <QtGlobal>
32#include <QDateTime>
33#include <QMutexLocker>
34#include <QFile>
35#include <QTextStream>
36
37//=============================================================================================================
38// USED NAMESPACES
39//=============================================================================================================
40
41using namespace UTILSLIB;
42
43//=============================================================================================================
44// Definitions
45//=============================================================================================================
46
47#ifdef WIN32
48#include <wchar.h>
49#include <windows.h>
50#define COLOR_INFO "\033[32;1m"
51#define COLOR_DEBUG "\033[32;1m"
52#define COLOR_WARN "\033[33;1m"
53#define COLOR_CRITICAL "\033[31;1m"
54#define COLOR_FATAL "\033[33;1m"
55#define COLOR_RESET "\033[0m"
56#else
57#define COLOR_INFO "\033[32;1m" //green
58#define COLOR_DEBUG "\033[32;1m" //green
59#define COLOR_WARN "\033[33;1m" //yellow
60#define COLOR_CRITICAL "\033[31;1m" //red
61#define COLOR_FATAL "\033[33;1m" //yellow
62#define COLOR_RESET "\033[0m" //reset
63#endif
64
65std::mutex MNELogger::m_mutex;
66QString MNELogger::m_sLogFilePath;
67
68//=============================================================================================================
69// DEFINE MEMBER METHODS
70//=============================================================================================================
71
72bool MNELogger::setLogFile(const QString& sFilePath)
73{
74 std::lock_guard<std::mutex> lock(m_mutex);
75
76 if (sFilePath.isEmpty()) {
77 m_sLogFilePath.clear();
78 return true;
79 }
80
81 //
82 // Make sure the destination is writable now rather than silently dropping
83 // every message later on.
84 //
85 QFile file(sFilePath);
86 if (!file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
87 return false;
88 }
89 file.close();
90
91 m_sLogFilePath = sFilePath;
92
93 return true;
94}
95
96//=============================================================================================================
97
99{
100 std::lock_guard<std::mutex> lock(m_mutex);
101
102 return m_sLogFilePath;
103}
104
105void MNELogger::customLogWriter(QtMsgType type,
106 const QMessageLogContext& context,
107 const QString& msg)
108{
109 Q_UNUSED(context)
110
111 // Map Qt message type to numeric level (must match CMake MNE_LOG_LEVEL values)
112 // 0=DEBUG, 1=INFO, 2=WARN, 3=CRIT, 4=FATAL
113 int msgLevel = 0;
114 switch (type) {
115 case QtDebugMsg:
116 msgLevel = 0;
117 break;
118 case QtInfoMsg:
119 msgLevel = 1;
120 break;
121 case QtWarningMsg:
122 msgLevel = 2;
123 break;
124 case QtCriticalMsg:
125 msgLevel = 3;
126 break;
127 case QtFatalMsg:
128 msgLevel = 4;
129 break;
130 default:
131 msgLevel = 0;
132 break;
133 }
134
135#ifdef MNE_LOG_LEVEL
136 if (msgLevel < MNE_LOG_LEVEL)
137 return;
138#endif
139
140 std::string text = msg.toStdString();
141
142 std::lock_guard<std::mutex> lock(m_mutex);
143
144 //
145 // Mirror the message into the log file when one was configured. This is
146 // kept free of the colour escapes so the file stays readable, and carries
147 // a timestamp because a log that outlives the session needs one.
148 //
149 if (!m_sLogFilePath.isEmpty()) {
150 QFile logFile(m_sLogFilePath);
151 if (logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
152 const char* fileLevel = "";
153 switch (type) {
154 case QtDebugMsg:
155 fileLevel = "DEBUG";
156 break;
157 case QtInfoMsg:
158 fileLevel = "INFO";
159 break;
160 case QtWarningMsg:
161 fileLevel = "WARN";
162 break;
163 case QtCriticalMsg:
164 fileLevel = "CRIT";
165 break;
166 case QtFatalMsg:
167 fileLevel = "FATAL";
168 break;
169 default:
170 fileLevel = "LOG";
171 break;
172 }
173
174 QTextStream stream(&logFile);
175 stream << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz")
176 << " [" << fileLevel << "] "
177 << QString::fromStdString(text).trimmed() << '\n';
178 logFile.close();
179 }
180 }
181
182 // Results go to stdout and diagnostics to stderr, so piped tool output stays parseable.
183 const bool bDiagnostic = msgLevel >= 2;
184 std::ostream& stream = bDiagnostic ? std::cerr : std::cout;
185
186#ifdef MNE_LOG_MODE_FORMATTED
187 static bool s_startOfLine[2] = {true, true};
188 bool& startOfLine = s_startOfLine[bDiagnostic ? 1 : 0];
189
190 // Determine color and level tag
191 const char* color = COLOR_RESET;
192 const char* level = "";
193 switch (type) {
194 case QtDebugMsg:
195 color = COLOR_DEBUG;
196 level = "[DEBUG] ";
197 break;
198 case QtInfoMsg:
199 color = COLOR_INFO;
200 level = "[INFO] ";
201 break;
202 case QtWarningMsg:
203 color = COLOR_WARN;
204 level = "[WARN] ";
205 break;
206 case QtCriticalMsg:
207 color = COLOR_CRITICAL;
208 level = "[CRIT] ";
209 break;
210 case QtFatalMsg:
211 color = COLOR_FATAL;
212 level = "[FATAL] ";
213 break;
214 default:
215 level = "";
216 break;
217 }
218
219 // Uncomment the following line to include date/time in log prefix:
220 // std::string sDateTime = QDateTime::currentDateTime().toString("dd/MM/yyyy hh:mm:ss.z ").toStdString();
221 std::string sDateTime;
222
223 std::string prefix = std::string(color) + sDateTime + level + COLOR_RESET;
224
225 // Walk through the message character by character.
226 // Print the prefix only at the start of each new line.
227 for (size_t i = 0; i < text.size(); ++i) {
228 if (startOfLine && text[i] != '\n') {
229 stream << prefix;
230 startOfLine = false;
231 }
232 stream << text[i];
233 if (text[i] == '\n') {
234 startOfLine = true;
235 }
236 }
237
238 if (text.empty() || text.back() != '\n') {
239 stream << '\n';
240 startOfLine = true;
241 }
242#else
243 // PLAIN mode: raw text, like printf
244 stream << text;
245 if (text.empty() || text.back() != '\n') {
246 stream << '\n';
247 }
248#endif
249
250 stream.flush();
251}
#define COLOR_INFO
#define COLOR_RESET
#define COLOR_DEBUG
#define COLOR_CRITICAL
#define COLOR_WARN
#define COLOR_FATAL
Custom Qt message handler that adds ANSI colour, timestamps and source-location tags to qDebug/qWarni...
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
static void customLogWriter(QtMsgType type, const QMessageLogContext &context, const QString &msg)
static bool setLogFile(const QString &sFilePath)
static QString logFile()