Moved color logging to separate library for reusing it in PDDL parser.

This commit is contained in:
2017-06-22 20:58:31 +02:00
parent 595891f040
commit e93085d88a
44 changed files with 330 additions and 294 deletions

View File

@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 2.6)
project(colorlog)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wpedantic -Werror ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "-g ${CMAKE_CXX_FLAGS_DEBUG}")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
if (CMAKE_GENERATOR STREQUAL "Ninja" AND
((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) OR
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)))
# Force colored warnings in Ninja's output, if the compiler has -fdiagnostics-color support.
# Rationale in https://github.com/ninja-build/ninja/issues/814
set(CMAKE_CXX_FLAGS "-fdiagnostics-color=always ${CMAKE_CXX_FLAGS}")
endif()
add_subdirectory(src)

View File

@@ -0,0 +1,291 @@
#ifndef __COLOR_LOG__COLOR_STREAM_H
#define __COLOR_LOG__COLOR_STREAM_H
#include <iostream>
#include <unistd.h>
namespace colorlog
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ColorStream
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class ColorStream
{
public:
enum class ColorPolicy
{
Never,
Auto,
Always
};
private:
using CharacterType = std::ostream::char_type;
using TraitsType = std::ostream::traits_type;
public:
ColorStream(std::ostream &stream)
: m_stream{stream},
m_colorPolicy{ColorPolicy::Auto}
{
}
void setColorPolicy(ColorPolicy colorPolicy)
{
m_colorPolicy = colorPolicy;
}
bool supportsColor() const
{
if (m_colorPolicy == ColorPolicy::Never)
return false;
if (m_colorPolicy == ColorPolicy::Always)
return true;
if (&m_stream == &std::cout)
return isatty(fileno(stdout));
if (&m_stream == &std::cerr)
return isatty(fileno(stderr));
return false;
}
std::ostream &stream()
{
return m_stream;
}
inline ColorStream &operator<<(short value);
inline ColorStream &operator<<(unsigned short value);
inline ColorStream &operator<<(int value);
inline ColorStream &operator<<(unsigned int value);
inline ColorStream &operator<<(long value);
inline ColorStream &operator<<(unsigned long value);
inline ColorStream &operator<<(long long value);
inline ColorStream &operator<<(unsigned long long value);
inline ColorStream &operator<<(float value);
inline ColorStream &operator<<(double value);
inline ColorStream &operator<<(long double value);
inline ColorStream &operator<<(bool value);
inline ColorStream &operator<<(const void *value);
inline ColorStream &operator<<(const char *value);
inline ColorStream &operator<<(const signed char *value);
inline ColorStream &operator<<(const unsigned char *value);
inline ColorStream &operator<<(std::basic_streambuf<CharacterType, TraitsType> *sb);
inline ColorStream &operator<<(std::ios_base &(*func)(std::ios_base &));
inline ColorStream &operator<<(std::basic_ios<CharacterType, TraitsType> &(*func)(std::basic_ios<CharacterType, TraitsType> &));
inline ColorStream &operator<<(std::basic_ostream<CharacterType, TraitsType> &(*func)(std::basic_ostream<CharacterType, TraitsType> &));
inline ColorStream &operator<<(char value);
inline ColorStream &operator<<(signed char value);
inline ColorStream &operator<<(unsigned char value);
private:
std::ostream &m_stream;
ColorPolicy m_colorPolicy;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(short value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(unsigned short value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(int value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(unsigned int value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(long value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(unsigned long value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(long long value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(unsigned long long value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(float value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(double value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(long double value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(bool value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(const void *value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(const char *value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(const signed char *value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(const unsigned char *value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(std::basic_streambuf<CharacterType, TraitsType>* sb)
{
m_stream << sb;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(std::ios_base &(*func)(std::ios_base &))
{
m_stream << func;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(std::basic_ios<CharacterType, TraitsType> &(*func)(std::basic_ios<CharacterType, TraitsType> &))
{
m_stream << func;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(std::basic_ostream<CharacterType, TraitsType> &(*func)(std::basic_ostream<CharacterType, TraitsType> &))
{
m_stream << func;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class CharacterType, class Traits, class Allocator>
inline ColorStream &operator<<(ColorStream &colorStream, const std::basic_string<CharacterType, Traits, Allocator> &string)
{
colorStream.stream() << string;
return colorStream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(char value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(signed char value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(unsigned char value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@@ -0,0 +1,310 @@
#ifndef __COLOR_LOG__FORMATTING_H
#define __COLOR_LOG__FORMATTING_H
#include <iostream>
#include <colorlog/ColorStream.h>
namespace colorlog
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Formatting
//
////////////////////////////////////////////////////////////////////////////////////////////////////
enum class Color
{
Default = 39,
Black = 30,
Red = 31,
Green = 32,
Yellow = 33,
Blue = 34,
Magenta = 35,
Cyan = 36,
LightGray = 37,
DarkGray = 90,
LightRed = 91,
LightGreen = 92,
LightYellow = 93,
LightBlue = 94,
LightMagenta = 95,
LightCyan = 96,
White = 97
};
////////////////////////////////////////////////////////////////////////////////////////////////////
enum class FontWeight
{
Normal = 21,
Bold = 1
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Format
{
Color color = Color::Default;
FontWeight fontWeight = FontWeight::Normal;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Format &format)
{
if (!stream.supportsColor())
return stream;
const auto fontWeightCode = static_cast<int>(format.fontWeight);
const auto colorCode = static_cast<int>(format.color);
return (stream << "\033[" << fontWeightCode << ";" << colorCode << "m");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct ResetFormat
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const ResetFormat &)
{
if (!stream.supportsColor())
return stream;
return (stream << "\033[0m");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Function
{
Function(const char *name)
: name{name}
{
};
const char *name;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Function &function)
{
return (stream
<< Format({Color::White, FontWeight::Normal})
<< function.name
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Keyword
{
Keyword(const char *name)
: name{name}
{
};
const char *name;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Keyword &keyword)
{
return (stream
<< Format({Color::Blue, FontWeight::Normal})
<< keyword.name
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Operator
{
Operator(const char *name)
: name{name}
{
};
const char *name;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Operator &operator_)
{
return (stream << operator_.name);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename T>
struct Number
{
Number(T value)
: value{value}
{
};
T value;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename T>
inline ColorStream &operator<<(ColorStream &stream, const Number<T> &number)
{
return (stream
<< Format({Color::Yellow, FontWeight::Normal})
<< number.value
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Variable
{
Variable(const char *name)
: name{name}
{
};
const char *name;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Variable &variable)
{
return (stream
<< Format({Color::Green, FontWeight::Bold})
<< variable.name
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct String
{
String(const char *content)
: content{content}
{
};
const char *content;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const String &string)
{
return (stream
<< Format({Color::Green, FontWeight::Normal})
<< "\"" << string.content << "\""
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Boolean
{
Boolean(const char *value)
: value{value}
{
};
const char *value;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Boolean &boolean)
{
return (stream
<< Format({Color::Red, FontWeight::Normal})
<< boolean.value
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Reserved
{
Reserved(const char *name)
: name{name}
{
};
const char *name;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Reserved &reserved)
{
return (stream
<< Format({Color::White, FontWeight::Normal})
<< reserved.name
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Heading1
{
Heading1(const char *content)
: content{content}
{
};
const char *content;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Heading1 &heading1)
{
return (stream
<< Format({Color::Blue, FontWeight::Bold})
<< "%---------------------------------------" << std::endl
<< "% " << heading1.content << std::endl
<< "%---------------------------------------"
<< ResetFormat()
<< std::endl);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Heading2
{
Heading2(const char *content)
: content{content}
{
};
const char *content;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Heading2 &heading2)
{
return (stream
<< Format({Color::Blue, FontWeight::Bold})
<< "% " << heading2.content
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@@ -0,0 +1,53 @@
#ifndef __COLOR_LOG__LOGGER_H
#define __COLOR_LOG__LOGGER_H
#include <string>
#include <colorlog/ColorStream.h>
#include <colorlog/Priority.h>
#include <tokenize/Location.h>
namespace colorlog
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Logger
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class Logger
{
public:
explicit Logger();
explicit Logger(ColorStream &&outputStream);
explicit Logger(ColorStream &&outputStream, ColorStream &&errorStream);
ColorStream &outputStream();
ColorStream &errorStream();
// The priority from which on messages should be printed
void setLogPriority(Priority logPriority);
// Messages with this priority (or higher) will terminate the programs execution
void setAbortPriority(Priority abortPriority);
void setColorPolicy(ColorStream::ColorPolicy colorPolicy);
void log(Priority priority, const char *message);
void log(Priority priority, const std::string &message);
void log(Priority priority, const tokenize::Location &location, const char *message);
void log(Priority priority, const tokenize::Location &location, const std::string &message);
private:
ColorStream m_outputStream;
ColorStream m_errorStream;
Priority m_logPriority;
Priority m_abortPriority;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@@ -0,0 +1,63 @@
#ifndef __COLOR_LOG__PRIORITY_H
#define __COLOR_LOG__PRIORITY_H
#include <cstring>
#include <exception>
namespace colorlog
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Priority
//
////////////////////////////////////////////////////////////////////////////////////////////////////
enum class Priority
{
Debug,
Info,
Warning,
Error
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline constexpr const char *priorityName(Priority priority)
{
switch (priority)
{
case Priority::Debug:
return "debug";
case Priority::Info:
return "info";
case Priority::Warning:
return "warning";
case Priority::Error:
return "error";
}
return "unknown";
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Priority priorityFromName(const char *priorityName)
{
if (std::strcmp(priorityName, "debug") == 0)
return Priority::Debug;
if (std::strcmp(priorityName, "info") == 0)
return Priority::Info;
if (std::strcmp(priorityName, "warning") == 0)
return Priority::Warning;
if (std::strcmp(priorityName, "error") == 0)
return Priority::Error;
throw std::runtime_error("unknown log priority");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@@ -0,0 +1,21 @@
set(target colorlog)
file(GLOB core_sources "colorlog/*.cpp")
file(GLOB core_headers "../include/colorlog/*.h")
set(includes
${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/../../lib/tokenize/include
)
set(sources
${core_sources}
${core_headers}
)
set(libraries
)
add_library(${target} ${sources})
target_include_directories(${target} PRIVATE ${includes})
target_link_libraries(${target} ${libraries})

View File

@@ -0,0 +1,165 @@
#include <colorlog/Logger.h>
#include <colorlog/Formatting.h>
namespace colorlog
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Logger
//
////////////////////////////////////////////////////////////////////////////////////////////////////
constexpr Format priorityFormat(Priority priority)
{
switch (priority)
{
case Priority::Debug:
return {Color::Green, FontWeight::Bold};
case Priority::Info:
return {Color::Blue, FontWeight::Bold};
case Priority::Warning:
return {Color::Magenta, FontWeight::Bold};
case Priority::Error:
return {Color::Red, FontWeight::Bold};
}
return {Color::White, FontWeight::Bold};
}
////////////////////////////////////////////////////////////////////////////////////////////////////
constexpr const Format MessageBodyFormat = {Color::White, FontWeight::Bold};
////////////////////////////////////////////////////////////////////////////////////////////////////
constexpr const Format LocationFormat = {Color::White, FontWeight::Bold};
////////////////////////////////////////////////////////////////////////////////////////////////////
Logger::Logger()
: Logger(std::cout, std::cerr)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Logger::Logger(ColorStream &&outputStream)
: Logger(std::forward<ColorStream &&>(outputStream), std::cerr)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Logger::Logger(ColorStream &&outputStream, ColorStream &&errorStream)
: m_outputStream{outputStream},
m_errorStream{errorStream},
m_logPriority{Priority::Info},
m_abortPriority{Priority::Error}
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &Logger::outputStream()
{
return m_outputStream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &Logger::errorStream()
{
return m_errorStream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::setLogPriority(Priority logPriority)
{
m_logPriority = logPriority;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::setAbortPriority(Priority abortPriority)
{
m_abortPriority = abortPriority;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::setColorPolicy(ColorStream::ColorPolicy colorPolicy)
{
m_outputStream.setColorPolicy(colorPolicy);
m_errorStream.setColorPolicy(colorPolicy);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::log(Priority priority, const char *message)
{
const auto priorityID = static_cast<int>(priority);
if (priorityID < static_cast<int>(m_logPriority) &&
priorityID < static_cast<int>(m_abortPriority))
{
return;
}
m_errorStream
<< priorityFormat(priority) << priorityName(priority) << ":"
<< ResetFormat() << " "
<< MessageBodyFormat << message
<< ResetFormat() << std::endl;
if (priority != Priority::Error && priorityID >= static_cast<int>(m_abortPriority))
throw std::runtime_error("received warning (treated as error by configuration)");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::log(Priority priority, const std::string &message)
{
log(priority, message.c_str());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::log(Priority priority, const tokenize::Location &location, const char *message)
{
const auto priorityID = static_cast<int>(priority);
// Always show messages that lead to program termination
if (priorityID < static_cast<int>(m_logPriority) &&
priorityID < static_cast<int>(m_abortPriority))
{
return;
}
m_errorStream
<< LocationFormat
<< location.sectionStart << ":" << location.rowStart << ":" << location.columnStart << ":"
<< ResetFormat() << " "
<< priorityFormat(priority) << priorityName(priority) << ":"
<< ResetFormat() << " "
<< MessageBodyFormat << message
<< ResetFormat() << std::endl;
// TODO: print original warning message
// TODO: refactor
if (priority != Priority::Error && priorityID >= static_cast<int>(m_abortPriority))
throw std::runtime_error("received warning (treated as error by configuration)");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::log(Priority priority, const tokenize::Location &location, const std::string &message)
{
log(priority, location, message.c_str());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}