Fix and improve logging support
authorManuel Nickschas <sputnick@quassel-irc.org>
Sat, 21 Jan 2012 18:52:15 +0000 (19:52 +0100)
committerManuel Nickschas <sputnick@quassel-irc.org>
Sat, 21 Jan 2012 18:52:15 +0000 (19:52 +0100)
It's really inefficient to parse command line options and open the logfile on every message
we log, so move that into the global Quassel class instead. Also fix CMakeLists.txt to
actually enably syslog support in the code, and allow for logging to both syslog and a file.

CMakeLists.txt
src/common/logger.cpp
src/common/logger.h
src/common/main.cpp
src/common/quassel.cpp
src/common/quassel.h

index 319d637..4ddaf66 100644 (file)
@@ -11,7 +11,7 @@
 # -DWITH_KDE=ON          : Enable KDE4 support
 # -DWITH_CRYPT=OFF       : Disable encryption support
 # -DWITH_OXYGEN=(ON|OFF) : Whether to install Oxygen icons (default: yes, unless KDE > 4.3.0 is present and enabled)
-# -DWITH_SYSLOG=OFF       : Use syslog for logging
+# -DWITH_SYSLOG=OFF      : Disable syslog support
 #
 # -DEMBED_DATA=ON        : Embed all data files in icons the binary, rather than installing them separately
 #
@@ -23,6 +23,8 @@
 
 project(QuasselIRC)
 
+include(CheckIncludeFile)
+
 # cmake 2.6.2 is required for KDE >=4.2 and should be widespread enough now
 cmake_minimum_required(VERSION 2.6.2 FATAL_ERROR)
 
@@ -47,7 +49,7 @@ option(WITH_PHONON   "Enable Phonon support (for audio notifications)"        ON)
 option(WITH_LIBINDICATE "Enable Ayatana notification support"           ON)
 option(WITH_KDE      "Enable KDE4 integration"                         OFF)
 option(WITH_CRYPT    "Enable encryption support if present on system"  ON)
-option(WITH_SYSLOG    "Use syslog for storing log data"          OFF)
+option(WITH_SYSLOG   "Use syslog for storing log data"                 ON)
 
 # We use icon paths from KDE 4.3.x, which are partially invalid on older and possibly
 # even on newer KDE versions. Do not disable this unless you are sure that your Quassel will
@@ -60,10 +62,6 @@ if(APPLE)
   option(DEPLOY        "Mac OS X only! Adds required libs to bundle resources and create a dmg. Note: requires Qt to be built with 10.4u SDK" OFF)
 endif(APPLE)
 
-if(WITH_SYSLOG)
-  check_include_file(syslog.h HAVE_SYSLOG_H)
-endif(WITH_SYSLOG)
-
 # Default to embedding data in the static case
 if(STATIC OR WIN32)
   set(EMBED_DEFAULT ON)
@@ -321,6 +319,20 @@ if(BUILD_CORE)
     message(STATUS "Not enabling encryption support")
   endif(WITH_CRYPT)
 
+  # Setup syslog support
+  if(WITH_SYSLOG)
+    check_include_file(syslog.h HAVE_SYSLOG_H)
+    if(HAVE_SYSLOG_H)
+      message(STATUS "Enabling syslog support")
+      set(HAVE_SYSLOG true)
+      add_definitions(-DHAVE_SYSLOG)
+    else(HAVE_SYSLOG_H)
+      message(STATUS "Disabling syslog support")
+    endif(HAVE_SYSLOG_H)
+  else(WITH_SYSLOG)
+    message(STATUS "Not enabling syslog support")
+  endif(WITH_SYSLOG)
+
 endif(BUILD_CORE)
 
 # needed to compile with mingw without kde
index d8da4c7..d9708f7 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005 by the Quassel Project                             *
+ *   Copyright (C) 2005-2012 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#include "logger.h"
-#include "quassel.h"
-
-#ifdef HAVE_SYSLOG_H
-#include <syslog.h>
-#else
 #include <QFile>
 #include <QTextStream>
 #include <QDateTime>
+
+#ifdef HAVE_SYSLOG
+#  include <syslog.h>
 #endif
 
