QtWebApp
filelogger.cpp
Go to the documentation of this file.
1 
6 #include "filelogger.h"
7 #include <QTime>
8 #include <QStringList>
9 #include <QThread>
10 #include <QtGlobal>
11 #include <QFile>
12 #include <QTimerEvent>
13 #include <QDir>
14 #include <QFileInfo>
15 #include <stdio.h>
16 
17 using namespace stefanfrings;
18 
19 void FileLogger::refreshSettings()
20 {
21  mutex.lock();
22  // Save old file name for later comparision with new settings
23  QString oldFileName=fileName;
24 
25  // Load new config settings
26  settings->sync();
27  fileName=settings->value("fileName").toString();
28  // Convert relative fileName to absolute, based on the directory of the config file.
29 #ifdef Q_OS_WIN32
30  if (QDir::isRelativePath(fileName) && settings->format()!=QSettings::NativeFormat)
31 #else
32  if (QDir::isRelativePath(fileName))
33 #endif
34  {
35  QFileInfo configFile(settings->fileName());
36  fileName=QFileInfo(configFile.absolutePath(),fileName).absoluteFilePath();
37  }
38  maxSize=settings->value("maxSize",0).toLongLong();
39  maxBackups=settings->value("maxBackups",0).toInt();
40  msgFormat=settings->value("msgFormat","{timestamp} {type} {msg}").toString();
41  timestampFormat=settings->value("timestampFormat","yyyy-MM-dd hh:mm:ss.zzz").toString();
42  bufferSize=settings->value("bufferSize",0).toInt();
43 
44  // Translate log level settings to enumeration value
45  QByteArray minLevelStr = settings->value("minLevel","ALL").toByteArray();
46  if (minLevelStr=="ALL" || minLevelStr=="DEBUG" || minLevelStr=="0")
47  {
48  minLevel=QtMsgType::QtDebugMsg;
49  }
50  else if (minLevelStr=="WARNING" || minLevelStr=="WARN" || minLevelStr=="1")
51  {
52  minLevel=QtMsgType::QtWarningMsg;
53  }
54  else if (minLevelStr=="ERROR" || minLevelStr=="CRITICAL" || minLevelStr=="2")
55  {
56  minLevel=QtMsgType::QtCriticalMsg;
57  }
58  else if (minLevelStr=="FATAL" || minLevelStr=="3")
59  {
60  minLevel=QtMsgType::QtFatalMsg;
61  }
62  else if (minLevelStr=="INFO" || minLevelStr=="4")
63  {
64  minLevel=QtMsgType::QtInfoMsg;
65  }
66 
67  // Create new file if the filename has been changed
68  if (oldFileName!=fileName)
69  {
70  fprintf(stderr,"Logging to %s\n",qPrintable(fileName));
71  close();
72  open();
73  }
74  mutex.unlock();
75 }
76 
77 
78 FileLogger::FileLogger(QSettings *settings, const int refreshInterval, QObject* parent)
79  : Logger(parent)
80 {
81  Q_ASSERT(settings!=nullptr);
82  Q_ASSERT(refreshInterval>=0);
83  this->settings=settings;
84  file=nullptr;
85  if (refreshInterval>0)
86  {
87  refreshTimer.start(refreshInterval,this);
88  }
89  flushTimer.start(1000,this);
90  refreshSettings();
91 }
92 
93 
95 {
96  close();
97 }
98 
99 
100 void FileLogger::write(const LogMessage* logMessage)
101 {
102  // Try to write to the file
103  if (file)
104  {
105 
106  // Write the message
107  file->write(qPrintable(logMessage->toString(msgFormat,timestampFormat)));
108 
109  // Flush error messages immediately, to ensure that no important message
110  // gets lost when the program terinates abnormally.
111  if (logMessage->getType()>=QtCriticalMsg)
112  {
113  file->flush();
114  }
115 
116  // Check for success
117  if (file->error())
118  {
119  qWarning("Cannot write to log file %s: %s",qPrintable(fileName),qPrintable(file->errorString()));
120  close();
121  }
122 
123  }
124 
125  // Fall-back to the super class method, if writing failed
126  if (!file)
127  {
128  Logger::write(logMessage);
129  }
130 
131 }
132 
133 void FileLogger::open()
134 {
135  if (fileName.isEmpty())
136  {
137  qWarning("Name of logFile is empty");
138  }
139  else {
140  file=new QFile(fileName);
141  if (!file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
142  {
143  qWarning("Cannot open log file %s: %s",qPrintable(fileName),qPrintable(file->errorString()));
144  file=nullptr;
145  }
146  }
147 }
148 
149 
150 void FileLogger::close()
151 {
152  if (file)
153  {
154  file->close();
155  delete file;
156  file=nullptr;
157  }
158 }
159 
160 void FileLogger::rotate() {
161  // count current number of existing backup files
162  int count=0;
163  forever
164  {
165  QFile bakFile(QString("%1.%2").arg(fileName).arg(count+1));
166  if (bakFile.exists())
167  {
168  ++count;
169  }
170  else
171  {
172  break;
173  }
174  }
175 
176  // Remove all old backup files that exceed the maximum number
177  while (maxBackups>0 && count>=maxBackups)
178  {
179  QFile::remove(QString("%1.%2").arg(fileName).arg(count));
180  --count;
181  }
182 
183  // Rotate backup files
184  for (int i=count; i>0; --i) {
185  QFile::rename(QString("%1.%2").arg(fileName).arg(i),QString("%1.%2").arg(fileName).arg(i+1));
186  }
187 
188  // Backup the current logfile
189  QFile::rename(fileName,fileName+".1");
190 }
191 
192 
193 void FileLogger::timerEvent(QTimerEvent* event)
194 {
195  if (!event)
196  {
197  return;
198  }
199  else if (event->timerId()==refreshTimer.timerId())
200  {
201  refreshSettings();
202  }
203  else if (event->timerId()==flushTimer.timerId() && file)
204  {
205  mutex.lock();
206 
207  // Flush the I/O buffer
208  file->flush();
209 
210  // Rotate the file if it is too large
211  if (maxSize>0 && file->size()>=maxSize)
212  {
213  close();
214  rotate();
215  open();
216  }
217 
218  mutex.unlock();
219  }
220 }
void timerEvent(QTimerEvent *event)
Handler for timer events.
Definition: filelogger.cpp:193
FileLogger(QSettings *settings, const int refreshInterval=10000, QObject *parent=nullptr)
Constructor.
Definition: filelogger.cpp:78
virtual void write(const LogMessage *logMessage)
Write a message to the log file.
Definition: filelogger.cpp:100
virtual ~FileLogger()
Destructor.
Definition: filelogger.cpp:94
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
QtMsgType getType() const
Get the message type.
Definition: logmessage.cpp:84
Decorates and writes log messages to the console, stderr.
Definition: logger.h:52
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
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