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 "logging.h"
#include <boost/log/sinks/unlocked_frontend.hpp> #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/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 <centiseconds.h>
#include "tools.h" #include "tools.h"
@ -14,6 +20,9 @@ using std::tuple;
using std::make_tuple; using std::make_tuple;
namespace expr = boost::log::expressions; namespace expr = boost::log::expressions;
namespace keywords = boost::log::keywords;
namespace sinks = boost::log::sinks;
namespace attr = boost::log::attributes;
template <> template <>
const string& getEnumTypeName<LogLevel>() { const string& getEnumTypeName<LogLevel>() {
@ -75,7 +84,17 @@ void PausableBackendAdapter::resume() {
buffer.clear(); 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 // Create logging backend that logs to stderr
auto streamBackend = boost::make_shared<text_ostream_backend>(); auto streamBackend = boost::make_shared<text_ostream_backend>();
streamBackend->add_stream(boost::shared_ptr<std::ostream>(&std::cerr, [](std::ostream*) {})); 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 // Create a sink that feeds into the adapter
auto sink = boost::make_shared<unlocked_sink<PausableBackendAdapter>>(pausableAdapter); auto sink = boost::make_shared<unlocked_sink<PausableBackendAdapter>>(pausableAdapter);
sink->set_formatter(expr::stream << "[" << severity << "] " << expr::smessage);
// Set output formatting sink->set_filter(severity >= minLogLevel);
sink->set_formatter(expr::stream << "[" << expr::attr<LogLevel>("Severity") << "] " << expr::smessage);
boost::log::core::get()->add_sink(sink); boost::log::core::get()->add_sink(sink);
return pausableAdapter; 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) { void logTimedEvent(const string& eventName, centiseconds start, centiseconds end, const string& value) {
LOG_DEBUG << "##" << eventName << "[" << formatDuration(start) << "-" << formatDuration(end) << "]: " << value; LOG_DEBUG << "##" << eventName << "[" << formatDuration(start) << "-" << formatDuration(end) << "]: " << value;
} }

View File

@ -9,6 +9,7 @@
#include <mutex> #include <mutex>
#include <tuple> #include <tuple>
#include "centiseconds.h" #include "centiseconds.h"
#include <boost/filesystem.hpp>
#include "enumTools.h" #include "enumTools.h"
enum class LogLevel { enum class LogLevel {
@ -33,7 +34,7 @@ std::istream& operator>>(std::istream& stream, LogLevel& value);
using LoggerType = boost::log::sources::severity_logger_mt<LogLevel>; 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) \ #define LOG(level) \
BOOST_LOG_STREAM_WITH_PARAMS(globalLogger::get(), (::boost::log::keywords::severity = level)) BOOST_LOG_STREAM_WITH_PARAMS(globalLogger::get(), (::boost::log::keywords::severity = level))
@ -61,6 +62,8 @@ private:
bool isPaused = false; 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); 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::exception;
using std::string; using std::string;
using std::vector;
using std::unique_ptr; using std::unique_ptr;
using std::map; using std::map;
using std::chrono::duration; using std::chrono::duration;
@ -23,6 +24,8 @@ using std::chrono::duration_cast;
using boost::filesystem::path; using boost::filesystem::path;
using boost::property_tree::ptree; using boost::property_tree::ptree;
namespace tclap = TCLAP;
string getMessage(const exception& e) { string getMessage(const exception& e) {
string result(e.what()); string result(e.what());
try { try {
@ -69,36 +72,45 @@ ptree createXmlTree(const path& filePath, const map<centiseconds, Phone>& phones
return tree; return tree;
} }
// Tell TCLAP how to handle boost::optional // Tell TCLAP how to handle our types
namespace TCLAP { namespace TCLAP {
template<> template<>
struct ArgTraits<boost::optional<string>> { struct ArgTraits<LogLevel> {
typedef TCLAP::StringLike ValueCategory; typedef ValueLike ValueCategory;
}; };
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
auto logOutputController = initLogging(); auto pausableStderrSink = addPausableStderrSink(LogLevel::Warning);
logOutputController->pause(); pausableStderrSink->pause();
// Define command-line parameters // Define command-line parameters
const char argumentValueSeparator = ' '; const char argumentValueSeparator = ' ';
TCLAP::CmdLine cmd(appName, argumentValueSeparator, appVersion); tclap::CmdLine cmd(appName, argumentValueSeparator, appVersion);
cmd.setExceptionHandling(false); cmd.setExceptionHandling(false);
cmd.setOutput(new NiceCmdLineOutput()); cmd.setOutput(new NiceCmdLineOutput());
TCLAP::UnlabeledValueArg<string> inputFileName("inputFile", "The input file. Must be a sound file in WAVE format.", true, "", "string", cmd); auto logLevels = vector<LogLevel>(getEnumValues<LogLevel>());
TCLAP::ValueArg<boost::optional<string>> dialog("d", "dialog", "The text of the dialog.", false, boost::optional<string>(), "string", cmd); 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 { try {
auto resumeLogging = gsl::finally([&]() { auto resumeLogging = gsl::finally([&]() {
std::cerr << std::endl << std::endl; std::cerr << std::endl << std::endl;
logOutputController->resume(); pausableStderrSink->resume();
std::cerr << std::endl; std::cerr << std::endl;
}); });
// Parse command line // Parse command line
cmd.parse(argc, argv); cmd.parse(argc, argv);
// Set up log file
if (logFileName.isSet()) {
addFileSink(path(logFileName.getValue()), logLevel.getValue());
}
// Detect phones // Detect phones
const int columnWidth = 30; const int columnWidth = 30;
std::cerr << std::left; std::cerr << std::left;
@ -108,7 +120,7 @@ int main(int argc, char *argv[]) {
ProgressBar progressBar; ProgressBar progressBar;
phones = detectPhones( phones = detectPhones(
createAudioStream(inputFileName.getValue()), createAudioStream(inputFileName.getValue()),
dialog.getValue(), dialog.isSet() ? dialog.getValue() : boost::optional<string>(),
progressBar); progressBar);
} }
std::cerr << "Done" << std::endl; 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)); boost::property_tree::write_xml(std::cout, xmlTree, boost::property_tree::xml_writer_settings<string>(' ', 2));
return 0; return 0;
} catch (TCLAP::ArgException& e) { } catch (tclap::ArgException& e) {
// Error parsing command-line args. // Error parsing command-line args.
cmd.getOutput()->failure(cmd, e); cmd.getOutput()->failure(cmd, e);
std::cerr << std::endl; std::cerr << std::endl;
return 1; return 1;
} catch (TCLAP::ExitException&) { } catch (tclap::ExitException&) {
// A built-in TCLAP command (like --help) has finished. Exit application. // A built-in TCLAP command (like --help) has finished. Exit application.
std::cerr << std::endl; std::cerr << std::endl;
return 0; return 0;