19 changed files with 1124 additions and 142 deletions
			
			
		- 
					10CMakeLists.txt
- 
					13resources/3rdparty/CMakeLists.txt
- 
					21resources/3rdparty/l3pp/LICENSE
- 
					107resources/3rdparty/l3pp/Readme.md
- 
					158resources/3rdparty/l3pp/formatter.h
- 
					106resources/3rdparty/l3pp/impl/formatter.h
- 
					123resources/3rdparty/l3pp/impl/logger.h
- 
					32resources/3rdparty/l3pp/impl/logging.h
- 
					18resources/3rdparty/l3pp/impl/sink.h
- 
					165resources/3rdparty/l3pp/l3pp.h
- 
					179resources/3rdparty/l3pp/logger.h
- 
					108resources/3rdparty/l3pp/sink.h
- 
					2src/builder/ExplicitDFTModelBuilder.cpp
- 
					7src/cli/cli.cpp
- 
					2src/settings/modules/DebugSettings.cpp
- 
					33src/utility/initialize.cpp
- 
					7src/utility/initialize.h
- 
					23src/utility/logging.h
- 
					128src/utility/macros.h
| @ -0,0 +1,21 @@ | |||||
|  | The MIT License (MIT) | ||||
|  | 
 | ||||
|  | Copyright (c) 2016 nafur | ||||
|  | 
 | ||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||
|  | in the Software without restriction, including without limitation the rights | ||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||
|  | furnished to do so, subject to the following conditions: | ||||
|  | 
 | ||||
|  | The above copyright notice and this permission notice shall be included in all | ||||
|  | copies or substantial portions of the Software. | ||||
|  | 
 | ||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  | SOFTWARE. | ||||
| @ -0,0 +1,107 @@ | |||||
|  | L3++: Lightweight Logging Library for C++ | ||||
|  | ===== | ||||
|  | 
 | ||||
|  | L3++ is a self-contained, single-header, cross-platform logging library for C++. | ||||
|  | 
 | ||||
|  | The main goals for this library are simplicity, modularity and ease of use. | ||||
|  | This library is released under the MIT License. | ||||
|  | 
 | ||||
|  | Copyright (C) 2015 Gereon Kremer | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | Concepts | ||||
|  | ===== | ||||
|  | 
 | ||||
|  | L3++ is based on the following conceptual components: | ||||
|  | 
 | ||||
|  | * RecordInfo: A record info stores auxiliary information of a log message like the filename, line number and function name where the log message was emitted. | ||||
|  | * Logger: A logger categorizes log messages, usually according to logical components or modules in the source code. | ||||
|  | * Sink: A sink represents a logging output, for example the terminal or a log file. | ||||
|  | * Formatter: A formatter is associated with a sink and converts a log message into an actual string. | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | Log levels | ||||
|  | ----- | ||||
|  | The following log levels exist (from `l3pp::LogLevel`): | ||||
|  | * ALL | ||||
|  | * TRACE | ||||
|  | * DEBUG | ||||
|  | * INFO | ||||
|  | * WARN | ||||
|  | * ERR | ||||
|  | * FATAL | ||||
|  | * OFF | ||||
|  | 
 | ||||
|  | Hierarchical Loggers | ||||
|  | ----- | ||||
|  | Loggers are hierarchically structured strings like `"app.module.submodule"`. In this example, `submodule` is considered a sublogger of `module` and `app` the parent of `module`. A sublogger implicitly inherits all sinks and the log level of the parent, unless explicitly configured otherwise. | ||||
|  | 
 | ||||
|  | The hierarchical tree of loggers always contains the root logger at the top. The root logger itself does not have a parent, nor a name. It can be accessed via `l3pp::Logging::getRootLogger()`. | ||||
|  | 
 | ||||
|  | Each logger is assigned a log level, or is configured to inherit the log level of the parent (with the special log level `l3pp::LogLevel::INHERIT`). Note that the root logger cannot inherit a log level. Any log entry with a lower level is filtered out and will not be logged. | ||||
|  | 
 | ||||
|  | A logger can also be assigned one or more sinks. By default, a logger will log to both the sinks of its parent, as well as its own sinks. Should a logger only use it own sinks, it should be set to non-additive (using `Logger::setAdditive(false)`). | ||||
|  | 
 | ||||
|  | Sinks | ||||
|  | ----- | ||||
|  | A sink provides an output for loggers. Loggers may define multiple sinks, and sinks may be shared between loggers. Sinks are associated with a formatter and a log level. The log level specifies the minimum level of a message for it to be output (independent of the log level of a logger), and by default permits all log messages. A formatter formats the log messages before being output. By default, a simple formatter is used which prints the log level, message and a newline, but other formatters can be specified. | ||||
|  | 
 | ||||
|  | Formatters | ||||
|  | ----- | ||||
|  | A formatter shapes a log message before being sent to its final destination. A non-configurable simple formatter exists, as well as a template-based formatter. The latter specifies the format of a message by means of its template arguments, see `l3pp::makeTemplateFormatter`. | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | Basic Usage | ||||
|  | ===== | ||||
|  | 
 | ||||
|  | A logger object can be accessed via `l3pp::Logger::getLogger()` or `l3pp::Logger::getRootLogger()`. By default, the root logger does not output anywhere. Therefore, a sink should be added. An initial configuration may look like this: | ||||
|  | 
 | ||||
|  |     l3pp::Logger::initialize(); | ||||
|  |     l3pp::SinkPtr sink = log4carl::StreamSink::create(std::clog); | ||||
|  |     l3pp::Logger::getRootLogger()->addSink(sink); | ||||
|  |     l3pp::Logger::getRootLogger()->setLevel(log4carl::LogLevel::INFO); | ||||
|  | 
 | ||||
|  | In this demo, a single sink is created that passes log messages to the standard logging stream `std::clog`. All messages must have at least level `LVL_INFO` before being printed. | ||||
|  | 
 | ||||
|  | The actual logging is performed using a handful of macros. | ||||
|  | These macros | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | Considerations | ||||
|  | ===== | ||||
|  | 
 | ||||
