comparison Utils/Log.cpp @ 1:0b3630a29ad8

Initial version based on previous repository. Project was ported to QT6 and in now cmake based.
author Ideenmodellierer <tiefenrauscher@web.de>
date Thu, 27 Nov 2025 18:40:28 +0100
parents
children
comparison
equal deleted inserted replaced
0:76ccd6ce50c0 1:0b3630a29ad8
1 //////////////////////////////////////////////////////////////////////////////
2 /// \file Log.cpp
3 /// \brief Basic logging tool
4 /// \author JD Gascuel.
5 /// \copyright (c) 2011-2016 JD Gascuel. All rights reserved.
6 /// $Id$
7 //////////////////////////////////////////////////////////////////////////////
8 //
9 // BSD 2-Clause License:
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions
13 // are met:
14 //
15 // 1. Redistributions of source code must retain the above copyright notice,
16 // this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright notice,
19 // this list of conditions and the following disclaimer in the documentation
20 // and/or other materials provided with the distribution.
21 //
22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 // THE POSSIBILITY OF SUCH DAMAGE.
33 //
34 //////////////////////////////////////////////////////////////////////////////
35
36 #include "Utils/Log.h"
37
38 #include "Utils/Exception.h"
39 #include "Utils/LogConsole.h"
40 #include "Utils/LogFile.h"
41
42 #include "Utils/LogAppender.h"
43
44 #include <QDir>
45 #include <QStringList>
46 #include <QRegularExpression>
47
48 // 2013-08-30 jDG: Because of Linux compile,
49 // we need to keep some minimal Qt4.8 compatibility...
50 #if !defined(NO_WIDGETS) && QT_VERSION > 0x050100
51 # include <QWindow>
52 #endif
53
54 // Will be automaticallt set more verbose by File or Console appender,
55 // if needed.
56 Log::Level Log::minLevel = Log::LEVEL_WARNING;
57 QString Log::_applicationPath;
58 QString Log::_applicationName;
59
60 //////////////////////////////////////////////////////////////////////////////
61
62 static QtMessageHandler forwarder = 0;
63 static void Qt5Error(QtMsgType type, const QMessageLogContext &ctx, const QString &msg)
64 {
65 // Spurious error from Qt 5.4.1, when we DO NOT USE any SSL socket...
66 if( ctx.category && strcmp(ctx.category, "qt.network.ssl") == 0 )
67 return;
68
69 switch(type) {
70 case QtDebugMsg: LogAction(Log::LEVEL_DEBUG, ctx.file, ctx.line, ctx.function) << msg; break;
71 case QtInfoMsg: LogAction(Log::LEVEL_TRACE, ctx.file, ctx.line, ctx.function) << msg; break;
72 case QtWarningMsg: LogAction(Log::LEVEL_WARNING, ctx.file, ctx.line, ctx.function) << msg; break;
73 case QtCriticalMsg: LogAction(Log::LEVEL_ERROR, ctx.file, ctx.line, ctx.function) << msg; break;
74 case QtFatalMsg: LogAction(Log::LEVEL_ERROR, ctx.file, ctx.line, ctx.function) << msg; break;
75 }
76 }
77
78 //////////////////////////////////////////////////////////////////////////////
79
80 void Log::init(int& argc, char* argv[])
81 {
82 minLevel = Log::LEVEL_WARNING;
83
84 //---- Get the current application name ----------------------------------
85 if( argc > 0 && _applicationPath.isEmpty() )
86 {
87 _applicationPath = QDir::current().absoluteFilePath(
88 QString::fromLatin1(argv[0])
89 .replace('\\', '/'));
90 _applicationName = _applicationPath.section('/', -1);
91 _applicationPath = _applicationPath.section('/', 0, -2);
92
93 #ifdef Q_OS_WIN32
94 if( _applicationName.endsWith(".exe") )
95 _applicationName = _applicationName.section('.', 0, -2);
96 #elif defined(Q_OS_MACX)
97 if( _applicationPath.endsWith("/MacOS") )
98 _applicationPath = _applicationPath.section('/', 0, -2);
99 #elif defined(Q_OS_LINUX)
100 // Nothing special, yet.
101 #else
102 # error Unknown OS not yet implemented
103 #endif
104
105 // Pop "/build/kitName" tail added by the QtCreator build process:
106 if( _applicationPath.section('/', -2, -2) == "build" )
107 _applicationPath = _applicationPath.section('/', 0, -3);
108 if( _applicationPath.section('/', -1, -1) == "build" )
109 _applicationPath = _applicationPath.section('/', 0, -2);
110
111 // Pop /debug or /release tail too (Unix, Visual):
112 // QRegExp tail("[.]?(debug|release)", Qt::CaseInsensitive);
113 QRegularExpression tail(
114 R"([.]?(debug|release))",
115 QRegularExpression::CaseInsensitiveOption
116 );
117
118 // if( tail.exactMatch(_applicationPath.section('/', -1, -1)) )
119 QRegularExpressionMatch match =
120 tail.match(_applicationPath.section('/', -1, -1));
121 if (match.hasMatch())
122 _applicationPath = _applicationPath.section('/', 0, -2);
123 if( _applicationName.endsWith(" DEBUG", Qt::CaseInsensitive) )
124 _applicationName = _applicationName.left(_applicationName.length()-6);
125
126 // Pop "/bin/" tail added by the configured build process:
127 if( _applicationPath.section('/', -1) == "bin" )
128 _applicationPath = _applicationPath.section('/', 0, -2);
129
130 if( _applicationName.isEmpty() )
131 _applicationName = "log";
132 }
133
134 //---- Forward Qt's messages ---------------------------------------------
135 forwarder = qInstallMessageHandler(Qt5Error);
136
137 //---- Instanciate 2 appenders -------------------------------------------
138 new LogConsole(argc, argv);
139 new LogFile(argc, argv);
140 }
141
142 //////////////////////////////////////////////////////////////////////////////
143
144 void Log::close()
145 {
146 LOG_TRACE("Closing logs.");
147 foreach(LogAppender* i, LogAppender::list())
148 delete i;
149 }
150
151 //////////////////////////////////////////////////////////////////////////////
152
153 Log::Log(Level level, const char *f, int line, const char *function)
154 : level(level),
155 line(line),
156 function(function)
157 {
158 // Skip trailing "../" in file name (due to QtCreator build dir):
159 while( f && f[0] == '.' && f[1] == '.' && (f[2] == '\\' || f[2] == '/') )
160 f += 3;
161 const_cast<QString&>(file) = QString::fromLatin1(f).replace('\\', '/');
162 }
163
164 LogAction::LogAction(Level level, const char *file, int line, const char *function)
165 : Log(level, file, line, function)
166 {}
167
168 //////////////////////////////////////////////////////////////////////////////
169 LogAction::~LogAction()
170 {
171 LogAppender::all(*this);
172 }
173
174 //////////////////////////////////////////////////////////////////////////////
175 LogAction &LogAction::operator<<(char msg)
176 {
177 if( message.length() < (LOG_MAX_MESSAGE_LENGTH-1) )
178 message += QChar(msg); // UTF-8 by default.
179 return *this;
180 }
181
182 LogAction &LogAction::operator<<(unsigned char msg)
183 {
184 if( message.length() < (LOG_MAX_MESSAGE_LENGTH-1) )
185 message += QChar(msg); // UTF-8 by default.
186 return *this;
187 }
188
189 LogAction& LogAction::operator<<(const char* msg)
190 {
191 if( message.length()+strlen(msg) < (LOG_MAX_MESSAGE_LENGTH) )
192 message += QString::fromUtf8(msg);
193 return *this;
194 }
195
196 //////////////////////////////////////////////////////////////////////////////
197 LogAction& LogAction::operator<<(const QString& msg)
198 {
199 if( message.length()+msg.length() < (LOG_MAX_MESSAGE_LENGTH) )
200 message += msg;
201 return *this;
202 }
203
204 LogAction &LogAction::operator <<(const QStringList& list)
205 {
206 *this << "{";
207 for(int i=0; i<list.count(); ++i)
208 {
209 if( i > 0 )
210 *this << ", ";
211 *this << list[i];
212 }
213 *this << "}";
214
215 return *this;
216 }
217
218
219 //////////////////////////////////////////////////////////////////////////////
220 LogAction& LogAction::operator<<(const QByteArray& msg)
221 {
222 operator<<(QString::fromUtf8(msg));
223 return *this;
224 }
225
226 //////////////////////////////////////////////////////////////////////////////
227 LogAction& LogAction::operator<<(double value)
228 {
229 operator<<(QString::number(value));
230 return *this;
231 }
232
233 //////////////////////////////////////////////////////////////////////////////
234 LogAction& LogAction::operator<<(int value)
235 {
236 operator<<(QString::number(value));
237 return *this;
238 }
239
240 LogAction& LogAction::operator<<(unsigned int value)
241 {
242 operator<<(QString::number(value));
243 return *this;
244 }
245
246 //////////////////////////////////////////////////////////////////////////////
247
248 LogAction &LogAction::operator <<(unsigned long value)
249 {
250 operator<<(QString::number((qulonglong)value));
251 return *this;
252 }
253
254 LogAction &LogAction::operator <<(long value)
255 {
256 operator<<(QString::number((qlonglong)value));
257 return *this;
258 }
259
260 //////////////////////////////////////////////////////////////////////////////
261
262 LogAction &LogAction::operator <<(unsigned long long value)
263 {
264 operator<<(QString::number(value));
265 return *this;
266 }
267
268 LogAction &LogAction::operator <<(long long value)
269 {
270 operator<<(QString::number(value));
271 return *this;
272 }
273
274 //////////////////////////////////////////////////////////////////////////////
275 LogAction &LogAction::operator <<(const void *ptr)
276 {
277 operator<<("0x");
278 operator<<(QString::number((qulonglong)ptr, 16));
279
280 return *this;
281 }