You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
4.5 KiB
158 lines
4.5 KiB
/**
|
|
* @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)...);
|
|
}
|
|
|
|
}
|