|  | Performance | ||||
|  | ----- | ||||
|  | While the use of hierarchical loggers and multiple sinks with associated formatters gives a lot of flexibility, it comes at a certain price. As the configuration is done at runtime (and may even change at runtime), the question whether a certain message is printed can only be answered at runtime. Therefore, every message, whether you will ever see it or not, has to pass through the logger and cost runtime. | ||||
|  | 
 | ||||
|  | To mitigate this, we suggest the following: | ||||
|  | 
 | ||||
|  | Create a preprocessor flag (like `ENABLE_LOGGING`) and define your own set of logging macros. | ||||
|  | If this flag is defined, make your macros forward to the `L3PP_LOG_*` macros. | ||||
|  | If this flag is not defined, make your macros do nothing. | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | Multiple usages in the same project | ||||
|  | ----- | ||||
|  | Assume you have an application that uses L3++ for logging as well as some other library that also uses L3++. | ||||
|  | L3++ will play nicely in this scenario (partly, it was designed for this case). | ||||
|  | 
 | ||||
|  | However, you should take care of a few things: | ||||
|  | * Colliding loggers: Prefix your loggers with some unique prefix. | ||||
|  | * Colliding macros: If you implement the aforementioned `ENABLE_LOGGING` macro, prefix your macros with your project name. Otherwise, these macros will collide. | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | Implementation Details | ||||
|  | ===== | ||||
|  | 
 | ||||
|  | Sinks | ||||
|  | ----- | ||||
|  | A sink is a class that provides some `log` method. Any class that inherits from `l3pp::Sink` can be used. | ||||
|  | 
 | ||||
|  | As of now, two implementations are available:  | ||||
|  | * FileSink: Writes to a output file. | ||||
|  | * StreamSink: Writes to any given `std::ostream`, for example to `std::cout`. | ||||
|  | 
 | ||||
|  | Formatters | ||||
|  | ----- | ||||
|  | A formatter is a functor that given a log entry, provides a formatted string. The base class `Formatter` provides some very simple formatting, whereas `TemplateFormatter` provides more control over the shape. Internally, a `TemplateFormatter` streams its arguments to a stream before constructing the string. The special types `FieldStr` and `TimeStr` can be used to format particular attributes of a log entry. | ||||
| @ -0,0 +1,158 @@ | |||||
|  | /** | ||||
|  |  * @file formatter.h | ||||
|  |  * @author Harold Bruintjes <h.bruintjes@cs.rwth-aachen.de> | ||||
|  |  * | ||||
|  |  * Define the Formatter class, used to format output of a sink | ||||
|  |  */ | ||||
|  | 
 | ||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | #include <string> | ||||
|  | #include <tuple> | ||||
|  | 
 | ||||
