Implemented logging to log file

This commit is contained in:
Daniel Wolf 2016-03-08 22:59:44 +01:00
parent 35ec1f8a45
commit af5a6649c1
3 changed files with 63 additions and 19 deletions

View File

@ -1,6 +1,12 @@
#include "logging.h"
#include <boost/log/sinks/unlocked_frontend.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/keywords/file_name.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
// ReSharper disable once CppUnusedIncludeDirective
#include <boost/log/support/date_time.hpp>
#include <centiseconds.h>
#include "tools.h"
@ -14,6 +20,9 @@ using std::tuple;
using std::make_tuple;
namespace expr = boost::log::expressions;
namespace keywords = boost::log::keywords;
namespace sinks = boost::log::sinks;
namespace attr = boost::log::attributes;
template <>
const string& getEnumTypeName<LogLevel>() {
@ -75,7 +84,17 @@ void PausableBackendAdapter::resume() {
buffer.clear();
}
boost::shared_ptr<PausableBackendAdapter> initLogging() {
BOOST_LOG_GLOBAL_LOGGER_INIT(globalLogger, LoggerType) {
LoggerType logger;
logger.add_attribute("TimeStamp", attr::local_clock());
return logger;
}
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", LogLevel)
boost::shared_ptr<PausableBackendAdapter> addPausableStderrSink(LogLevel minLogLevel) {
// 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*) {}));
@ -86,14 +105,24 @@ boost::shared_ptr<PausableBackendAdapter> initLogging() {
// 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);
sink->set_formatter(expr::stream << "[" << severity << "] " << expr::smessage);
sink->set_filter(severity >= minLogLevel);
boost::log::core::get()->add_sink(sink);
return pausableAdapter;
}
void addFileSink(const boost::filesystem::path& logFilePath, LogLevel minLogLevel) {
auto textFileBackend = boost::make_shared<sinks::text_file_backend>(
keywords::file_name = logFilePath.string());
auto sink = boost::make_shared<sinks::synchronous_sink<sinks::text_file_backend>>(textFileBackend);
sink->set_formatter(expr::stream
<< "[" << expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d %H:%M:%S")
<< "] [" << severity << "] " << expr::smessage);
sink->set_filter(severity >= minLogLevel);
boost::log::core::get()->add_sink(sink);
}
void logTimedEvent(const string& eventName, centiseconds start, centiseconds end, const string& value) {
LOG_DEBUG << "##" << eventName << "[" << formatDuration(start) << "-" << formatDuration(end) << "]: " << value;
}

View File

@ -9,6 +9,7 @@
#include <mutex>
#include <tuple>
#include "centiseconds.h"
#include <boost/filesystem.hpp>
#include "enumTools.h"
enum class LogLevel {
@ -33,7 +34,7 @@ std::istream& operator>>(std::istream& stream, LogLevel& value);
using LoggerType = boost::log::sources::severity_logger_mt<LogLevel>;
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(globalLogger, LoggerType)
BOOST_LOG_GLOBAL_LOGGER(globalLogger, LoggerType)
#define LOG(level) \
BOOST_LOG_STREAM_WITH_PARAMS(globalLogger::get(), (::boost::log::keywords::severity = level))
@ -61,6 +62,8 @@ private:
bool isPaused = false;
};
boost::shared_ptr<PausableBackendAdapter> initLogging();
boost::shared_ptr<PausableBackendAdapter> addPausableStderrSink(LogLevel minLogLevel);
void addFileSink(const boost::filesystem::path& logFilePath, LogLevel minLogLevel);
void logTimedEvent(const std::string& eventName, centiseconds start, centiseconds end, const std::string& value);

View File

@ -16,6 +16,7 @@
using std::exception;
using std::string;
using std::vector;
using std::unique_ptr;
using std::map;
using std::chrono::duration;
@ -23,6 +24,8 @@ using std::chrono::duration_cast;
using boost::filesystem::path;
using boost::property_tree::ptree;
namespace tclap = TCLAP;
string getMessage(const exception& e) {
string result(e.what());
try {
@ -69,36 +72,45 @@ ptree createXmlTree(const path& filePath, const map<centiseconds, Phone>& phones
return tree;
}
// Tell TCLAP how to handle boost::optional
// Tell TCLAP how to handle our types
namespace TCLAP {
template<>
struct ArgTraits<boost::optional<string>> {
typedef TCLAP::StringLike ValueCategory;
struct ArgTraits<LogLevel> {
typedef ValueLike ValueCategory;
};
}
int main(int argc, char *argv[]) {
auto logOutputController = initLogging();
logOutputController->pause();
auto pausableStderrSink = addPausableStderrSink(LogLevel::Warning);
pausableStderrSink->pause();
// Define command-line parameters
const char argumentValueSeparator = ' ';
TCLAP::CmdLine cmd(appName, argumentValueSeparator, appVersion);
tclap::CmdLine cmd(appName, argumentValueSeparator, appVersion);
cmd.setExceptionHandling(false);
cmd.setOutput(new NiceCmdLineOutput());
TCLAP::UnlabeledValueArg<string> inputFileName("inputFile", "The input file. Must be a sound file in WAVE format.", true, "", "string", cmd);
TCLAP::ValueArg<boost::optional<string>> dialog("d", "dialog", "The text of the dialog.", false, boost::optional<string>(), "string", cmd);
auto logLevels = vector<LogLevel>(getEnumValues<LogLevel>());
tclap::ValuesConstraint<LogLevel> logLevelConstraint(logLevels);
tclap::ValueArg<LogLevel> logLevel("", "logLevel", "The minimum log level to log", false, LogLevel::Debug, &logLevelConstraint, cmd);
tclap::ValueArg<string> logFileName("", "logFile", "The log file path.", false, string(), "string", cmd);
tclap::ValueArg<string> dialog("d", "dialog", "The text of the dialog.", false, string(), "string", cmd);
tclap::UnlabeledValueArg<string> inputFileName("inputFile", "The input file. Must be a sound file in WAVE format.", true, "", "string", cmd);
try {
auto resumeLogging = gsl::finally([&]() {
std::cerr << std::endl << std::endl;
logOutputController->resume();
pausableStderrSink->resume();
std::cerr << std::endl;
});
// Parse command line
cmd.parse(argc, argv);
// Set up log file
if (logFileName.isSet()) {
addFileSink(path(logFileName.getValue()), logLevel.getValue());
}
// Detect phones
const int columnWidth = 30;
std::cerr << std::left;
@ -108,7 +120,7 @@ int main(int argc, char *argv[]) {
ProgressBar progressBar;
phones = detectPhones(
createAudioStream(inputFileName.getValue()),
dialog.getValue(),
dialog.isSet() ? dialog.getValue() : boost::optional<string>(),
progressBar);
}
std::cerr << "Done" << std::endl;
@ -125,12 +137,12 @@ int main(int argc, char *argv[]) {
boost::property_tree::write_xml(std::cout, xmlTree, boost::property_tree::xml_writer_settings<string>(' ', 2));
return 0;
} catch (TCLAP::ArgException& e) {
} catch (tclap::ArgException& e) {
// Error parsing command-line args.
cmd.getOutput()->failure(cmd, e);
std::cerr << std::endl;
return 1;
} catch (TCLAP::ExitException&) {
} catch (tclap::ExitException&) {
// A built-in TCLAP command (like --help) has finished. Exit application.
std::cerr << std::endl;
return 0;