+#include "logger.h"
+#include "quassel.h"
+
 Logger::~Logger() {
-  QDateTime date = QDateTime::currentDateTime();
+  log();
+}
+
+void Logger::log() {
+  if(_logLevel < Quassel::logLevel())
+    return;
+
+  switch(_logLevel) {
+  case Quassel::DebugLevel:
+    _buffer.prepend("Debug: ");
+    break;
+  case Quassel::InfoLevel:
+    _buffer.prepend("Info: ");
+    break;
+    case Quassel::WarningLevel:
+    _buffer.prepend("Warning: ");
+    break;
+  case Quassel::ErrorLevel:
+    _buffer.prepend("Error: ");
+    break;
+  default:
+    break;
+  }
 
-  switch (_logLevel) {
-    case DebugLevel:
-      _buffer.prepend("Debug: ");
+#ifdef HAVE_SYSLOG
+  if(Quassel::logToSyslog()) {
+    int prio;
+    switch(_logLevel) {
+    case Quassel::DebugLevel:
+      prio = LOG_DEBUG;
       break;
-    case InfoLevel:
-      _buffer.prepend("Info: ");
+    case Quassel::InfoLevel:
+      prio = LOG_INFO;
       break;
-    case WarningLevel:
-      _buffer.prepend("Warning: ");
+    case Quassel::WarningLevel:
+      prio = LOG_WARNING;
       break;
-    case ErrorLevel:
-      _buffer.prepend("Error: ");
+    case Quassel::ErrorLevel:
+      prio = LOG_ERR;
       break;
     default:
-      Q_ASSERT(_logLevel); // There should be no unknown log level
+      prio = LOG_INFO;
       break;
+    }
+    syslog(LOG_USER & prio, "%s", qPrintable(_buffer));
   }
-#ifndef HAVE_SYSLOG_H
-  _buffer.prepend(date.toString("yyyy-MM-dd hh:mm:ss "));
 #endif
-  log();
-}
 
-void Logger::log() {
-  LogLevel lvl;
-  if (Quassel::optionValue("loglevel") == "Debug") lvl = DebugLevel;
-  else if (Quassel::optionValue("loglevel") == "Info") lvl = InfoLevel;
-  else if (Quassel::optionValue("loglevel") == "Warning") lvl = WarningLevel;
-  else if (Quassel::optionValue("loglevel") == "Error") lvl = ErrorLevel;
-  else lvl = InfoLevel;
+  _buffer.prepend(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss "));
 
-  if(_logLevel < lvl) return;
+  // if we don't have a logfile we log to stdout
 
-#ifdef HAVE_SYSLOG_H
-  if (Quassel::isOptionSet("syslog")) {
-    int prio;
-    switch (lvl) {
-      case DebugLevel:
-        prio = LOG_DEBUG;
-        break;
-      case InfoLevel:
-        prio = LOG_INFO;
-        break;
-      case WarningLevel:
-        prio = LOG_WARNING;
-        break;
-      case ErrorLevel:
-        prio = LOG_ERR;
-        break;
-      default:
-        prio = LOG_INFO;
-        break;
-    }
-    syslog(LOG_USER & prio, "%s", qPrintable(_buffer));
-  }
-#else
-  // if we can't open logfile we log to stdout
   QTextStream out(stdout);
-  QFile file;
-  if(!Quassel::optionValue("logfile").isEmpty()) {
-    file.setFileName(Quassel::optionValue("logfile"));
-    if (file.open(QIODevice::Append | QIODevice::Text)) {
-      out.setDevice(&file);
-      _buffer.remove(QChar('\n'));
-    }
+  if(Quassel::logFile() && Quassel::logFile()->isOpen()) {
+    _buffer.remove(QChar('\n'));
+    out.setDevice(Quassel::logFile());
   }
+
   out << _buffer << endl;
-  if(file.isOpen()) file.close();
-#endif
 }
 
 
 void Logger::logMessage(QtMsgType type, const char *msg) {
   switch (type) {
   case QtDebugMsg:
-    Logger(Logger::DebugLevel) << msg;
+    Logger(Quassel::DebugLevel) << msg;
     break;
   case QtWarningMsg:
-    Logger(Logger::WarningLevel) << msg;
+    Logger(Quassel::WarningLevel) << msg;
     break;
   case QtCriticalMsg:
-    Logger(Logger::ErrorLevel) << msg;
+    Logger(Quassel::ErrorLevel) << msg;
     break;
   case QtFatalMsg:
-    Logger(Logger::ErrorLevel) << msg;
+    Logger(Quassel::ErrorLevel) << msg;
     Quassel::logFatalMessage(msg);
     return;
   }
index 352b0ce..744c980 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005 by the Quassel Project                             *
+ *   Copyright (C) 2005-2012 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 #ifndef LOGGER_H
 #define LOGGER_H
 
-#include "types.h"
-
-#include <QString>
 #include <QStringList>
 #include <QTextStream>
 
+#include "quassel.h"
+#include "types.h"
+
 class Logger {
 public:
-  enum LogLevel {
-    DebugLevel,
-    InfoLevel,
-    WarningLevel,
-    ErrorLevel
-  };
-
-  inline Logger(LogLevel level) : _stream(&_buffer, QIODevice::WriteOnly), _logLevel(level) {}
+  inline Logger(Quassel::LogLevel level) : _stream(&_buffer, QIODevice::WriteOnly), _logLevel(level) {}
   ~Logger();
 
   static void logMessage(QtMsgType type, const char *msg);
@@ -50,22 +43,22 @@ private:
   void log();
   QTextStream _stream;
   QString _buffer;
-  LogLevel _logLevel;
+  Quassel::LogLevel _logLevel;
 };
 
 class quInfo : public Logger {
 public:
-  inline quInfo() : Logger(Logger::InfoLevel) {}
+  inline quInfo() : Logger(Quassel::InfoLevel) {}
 };
 
 class quWarning : public Logger {
 public:
-  inline quWarning() : Logger(Logger::WarningLevel) {}
+  inline quWarning() : Logger(Quassel::WarningLevel) {}
 };
 
 class quError : public Logger {
 public:
-  inline quError() : Logger(Logger::ErrorLevel) {}
+  inline quError() : Logger(Quassel::ErrorLevel) {}
 };
 
 #endif
index 2bb2cda..34fb70e 100644 (file)
@@ -105,12 +105,11 @@ int main(int argc, char **argv) {
   cliParser->addOption("port <port>",'p', "The port quasselcore will listen at", QString("4242"));
   cliParser->addSwitch("norestore", 'n', "Don't restore last core's state");
   cliParser->addOption("loglevel <level>", 'L', "Loglevel Debug|Info|Warning|Error", "Info");
-#ifdef HAVE_SYSLOG_H
-  cliParser->addSwitch("syslog", 0, "Send the log to syslog.");
-#else
-  cliParser->addOption("logfile <path>", 'l', "Path to logfile");
+#ifdef HAVE_SYSLOG
+  cliParser->addSwitch("syslog", 0, "Log to syslog");
 #endif
-  cliParser->addOption("select-backend <backendidentifier>", 0, "Starts an interactive session and switches your current storage backend to the new one. Attempts a merge if the new backend is uninitialized and the old backend supports migration. Otherwise prompts for new user credentials!");
+  cliParser->addOption("logfile <path>", 'l', "Log to a file");
+  cliParser->addOption("select-backend <backendidentifier>", 0, "Switch storage backend (migrating data if possible)");
   cliParser->addSwitch("add-user", 0, "Starts an interactive session to add a new core user");
   cliParser->addOption("change-userpass <username>", 0, "Starts an interactive session to change the password of the user identified by username");
 #endif
index bf63798..30572fa 100644 (file)
@@ -51,6 +51,9 @@ bool Quassel::DEBUG = false;
 QString Quassel::_coreDumpFileName;
 Quassel *Quassel::_instance = 0;
 bool Quassel::_handleCrashes = true;
+Quassel::LogLevel Quassel::_logLevel = InfoLevel;
+QFile *Quassel::_logFile = 0;
+bool Quassel::_logToSyslog = false;
 
 Quassel::Quassel() {
   Q_ASSERT(!_instance);
@@ -62,6 +65,10 @@ Quassel::Quassel() {
 }
 
 Quassel::~Quassel() {
+  if(logFile()) {
+    logFile()->close();
+    logFile()->deleteLater();
+  }
   delete _cliParser;
 }
 
@@ -109,6 +116,29 @@ bool Quassel::init() {
   }
 
   DEBUG = isOptionSet("debug");
+
+  // set up logging
+  if(isOptionSet("loglevel")) {
+    QString level = optionValue("loglevel");
+
+    if(level == "Debug") _logLevel = DebugLevel;
+    else if(level == "Info") _logLevel = InfoLevel;
+    else if(level == "Warning") _logLevel= WarningLevel;
+    else if(level == "Error") _logLevel = ErrorLevel;
+  }
+
+  QString logfilename = optionValue("logfile");
+  if(!logfilename.isEmpty()) {
+    _logFile = new QFile(logfilename);
+    if(!_logFile->open(QIODevice::Append | QIODevice::Text)) {
+      qWarning() << "Could not open log file" << logfilename << ":" << _logFile->errorString();
+      _logFile->deleteLater();
+      _logFile = 0;
+    }
+  }
+
+  _logToSyslog = isOptionSet("syslog");
+
   return true;
 }
 
index 86469c4..30e02b2 100644 (file)
@@ -27,6 +27,8 @@
 
 #include "abstractcliparser.h"
 
+class QFile;
+
 class Quassel {
   Q_DECLARE_TR_FUNCTIONS(Quassel)
 
@@ -121,6 +123,17 @@ public:
 
   static bool DEBUG;
 
+  enum LogLevel {
+    DebugLevel,
+    InfoLevel,
+    WarningLevel,
+    ErrorLevel
+  };
+
+  static inline LogLevel logLevel();
+  static inline QFile *logFile();
+  static inline bool logToSyslog();
+
   static void logFatalMessage(const char *msg);
 
 protected:
@@ -150,6 +163,10 @@ private:
   static QString _configDirPath;
   static QStringList _dataDirPaths;
   static QString _translationDirPath;
+
+  static LogLevel _logLevel;
+  static QFile *_logFile;
+  static bool _logToSyslog;
 };
 
 Q_DECLARE_OPERATORS_FOR_FLAGS(Quassel::Features);
@@ -165,4 +182,8 @@ AbstractCliParser *Quassel::cliParser() { return _cliParser; }
 QString Quassel::optionValue(const QString &key) { return cliParser()->value(key); }
 bool Quassel::isOptionSet(const QString &key) { return cliParser()->isSet(key); }
 
+Quassel::LogLevel Quassel::logLevel() { return _logLevel; }
+QFile *Quassel::logFile() { return _logFile; }
+bool Quassel::logToSyslog() { return _logToSyslog; }
+
 #endif