[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[vidalia-svn] r1642: Add a utility class for logging debugging messages. The Log (in trunk: . src/util)



Author: edmanm
Date: 2007-02-20 12:33:13 -0500 (Tue, 20 Feb 2007)
New Revision: 1642

Added:
   trunk/src/util/log.cpp
   trunk/src/util/log.h
Modified:
   trunk/
   trunk/src/util/util.pri
Log:
 r1679@adrastea:  edmanm | 2007-02-20 12:10:14 -0500
 Add a utility class for logging debugging messages. The Log class is similar
 to the QDebug class provided with Qt, but with finer-grained logging levels
 (same levels as Tor), slightly different output (for example, not everything
 is wrapped in double quotes), supports using .arg(), and can still be used
 even if Qt was compiled with QT_NO_DEBUG_STREAM.



Property changes on: trunk
___________________________________________________________________
 svk:merge ticket from /vidalia/local/trunk [r1679] on 54b3572a-7227-0410-958f-53ecd705b71a

Added: trunk/src/util/log.cpp
===================================================================
--- trunk/src/util/log.cpp	                        (rev 0)
+++ trunk/src/util/log.cpp	2007-02-20 17:33:13 UTC (rev 1642)
@@ -0,0 +1,184 @@
+/****************************************************************
+ *  Vidalia is distributed under the following license:
+ *
+ *  Copyright (C) 2007,  Matt Edman, Justin Hipple
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ *  Boston, MA  02110-1301, USA.
+ ****************************************************************/
+
+/** 
+ * \file log.cpp
+ * \version $Id$
+ * \brief Debug message logging
+ */
+
+#include <QDateTime>
+#include <QTextStream>
+
+#include "log.h"
+
+/** Open log files for appending as write-only text. */
+#define LOGFILE_MODE  \
+  (QIODevice::WriteOnly|QIODevice::Append|QIODevice::Text)
+/** Format for log message timestamps. */
+#define TIMESTAMP_FMT   "MMM dd HH:mm:ss.zzz"
+
+
+/** Default constructor. Logs at level Notice by default. */
+Log::Log()
+{
+  _logLevel = Notice;
+}
+
+/** Destructor. Closes the log file. */
+Log::~Log()
+{
+  close();
+}
+
+/** Returns a list of strings representing available log levels. */
+QStringList
+Log::logLevels()
+{
+  return (QStringList() << "debug" << "info" << "notice" 
+                        << "warn" << "error");
+}
+
+/** Sets the current log level to <b>level</b>. If <b>level</b> is Off, then
+ * the log file will be closed as well. If <b>level</b> is Unknown, no change
+ * to the current log level is made. */
+void
+Log::setLogLevel(LogLevel level)
+{
+  if (level >= Debug && level < Unknown)
+    _logLevel = level;
+  if (level == Off)
+    _logFile.close();
+}
+
+/** Opens <b>file</b> for appending, to which log messages will be written. */
+bool
+Log::open(FILE *file)
+{
+  if (_logFile.isOpen())
+    close();
+
+  _logFile.open(file, LOGFILE_MODE);
+  return isOpen();
+}
+
+/** Opens <b>file</b> for appending, to which log messages will be written. */
+bool
+Log::open(QString file)
+{
+  if (_logFile.isOpen())
+    close();
+
+  _logFile.setFileName(file);
+  _logFile.open(LOGFILE_MODE);
+  return isOpen();
+}
+
+/** Flushes any outstanding log messages and closes the log file. */
+void
+Log::close()
+{
+  _logFile.flush();
+  _logFile.close();
+}
+
+/** Creates a log message with severity <b>level</b> and initial message
+ * contents <b>message<b>. The log message can be appended to until the
+ * returned LogMessage's destructor is called, at which point the complete
+ * message is written to the log file. */
+inline Log::LogMessage
+Log::log(LogLevel level)
+{
+  if (level < _logLevel)
+    return LogMessage(level, 0);
+  return LogMessage(level, &_logFile);
+}
+
+/** Creates a log message with severity <b>level</b>. The log message can be
+ * appended to until the returned LogMessage's destructor is called, at
+ * which point the complete message is written to the log file. */
+Log::LogMessage
+Log::log(LogLevel level, QString msg)
+{
+  return log(level) << msg;
+}
+
+/** Returns a string description of the given LogLevel <b>level</b>. */
+inline QString
+Log::logLevelToString(LogLevel level)
+{
+  switch (level) {
+    case Debug:   return "debug";
+    case Info:    return "info";
+    case Notice:  return "notice";
+    case Warn:    return "warn";
+    case Error:   return "error";
+    case Off:     return "off";
+    default:      return "unknown";
+  }
+}
+
+/** Returns a LogLevel for the level given by <b>str</b>, or Unknown if the
+ * given string does not represent a valid LogLevel value. */
+Log::LogLevel
+Log::stringToLogLevel(QString str)
+{
+  str = str.toLower();
+  if (str == "debug")
+    return Debug;
+  else if (str == "info")
+    return Info;
+  else if (str == "notice")
+    return Notice;
+  else if (str == "warn")
+    return Warn;
+  else if (str == "error")
+    return Error;
+  else if (str == "off")
+    return Off;
+  return Unknown;
+}
+
+/** Returns a formatted log message, prefixed with a timestamp and the log
+ * message severity level. */
+inline QString
+Log::LogMessage::toString() const
+{
+  QString msg = QDateTime::currentDateTime().toString(TIMESTAMP_FMT);
+  msg.append(" [" + Log::logLevelToString(stream->type) + "] ");
+  msg.append(stream->buf);
+  return msg;
+}
+
+/** Destructor. Writes the buffered log message out to the log file specified
+ * in the constructor. */
+Log::LogMessage::~LogMessage()
+{
+  if (!--stream->ref) {
+    if (stream->out && !stream->buf.isEmpty()) {
+      QTextStream log(stream->out);
+      log << toString() << endl;
+      log.flush();
+    }
+    delete stream;
+  }
+}
+


Property changes on: trunk/src/util/log.cpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: trunk/src/util/log.h
===================================================================
--- trunk/src/util/log.h	                        (rev 0)
+++ trunk/src/util/log.h	2007-02-20 17:33:13 UTC (rev 1642)
@@ -0,0 +1,164 @@
+/****************************************************************
+ *  Vidalia is distributed under the following license:
+ *
+ *  Copyright (C) 2007,  Matt Edman, Justin Hipple
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ *  Boston, MA  02110-1301, USA.
+ ****************************************************************/
+
+/** 
+ * \file log.h
+ * \version $Id$
+ * \brief Debug message logging
+ */
+
+#ifndef _LOG_H
+#define _LOG_H
+
+#include <QObject>
+#include <QFile>
+#include <QStringList>
+#include <QIODevice>
+#include <QHostAddress>
+
+
+/** The Log class is similar to the QDebug class provided with Qt, but with
+ * finer-grained logging levels, slightly different output (for example, not
+ * everything is wrapped in double quotes), supports using .arg(), and can 
+ * still be used even if Qt was compiled with QT_NO_DEBUG_STREAM. */
+class Log
+{
+public:
+  /** Logging severity levels. */
+  enum LogLevel {
+    Debug = 0,  /**< Verbose debugging output. */
+    Info,       /**< Primarily program flow output. */
+    Notice,     /**< Non-failure (but important) events. */
+    Warn,       /**< Recoverable failure conditions. */
+    Error,      /**< Critical, non-recoverable errors. */
+    Off,        /**< No logging output. */
+    Unknown     /**< Unknown/invalid log level. */
+  };
+  class LogMessage;
+  
+  /** Default constructor. */
+  Log();
+  /** Destructor. */
+  ~Log();
+
+  /** Opens a file on disk (or stdout or stderr) to which log messages will be
+   * written. */
+  bool open(FILE *file);
+  /** Opens a file on disk to which log messages will be written. */
+  bool open(QString file);
+  /** Closes the log file. */ 
+  void close();
+  /** Returns true if the log file is open and ready for writing. */
+  bool isOpen() { return _logFile.isOpen() && _logFile.isWritable(); }
+  /** Returns a string description of the last file error encountered. */
+  QString errorString() { return _logFile.errorString(); }
+  
+  /** Sets the current log level to <b>level</b>. */
+  void setLogLevel(LogLevel level);
+  /** Returns a list of strings representing valid log levels. */
+  static QStringList logLevels();
+  /** Returns a string description of the given LogLevel <b>level</b>. */
+  static inline QString logLevelToString(LogLevel level);
+  /** Returns a LogLevel for the level given by <b>str</b>. */
+  static LogLevel stringToLogLevel(QString str);
+  
+  /** Creates a log message with severity <b>level</b> and initial message
+   * contents <b>message<b>. The log message can be appended to until the
+   * returned LogMessage's destructor is called, at which point the complete
+   * message is written to the log file. */
+  LogMessage log(LogLevel level, QString message);
+  /** Creates a log message with severity <b>level</b>. The log message can be
+   * appended to until the returned LogMessage's destructor is called, at
+   * which point the complete message is written to the log file. */
+  inline LogMessage log(LogLevel level);
+  
+private:
+  LogLevel _logLevel; /**< Minimum log severity level. */
+  QFile _logFile;     /**< Log output destination. */
+};
+
+/** This internal class represents a single message that is to be written to 
+ * the log destination. The message is buffered until it is written to the
+ * log in this class's destructor. */
+class Log::LogMessage
+{
+public:
+  struct Stream {
+    Stream(Log::LogLevel t, QIODevice *o) 
+      : type(t), out(o), ref(1) {}
+    Log::LogLevel type;
+    QIODevice *out;
+    int ref;
+    QString buf;
+  } *stream;
+ 
+  inline LogMessage(Log::LogLevel t, QIODevice *o)
+    : stream(new Stream(t,o)) {}
+  inline LogMessage(const LogMessage &o) 
+    : stream(o.stream) { ++stream->ref; }
+  inline QString toString() const;
+  ~LogMessage();
+ 
+  /* Support both the << and .arg() methods */
+  inline LogMessage &operator<<(const QString &t) 
+    { stream->buf += t; return *this; }
+  inline LogMessage arg(const QString &a)
+    { stream->buf = stream->buf.arg(a); return *this; }
+  inline LogMessage &operator<<(const QHostAddress &a)
+    { stream->buf += a.toString(); return *this; }
+  inline LogMessage arg(const QHostAddress &a)
+    { stream->buf = stream->buf.arg(a.toString()); return *this; }
+  inline LogMessage &operator<<(short a)
+    { stream->buf += QString::number(a); return *this; }
+  inline LogMessage arg(short a)
+    { stream->buf = stream->buf.arg(a); return *this; }
+  inline LogMessage &operator<<(ushort a)
+    { stream->buf += QString::number(a); return *this; }
+  inline LogMessage arg(ushort a)
+    { stream->buf = stream->buf.arg(a); return *this; }
+  inline LogMessage &operator<<(int a)
+    { stream->buf += QString::number(a); return *this; }
+  inline LogMessage arg(int a)
+    { stream->buf = stream->buf.arg(a); return *this; }
+  inline LogMessage &operator<<(uint a)
+    { stream->buf += QString::number(a); return *this; }
+  inline LogMessage arg(uint a)
+    { stream->buf = stream->buf.arg(a); return *this; }
+  inline LogMessage &operator<<(long a)
+    { stream->buf += QString::number(a); return *this; }
+  inline LogMessage arg(long a)
+    { stream->buf = stream->buf.arg(a); return *this; }
+  inline LogMessage &operator<<(ulong a)
+    { stream->buf += QString::number(a); return *this; }
+  inline LogMessage arg(ulong a)
+    { stream->buf = stream->buf.arg(a); return *this; }
+  inline LogMessage &operator<<(qlonglong a)
+    { stream->buf += QString::number(a); return *this; }
+  inline LogMessage arg(qlonglong a)
+    { stream->buf = stream->buf.arg(a); return *this; }
+  inline LogMessage &operator<<(qulonglong a)
+    { stream->buf += QString::number(a); return *this; }
+  inline LogMessage arg(qulonglong a)
+    { stream->buf = stream->buf.arg(a); return *this; }
+};
+
+#endif
+


Property changes on: trunk/src/util/log.h
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Modified: trunk/src/util/util.pri
===================================================================
--- trunk/src/util/util.pri	2007-02-20 17:33:03 UTC (rev 1641)
+++ trunk/src/util/util.pri	2007-02-20 17:33:13 UTC (rev 1642)
@@ -28,7 +28,8 @@
            $$PWD/html.h \
            $$PWD/process.h \
            $$PWD/file.h \
-           $$PWD/zlibbytearray.h
+           $$PWD/zlibbytearray.h \
+           $$PWD/log.h
            
 SOURCES += $$PWD/net.cpp \
            $$PWD/http.cpp \
@@ -37,7 +38,8 @@
            $$PWD/html.cpp \
            $$PWD/process.cpp \
            $$PWD/file.cpp \
-           $$PWD/zlibbytearray.cpp
+           $$PWD/zlibbytearray.cpp \
+           $$PWD/log.cpp
 
 win32 {
     HEADERS += $$PWD/win32.h