Added file logger

This commit is contained in:
Petr Mrázek
2013-10-06 01:13:40 +02:00
parent eba9b3d759
commit f83119ce7e
69 changed files with 1375 additions and 827 deletions

52
logger/QsDebugOutput.cpp Normal file
View File

@ -0,0 +1,52 @@
// Copyright (c) 2010, Razvan Petru
// All rights reserved.
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
// * The name of the contributors may not be used to endorse or promote products
// derived from this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
#include "QsDebugOutput.h"
#include <QString>
#include <QtGlobal>
#if defined(Q_OS_WIN)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
void QsDebugOutput::output(const QString &message)
{
OutputDebugStringW(reinterpret_cast<const WCHAR *>(message.utf16()));
OutputDebugStringW(L"\n");
}
#elif defined(Q_OS_SYMBIAN)
#include <e32debug.h>
void QsDebugOutput::output(const QString &message)
{
TPtrC8 symbianMessage(reinterpret_cast<const TUint8 *>(qPrintable(message)));
RDebug::RawPrint(symbianMessage);
}
#elif defined(Q_OS_UNIX)
#include <cstdio>
void QsDebugOutput::output(const QString &message)
{
fprintf(stderr, "%s\n", qPrintable(message));
fflush(stderr);
}
#endif

34
logger/QsDebugOutput.h Normal file
View File

@ -0,0 +1,34 @@
// Copyright (c) 2010, Razvan Petru
// All rights reserved.
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
// * The name of the contributors may not be used to endorse or promote products
// derived from this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
class QString;
class QsDebugOutput
{
public:
static void output(const QString &a_message);
};

141
logger/QsLog.cpp Normal file
View File

@ -0,0 +1,141 @@
// Copyright (c) 2010, Razvan Petru
// All rights reserved.
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
// * The name of the contributors may not be used to endorse or promote products
// derived from this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
#include "QsLog.h"
#include "QsLogDest.h"
#include <QMutex>
#include <QList>
#include <QDateTime>
#include <QtGlobal>
#include <cassert>
#include <cstdlib>
#include <stdexcept>
namespace QsLogging
{
typedef QList<Destination *> DestinationList;
static const char *LevelStrings[] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"
"UNKNOWN"};
// not using Qt::ISODate because we need the milliseconds too
static const QString fmtDateTime("hhhh:mm:ss.zzz");
static const char *LevelToText(Level theLevel)
{
if (theLevel > FatalLevel)
{
assert(!"bad log level");
return LevelStrings[UnknownLevel];
}
return LevelStrings[theLevel];
}
class LoggerImpl
{
public:
LoggerImpl() : level(InfoLevel), start_time(QDateTime::currentDateTime())
{
}
QMutex logMutex;
Level level;
DestinationList destList;
QDateTime start_time;
};
Logger::Logger() : d(new LoggerImpl)
{
}
Logger::~Logger()
{
delete d;
}
void Logger::addDestination(Destination *destination)
{
assert(destination);
d->destList.push_back(destination);
}
void Logger::setLoggingLevel(Level newLevel)
{
d->level = newLevel;
}
Level Logger::loggingLevel() const
{
return d->level;
}
//! creates the complete log message and passes it to the logger
void Logger::Helper::writeToLog()
{
const char *const levelName = LevelToText(level);
const QString completeMessage(QString("%1\t%2\t%3")
.arg(QDateTime::currentDateTime().toString(fmtDateTime))
.arg(levelName, 5)
.arg(buffer));
Logger &logger = Logger::instance();
QMutexLocker lock(&logger.d->logMutex);
logger.write(completeMessage);
}
Logger::Helper::Helper(Level logLevel) : level(logLevel), qtDebug(&buffer)
{
}
Logger::Helper::~Helper()
{
try
{
writeToLog();
}
catch (std::exception &e)
{
// you shouldn't throw exceptions from a sink
Q_UNUSED(e);
assert(!"exception in logger helper destructor");
throw;
}
}
//! sends the message to all the destinations
void Logger::write(const QString &message)
{
for (DestinationList::iterator it = d->destList.begin(), endIt = d->destList.end();
it != endIt; ++it)
{
if (!(*it))
{
assert(!"null log destination");
continue;
}
(*it)->write(message);
}
}
} // end namespace

130
logger/QsLog.h Normal file
View File

