mitsuba/include/mitsuba/core/logger.h

226 lines
7.2 KiB
C++

/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2012 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined(__MITSUBA_CORE_LOGGER_H_)
#define __MITSUBA_CORE_LOGGER_H_
#include <mitsuba/core/formatter.h>
// -----------------------------------------------------------------------
// Logging
// -----------------------------------------------------------------------
MTS_NAMESPACE_BEGIN
/*! \addtogroup libcore */
/*! @{ */
/// Write a Log message to the console (to be used within subclasses of <tt>Object</tt>)
#define Log(level, fmt, ...) do { \
mitsuba::Thread *thread = mitsuba::Thread::getThread(); \
if (EXPECT_NOT_TAKEN(thread == NULL)) \
throw std::runtime_error("Null thread pointer"); \
mitsuba::Logger *logger = thread->getLogger(); \
if (logger != NULL && level >= logger->getLogLevel()) \
logger->log(level, m_theClass, \
__FILE__, __LINE__, fmt, ## __VA_ARGS__); \
} while (0)
/**
* \brief Write a Log message to the console (static version - to be used
* outside of classes that derive from Object)
*/
#define SLog(level, fmt, ...) do { \
mitsuba::Thread *thread = mitsuba::Thread::getThread(); \
if (EXPECT_NOT_TAKEN(thread == NULL)) \
throw std::runtime_error("Null thread pointer"); \
mitsuba::Logger *logger = thread->getLogger(); \
if (logger != NULL && level >= logger->getLogLevel()) \
logger->log(level, NULL, \
__FILE__, __LINE__, fmt, ## __VA_ARGS__); \
} while (0)
/*! @} */
#ifdef MTS_NDEBUG
#define Assert(cond) ((void) 0)
#define AssertEx(cond, explanation) ((void) 0)
#define SAssert(cond) ((void) 0)
#define SAssertEx(cond, explanation) ((void) 0)
#else
/* Assertions */
/*! \addtogroup libcore */
/*! @{ */
/// Assert that a condition is true (to be used \a inside of classes that derive from \ref Object)
#define Assert(cond) do { \
if (!(cond)) Log(EError, "Assertion \"%s\" failed in %s:%i", \
#cond, __FILE__, __LINE__); \
} while (0)
/// ``Static'' assertion (to be used \a outside of classes that derive from \ref Object)
#define SAssert(cond) do { \
if (!(cond)) SLog(EError, "Assertion \"%s\" failed in %s:%i", \
#cond, __FILE__, __LINE__); \
} while (0)
/// Assertion with a customizable error explanation
#define AssertEx(cond, explanation) do { \
if (!(cond)) Log(EError, "Assertion \"%s\" failed in %s:%i (" explanation ")", \
#cond, __FILE__, __LINE__); \
} while (0)
/// Static assertion with a customizable error explanation (see \ref SLog)
#define SAssertEx(cond, explanation) do { \
if (!(cond)) SLog(EError, "Assertion \"%s\" failed in %s:%i (" explanation ")", \
#cond, __FILE__, __LINE__); \
} while (0)
#endif
/// Throw an exception reporting that the given function is not implemented
#define NotImplementedError(funcName) \
throw std::runtime_error(formatString("%s::" funcName "(): Not implemented!", \
getClass()->getName().c_str()));
/*! @} */
/**
* \headerfile mitsuba/core/logger.h mitsuba/mitsuba.h
* \brief Responsible for processing log messages
*
* Upon receiving a log message, the Logger class invokes
* a Formatter to convert it into a human-readable form.
* Following that, it sends this information to every
* registered Appender.
*
* \ingroup libcore
* \ingroup libpython
*/
class MTS_EXPORT_CORE Logger : public Object {
public:
/// Construct a new logger with the given minimum log level
Logger(ELogLevel logLevel = EDebug);
/**
* \brief Process a log message
* \param level Log level of the message
* \param theClass Class descriptor of the message creator
* \param fileName Source file of the message creator
* \param lineNumber Source line number of the message creator
* \param fmt printf-style string formatter
* \note This function is not exposed in the Python bindings.
* Instead, please use \cc mitsuba.core.Log
*/
void log(ELogLevel level, const Class *theClass,
const char *fileName, int lineNumber,
const char *fmt, ...);
/**
* \brief Process a progress message
* \param progress Percentage value in [0,100]
* \param name Title of the progress message
* \param formatted Formatted string representation of the message
* \param eta Estimated time until 100% is reached.
* \param ptr Custom pointer payload. This is used to express the
* context of a progress message. When rendering a scene, it
* will usually contain a pointer to the associated \c RenderJob.
* \remark The \c ptr argument is missing in the Python bindings
*/
void logProgress(Float progress, const std::string &name,
const std::string &formatted, const std::string &eta,
const void *ptr);
/// Set the log level (everything below will be ignored)
void setLogLevel(ELogLevel level);
/**
* \brief Set the error log level (this level and anything
* above will throw exceptions).
*
* The value provided here can be used for instance to turn
* warnings into errors. But \a level must always be
* less than \ref EError, i.e. it isn't possible to
* cause errors not to throw an exception.
*/
void setErrorLevel(ELogLevel level);
/// Return the current log level
inline ELogLevel getLogLevel() const { return m_logLevel; }
/// Return the current error level
inline ELogLevel getErrorLevel() const { return m_errorLevel; }
/// Add an appender to this logger
void addAppender(Appender *appender);
/// Remove an appender from this logger
void removeAppender(Appender *appender);
/// Remove all appenders from this logger
void clearAppenders();
/// Return the number of registered appenders
inline size_t getAppenderCount() const { return m_appenders.size(); }
/// Return one of the appenders
inline Appender *getAppender(size_t index) { return m_appenders[index]; }
/// Return one of the appenders
inline const Appender *getAppender(size_t index) const { return m_appenders[index]; }
/// Set the logger's formatter implementation
void setFormatter(Formatter *formatter);
/// Return the logger's formatter implementation
inline Formatter *getFormatter() { return m_formatter; }
/**
* \brief Return the contents of the log file as a string (if it exists)
*
* \return \c true upon success
*/
bool readLog(std::string &target);
/// Return the number of warnings reported so far
inline size_t getWarningCount() const { return m_warningCount; }
/// Initialize logging
static void staticInitialization();
/// Shutdown logging
static void staticShutdown();
MTS_DECLARE_CLASS()
protected:
/// Virtual destructor
virtual ~Logger();
private:
ELogLevel m_logLevel;
ELogLevel m_errorLevel;
ref<Formatter> m_formatter;
ref<Mutex> m_mutex;
std::vector<Appender *> m_appenders;
size_t m_warningCount;
};
MTS_NAMESPACE_END
#endif /* __MITSUBA_CORE_LOGGER_H_ */