|  | namespace l3pp { | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Formats a log messages. This is a base class that simply print the message | ||||
|  |  * with the log level prefix, see derived classes such as TemplatedFormatter | ||||
|  |  * for more interesting data. | ||||
|  |  */ | ||||
|  | class Formatter { | ||||
|  | 	friend class Logger; | ||||
|  | 
 | ||||
|  | 	static void initialize(); | ||||
|  | 
 | ||||
|  | 	virtual std::string format(EntryContext const& context, std::string const& msg) const; | ||||
|  | public: | ||||
|  | 	virtual ~Formatter() {} | ||||
|  | 
 | ||||
|  | 	std::string operator()(EntryContext const& context, std::string const& msg) { | ||||
|  | 		return format(context, msg); | ||||
|  | 	} | ||||
|  | }; | ||||
|  | typedef std::shared_ptr<Formatter> FormatterPtr; | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Possible fields for FieldStr instance | ||||
|  |  */ | ||||
|  | enum class Field { | ||||
|  | 	/// Name of the file (everything following the last path separator) | ||||
|  | 	FileName, | ||||
|  | 	/// Full path of the file | ||||
|  | 	FilePath, | ||||
|  | 	/// Line number | ||||
|  | 	Line, | ||||
|  | 	/// Name of function currently executed | ||||
|  | 	Function, | ||||
|  | 	/// Name of the logger | ||||
|  | 	LoggerName, | ||||
|  | 	/// Message to be logged | ||||
|  | 	Message, | ||||
|  | 	/// Level of the log entry | ||||
|  | 	LogLevel, | ||||
|  | 	/// Number of milliseconds since the logger was initialized | ||||
|  | 	WallTime, | ||||
|  | }; | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Controls justification of formatted log fields. | ||||
|  |  */ | ||||
|  | enum class Justification { | ||||
|  | 	/// Left align field | ||||
|  | 	LEFT, | ||||
|  | 	/// Right align field | ||||
|  | 	RIGHT | ||||
|  | }; | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Formatter for log entry fields, with the exception of time stamp formatting | ||||
|  |  * (see TimeStr for that). The Field template argument determines which field | ||||
|  |  * is printed, see logging::Field. | ||||
|  |  * The other template arguments control the alignment of the output string. | ||||
|  |  */ | ||||
|  | template<Field field, int Width = 0, Justification j = Justification::RIGHT, char Fill = ' '> | ||||
|  | class FieldStr { | ||||
|  | public: | ||||
|  | 	void stream(std::ostream& os, EntryContext const& context, std::string const& msg) const; | ||||
|  | }; | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Formatter for log time stamps. The constructor expects a single string | ||||
|  |  * argument which is a formatter for the time stamp. For the specification of | ||||
|  |  * this format string see the documentation for std::put_time . You can use for | ||||
|  |  * example "%c" or "%T". | ||||
|  |  * The template arguments control the alignment of the output string. | ||||
|  |  */ | ||||
|  | class TimeStr { | ||||
|  | 	std::string formatStr; | ||||
|  | 
 | ||||
|  | public: | ||||
|  | 	TimeStr(char const* format) : formatStr(format) { | ||||
|  | 	} | ||||
|  | 	TimeStr(std::string const& format) : formatStr(format) { | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	void stream(std::ostream& os, EntryContext const& context, std::string const&) const; | ||||
|  | }; | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Formatter which formats the output based on the (templated) arguments given. | ||||
|  |  * The arguments can be anything that implements the stream operator <<, but | ||||
|  |  * more interestingly also the various FormatField subclasses. These classes | ||||
|  |  * can output the various fields associated with a log entry. | ||||
|  |  */ | ||||
|  | template<typename ... Formatters> | ||||
|  | class TemplateFormatter : public Formatter { | ||||
|  | 	std::tuple<Formatters...> formatters; | ||||
|  | 
 | ||||
|  | 	template <int N> | ||||
|  | 	typename std::enable_if<N < (sizeof...(Formatters))>::type | ||||
|  | 	formatTuple(EntryContext const& context, std::string const& msg, std::ostream& os) const { | ||||
|  | 		formatElement(std::get<N>(formatters), os, context, msg); | ||||
|  | 		formatTuple<N+1>(context, msg, os); | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	template <int N> | ||||
|  | 	typename std::enable_if<(N >= sizeof...(Formatters))>::type | ||||
|  | 	formatTuple(EntryContext const&, std::string const&, std::ostream&) const { | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	template<Field field, int Width, Justification j, char Fill> | ||||
|  | 	void formatElement(FieldStr<field, Width, j, Fill> const& t, std::ostream& stream, EntryContext const& context, std::string const& msg) const { | ||||
|  | 		t.stream(stream, context, msg); | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	void formatElement(TimeStr const& t, std::ostream& stream, EntryContext const& context, std::string const& msg) const { | ||||
|  | 		t.stream(stream, context, msg); | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	template<typename T> | ||||
|  | 	void formatElement(T const& t, std::ostream& stream, EntryContext const&, std::string const&) const { | ||||
|  | 		stream << t; | ||||
|  | 	} | ||||
|  | public: | ||||
|  | 	TemplateFormatter(Formatters ... formatters) : | ||||
|  | 		formatters(std::forward<Formatters>(formatters)...) | ||||
|  | 	{ | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	std::string format(EntryContext const& context, std::string const& msg) const override; | ||||
|  | }; | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Helper function to create a TemplateFormatter. Simply call with some | ||||
|  |  * formatable arguments, e.g., | ||||
|  |  * @code{.cpp} | ||||
|  |  * logging::makeTemplateFormatter( | ||||
|  |  *     logging::FieldStr<logging::Field::LogLevel>(), " - ", | ||||
|  |  *     logging::FieldStr<logging::Field::Message>(), "\n"); | ||||
|  |  * @endcode | ||||
|  |  */ | ||||
|  | template<typename ... Formatters> | ||||
|  | FormatterPtr makeTemplateFormatter(Formatters&& ... formatters) { | ||||
|  | 	return std::make_shared<TemplateFormatter<Formatters...>>(std::forward<Formatters>(formatters)...); | ||||
|  | } | ||||
|  | 
 | ||||
|  | } | ||||
| @ -0,0 +1,106 @@ | |||||
|  | /** | ||||
|  |  * @file formatter.h | ||||
|  |  * @author Harold Bruintjes <h.bruintjes@cs.rwth-aachen.de> | ||||
|  |  * | ||||
|  |  * Implementation of Formatter classes | ||||
|  |  */ | ||||
|  | 
 | ||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | #include <chrono> | ||||
|  | #include <ctime> | ||||
|  | #include <iomanip> | ||||
|  | #include <sstream> | ||||
|  | #include <cstring> //strrchr | ||||
|  | 
 | ||||
|  | namespace l3pp { | ||||
|  | 
 | ||||
|  | namespace detail { | ||||
|  | 	/** | ||||
|  | 	 * Internal function to get wall-time | ||||
|  | 	 */ | ||||
|  | 	inline static std::chrono::system_clock::time_point GetStartTime() { | ||||
|  | 		static std::chrono::system_clock::time_point startTime = std::chrono::system_clock::now(); | ||||
|  | 		return startTime; | ||||
|  | 	} | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline void Formatter::initialize() { | ||||
|  | 	// Init wall-time | ||||
|  | 	detail::GetStartTime(); | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline std::string Formatter::format(EntryContext const& context, std::string const& msg) const { | ||||
|  | 	std::stringstream stream; | ||||
|  | 	stream << context.level << " - " << msg << '\n'; | ||||
|  | 	return stream.str(); | ||||
|  | } | ||||
|  | 
 | ||||
|  | template<Field field, int Width, Justification j, char Fill> | ||||
|  | inline void FieldStr<field, Width, j, Fill>::stream(std::ostream& os, EntryContext const& context, std::string const& msg) const { | ||||
|  | 	os << std::setw(Width); | ||||
|  | 	os << std::setfill(Fill); | ||||
|  | 	switch(j) { | ||||
|  | 		case Justification::LEFT: | ||||
|  | 			os << std::left; | ||||
|  | 		case Justification::RIGHT: | ||||
|  | 			os << std::right; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	switch(field) { | ||||
|  | 		case Field::FileName: | ||||
|  | #ifdef _WIN32 | ||||
|  | 			os << strrchr(context.filename, '\\')+1; | ||||
|  | #else | ||||
|  | 			os << strrchr(context.filename, '/')+1; | ||||
|  | #endif | ||||
|  | 			break; | ||||
|  | 		case Field::FilePath: | ||||
|  | 			os << context.filename; | ||||
|  | 			break; | ||||
|  | 		case Field::Line: | ||||
|  | 			os << context.line; | ||||
|  | 			break; | ||||
|  | 		case Field::Function: | ||||
|  | 			os << context.funcname; | ||||
|  | 			break; | ||||
|  | 		case Field::LoggerName: | ||||
|  | 			os << context.logger->getName(); | ||||
|  | 			break; | ||||
|  | 		case Field::Message: | ||||
|  | 			os << msg; | ||||
|  | 			break; | ||||
|  | 		case Field::LogLevel: | ||||
|  | 			os << context.level; | ||||
|  | 			break; | ||||
|  | 		case Field::WallTime: | ||||
|  | 			auto runtime = context.timestamp - detail::GetStartTime(); | ||||
|  | 			os << std::chrono::duration_cast<std::chrono::milliseconds>(runtime).count(); | ||||
|  | 			break; | ||||
|  | 	} | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline void TimeStr::stream(std::ostream& os, EntryContext const& context, std::string const&) const { | ||||
|  | 	auto time = std::chrono::system_clock::to_time_t(context.timestamp); | ||||
|  | 	auto timeinfo = localtime (&time); | ||||
|  | #if __GNUC__ >= 5 || __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 7) || _MSC_VER >= 1700 | ||||
|  | //TODO: Need better way to detect thing | ||||
|  | 	os << std::put_time(timeinfo, formatStr.c_str()); | ||||
|  | #else | ||||
|  | 	char buffer[1024]; | ||||
|  | 	if (strftime(buffer, 1024, formatStr.c_str(), timeinfo)) { | ||||
|  | 		os << buffer; | ||||
|  | 	} | ||||
|  | #endif | ||||
|  | } | ||||
|  | 
 | ||||
|  | template<typename ... Formatters> | ||||
|  | inline std::string TemplateFormatter<Formatters...>::format(EntryContext const& context, std::string const& msg) const { | ||||
|  | 	std::stringstream stream; | ||||
|  | 
 | ||||
|  | 	formatTuple<0>(context, msg, stream); | ||||
|  | 
 | ||||
|  | 	return stream.str(); | ||||
|  | } | ||||
|  | 
 | ||||
|  | } | ||||
| @ -0,0 +1,123 @@ | |||||
|  | /** | ||||
|  |  * @file logger.h | ||||
|  |  * | ||||
|  |  * Defines the base Logger class | ||||
|  |  */ | ||||
|  | 
 | ||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | #include <vector> | ||||
|  | #include <algorithm> | ||||
|  | #include <map> | ||||
|  | #include <sstream> | ||||
|  | 
 | ||||
|  | namespace l3pp { | ||||
|  | 
 | ||||
|  | namespace detail { | ||||
|  | 	/** | ||||
|  | 	 * Internal function to get all configured loggers. Should not be used | ||||
|  | 	 * directly, see Logger::getLogger() | ||||
|  | 	 */ | ||||
|  | 	static inline std::map<std::string, LogPtr>& GetLoggers() { | ||||
|  | 		static std::map<std::string, LogPtr> loggers; | ||||
|  | 		return loggers; | ||||
|  | 	} | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline LogStream::~LogStream() { | ||||
|  | 	if (level != LogLevel::OFF) { | ||||
|  | 		logger.log(level, stream.str(), context); | ||||
|  | 	} | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline void Logger::logEntry(EntryContext const& context, std::string const& msg) { | ||||
|  | 	for(auto& sink: sinks) { | ||||
|  | 		sink->log(context, msg); | ||||
|  | 	} | ||||
|  | 	if (additive && parent) { | ||||
|  | 		parent->logEntry(context, msg); | ||||
|  | 	} | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline void Logger::removeSink(SinkPtr sink) { | ||||
|  | 	std::vector<SinkPtr>::iterator pos = std::find(sinks.begin(), sinks.end(), sink); | ||||
|  | 	if (pos != sinks.end()) { | ||||
|  | 		sinks.erase(pos); | ||||
|  | 	} | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline void Logger::log(LogLevel level, std::string const& msg, EntryContext context) { | ||||
|  | 	if (level < getLevel()) { | ||||
|  | 		return; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	context.level = level; | ||||
|  | 	context.logger = this; | ||||
|  | 	logEntry(context, msg); | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline LogStream Logger::log(LogLevel level, EntryContext context) { | ||||
|  | 	if (level < getLevel()) { | ||||
|  | 		// Effectively disables the stream | ||||
|  | 		return LogStream(*this, LogLevel::OFF, context); | ||||
|  | 	} else { | ||||
|  | 		return LogStream(*this, level, context); | ||||
|  | 	} | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline void Logger::initialize() { | ||||
|  | 	// Setup root logger | ||||
|  | 	getRootLogger(); | ||||
|  | 	// Set wall time | ||||
|  | 	Formatter::initialize(); | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline void Logger::deinitialize() { | ||||
|  | 	detail::GetLoggers().clear(); | ||||
|  | 	getRootLogger()->sinks.clear(); | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline LogPtr Logger::getRootLogger() { | ||||
|  | 	static LogPtr rootLogger = LogPtr(new Logger()); | ||||
|  | 	return rootLogger; | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline LogPtr Logger::getLogger(std::string name) { | ||||
|  | 	if (name.size() == 0) { | ||||
|  | 		// Root logger | ||||
|  | 		return getRootLogger(); | ||||
|  | 	} | ||||
|  | 	auto& loggers = detail::GetLoggers(); | ||||
|  | 	auto it = loggers.find(name); | ||||
|  | 	if (it != loggers.end()) { | ||||
|  | 		return it->second; | ||||
|  | 	} else { | ||||
|  | 		auto n = name.rfind('.'); | ||||
|  | 		LogPtr parent; | ||||
|  | 		if (n == std::string::npos) { | ||||
|  | 			parent = getRootLogger(); | ||||
|  | 		} else{ | ||||
|  | 			parent = getLogger(name.substr(0, n)); | ||||
|  | 		} | ||||
|  | 		LogPtr newLogger = LogPtr(new Logger(name, parent)); | ||||
|  | 		loggers.emplace(name, newLogger); | ||||
|  | 		return newLogger; | ||||
|  | 	} | ||||
|  | } | ||||
|  | 
 | ||||
|  | template<typename T> | ||||
|  | inline LogStream const& operator<<(LogStream const& stream, T const& val) { | ||||
|  | 	if (stream.level != LogLevel::OFF) { | ||||
|  | 		stream.stream << val; | ||||
|  | 	} | ||||
|  | 	return stream; | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline LogStream const& operator<<(LogStream const& stream, std::ostream& (*F)(std::ostream&)) { | ||||
|  | 	if (stream.level != LogLevel::OFF) { | ||||
|  | 		stream.stream << F; | ||||
|  | 	} | ||||
|  | 	return stream; | ||||
|  | } | ||||
|  | 
 | ||||
|  | } | ||||
| @ -0,0 +1,32 @@ | |||||
|  | /** | ||||
|  |  * @file logging.h | ||||
|  |  * | ||||
|  |  * Implementation of general logging functionality | ||||
|  |  */ | ||||
|  | 
 | ||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | #include <ostream> | ||||
|  | 
 | ||||
|  | namespace l3pp { | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Streaming operator for LogLevel. | ||||
|  |  * @param os Output stream. | ||||
|  |  * @param level LogLevel. | ||||
|  |  * @return os. | ||||
|  |  */ | ||||
|  | inline std::ostream& operator<<(std::ostream& os, LogLevel level) { | ||||
|  | 	switch (level) { | ||||
|  | 		case LogLevel::TRACE:   return os << "TRACE"; | ||||
|  | 		case LogLevel::DEBUG:   return os << "DEBUG"; | ||||
|  | 		case LogLevel::INFO:    return os << "INFO"; | ||||
|  | 		case LogLevel::WARN:    return os << "WARN"; | ||||
|  | 		case LogLevel::ERR:     return os << "ERROR"; | ||||
|  | 		case LogLevel::FATAL:   return os << "FATAL"; | ||||
|  | 		case LogLevel::OFF:     return os << "OFF"; | ||||
|  | 		default:                return os << "???"; | ||||
|  | 	} | ||||
|  | } | ||||
|  | 
 | ||||
|  | } | ||||
| @ -0,0 +1,18 @@ | |||||
|  | /** | ||||
|  |  * @file sink.h | ||||
|  |  * | ||||
|  |  * Implementation for Sinks | ||||
|  |  */ | ||||
|  | 
 | ||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | namespace l3pp { | ||||
|  | 
 | ||||
|  | inline void Sink::log(EntryContext const& context, std::string const& message) const { | ||||
|  | 	if (context.level >= this->level) { | ||||
|  | 		logEntry((*formatter)(context, message)); | ||||
|  | 	} | ||||
|  | } | ||||
|  | 
 | ||||
|  | } | ||||
|  | 
 | ||||
| @ -0,0 +1,165 @@ | |||||
|  | /** | ||||
|  |  * @file l3pp.h | ||||
|  |  * @author Gereon Kremer <gereon.kremer@cs.rwth-aachen.de> | ||||
|  |  * @author Harold Bruintjes <h.bruintjes@cs.rwth-aachen.de> | ||||
|  |  * | ||||
|  |  * The lightweight logging library for C++. | ||||
|  |  * | ||||
|  |  * This logging facility is fairly generic and is used as a simple and | ||||
|  |  * header-only alternative to more advanced solutions like log4cplus or | ||||
|  |  * boost::log. | ||||
|  |  * | ||||
|  |  * The basic components are Sinks, Formatters and Loggers. | ||||
|  |  * | ||||
|  |  * A Sink represents a logging output like a terminal or a log file. | ||||
|  |  * This implementation provides a FileSink and a StreamSink, but the basic | ||||
|  |  * Sink class can be extended as necessary. | ||||
|  |  * | ||||
|  |  * A Formatter is associated with a Sink and produces the actual string that is | ||||
|  |  * sent to the Sink. | ||||
|  |  * Usually, it adds auxiliary information like the current time, LogLevel and | ||||
|  |  * source location to the string logged by the user. | ||||
|  |  * The Formatter implements a reasonable default behavior for simple logging, | ||||
|  |  * but it can be subclassed and modified as necessary. | ||||
|  |  * | ||||
|  |  * The Logger class finally plugs all these components together. | ||||
|  |  * Individual loggers can log to one or more sinks (inheritable) and are | ||||
|  |  * associated with an (inheritable) log level. | ||||
|  |  * | ||||
|  |  * Initial configuration may look like this: | ||||
|  |  * @code{.cpp} | ||||
|  |  * l3pp::Logger::initialize(); | ||||
|  |  * l3pp::SinkPtr sink = l3pp::StreamSink::create(std::clog); | ||||
|  |  * l3pp::Logger::getRootLogger()->addSink(sink); | ||||
|  |  * l3pp::Logger::getRootLogger()->setLevel(l3pp::LogLevel::INFO); | ||||
|  |  * @endcode | ||||
|  |  *  | ||||
|  |  * Macro facilitate the usage: | ||||
|  |  * <ul> | ||||
|  |  * <li>`L3PP_LOG_<LVL>(logger, msg)` produces a normal log message where | ||||
|  |  * logger should be string identifying the logger (or a LogPtr) and msg is the | ||||
|  |  * message to be logged.</li> | ||||
|  |  * </ul> | ||||
|  |  * Any message (`msg`) can be an arbitrary expression that one would | ||||
|  |  * stream to an `std::ostream` like `stream << (msg);`. The default formatter | ||||
|  |  * adds newlines. | ||||
|  |  * Manipulators are generally supported. However, for performance avoid std::endl | ||||
|  |  * and use '\n' directly. | ||||
|  |  */ | ||||
|  | 
 | ||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | #include <chrono> | ||||
|  | #include <memory> | ||||
|  | 
 | ||||
|  | namespace l3pp { | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Indicated which log messages should be forwarded to some sink. | ||||
|  |  *  | ||||
|  |  * All messages which have a level that is equal or greater than the specified | ||||
|  |  * value will be forwarded. | ||||
|  |  */ | ||||
|  | enum class LogLevel { | ||||
|  | 	/// Log messages used for tracing the program flow in detail. | ||||
|  | 	TRACE, | ||||
|  | 	/// Log messages used for debugging. | ||||
|  | 	DEBUG, | ||||
|  | 	/// Log messages used for information. | ||||
|  | 	INFO, | ||||
|  | 	/// Log messages used to warn about an undesired state. | ||||
|  | 	WARN, | ||||
|  | 	/// Log messages used for errors that can be handled. | ||||
|  | 	ERR, | ||||
|  | 	/// Log messages used for errors that lead to program termination. | ||||
|  | 	FATAL, | ||||
|  | 	/// Log no messages. | ||||
|  | 	OFF, | ||||
|  | 	/// Parent level | ||||
|  | 	INHERIT, | ||||
|  | 	/// Default log level. | ||||
|  | 	DEFAULT = WARN, | ||||
|  | 	/// All log messages. | ||||
|  | 	ALL = TRACE | ||||
|  | }; | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Streaming operator for LogLevel. | ||||
|  |  * @param os Output stream. | ||||
|  |  * @param level LogLevel. | ||||
|  |  * @return os. | ||||
|  |  */ | ||||
|  | inline std::ostream& operator<<(std::ostream& os, LogLevel level); | ||||
|  | 
 | ||||
|  | class Logger; | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Contextual information for a new log entry, contains such this as location, | ||||
|  |  * log info (level, logger) and the time of the event. | ||||
|  |  * A context will be created automatically by using the macros | ||||
|  |  */ | ||||
|  | struct EntryContext { | ||||
|  | 	// Program location | ||||
|  | 	const char* filename; | ||||
|  | 	size_t line; | ||||
|  | 	const char* funcname; | ||||
|  | 
 | ||||
|  | 	// Time of entry | ||||
|  | 	std::chrono::system_clock::time_point timestamp; | ||||
|  | 
 | ||||
|  | 	// Log event info | ||||
|  | 	Logger const* logger; | ||||
|  | 	LogLevel level; | ||||
|  | 
 | ||||
|  | 	EntryContext(const char* filename, size_t line, const char* funcname) : | ||||
|  | 		filename(filename), line(line), funcname(funcname), | ||||
|  | 		timestamp(std::chrono::system_clock::now()), logger(nullptr), | ||||
|  | 		level(LogLevel::OFF) | ||||
|  | 	{ | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	EntryContext() : | ||||
|  | 		filename(""), line(0), funcname(""), | ||||
|  | 		timestamp(std::chrono::system_clock::now()), logger(nullptr), | ||||
|  | 		level(LogLevel::OFF) | ||||
|  | 	{ | ||||
|  | 	} | ||||
|  | }; | ||||
|  | 
 | ||||
|  | } | ||||
|  | 
 | ||||
|  | #include "formatter.h" | ||||
|  | #include "sink.h" | ||||
|  | #include "logger.h" | ||||
|  | 
 | ||||
|  | #include "impl/logging.h" | ||||
|  | #include "impl/logger.h" | ||||
|  | #include "impl/formatter.h" | ||||
|  | #include "impl/sink.h" | ||||
|  | 
 | ||||
|  | #ifdef _MSC_VER | ||||
|  | #define __func__ __FUNCTION__ | ||||
|  | #endif | ||||
|  | 
 | ||||
|  | /// Create a record info. | ||||
|  | #define __L3PP_LOG_RECORD l3pp::EntryContext(__FILE__, __LINE__, __func__) | ||||
|  | /// Basic logging macro. | ||||
|  | #define __L3PP_LOG(level, channel, expr) do { \ | ||||
|  |     auto L3PP_channel = ::l3pp::Logger::getLogger(channel); \ | ||||
|  |     if (L3PP_channel->getLevel() <= level) { \ | ||||
|  |         L3PP_channel->log(level, __L3PP_LOG_RECORD) << expr; \ | ||||
|  |     } \ | ||||
|  | } while(false) | ||||
|  | 
 | ||||
|  | /// Log with level TRACE. | ||||
|  | #define L3PP_LOG_TRACE(channel, expr) __L3PP_LOG(::l3pp::LogLevel::TRACE, channel, expr) | ||||
|  | /// Log with level DEBUG. | ||||
|  | #define L3PP_LOG_DEBUG(channel, expr) __L3PP_LOG(::l3pp::LogLevel::DEBUG, channel, expr) | ||||
|  | /// Log with level INFO. | ||||
|  | #define L3PP_LOG_INFO(channel, expr) __L3PP_LOG(::l3pp::LogLevel::INFO, channel, expr) | ||||
|  | /// Log with level WARN. | ||||
|  | #define L3PP_LOG_WARN(channel, expr) __L3PP_LOG(::l3pp::LogLevel::WARN, channel, expr) | ||||
|  | /// Log with level ERROR. | ||||
|  | #define L3PP_LOG_ERROR(channel, expr) __L3PP_LOG(::l3pp::LogLevel::ERR, channel, expr) | ||||
|  | /// Log with level FATAL. | ||||
|  | #define L3PP_LOG_FATAL(channel, expr) __L3PP_LOG(::l3pp::LogLevel::FATAL, channel, expr) | ||||
| @ -0,0 +1,179 @@ | |||||
|  | /** | ||||
|  |  * @file logger.h | ||||
|  |  * | ||||
|  |  * Defines the base Logger class | ||||
|  |  */ | ||||
|  | 
 | ||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | #include <vector> | ||||
|  | #include <sstream> | ||||
|  | 
 | ||||
|  | namespace l3pp { | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * LogStream is a logger object that can be streamed into, writing an entry | ||||
|  |  * to the logger associated upon destruction. Instances of this classer are | ||||
|  |  * returned by Logger log() functions, so they can be used as such: | ||||
|  |  * logger->debug() << "Message"; | ||||
|  |  */ | ||||
|  | class LogStream { | ||||
|  | 	friend class Logger; | ||||
|  | 
 | ||||
|  | 	Logger& logger; | ||||
|  | 	LogLevel level; | ||||
|  | 	EntryContext context; | ||||
|  | 	mutable std::ostringstream stream; | ||||
|  | 
 | ||||
|  | 	LogStream(Logger& logger, LogLevel level, EntryContext context) : | ||||
|  | 		logger(logger), level(level), context(context) | ||||
|  | 	{ | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	LogStream(const LogStream&) = delete; | ||||
|  | 	LogStream& operator=(const LogStream&) = delete; | ||||
|  | public: | ||||
|  | 	LogStream(LogStream&& other) : | ||||
|  | 		logger(other.logger), level(other.level), context(std::move(other.context))/*, | ||||
|  | 		stream(std::move(other.stream))*/ | ||||
|  | 	{ | ||||
|  | 		stream.str(other.stream.str()); | ||||
|  | 	} | ||||
|  | 	~LogStream(); | ||||
|  | 
 | ||||
|  | 	template<typename T> | ||||
|  | 	friend LogStream const& operator<<(LogStream const& stream, T const& val); | ||||
|  | 	friend LogStream const& operator<<(LogStream const& stream, std::ostream& (*F)(std::ostream&)); | ||||
|  | }; | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Main logger class. Keeps track of all Logger instances, and can be used to | ||||
|  |  * log various messages. Before the logging library is used, make sure to | ||||
|  |  * call Logger::initialize(). Loggers are hierarchically nested, by means of | ||||
|  |  * names separated by a period. All loggers are a (indirect) child of the root | ||||
|  |  * logger, see Logger::getRootLogger() and Logger::getLogger(). | ||||
|  |  * A logger is associated with a LogLevel. Any entry with a level below this | ||||
|  |  * level will be filtered out. A LogLevel of INHERIT means the parent log | ||||
|  |  * level will be compared against instead. | ||||
|  |  * A logger can be associated with 1 or more Sinks. A log entry is printed to | ||||
|  |  * each associated sink. If the Logger is set additive (see getAdditive(), | ||||
|  |  * setAdditive()) parent sinks are logged to as well (by default true). | ||||
|  |  * Logging can be performed either as a single string message, or by using a | ||||
|  |  * stream. The latter requires the end() method to be called before the entry | ||||
|  |  * is logged. For convenience, various logging macros are defined at the end | ||||
|  |  * of this header. | ||||
|  |  */ | ||||
|  | class Logger { | ||||
|  | 	friend class Formatter; | ||||
|  | 
 | ||||
|  | 	typedef std::shared_ptr<Logger> LogPtr; | ||||
|  | 
 | ||||
|  | 	LogPtr parent; | ||||
|  | 	std::string name; | ||||
|  | 	LogLevel level; | ||||
|  | 	std::vector<SinkPtr> sinks; | ||||
|  | 	bool additive; | ||||
|  | 
 | ||||
|  | 	// Logger constructors are private | ||||
|  | 	Logger() : parent(nullptr), name(""), level(LogLevel::DEFAULT), | ||||
|  | 		additive(true) | ||||
|  | 	{ | ||||
|  | 
 | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	Logger(std::string const& name, LogPtr parent) : parent(parent), name(name), | ||||
|  | 		level(LogLevel::INHERIT), additive(true) | ||||
|  | 	{ | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	void logEntry(EntryContext const& context, std::string const& msg); | ||||
|  | 
 | ||||
|  | public: | ||||
|  | 	void addSink(SinkPtr sink) { | ||||
|  | 		sinks.push_back(sink); | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	void removeSink(SinkPtr sink); | ||||
|  | 
 | ||||
|  | 	void setLevel(LogLevel level) { | ||||
|  | 		if (level == LogLevel::INHERIT && !parent) { | ||||
|  | 			return; | ||||
|  | 		} | ||||
|  | 		this->level = level; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	LogLevel getLevel() const { | ||||
|  | 		if (level == LogLevel::INHERIT) { | ||||
|  | 			return parent->getLevel(); | ||||
|  | 		} | ||||
|  | 		return level; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	std::string const& getName() const { | ||||
|  | 		return name; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	bool getAdditive() const { | ||||
|  | 		return additive; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	void setAdditive(bool additive) { | ||||
|  | 		this->additive = additive; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	void log(LogLevel level, std::string const& msg, EntryContext context = EntryContext()); | ||||
|  | 
 | ||||
|  | 	void trace(std::string const& msg, EntryContext context = EntryContext()) { | ||||
|  | 		log(LogLevel::TRACE, msg, context); | ||||
|  | 	} | ||||
|  | 	void debug(std::string const& msg, EntryContext context = EntryContext()) { | ||||
|  | 		log(LogLevel::DEBUG, msg, context); | ||||
|  | 	} | ||||
|  | 	void info(std::string const& msg, EntryContext context = EntryContext()) { | ||||
|  | 		log(LogLevel::INFO, msg, context); | ||||
|  | 	} | ||||
|  | 	void warn(std::string const& msg, EntryContext context = EntryContext()) { | ||||
|  | 		log(LogLevel::WARN, msg, context); | ||||
|  | 	} | ||||
|  | 	void error(std::string const& msg, EntryContext context = EntryContext()) { | ||||
|  | 		log(LogLevel::ERR, msg, context); | ||||
|  | 	} | ||||
|  | 	void fatal(std::string const& msg, EntryContext context = EntryContext()) { | ||||
|  | 		log(LogLevel::FATAL, msg, context); | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	LogStream log(LogLevel level, EntryContext context = EntryContext()); | ||||
|  | 
 | ||||
|  | 	LogStream trace(EntryContext context = EntryContext()) { | ||||
|  | 		return log(LogLevel::TRACE, context); | ||||
|  | 	} | ||||
|  | 	LogStream debug(EntryContext context = EntryContext()) { | ||||
|  | 		return log(LogLevel::DEBUG, context); | ||||
|  | 	} | ||||
|  | 	LogStream info(EntryContext context = EntryContext()) { | ||||
|  | 		return log(LogLevel::INFO, context); | ||||
|  | 	} | ||||
|  | 	LogStream warn(EntryContext context = EntryContext()) { | ||||
|  | 		return log(LogLevel::WARN, context); | ||||
|  | 	} | ||||
|  | 	LogStream error(EntryContext context = EntryContext()) { | ||||
|  | 		return log(LogLevel::ERR, context); | ||||
|  | 	} | ||||
|  | 	LogStream fatal(EntryContext context = EntryContext()) { | ||||
|  | 		return log(LogLevel::FATAL, context); | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	static void initialize(); | ||||
|  | 	static void deinitialize(); | ||||
|  | 
 | ||||
|  | 	static LogPtr getRootLogger(); | ||||
|  | 
 | ||||
|  | 	static LogPtr getLogger(LogPtr logger) { | ||||
|  | 		return logger; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	static LogPtr getLogger(std::string name); | ||||
|  | }; | ||||
|  | typedef std::shared_ptr<Logger> LogPtr; | ||||
|  | 
 | ||||
|  | } | ||||
| @ -0,0 +1,108 @@ | |||||
|  | /** | ||||
|  |  * @file sink.h | ||||
|  |  * | ||||
|  |  * Defines classes for log sinks (i.e. outputs) | ||||
|  |  */ | ||||
|  | 
 | ||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | #include <ostream> | ||||
|  | #include <fstream> | ||||
|  | 
 | ||||
|  | namespace l3pp { | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Base class for a logging sink. It can only log some log entry to which some | ||||
|  |  * formatting is applied (see Formatter). A Sink may be given a log level, | ||||
|  |  * which filters out all entries below that level. By default is logs all | ||||
|  |  * entries. | ||||
|  |  */ | ||||
|  | class Sink { | ||||
|  | 	LogLevel level; | ||||
|  | 	FormatterPtr formatter; | ||||
|  | 
 | ||||
|  | 	virtual void logEntry(std::string const& entry) const = 0; | ||||
|  | public: | ||||
|  | 	Sink() : level(LogLevel::ALL), formatter(std::make_shared<Formatter>()) { | ||||
|  | 
 | ||||
|  | 	} | ||||
|  | 	Sink(FormatterPtr formatter) : level(LogLevel::ALL), formatter(formatter) { | ||||
|  | 
 | ||||
|  | 	} | ||||
|  | 	/** | ||||
|  | 	 * Default destructor. | ||||
|  |      */ | ||||
|  | 	virtual ~Sink() {} | ||||
|  | 
 | ||||
|  | 	LogLevel getLevel() const { | ||||
|  | 		return level; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	void setLevel(LogLevel level) { | ||||
|  | 		this->level = level; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	FormatterPtr getFormatter() const { | ||||
|  | 		return formatter; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	void setFormatter(FormatterPtr formatter) { | ||||
|  | 		this->formatter = formatter; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	/** | ||||
|  | 	 * Logs the given message with context info | ||||
|  | 	 */ | ||||
|  | 	void log(EntryContext const& context, std::string const& message) const; | ||||
|  | }; | ||||
|  | typedef std::shared_ptr<Sink> SinkPtr; | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Logging sink that wraps an arbitrary `std::ostream`. | ||||
|  |  * It is meant to be used for streams like `std::cout` or `std::cerr`. | ||||
|  |  */ | ||||
|  | class StreamSink: public Sink { | ||||
|  | 	/// Output stream. | ||||
|  | 	mutable std::ostream os; | ||||
|  | 
 | ||||
|  | 	void logEntry(std::string const& entry) const override { | ||||
|  | 		os << entry << std::flush; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	explicit StreamSink(std::ostream& _os) : | ||||
|  | 		os(_os.rdbuf()) {} | ||||
|  | public: | ||||
|  | 	/** | ||||
|  | 	 * Create a StreamSink from some output stream. | ||||
|  |      * @param os Output stream. | ||||
|  |      */ | ||||
|  | 	static SinkPtr create(std::ostream& os) { | ||||
|  | 		return SinkPtr(new StreamSink(os)); | ||||
|  | 	} | ||||
|  | }; | ||||
|  | /** | ||||
|  |  * Logging sink for file output. | ||||
|  |  */ | ||||
|  | class FileSink: public Sink { | ||||
|  | 	/// File output stream. | ||||
|  | 	mutable std::ofstream os; | ||||
|  | 
 | ||||
|  | 	void logEntry(std::string const& entry) const override { | ||||
|  | 		os << entry << std::flush; | ||||
|  | 	} | ||||
|  | 
 | ||||
|  | 	explicit FileSink(const std::string& filename) : | ||||
|  | 		os(filename, std::ios::out) {} | ||||
|  | public: | ||||
|  | 	/** | ||||
|  | 	 * Create a FileSink that logs to the specified file. | ||||
|  | 	 * The file is truncated upon construction. | ||||
|  |      * @param filename | ||||
|  |      */ | ||||
|  | 	static SinkPtr create(const std::string& filename) { | ||||
|  | 		return SinkPtr(new FileSink(filename)); | ||||
|  | 	} | ||||
|  | }; | ||||
|  | 
 | ||||
|  | } | ||||
|  | 
 | ||||
| @ -0,0 +1,23 @@ | |||||
|  | #ifndef STORM_UTILITY_LOGGING_H_ | ||||
|  | #define STORM_UTILITY_LOGGING_H_ | ||||
|  | 
 | ||||
|  | #include <l3pp.h> | ||||
|  | 
 | ||||
|  | #if !defined(STORM_LOG_DISABLE_DEBUG) && !defined(STORM_LOG_DISABLE_TRACE) | ||||
|  | #define STORM_LOG_TRACE(message) L3PP_LOG_TRACE(l3pp::Logger::getRootLogger(), message) | ||||
|  | #else | ||||
|  | #define STORM_LOG_TRACE(message) (void)(0) | ||||
|  | #endif | ||||
|  | 
 | ||||
|  | #if !defined(STORM_LOG_DISABLE_DEBUG) | ||||
|  | #define STORM_LOG_DEBUG(message) L3PP_LOG_DEBUG(l3pp::Logger::getRootLogger(), message) | ||||
|  | #else | ||||
|  | #define STORM_LOG_DEBUG(message) (void)(0) | ||||
|  | #endif | ||||
|  | 
 | ||||
|  | // Define STORM_LOG_WARN, STORM_LOG_ERROR and STORM_LOG_INFO to log the given message with the corresponding log levels. | ||||
|  | #define STORM_LOG_INFO(message) L3PP_LOG_INFO(l3pp::Logger::getRootLogger(), message) | ||||
|  | #define STORM_LOG_WARN(message) L3PP_LOG_WARN(l3pp::Logger::getRootLogger(), message) | ||||
|  | #define STORM_LOG_ERROR(message) L3PP_LOG_ERROR(l3pp::Logger::getRootLogger(), message) | ||||
|  | 
 | ||||
|  | #endif /* STORM_UTILITY_LOGGING_H_ */ | ||||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue