QtWebApp
logger.cpp
Go to the documentation of this file.
1 
6 #include "logger.h"
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <QDateTime>
10 #include <QThread>
11 #include <QObject>
12 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
13  #include <QRecursiveMutex>
14 #endif
15 
16 using namespace stefanfrings;
17 
18 Logger* Logger::defaultLogger=nullptr;
19 
20 
21 QThreadStorage<QHash<QString,QString>*> Logger::logVars;
22 
23 
24 QMutex Logger::mutex;
25 
26 
27 Logger::Logger(QObject* parent)
28  : QObject(parent),
29  msgFormat("{timestamp} {type} {msg}"),
30  timestampFormat("dd.MM.yyyy hh:mm:ss.zzz"),
31  minLevel(QtDebugMsg),
32  bufferSize(0)
33  {}
34 
35 
36 Logger::Logger(const QString msgFormat, const QString timestampFormat, const QtMsgType minLevel, const int bufferSize, QObject* parent)
37  :QObject(parent)
38 {
39  this->msgFormat=msgFormat;
40  this->timestampFormat=timestampFormat;
41  this->minLevel=minLevel;
42  this->bufferSize=bufferSize;
43 }
44 
45 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
46  static QRecursiveMutex recursiveMutex;
47  static QMutex nonRecursiveMutex;
48 #else
49  static QMutex recursiveMutex(QMutex::Recursive);
50  static QMutex nonRecursiveMutex(QMutex::NonRecursive);
51 #endif
52 
53 void Logger::msgHandler(const QtMsgType type, const QString &message, const QString &file, const QString &function, const int line)
54 {
55  // Prevent multiple threads from calling this method simultaneoulsy.
56  // But allow recursive calls, which is required to prevent a deadlock
57  // if the logger itself produces an error message.
58  recursiveMutex.lock();
59 
60  // Fall back to stderr when this method has been called recursively.
61  if (defaultLogger && nonRecursiveMutex.tryLock())
62  {
63  defaultLogger->log(type, message, file, function, line);
64  nonRecursiveMutex.unlock();
65  }
66  else
67  {
68  fputs(qPrintable(message),stderr);
69  fflush(stderr);
70  }
71 
72  // Abort the program after logging a fatal message
73  if (type==QtFatalMsg)
74  {
75  abort();
76  }
77 
78  recursiveMutex.unlock();
79 }
80 
81 
82 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
83  void Logger::msgHandler5(const QtMsgType type, const QMessageLogContext &context, const QString &message)
84  {
85  (void)(context); // suppress "unused parameter" warning
86  msgHandler(type,message,context.file,context.function,context.line);
87  }
88 #else
89  void Logger::msgHandler4(const QtMsgType type, const char* message)
90  {
91  msgHandler(type,message);
92  }
93 #endif
94 
95 
97 {
98  if (defaultLogger==this)
99  {
100 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
101  qInstallMessageHandler(nullptr);
102 #else
103  qInstallMsgHandler(nullptr);
104 #endif
105  defaultLogger=nullptr;
106  }
107 }
108 
109 
110 void Logger::write(const LogMessage* logMessage)
111 {
112  fputs(qPrintable(logMessage->toString(msgFormat,timestampFormat)),stderr);
113  fflush(stderr);
114 }
115 
116 
118 {
119  defaultLogger=this;
120 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
121  qInstallMessageHandler(msgHandler5);
122 #else
123  qInstallMsgHandler(msgHandler4);
124 #endif
125 }
126 
127 
128 void Logger::set(const QString& name, const QString& value)
129 {
130  mutex.lock();
131  if (!logVars.hasLocalData())
132  {
133  logVars.setLocalData(new QHash<QString,QString>);
134  }
135  logVars.localData()->insert(name,value);
136  mutex.unlock();
137 }
138 
139 
140 void Logger::clear(const bool buffer, const bool variables)
141 {
142  mutex.lock();
143  if (buffer && buffers.hasLocalData())
144  {
145  QList<LogMessage*>* buffer=buffers.localData();
146  while (buffer && !buffer->isEmpty())
147  {
148  LogMessage* logMessage=buffer->takeLast();
149  delete logMessage;
150  }
151  }
152  if (variables && logVars.hasLocalData())
153  {
154  logVars.localData()->clear();
155  }
156  mutex.unlock();
157 }
158 
159 
160 void Logger::log(const QtMsgType type, const QString& message, const QString &file, const QString &function, const int line)
161 {
162  // Check if the type of the message reached the configured minLevel in the order
163  // DEBUG, INFO, WARNING, CRITICAL, FATAL
164  // Since Qt 5.5: INFO messages are between DEBUG and WARNING
165  bool toPrint=false;
166  switch (type)
167  {
168  case QtDebugMsg:
169  if (minLevel==QtDebugMsg)
170  {
171  toPrint=true;
172  }
173  break;
174 
175  #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
176  case QtInfoMsg:
177  if (minLevel==QtDebugMsg ||
178  minLevel==QtInfoMsg)
179  {
180  toPrint=true;
181  }
182  break;
183  #endif
184 
185  case QtWarningMsg:
186  if (minLevel==QtDebugMsg ||
187  #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
188  minLevel==QtInfoMsg ||
189  #endif
190  minLevel==QtWarningMsg)
191  {
192  toPrint=true;
193  }
194  break;
195 
196  case QtCriticalMsg: // or QtSystemMsg which has the same int value
197  if (minLevel==QtDebugMsg ||
198  #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
199  minLevel==QtInfoMsg ||
200  #endif
201  minLevel==QtWarningMsg ||
202  minLevel==QtCriticalMsg)
203  {
204  toPrint=true;
205  }
206  break;
207 
208  case QtFatalMsg:
209  toPrint=true;
210  break;
211 
212  default: // For additional type that might get introduced in future
213  toPrint=true;
214  }
215 
216  mutex.lock();
217 
218  // If the buffer is enabled, write the message into it
219  if (bufferSize>0)
220  {
221  // Create new thread local buffer, if necessary
222  if (!buffers.hasLocalData())
223  {
224  buffers.setLocalData(new QList<LogMessage*>());
225  }
226  QList<LogMessage*>* buffer=buffers.localData();
227 
228  // Append the decorated log message to the buffer
229  LogMessage* logMessage=new LogMessage(type,message,logVars.localData(),file,function,line);
230  buffer->append(logMessage);
231 
232  // Delete oldest message if the buffer became too large
233  if (buffer->size()>bufferSize)
234  {
235  delete buffer->takeFirst();
236  }
237 
238  // Print the whole buffer if the type is high enough
239  if (toPrint)
240  {
241  // Print the whole buffer content
242  while (!buffer->isEmpty())
243  {
244  LogMessage* logMessage=buffer->takeFirst();
245  write(logMessage);
246  delete logMessage;
247  }
248  }
249  }
250 
251  // Buffer is disabled, print the message if the type is high enough
252  else
253  {
254  if (toPrint)
255  {
256  LogMessage logMessage(type,message,logVars.localData(),file,function,line);
257  write(&logMessage);
258  }
259  }
260  mutex.unlock();
261 }
Represents a single log message together with some data that are used to decorate the log message.
Definition: logmessage.h:37
QString toString(const QString &msgFormat, const QString &timestampFormat) const
Returns the log message as decorated string.
Definition: logmessage.cpp:29
Decorates and writes log messages to the console, stderr.
Definition: logger.h:52
Logger(QObject *parent)
Constructor.
Definition: logger.cpp:27
QtMsgType minLevel
Minimum level of message types that are written out directly or trigger writing the buffered content.
Definition: logger.h:128
QString timestampFormat
Format string of timestamps.
Definition: logger.h:125
void installMsgHandler()
Installs this logger as the default message handler, so it can be used through the global static logg...
Definition: logger.cpp:117
virtual void clear(const bool buffer=true, const bool variables=true)
Clear the thread-local data of the current thread.
Definition: logger.cpp:140
virtual void write(const LogMessage *logMessage)
Decorate and write a log message to stderr.
Definition: logger.cpp:110
static QMutex mutex
Used to synchronize access of concurrent threads.
Definition: logger.h:134
int bufferSize
Size of backtrace buffer, number of messages per thread.
Definition: logger.h:131
QString msgFormat
Format string for message decoration.
Definition: logger.h:122
virtual ~Logger()
Destructor.
Definition: logger.cpp:96
static void set(const QString &name, const QString &value)
Sets a thread-local variable that may be used to decorate log messages.
Definition: logger.cpp:128
virtual void log(const QtMsgType type, const QString &message, const QString &file="", const QString &function="", const int line=0)
Decorate and log the message, if type>=minLevel.
Definition: logger.cpp:160