logger.cpp
1 /********************************************************************************
2  * FARSA Utilities Library *
3  * Copyright (C) 2007-2011 Gianluca Massera <emmegian@yahoo.it> *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
18  ********************************************************************************/
19 
20 #include "logger.h"
21 #include <QFile>
22 #include <QTextStream>
23 #include <QTextEdit>
24 #include <QDateTime>
25 #include <iostream>
26 #include <QObject>
27 #include <QEvent>
28 #include <QApplication>
29 #include <QMutex>
30 #include <QMutexLocker>
31 #include <QMessageBox>
32 
33 namespace farsa {
34 
35 namespace {
36  //--- This and the following are utilities class for updating textEdit into the GUI Thread
37  class TextToAppend : public QEvent {
38  public:
39  TextToAppend( QString text, QString level, QString pureMessage ) :
40  QEvent((Type)type),
41  text(text),
42  level(level),
43  pureMessage(pureMessage) { };
44  QString getText() {
45  return text;
46  };
47  QString getLevel() {
48  return level;
49  };
50  QString getPureMessage() {
51  return pureMessage;
52  };
53  private:
54  static int type;
55  QString text;
56  QString level;
57  QString pureMessage;
58  };
59  int TextToAppend::type = QEvent::registerEventType();
60 
61  class TextEditUpdater : public QObject {
62  public:
63  TextEditUpdater() :
64  QObject(),
65  textEdit(NULL)
66  {
67  }
68 
69  void setTextEditToUpdate(QTextEdit* e)
70  {
71  textEdit = e;
72  }
73 
74  bool hasTextEdit() const
75  {
76  return (textEdit != NULL);
77  }
78 
79  protected:
80  virtual void customEvent( QEvent* event ) {
81  // If textEdit is NULL we will crash here (this should never happend)
82  TextToAppend* tevent = dynamic_cast<TextToAppend*>( event );
83  if ( tevent ) {
84  textEdit->append( tevent->getText() );
85  textEdit->moveCursor( QTextCursor::End );
86  textEdit->moveCursor( QTextCursor::StartOfLine );
87  if ( tevent->getLevel() == "ERROR" ) {
88  QMessageBox::critical( 0, "Error from Component", tevent->getPureMessage() );
89  }
90  tevent->accept();
91  } else {
92  QObject::customEvent( event );
93  }
94  };
95 
96  QTextEdit* textEdit;
97  };
98 
99  // This class contains the core functionalities for logging. It is implemented
100  // as a singleton to have the correct initialization of all needed variables
101  // when the Logger is used for the first time
102  class LoggerImplementation
103  {
104  public:
105  // Returns the only instance of this class
106  static LoggerImplementation& getInstance();
107 
108  void info(QString msg);
109 
110  void warning(QString msg);
111 
112  void error(QString msg);
113 
114  void setQTextEdit(QTextEdit* textedit);
115 
116  void enableStdOut(bool enabled);
117 
118  void setLogLevel(Logger::LogLevel level);
119 
120  void setLogFilename(QString logfile);
121 
122  private:
123  // Constructor
124  LoggerImplementation();
125 
126  // Destructor
127  ~LoggerImplementation();
128 
129  // This is the main function for logging. This function is thread-safe
130  void logIt(QString level, QString msg);
131 
132  bool stdOut;
133  QFile* file;
134  TextEditUpdater* textEditUpdater;
135  Logger::LogLevel logLevel;
136  // The semaphores protecting the streams. The logger can be called from multiple threads simultaneously
137  QMutex outStreamMutex;
138  QMutex fileStreamMutex;
139 
140  private:
141  // Copy constructor, not implemented
142  LoggerImplementation(LoggerImplementation&);
143 
144  // Copy operator, not implemented
145  LoggerImplementation& operator=(LoggerImplementation&);
146  };
147 
148  LoggerImplementation& LoggerImplementation::getInstance()
149  {
150  // The meyer singleton
151  static LoggerImplementation loggerImplementation;
152 
153  return loggerImplementation;
154  }
155 
156  void LoggerImplementation::info(QString msg)
157  {
158  if (logLevel <= Logger::LogAll) {
159  logIt("INFO", msg);
160  }
161  }
162 
163  void LoggerImplementation::warning(QString msg)
164  {
165  if (logLevel <= Logger::Warning) {
166  logIt("WARNING", msg);
167  }
168  }
169 
170  void LoggerImplementation::error(QString msg)
171  {
172  if (logLevel <= Logger::Quiet) {
173  logIt("ERROR", msg);
174  }
175  }
176 
177  void LoggerImplementation::setQTextEdit(QTextEdit* textedit)
178  {
179  textEditUpdater->setTextEditToUpdate(textedit);
180  }
181 
182  void LoggerImplementation::enableStdOut(bool enabled)
183  {
184  stdOut = enabled;
185  }
186 
187  void LoggerImplementation::setLogLevel(Logger::LogLevel level)
188  {
189  logLevel = level;
190  }
191 
192  void LoggerImplementation::setLogFilename(QString logfile)
193  {
194  delete file;
195  file = new QFile(logfile);
196  }
197 
198  LoggerImplementation::LoggerImplementation() :
199  stdOut(true),
200  file(NULL),
201  textEditUpdater(new TextEditUpdater()),
202  logLevel(Logger::LogAll),
203  outStreamMutex(),
204  fileStreamMutex()
205  {
206  }
207 
208  LoggerImplementation::~LoggerImplementation()
209  {
210  delete textEditUpdater;
211  delete file;
212 
213  // These lines are here to have a "clean" crash if somebody tries to access
214  // the logger after returning from the main function
215  textEditUpdater = NULL;
216  file = NULL;
217  }
218 
219  //--- this is the main function for logging. This function is thread-safe
220  void LoggerImplementation::logIt(QString level, QString msg)
221  {
222  QString logtmpl("[%1] %2: %3");
223  QString timestamp = QDateTime::currentDateTime().toString( "dd-MM-yyyy hh:mm:ss.zzz" );
224  QString logmsg = logtmpl.arg( timestamp ).arg( level, -10 ).arg( msg );
225  if ( stdOut ) {
226  QMutexLocker locker(&outStreamMutex);
227 
228  QTextStream outStream(stdout, QIODevice::WriteOnly);
229  outStream << logmsg << "\n";
230  }
231  if ( textEditUpdater->hasTextEdit() ) {
232  // No semaphore here as we use the thread-safe postEvent function
233  QString color = "#ffffff";
234  if ( level == "INFO" ) {
235  color = "#afeeee";
236  } else if ( level == "WARNING" ) {
237  color = "#f0e68c";
238  } else if ( level == "ERROR" ) {
239  color = "#ff4500";
240  }
241  // --- here the postEvent is used because it is not possible to modify directly the content of
242  // textEdit because it is not thread-safe. In fact, this function might be called from multiple
243  // threads and outside the GUI thread
244  qApp->postEvent( textEditUpdater, new TextToAppend( QString("<pre style=\"margin-top: 0px; margin-bottom: 0px; color: ")+color+";\">"+logmsg+QString("</pre>"), level, msg ) );
245  //textEdit->append( QString("<pre style=\"margin-top: 0px; margin-bottom: 0px; color: ")+color+";\">"+logmsg+QString("</pre>") );
246  //textEdit->moveCursor( QTextCursor::End );
247  //textEdit->moveCursor( QTextCursor::StartOfLine );
248  }
249  if ( file != NULL ) {
250  QMutexLocker locker(&fileStreamMutex);
251 
252  QTextStream fileStream;
253  fileStream.setDevice(file);
254  fileStream << logmsg << "\n";
255  }
256  }
257 } //end anonymous namespace for LoggerImplementation class
258 
259 void Logger::info(QString msg)
260 {
261  LoggerImplementation::getInstance().info(msg);
262 }
263 
264 void Logger::warning(QString msg)
265 {
266  LoggerImplementation::getInstance().warning(msg);
267 }
268 
269 void Logger::error(QString msg)
270 {
271  LoggerImplementation::getInstance().error(msg);
272 }
273 
274 void Logger::setLogFilename(QString logfile)
275 {
276  LoggerImplementation::getInstance().setLogFilename(logfile);
277 }
278 
279 void Logger::setQTextEdit(QTextEdit* textedit)
280 {
281  LoggerImplementation::getInstance().setQTextEdit(textedit);
282 }
283 
284 void Logger::enableStdOut(bool enabled)
285 {
286  LoggerImplementation::getInstance().enableStdOut(enabled);
287 }
288 
290  LoggerImplementation::getInstance().setLogLevel(level);
291 }
292 
294 {
295  QString str = "unknown";
296 
297  switch(level)
298  {
299  case LogAll:
300  str = "LogAll";
301  break;
302  case Warning:
303  str = "Warning";
304  break;
305  case Quiet:
306  str = "Quiet";
307  break;
308  case Superquiet:
309  str = "Superquiet";
310  break;
311  }
312 
313  return str;
314 }
315 
317 {
318  LogLevel l = LogAll;
319 
320  if (level.toUpper() == "LOGALL") {
321  l = LogAll;
322  } else if (level.toUpper() == "WARNING") {
323  l = Warning;
324  } else if (level.toUpper() == "QUIET") {
325  l = Quiet;
326  } else if (level.toUpper() == "SUPERQUIET") {
327  l = Superquiet;
328  }
329 
330  return l;
331 }
332 
333 } // end namespace farsa
Only errors are logged.
Definition: logger.h:60
static void enableStdOut(bool enabled)
Enable/Disable the printing of log messages on the standard out.
Definition: logger.cpp:284
static void setLogFilename(QString logfile)
Set the filename where to log messages.
Definition: logger.cpp:274
static LogLevel stringToLogLevel(QString level)
Returns the log level given its string representation.
Definition: logger.cpp:316
A macro to deprecate functions.
static void setQTextEdit(QTextEdit *textedit)
Set a QTextEdit dedicated for showing log messages.
Definition: logger.cpp:279
static void setLogLevel(LogLevel level)
Sets the current log level (which influences what is logged and what isn't).
Definition: logger.cpp:289
static void info(QString msg)
Log an informative message.
Definition: logger.cpp:259
static void error(QString msg)
Log an error message.
Definition: logger.cpp:269
static QString logLevelToString(LogLevel level)
Returns the string representation of the given log level.
Definition: logger.cpp:293
Only warnings and errors are logged.
Definition: logger.h:58
Logs everything.
Definition: logger.h:56
Nothing is logged.
Definition: logger.h:62
static void warning(QString msg)
Log a warning message.
Definition: logger.cpp:264