Prepared for logging using Boost.Log v2

This commit is contained in:
Daniel Wolf 2016-02-29 21:00:38 +01:00
parent 7a1f446ca3
commit 7efea6f56b
4 changed files with 144 additions and 3 deletions

View File

@ -28,13 +28,16 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
add_compile_options(/MT$<$<CONFIG:Debug>:d>)
endif()
# Define flags variables for later use
# Set global flags and define flags variables for later use
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(enableWarningsFlags "-Wall;-Wextra")
set(disableWarningsFlags "-w")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(enableWarningsFlags "/W4")
set(disableWarningsFlags "/W0")
# Boost.Log causes this warning
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4714")
endif()
# Enable project folders
@ -46,7 +49,7 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(Boost_USE_STATIC_LIBS ON) # Use static libs
set(Boost_USE_MULTITHREADED ON) # Enable multithreading support
set(Boost_USE_STATIC_RUNTIME ON) # Use static C++ runtime
find_package(Boost REQUIRED COMPONENTS filesystem locale system)
find_package(Boost REQUIRED COMPONENTS filesystem locale system log date_time thread chrono)
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
# ... C++ Format
@ -105,6 +108,7 @@ set(SOURCE_FILES
src/NiceCmdLineOutput.cpp
src/TablePrinter.cpp
src/ProgressBar.cpp
src/logging.cpp
)
add_executable(rhubarb ${SOURCE_FILES})
target_link_libraries(rhubarb ${Boost_LIBRARIES} cppFormat sphinxbase pocketSphinx)

66
src/logging.cpp Normal file
View File

@ -0,0 +1,66 @@
#include "logging.h"
#include <array>
#include <boost/log/sinks/unlocked_frontend.hpp>
#include <boost/log/expressions.hpp>
using std::string;
using std::lock_guard;
using boost::log::sinks::text_ostream_backend;
using boost::log::record_view;
using boost::log::sinks::unlocked_sink;
namespace expr = boost::log::expressions;
string toString(LogLevel level) {
constexpr size_t levelCount = static_cast<size_t>(LogLevel::EndSentinel);
static const std::array<const string, levelCount> strings = {
"Trace", "Debug", "Info", "Warning", "Error", "Fatal"
};
return strings.at(static_cast<size_t>(level));
}
PausableBackendAdapter::PausableBackendAdapter(boost::shared_ptr<text_ostream_backend> backend) :
backend(backend) {}
void PausableBackendAdapter::consume(const record_view& recordView, const string message) {
lock_guard<std::mutex> lock(mutex);
if (isPaused) {
buffer.push_back(std::make_tuple(recordView, message));
} else {
backend->consume(recordView, message);
}
}
void PausableBackendAdapter::pause() {
lock_guard<std::mutex> lock(mutex);
isPaused = true;
}
void PausableBackendAdapter::resume() {
lock_guard<std::mutex> lock(mutex);
isPaused = false;
for (const auto& tuple : buffer) {
backend->consume(std::get<record_view>(tuple), std::get<string>(tuple));
}
buffer.clear();
}
boost::shared_ptr<PausableBackendAdapter> initLogging() {
// Create logging backend that logs to stderr
auto streamBackend = boost::make_shared<text_ostream_backend>();
streamBackend->add_stream(boost::shared_ptr<std::ostream>(&std::cerr, [](std::ostream*) {}));
streamBackend->auto_flush(true);
// Create an adapter that allows us to pause, buffer, and resume log output
auto pausableAdapter = boost::make_shared<PausableBackendAdapter>(streamBackend);
// Create a sink that feeds into the adapter
auto sink = boost::make_shared<unlocked_sink<PausableBackendAdapter>>(pausableAdapter);
// Set output formatting
sink->set_formatter(expr::stream << "[" << expr::attr<LogLevel>("Severity") << "] " << expr::smessage);
boost::log::core::get()->add_sink(sink);
return pausableAdapter;
}

58
src/logging.h Normal file
View File

@ -0,0 +1,58 @@
#pragma once
#include <boost/log/common.hpp>
#include <boost/log/sinks/basic_sink_backend.hpp>
#include <boost/log/sinks/frontend_requirements.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <string>
#include <vector>
#include <mutex>
#include <tuple>
enum class LogLevel {
Trace,
Debug,
Info,
Warning,
Error,
Fatal,
EndSentinel
};
std::string toString(LogLevel level);
template<typename CharT, typename TraitsT>
std::basic_ostream<CharT, TraitsT>& operator<< (std::basic_ostream<CharT, TraitsT>& stream, LogLevel level) {
return stream << toString(level);
}
using LoggerType = boost::log::sources::severity_logger_mt<LogLevel>;
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(globalLogger, LoggerType)
#define LOG(level) \
BOOST_LOG_STREAM_WITH_PARAMS(globalLogger::get(), (::boost::log::keywords::severity = level))
#define LOG_TRACE LOG(LogLevel::Trace)
#define LOG_DEBUG LOG(LogLevel::Debug)
#define LOG_INFO LOG(LogLevel::Info)
#define LOG_WARNING LOG(LogLevel::Warning)
#define LOG_ERROR LOG(LogLevel::Error)
#define LOG_FATAL LOG(LogLevel::Fatal)
class PausableBackendAdapter :
public boost::log::sinks::basic_formatted_sink_backend<char, boost::log::sinks::concurrent_feeding>
{
public:
PausableBackendAdapter(boost::shared_ptr<boost::log::sinks::text_ostream_backend> backend);
void consume(const boost::log::record_view& recordView, const std::string message);
void pause();
void resume();
private:
boost::shared_ptr<boost::log::sinks::text_ostream_backend> backend;
std::vector<std::tuple<boost::log::record_view, std::string>> buffer;
std::mutex mutex;
bool isPaused = false;
};
boost::shared_ptr<PausableBackendAdapter> initLogging();

View File

@ -10,6 +10,8 @@
#include "appInfo.h"
#include "NiceCmdLineOutput.h"
#include "ProgressBar.h"
#include "logging.h"
#include <gsl_util.h>
using std::exception;
using std::string;
@ -79,6 +81,9 @@ namespace TCLAP {
}
int main(int argc, char *argv[]) {
auto logOutputController = initLogging();
logOutputController->pause();
// Define command-line parameters
const char argumentValueSeparator = ' ';
TCLAP::CmdLine cmd(appName, argumentValueSeparator, appVersion);
@ -88,6 +93,12 @@ int main(int argc, char *argv[]) {
TCLAP::ValueArg<boost::optional<string>> dialog("d", "dialog", "The text of the dialog.", false, boost::optional<string>(), "string", cmd);
try {
auto resumeLogging = gsl::finally([&]() {
std::cerr << std::endl << std::endl;
logOutputController->resume();
std::cerr << std::endl;
});
// Parse command line
cmd.parse(argc, argv);
@ -120,13 +131,15 @@ int main(int argc, char *argv[]) {
} catch (TCLAP::ArgException& e) {
// Error parsing command-line args.
cmd.getOutput()->failure(cmd, e);
std::cerr << std::endl;
return 1;
} catch (TCLAP::ExitException&) {
// A built-in TCLAP command (like --help) has finished. Exit application.
std::cerr << std::endl;
return 0;
} catch (const exception& e) {
// Generic error
std::cerr << "An error occurred. " << getMessage(e);
std::cerr << "An error occurred. " << getMessage(e) << std::endl;
return 1;
}
}