|
|
/**
* @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)...); }
}
|