@ -0,0 +1,130 @@
// Copyright (c) 2010, Razvan Petru
// All rights reserved.
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
// * The name of the contributors may not be used to endorse or promote products
// derived from this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <QDebug>
#include <QString>
namespace QsLogging
{
class Destination;
enum Level
{
TraceLevel = 0,
DebugLevel,
InfoLevel,
WarnLevel,
ErrorLevel,
FatalLevel,
UnknownLevel
};
class LoggerImpl; // d pointer
class Logger
{
public:
static Logger &instance()
{
static Logger staticLog;
return staticLog;
}
//! Adds a log message destination. Don't add null destinations.
void addDestination(Destination *destination);
//! Logging at a level < 'newLevel' will be ignored
void setLoggingLevel(Level newLevel);
//! The default level is INFO
Level loggingLevel() const;
//! The helper forwards the streaming to QDebug and builds the final
//! log message.
class Helper
{
public:
explicit Helper(Level logLevel);
~Helper();
QDebug &stream()
{
return qtDebug;
}
private:
void writeToLog();
Level level;
QString buffer;
QDebug qtDebug;
};
private:
Logger();
Logger(const Logger &);
Logger &operator=(const Logger &);
~Logger();
void write(const QString &message);
LoggerImpl *d;
};
} // end namespace
#define QLOG_TRACE() \
if (QsLogging::Logger::instance().loggingLevel() <= QsLogging::TraceLevel) \
QsLogging::Logger::Helper(QsLogging::TraceLevel).stream()
#define QLOG_DEBUG() \
if (QsLogging::Logger::instance().loggingLevel() <= QsLogging::DebugLevel) \
QsLogging::Logger::Helper(QsLogging::DebugLevel).stream()
#define QLOG_INFO() \
if (QsLogging::Logger::instance().loggingLevel() <= QsLogging::InfoLevel) \
QsLogging::Logger::Helper(QsLogging::InfoLevel).stream()
#define QLOG_WARN() \
if (QsLogging::Logger::instance().loggingLevel() <= QsLogging::WarnLevel) \
QsLogging::Logger::Helper(QsLogging::WarnLevel).stream()
#define QLOG_ERROR() \
if (QsLogging::Logger::instance().loggingLevel() <= QsLogging::ErrorLevel) \
QsLogging::Logger::Helper(QsLogging::ErrorLevel).stream()
#define QLOG_FATAL() QsLogging::Logger::Helper(QsLogging::FatalLevel).stream()
/*
#define QLOG_TRACE() \
if (QsLogging::Logger::instance().loggingLevel() <= QsLogging::TraceLevel) \
QsLogging::Logger::Helper(QsLogging::TraceLevel).stream() << __FILE__ << '@' << __LINE__
#define QLOG_DEBUG() \
if (QsLogging::Logger::instance().loggingLevel() <= QsLogging::DebugLevel) \
QsLogging::Logger::Helper(QsLogging::DebugLevel).stream() << __FILE__ << '@' << __LINE__
#define QLOG_INFO() \
if (QsLogging::Logger::instance().loggingLevel() <= QsLogging::InfoLevel) \
QsLogging::Logger::Helper(QsLogging::InfoLevel).stream() << __FILE__ << '@' << __LINE__
#define QLOG_WARN() \
if (QsLogging::Logger::instance().loggingLevel() <= QsLogging::WarnLevel) \
QsLogging::Logger::Helper(QsLogging::WarnLevel).stream() << __FILE__ << '@' << __LINE__
#define QLOG_ERROR() \
if (QsLogging::Logger::instance().loggingLevel() <= QsLogging::ErrorLevel) \
QsLogging::Logger::Helper(QsLogging::ErrorLevel).stream() << __FILE__ << '@' << __LINE__
#define QLOG_FATAL() \
QsLogging::Logger::Helper(QsLogging::FatalLevel).stream() << __FILE__ << '@' << __LINE__
*/

83
logger/QsLogDest.cpp Normal file
View File

@ -0,0 +1,83 @@
// Copyright (c) 2010, Razvan Petru
// All rights reserved.
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
// * The name of the contributors may not be used to endorse or promote products
// derived from this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
#include "QsLogDest.h"
#include "QsDebugOutput.h"
#include <QFile>
#include <QTextStream>
#include <QString>
namespace QsLogging
{
//! file message sink
class FileDestination : public Destination
{
public:
FileDestination(const QString &filePath);
virtual void write(const QString &message);
private:
QFile mFile;
QTextStream mOutputStream;
};
FileDestination::FileDestination(const QString &filePath)
{
mFile.setFileName(filePath);
mFile.open(QFile::WriteOnly | QFile::Text |
QFile::Truncate); // fixme: should throw on failure
mOutputStream.setDevice(&mFile);
}
void FileDestination::write(const QString &message)
{
mOutputStream << message << endl;
mOutputStream.flush();
}
//! debugger sink
class DebugOutputDestination : public Destination
{
public:
virtual void write(const QString &message);
};
void DebugOutputDestination::write(const QString &message)
{
QsDebugOutput::output(message);
}
DestinationPtr DestinationFactory::MakeFileDestination(const QString &filePath)
{
return DestinationPtr(new FileDestination(filePath));
}
DestinationPtr DestinationFactory::MakeDebugOutputDestination()
{
return DestinationPtr(new DebugOutputDestination);
}
} // end namespace

53
logger/QsLogDest.h Normal file
View File

@ -0,0 +1,53 @@
// Copyright (c) 2010, Razvan Petru
// All rights reserved.
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
// * The name of the contributors may not be used to endorse or promote products
// derived from this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <memory>
class QString;
namespace QsLogging
{
class Destination
{
public:
virtual ~Destination()
{
}
virtual void write(const QString &message) = 0;
};
typedef std::shared_ptr<Destination> DestinationPtr;
//! Creates logging destinations/sinks. The caller will have ownership of
//! the newly created destinations.
class DestinationFactory
{
public:
static DestinationPtr MakeFileDestination(const QString &filePath);
static DestinationPtr MakeDebugOutputDestination();
};
} // end namespace