From 0ccb9b046eeab990623d6d583bef4567514daad6 Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Thu, 22 Nov 2018 19:44:03 -0600 Subject: [PATCH 1/7] starting to enhance Slic3r::Log; adding tests. --- src/CMakeLists.txt | 18 ++--- src/test/libslic3r/test_log.cpp | 119 ++++++++++++++++++++++++++++++++ xs/src/libslic3r/Log.cpp | 76 ++++++++++++++++++++ xs/src/libslic3r/Log.hpp | 69 ++++++++++++++++-- 4 files changed, 269 insertions(+), 13 deletions(-) create mode 100644 src/test/libslic3r/test_log.cpp create mode 100644 xs/src/libslic3r/Log.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 464253b97..0adf596f3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -198,6 +198,7 @@ add_library(libslic3r STATIC ${LIBDIR}/libslic3r/LayerRegionFill.cpp ${LIBDIR}/libslic3r/LayerHeightSpline.cpp ${LIBDIR}/libslic3r/Line.cpp + ${LIBDIR}/libslic3r/Log.cpp ${LIBDIR}/libslic3r/Model.cpp ${LIBDIR}/libslic3r/MotionPlanner.cpp ${LIBDIR}/libslic3r/MultiPoint.cpp @@ -284,18 +285,19 @@ set(UI_TEST_SOURCES set(SLIC3R_TEST_SOURCES ${TESTDIR}/test_harness.cpp ${TESTDIR}/test_data.cpp - ${TESTDIR}/libslic3r/test_trianglemesh.cpp ${TESTDIR}/libslic3r/test_config.cpp - ${TESTDIR}/libslic3r/test_support_material.cpp ${TESTDIR}/libslic3r/test_fill.cpp ${TESTDIR}/libslic3r/test_flow.cpp - ${TESTDIR}/libslic3r/test_model.cpp - ${TESTDIR}/libslic3r/test_printgcode.cpp - ${TESTDIR}/libslic3r/test_print.cpp - ${TESTDIR}/libslic3r/test_skirt_brim.cpp - ${TESTDIR}/libslic3r/test_test_data.cpp - ${TESTDIR}/libslic3r/test_geometry.cpp ${TESTDIR}/libslic3r/test_gcodewriter.cpp + ${TESTDIR}/libslic3r/test_geometry.cpp + ${TESTDIR}/libslic3r/test_log.cpp + ${TESTDIR}/libslic3r/test_model.cpp + ${TESTDIR}/libslic3r/test_print.cpp + ${TESTDIR}/libslic3r/test_printgcode.cpp + ${TESTDIR}/libslic3r/test_skirt_brim.cpp + ${TESTDIR}/libslic3r/test_support_material.cpp + ${TESTDIR}/libslic3r/test_test_data.cpp + ${TESTDIR}/libslic3r/test_trianglemesh.cpp ) diff --git a/src/test/libslic3r/test_log.cpp b/src/test/libslic3r/test_log.cpp new file mode 100644 index 000000000..83764059e --- /dev/null +++ b/src/test/libslic3r/test_log.cpp @@ -0,0 +1,119 @@ +#include +#include +#include "Log.hpp" + +using namespace std::literals::string_literals; +using namespace Slic3r; + +SCENARIO( "_Log output with std::string methods" ) { + GIVEN("A log stream and a _Log object") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic", "This"); + THEN("Output string is Topic FERR: This\\n") { + REQUIRE(log.str() == "Topic FERR: This\n"); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic", "This"); + THEN("Output string is Topic ERR: This\\n") { + REQUIRE(log.str() == "Topic ERR: This\n"); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is Topic INFO: This\\n") { + REQUIRE(log.str() == "Topic INFO: This\n"); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic", "This"); + THEN("Output string is Topic WARN: This\\n") { + REQUIRE(log.str() == "Topic WARN: This\n"); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is Topic INFO: This\\n") { + REQUIRE(log.str() == "Topic INFO: This\n"); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic", "This"); + THEN("Output string is Topic DEBUG: This\\n") { + REQUIRE(log.str() == "Topic DEBUG: This\n"); + } + } + WHEN("msg is called with text \"This\"") { + log.clear(); + cut->raw("This"); + THEN("Output string is This\\n") { + REQUIRE(log.str() == "This\n"); + } + } + } +} +SCENARIO( "_Log output with << methods" ) { + GIVEN("A log stream and a _Log object") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic") << "This"; + THEN("Output string is Topic FERR: This") { + REQUIRE(log.str() == "Topic FERR: This"); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic") << "This"; + THEN("Output string is Topic ERR: This") { + REQUIRE(log.str() == "Topic ERR: This"); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic") << "This"; + THEN("Output string is Topic INFO: This") { + REQUIRE(log.str() == "Topic INFO: This"); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic") << "This"; + THEN("Output string is Topic WARN: This") { + REQUIRE(log.str() == "Topic WARN: This"); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic") << "This"; + THEN("Output string is Topic INFO: This") { + REQUIRE(log.str() == "Topic INFO: This"); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic") << "This"; + THEN("Output string is Topic DEBUG: This") { + REQUIRE(log.str() == "Topic DEBUG: This"); + } + } + WHEN("msg is called with text \"This\"") { + log.clear(); + cut->raw() << "This"; + THEN("Output string is This") { + REQUIRE(log.str() == "This"); + } + } + + } +} + diff --git a/xs/src/libslic3r/Log.cpp b/xs/src/libslic3r/Log.cpp new file mode 100644 index 000000000..f9d763447 --- /dev/null +++ b/xs/src/libslic3r/Log.cpp @@ -0,0 +1,76 @@ +#include "Log.hpp" +#include +#include +#include +#include + +namespace Slic3r { + +std::unique_ptr<_Log> slic3r_log {_Log::make_log()}; + +_Log::_Log() : _out(std::clog), _wout(std::wclog) { +} + +_Log::_Log(std::ostream& out) : _out(out), _wout(std::wclog) { +} +_Log::_Log(std::wostream& out) : _out(std::clog), _wout(out) { +} + +void _Log::fatal_error(const std::string& topic, const std::wstring& message) { +// _wout << this->converter.from_bytes(topic); + _wout << std::setw(6) << "FERR" << ": "; + _wout << message << std::endl; +} +void _Log::fatal_error(const std::string& topic, const std::string& message) { + this->fatal_error(topic) << message << std::endl; +} +std::ostream& _Log::fatal_error(const std::string& topic) { + _out << topic << std::setfill(' ') << std::setw(6) << "FERR" << ": "; + return _out; +} + +void _Log::error(const std::string& topic, const std::string& message) { + this->error(topic) << message << std::endl; +} +std::ostream& _Log::error(const std::string& topic) { + _out << topic << std::setfill(' ') << std::setw(6) << "ERR" << ": "; + return _out; +} + +void _Log::info(const std::string& topic, const std::string& message) { + this->info(topic) << message << std::endl; +} + +std::ostream& _Log::info(const std::string& topic) { + _out << topic << std::setfill(' ') << std::setw(6) << "INFO" << ": "; + return _out; +} + +void _Log::warn(const std::string& topic, const std::string& message) { + this->warn(topic) << message << std::endl; +} + +std::ostream& _Log::warn(const std::string& topic) { + _out << topic << std::setfill(' ') << std::setw(6) << "WARN" << ": "; + return _out; +} + +void _Log::debug(const std::string& topic, const std::string& message) { + this->debug(topic) << message << std::endl; +} + +std::ostream& _Log::debug(const std::string& topic) { + _out << topic << std::setfill(' ') << std::setw(6) << "DEBUG" << ": "; + return _out; +} + +void _Log::raw(const std::string& message) { + this->raw() << message << std::endl; +} +std::ostream& _Log::raw() { + return _out; +} + + + +} // Slic3r diff --git a/xs/src/libslic3r/Log.hpp b/xs/src/libslic3r/Log.hpp index 4246d84a8..bf9ab5128 100644 --- a/xs/src/libslic3r/Log.hpp +++ b/xs/src/libslic3r/Log.hpp @@ -5,14 +5,68 @@ #include #include #include +#include +#include +#include // good until c++17 namespace Slic3r { +/// Singleton instance implementing logging functionality in Slic3r +/// Basic functionality is stubbed in currently, may pass through to Boost::Log +/// eventually. +class _Log { +public: + static std::unique_ptr<_Log> make_log() { + std::unique_ptr<_Log> tmp {new _Log()}; + return tmp; + } + static std::unique_ptr<_Log> make_log(std::ostream& out) { + std::unique_ptr<_Log> tmp {new _Log(out)}; + return tmp; + } + static std::unique_ptr<_Log> make_log(std::wostream& out) { + std::unique_ptr<_Log> tmp {new _Log(out)}; + return tmp; + } + void fatal_error(const std::string& topic, const std::wstring& message); + void fatal_error(const std::string& topic, const std::string& message); + std::ostream& fatal_error(const std::string& topic); + + void error(const std::string& topic, const std::wstring& message); + void error(const std::string& topic, const std::string& message); + std::ostream& error(const std::string& topic); + + void info(const std::string& topic, const std::string& message); + std::ostream& info(const std::string& topic); + void debug(const std::string& topic, const std::string& message); + std::ostream& debug(const std::string& topic); + void warn(const std::string& topic, const std::string& message); + std::ostream& warn(const std::string& topic); + void raw(const std::string& message); + std::ostream& raw(); + +// _Log(_Log const&) = delete; +// void operator=(_Log const&) = delete; +private: + std::ostream& _out; + std::wostream& _wout; + _Log(); + _Log(std::ostream& out); + _Log(std::wostream& out); + + std::wstring_convert> converter; + +}; + +/// Global log reference; initialized in Log.cpp +extern std::unique_ptr<_Log> slic3r_log; + +/// Static class for referencing the various logging functions. Refers to +/// class Log { public: static void fatal_error(std::string topic, std::wstring message) { - std::cerr << topic << " FERR" << ": "; - std::wcerr << message << std::endl; + slic3r_log->fatal_error(topic, message); } static void error(std::string topic, std::wstring message) { std::cerr << topic << " ERR" << ": "; @@ -67,13 +121,18 @@ public: std::cerr << topic << " INFO" << ": "; return std::cerr; } + + /// Unadorned ostream output for multiline constructions. + static std::ostream& raw() { + return std::cerr; + } }; -/// Utility debug function to transform a std::vector of anything that +/// Utility debug function to transform a std::vector of anything that /// supports ostream& operator<<() into a std::string. template -std::string -log_string(const std::vector& in) +std::string +log_string(const std::vector& in) { std::stringstream ss; bool first {true}; From 86c776287e4e93f3bc52bae7abe9aacb3a2c2e22 Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Thu, 22 Nov 2018 22:53:11 -0600 Subject: [PATCH 2/7] Implemented debug level filtering. --- src/test/libslic3r/test_log.cpp | 471 ++++++++++++++++++++++++++++++++ xs/src/libslic3r/Log.cpp | 87 +++++- xs/src/libslic3r/Log.hpp | 23 ++ 3 files changed, 568 insertions(+), 13 deletions(-) diff --git a/src/test/libslic3r/test_log.cpp b/src/test/libslic3r/test_log.cpp index 83764059e..33d250331 100644 --- a/src/test/libslic3r/test_log.cpp +++ b/src/test/libslic3r/test_log.cpp @@ -9,6 +9,8 @@ SCENARIO( "_Log output with std::string methods" ) { GIVEN("A log stream and a _Log object") { std::stringstream log; std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_level(log_t::DEBUG); + cut->set_inclusive(true); WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { log.clear(); cut->fatal_error("Topic", "This"); @@ -64,6 +66,8 @@ SCENARIO( "_Log output with << methods" ) { GIVEN("A log stream and a _Log object") { std::stringstream log; std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_level(log_t::DEBUG); + cut->set_inclusive(true); WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { log.clear(); cut->fatal_error("Topic") << "This"; @@ -117,3 +121,470 @@ SCENARIO( "_Log output with << methods" ) { } } +SCENARIO( "_Log output inclusive filtering with std::string methods" ) { + GIVEN("Single, inclusive log level of FERR (highest)") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->clear_level(log_t::FERR); + cut->set_inclusive(true); + cut->set_level(log_t::FERR); + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic", "This"); + THEN("Output string is Topic FERR: This\\n") { + REQUIRE(log.str() == "Topic FERR: This\n"); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + } + GIVEN("Single, inclusive log level of ERR (second-highest)") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_inclusive(true); + cut->set_level(log_t::ERR); + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic", "This"); + THEN("Output string is Topic FERR: This\\n") { + REQUIRE(log.str() == "Topic FERR: This\n"); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic", "This"); + THEN("Output string is Topic ERR: This\\n") { + REQUIRE(log.str() == "Topic ERR: This\n"); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + } + GIVEN("Single, inclusive log level of WARN (third-highest)") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_inclusive(true); + cut->set_level(log_t::WARN); + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic", "This"); + THEN("Output string is Topic FERR: This\\n") { + REQUIRE(log.str() == "Topic FERR: This\n"); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic", "This"); + THEN("Output string is Topic ERR: This\\n") { + REQUIRE(log.str() == "Topic ERR: This\n"); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic", "This"); + THEN("Output string is Topic WARN: This\\n") { + REQUIRE(log.str() == "Topic WARN: This\n"); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + } + GIVEN("Single, inclusive log level of INFO (fourth-highest)") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_inclusive(true); + cut->set_level(log_t::INFO); + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic", "This"); + THEN("Output string is Topic FERR: This\\n") { + REQUIRE(log.str() == "Topic FERR: This\n"); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic", "This"); + THEN("Output string is Topic ERR: This\\n") { + REQUIRE(log.str() == "Topic ERR: This\n"); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic", "This"); + THEN("Output string is Topic WARN: This\\n") { + REQUIRE(log.str() == "Topic WARN: This\n"); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is Topic INFO: This\\n") { + REQUIRE(log.str() == "Topic INFO: This\n"); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + } + GIVEN("Single, inclusive log level of DEBUG (fifth-highest)") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_inclusive(true); + cut->set_level(log_t::DEBUG); + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic", "This"); + THEN("Output string is Topic FERR: This\\n") { + REQUIRE(log.str() == "Topic FERR: This\n"); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic", "This"); + THEN("Output string is Topic ERR: This\\n") { + REQUIRE(log.str() == "Topic ERR: This\n"); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic", "This"); + THEN("Output string is Topic WARN: This\\n") { + REQUIRE(log.str() == "Topic WARN: This\n"); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is Topic INFO: This\\n") { + REQUIRE(log.str() == "Topic INFO: This\n"); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic", "This"); + THEN("Output string is Topic DEBUG: This\\n") { + REQUIRE(log.str() == "Topic DEBUG: This\n"); + } + } + } +} + +SCENARIO( "_Log output set filtering with std::string methods" ) { + + GIVEN("log level of DEBUG only") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_inclusive(false); + cut->clear_level(log_t::ALL); + cut->set_level(log_t::DEBUG); + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic", "This"); + THEN("Output string is Topic DEBUG: This\\n") { + REQUIRE(log.str() == "Topic DEBUG: This\n"); + } + } + } + GIVEN("log level of INFO only") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_inclusive(false); + cut->clear_level(log_t::ALL); + cut->set_level(log_t::INFO); + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is Topic INFO: This\\n") { + REQUIRE(log.str() == "Topic INFO: This\n"); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + } + GIVEN("log level of WARN only") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_inclusive(false); + cut->clear_level(log_t::ALL); + cut->set_level(log_t::WARN); + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic", "This"); + THEN("Output string is Topic WARN: This\\n") { + REQUIRE(log.str() == "Topic WARN: This\n"); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + } + GIVEN("log level of FERR only") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_inclusive(false); + cut->clear_level(log_t::ALL); + cut->set_level(log_t::FERR); + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic", "This"); + THEN("Output string is Topic FERR: This\\n") { + REQUIRE(log.str() == "Topic FERR: This\n"); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + } + GIVEN("log level of DEBUG and ERR") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_inclusive(false); + cut->clear_level(log_t::ALL); + cut->set_level(log_t::DEBUG); + cut->set_level(log_t::ERR); + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic", "This"); + THEN("Output string is Topic ERR: This\\n") { + REQUIRE(log.str() == "Topic ERR: This\n"); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic", "This"); + THEN("Output string is Topic DEBUG: This\\n") { + REQUIRE(log.str() == "Topic DEBUG: This\n"); + } + } + } + GIVEN("log level of INFO and WARN") { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_inclusive(false); + cut->clear_level(log_t::ALL); + cut->set_level(log_t::INFO); + cut->set_level(log_t::WARN); + cut->set_inclusive(false); + WHEN("fatal_error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->fatal_error("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("error is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->error("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + WHEN("warn is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->warn("Topic", "This"); + THEN("Output string is Topic WARN: This\\n") { + REQUIRE(log.str() == "Topic WARN: This\n"); + } + } + WHEN("info is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->info("Topic", "This"); + THEN("Output string is Topic INFO: This\\n") { + REQUIRE(log.str() == "Topic INFO: This\n"); + } + } + WHEN("debug is called with topic \"Topic\" and text \"This\"") { + log.clear(); + cut->debug("Topic", "This"); + THEN("Output string is blank") { + REQUIRE(log.str() == ""); + } + } + } +} diff --git a/xs/src/libslic3r/Log.cpp b/xs/src/libslic3r/Log.cpp index f9d763447..07ccf4f7a 100644 --- a/xs/src/libslic3r/Log.cpp +++ b/xs/src/libslic3r/Log.cpp @@ -1,11 +1,22 @@ -#include "Log.hpp" #include #include #include #include +#include "Log.hpp" + +/// Local class to suppress output +class NullStream : public std::streambuf +{ +public: + int overflow(int c) { return c; } +}; + namespace Slic3r { +static NullStream log_null; +static std::ostream null_log(&log_null); + std::unique_ptr<_Log> slic3r_log {_Log::make_log()}; _Log::_Log() : _out(std::clog), _wout(std::wclog) { @@ -13,28 +24,46 @@ _Log::_Log() : _out(std::clog), _wout(std::wclog) { _Log::_Log(std::ostream& out) : _out(out), _wout(std::wclog) { } + _Log::_Log(std::wostream& out) : _out(std::clog), _wout(out) { } +bool _Log::_has_log_level(log_t lvl) { + if (!this->_inclusive_levels && this->_log_level.find(lvl) != this->_log_level.end()) { + return true; + } else if (this->_inclusive_levels && *(std::max_element(this->_log_level.cbegin(), this->_log_level.cend())) >= lvl) { + return true; + } + return false; +} + void _Log::fatal_error(const std::string& topic, const std::wstring& message) { // _wout << this->converter.from_bytes(topic); - _wout << std::setw(6) << "FERR" << ": "; - _wout << message << std::endl; + if (this->_has_log_level(log_t::FERR)) { + _wout << std::setw(6) << "FERR" << ": "; + _wout << message << std::endl; + } } void _Log::fatal_error(const std::string& topic, const std::string& message) { this->fatal_error(topic) << message << std::endl; } std::ostream& _Log::fatal_error(const std::string& topic) { - _out << topic << std::setfill(' ') << std::setw(6) << "FERR" << ": "; - return _out; + if (this->_has_log_level(log_t::FERR)) { + _out << topic << std::setfill(' ') << std::setw(6) << "FERR" << ": "; + return _out; + } + return null_log; } void _Log::error(const std::string& topic, const std::string& message) { this->error(topic) << message << std::endl; } std::ostream& _Log::error(const std::string& topic) { - _out << topic << std::setfill(' ') << std::setw(6) << "ERR" << ": "; - return _out; + if (this->_has_log_level(log_t::ERR)) { + _out << topic << std::setfill(' ') << std::setw(6) << "ERR" << ": "; + return _out; + } + return null_log; } void _Log::info(const std::string& topic, const std::string& message) { @@ -42,8 +71,11 @@ void _Log::info(const std::string& topic, const std::string& message) { } std::ostream& _Log::info(const std::string& topic) { - _out << topic << std::setfill(' ') << std::setw(6) << "INFO" << ": "; - return _out; + if (this->_has_log_level(log_t::INFO)) { + _out << topic << std::setfill(' ') << std::setw(6) << "INFO" << ": "; + return _out; + } + return null_log; } void _Log::warn(const std::string& topic, const std::string& message) { @@ -51,8 +83,11 @@ void _Log::warn(const std::string& topic, const std::string& message) { } std::ostream& _Log::warn(const std::string& topic) { - _out << topic << std::setfill(' ') << std::setw(6) << "WARN" << ": "; - return _out; + if (this->_has_log_level(log_t::WARN)) { + _out << topic << std::setfill(' ') << std::setw(6) << "WARN" << ": "; + return _out; + } + return null_log; } void _Log::debug(const std::string& topic, const std::string& message) { @@ -60,17 +95,43 @@ void _Log::debug(const std::string& topic, const std::string& message) { } std::ostream& _Log::debug(const std::string& topic) { - _out << topic << std::setfill(' ') << std::setw(6) << "DEBUG" << ": "; - return _out; + if (this->_has_log_level(log_t::DEBUG)) { + _out << topic << std::setfill(' ') << std::setw(6) << "DEBUG" << ": "; + return _out; + } + return null_log; } void _Log::raw(const std::string& message) { this->raw() << message << std::endl; } + std::ostream& _Log::raw() { return _out; } +void _Log::set_level(log_t level) { + if (this->_inclusive_levels) { + this->_log_level.clear(); + this->_log_level.insert(level); + } else if (level == log_t::ALL) { + this->_log_level.insert(log_t::FERR); + this->_log_level.insert(log_t::ERR); + this->_log_level.insert(log_t::WARN); + this->_log_level.insert(log_t::INFO); + this->_log_level.insert(log_t::DEBUG); + } else { + this->_log_level.insert(level); + } +} +void _Log::clear_level(log_t level) { + if (level == log_t::ALL) { + this->_log_level.clear(); + } else { + if (this->_log_level.find(level) != this->_log_level.end()) + this->_log_level.erase(level); + } +} } // Slic3r diff --git a/xs/src/libslic3r/Log.hpp b/xs/src/libslic3r/Log.hpp index bf9ab5128..78e470b3c 100644 --- a/xs/src/libslic3r/Log.hpp +++ b/xs/src/libslic3r/Log.hpp @@ -7,10 +7,20 @@ #include #include #include +#include #include // good until c++17 + namespace Slic3r { +/// All available logging levels. +enum class log_t : uint8_t { FERR = 0, ERR = 4, WARN = 8, INFO = 16, DEBUG = 32, ALL = 255 }; + +inline bool operator>(const log_t lhs, const log_t rhs) { return static_cast(lhs) > static_cast(rhs); } +inline bool operator<(const log_t lhs, const log_t rhs) { return static_cast(lhs) < static_cast(rhs); } +inline bool operator>=(const log_t lhs, const log_t rhs) { return static_cast(lhs) > static_cast(rhs) || lhs == rhs; } +inline bool operator<=(const log_t lhs, const log_t rhs) { return static_cast(lhs) < static_cast(rhs) || lhs == rhs; } + /// Singleton instance implementing logging functionality in Slic3r /// Basic functionality is stubbed in currently, may pass through to Boost::Log /// eventually. @@ -45,6 +55,15 @@ public: void raw(const std::string& message); std::ostream& raw(); + template + void debug_svg(const std::string& topic, const T& path, bool append = true); + template + void debug_svg(const std::string& topic, const T* path, bool append = true); + + void set_level(log_t level); + void clear_level(log_t level); + void set_inclusive(bool v) { this->_inclusive_levels = v; } + // _Log(_Log const&) = delete; // void operator=(_Log const&) = delete; private: @@ -53,9 +72,13 @@ private: _Log(); _Log(std::ostream& out); _Log(std::wostream& out); + bool _inclusive_levels { true }; + std::set _log_level { }; std::wstring_convert> converter; + bool _has_log_level(log_t lvl); + }; /// Global log reference; initialized in Log.cpp From bd9b9cc416efc8f2c230717848b7d9e518c50699 Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Thu, 22 Nov 2018 23:03:10 -0600 Subject: [PATCH 3/7] refactor to only use log() and use locale converter to figure out the rest. --- xs/src/libslic3r/Log.cpp | 21 +++++++++------------ xs/src/libslic3r/Log.hpp | 14 ++++++-------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/xs/src/libslic3r/Log.cpp b/xs/src/libslic3r/Log.cpp index 07ccf4f7a..f2548efd9 100644 --- a/xs/src/libslic3r/Log.cpp +++ b/xs/src/libslic3r/Log.cpp @@ -19,13 +19,10 @@ static std::ostream null_log(&log_null); std::unique_ptr<_Log> slic3r_log {_Log::make_log()}; -_Log::_Log() : _out(std::clog), _wout(std::wclog) { +_Log::_Log() : _out(std::clog) { } -_Log::_Log(std::ostream& out) : _out(out), _wout(std::wclog) { -} - -_Log::_Log(std::wostream& out) : _out(std::clog), _wout(out) { +_Log::_Log(std::ostream& out) : _out(out) { } bool _Log::_has_log_level(log_t lvl) { @@ -37,13 +34,12 @@ bool _Log::_has_log_level(log_t lvl) { return false; } -void _Log::fatal_error(const std::string& topic, const std::wstring& message) { -// _wout << this->converter.from_bytes(topic); - if (this->_has_log_level(log_t::FERR)) { - _wout << std::setw(6) << "FERR" << ": "; - _wout << message << std::endl; - } -} +void _Log::fatal_error(const std::string& topic, const std::wstring& message) { this->fatal_error(topic, this->converter.to_bytes(message)); } +void _Log::error(const std::string& topic, const std::wstring& message) { this->error(topic, this->converter.to_bytes(message)); } +void _Log::warn(const std::string& topic, const std::wstring& message) { this->warn(topic, this->converter.to_bytes(message)); } +void _Log::info(const std::string& topic, const std::wstring& message) { this->info(topic, this->converter.to_bytes(message)); } +void _Log::debug(const std::string& topic, const std::wstring& message) { this->debug(topic, this->converter.to_bytes(message)); } + void _Log::fatal_error(const std::string& topic, const std::string& message) { this->fatal_error(topic) << message << std::endl; } @@ -105,6 +101,7 @@ std::ostream& _Log::debug(const std::string& topic) { void _Log::raw(const std::string& message) { this->raw() << message << std::endl; } +void _Log::raw(const std::wstring& message) { this->raw(this->converter.to_bytes(message)); } std::ostream& _Log::raw() { return _out; diff --git a/xs/src/libslic3r/Log.hpp b/xs/src/libslic3r/Log.hpp index 78e470b3c..2617c692e 100644 --- a/xs/src/libslic3r/Log.hpp +++ b/xs/src/libslic3r/Log.hpp @@ -34,25 +34,25 @@ public: std::unique_ptr<_Log> tmp {new _Log(out)}; return tmp; } - static std::unique_ptr<_Log> make_log(std::wostream& out) { - std::unique_ptr<_Log> tmp {new _Log(out)}; - return tmp; - } - void fatal_error(const std::string& topic, const std::wstring& message); void fatal_error(const std::string& topic, const std::string& message); + void fatal_error(const std::string& topic, const std::wstring& message); std::ostream& fatal_error(const std::string& topic); - void error(const std::string& topic, const std::wstring& message); void error(const std::string& topic, const std::string& message); + void error(const std::string& topic, const std::wstring& message); std::ostream& error(const std::string& topic); void info(const std::string& topic, const std::string& message); + void info(const std::string& topic, const std::wstring& message); std::ostream& info(const std::string& topic); void debug(const std::string& topic, const std::string& message); + void debug(const std::string& topic, const std::wstring& message); std::ostream& debug(const std::string& topic); void warn(const std::string& topic, const std::string& message); + void warn(const std::string& topic, const std::wstring& message); std::ostream& warn(const std::string& topic); void raw(const std::string& message); + void raw(const std::wstring& message); std::ostream& raw(); template @@ -68,10 +68,8 @@ public: // void operator=(_Log const&) = delete; private: std::ostream& _out; - std::wostream& _wout; _Log(); _Log(std::ostream& out); - _Log(std::wostream& out); bool _inclusive_levels { true }; std::set _log_level { }; From b538f33459090fb515a78e6d962301b6f761df4e Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Thu, 22 Nov 2018 23:03:58 -0600 Subject: [PATCH 4/7] Call through to underlying method for static Log methods --- xs/src/libslic3r/Log.hpp | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/xs/src/libslic3r/Log.hpp b/xs/src/libslic3r/Log.hpp index 2617c692e..36964cea8 100644 --- a/xs/src/libslic3r/Log.hpp +++ b/xs/src/libslic3r/Log.hpp @@ -90,62 +90,50 @@ public: slic3r_log->fatal_error(topic, message); } static void error(std::string topic, std::wstring message) { - std::cerr << topic << " ERR" << ": "; - std::wcerr << message << std::endl; + slic3r_log->error(topic, message); } static void error(std::string topic, std::string message) { - std::cerr << topic << " ERR" << ": "; - std::cerr << message << std::endl; + slic3r_log->error(topic, message); } static void info(std::string topic, std::wstring message) { - std::clog << topic << " INFO" << ": "; - std::wclog << message << std::endl; + slic3r_log->info(topic, message); } static void info(std::string topic, std::string message) { - std::clog << topic << " INFO" << ": "; - std::clog << message << std::endl; + slic3r_log->info(topic, message); } static void warn(std::string topic, std::wstring message) { - std::cerr << topic << " WARN" << ": "; - std::wcerr << message << std::endl; + slic3r_log->warn(topic, message); } static void warn(std::string topic, std::string message) { - std::cerr << topic << " WARN" << ": "; - std::cerr << message << std::endl; + slic3r_log->warn(topic, message); } static void debug(std::string topic, std::wstring message) { - std::cerr << topic << " DEBUG" << ": "; - std::wcerr << message << std::endl; + slic3r_log->debug(topic, message); } static void debug(std::string topic, std::string message) { - std::cerr << topic << " DEBUG" << ": "; - std::cerr << message << std::endl; + slic3r_log->debug(topic, message); } static std::ostream& error(std::string topic) { - std::cerr << topic << " ERR" << ": "; - return std::cerr; + return slic3r_log->error(topic); } static std::ostream& debug(std::string topic) { - std::cerr << topic << " DEBUG" << ": "; - return std::cerr; + return slic3r_log->debug(topic); } static std::ostream& warn(std::string topic) { - std::cerr << topic << " WARN" << ": "; - return std::cerr; + return slic3r_log->warn(topic); } static std::ostream& info(std::string topic) { - std::cerr << topic << " INFO" << ": "; - return std::cerr; + return slic3r_log->info(topic); } /// Unadorned ostream output for multiline constructions. static std::ostream& raw() { - return std::cerr; + return slic3r_log->raw(); } }; From 4a39f30ab5135b44733a928601373a5399be76f0 Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Thu, 22 Nov 2018 23:10:20 -0600 Subject: [PATCH 5/7] Add doxygen comments --- xs/src/libslic3r/Log.hpp | 48 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/xs/src/libslic3r/Log.hpp b/xs/src/libslic3r/Log.hpp index 36964cea8..0f0040c5a 100644 --- a/xs/src/libslic3r/Log.hpp +++ b/xs/src/libslic3r/Log.hpp @@ -86,47 +86,95 @@ extern std::unique_ptr<_Log> slic3r_log; /// class Log { public: + + /// Logs a fatal error with Slic3r. + /// \param topic [in] file or heading for error + /// \param message [in] text of the logged error message static void fatal_error(std::string topic, std::wstring message) { slic3r_log->fatal_error(topic, message); } + + /// Logs a regular error with Slic3r. + /// \param topic [in] file or heading for error + /// \param message [in] text of the logged error message static void error(std::string topic, std::wstring message) { slic3r_log->error(topic, message); } + /// Logs a fatal error with Slic3r. + /// \param topic [in] file or heading for error + /// \param message [in] text of the logged error message static void error(std::string topic, std::string message) { slic3r_log->error(topic, message); } + /// Logs an informational message with Slic3r. + /// \param topic [in] file or heading for message + /// \param message [in] text of the logged message static void info(std::string topic, std::wstring message) { slic3r_log->info(topic, message); } + /// Logs an informational message with Slic3r. + /// \param topic [in] file or heading for message + /// \param message [in] text of the logged message static void info(std::string topic, std::string message) { slic3r_log->info(topic, message); } + /// Logs a warning message with Slic3r. + /// \param topic [in] file or heading for message + /// \param message [in] text of the logged message static void warn(std::string topic, std::wstring message) { slic3r_log->warn(topic, message); } + + /// Logs a warning message with Slic3r. + /// \param topic [in] file or heading for message + /// \param message [in] text of the logged message static void warn(std::string topic, std::string message) { slic3r_log->warn(topic, message); } + /// Logs a debugging message with Slic3r. + /// \param topic [in] file or heading for message + /// \param message [in] text of the logged message static void debug(std::string topic, std::wstring message) { slic3r_log->debug(topic, message); } + /// Logs a debugging message with Slic3r. + /// \param topic [in] file or heading for message + /// \param message [in] text of the logged message static void debug(std::string topic, std::string message) { slic3r_log->debug(topic, message); } + + + /// Logs an error message with Slic3r. + /// \param topic [in] file or heading for message + /// \return reference to output ostream for << chaining. + /// \note Developer is expected to add newlines. static std::ostream& error(std::string topic) { return slic3r_log->error(topic); } + /// Logs a debugging message with Slic3r. + /// \param topic [in] file or heading for message + /// \return reference to output ostream for << chaining. + /// \note Developer is expected to add newlines. static std::ostream& debug(std::string topic) { return slic3r_log->debug(topic); } + /// Logs a warning message with Slic3r. + /// \param topic [in] file or heading for message + /// \return reference to output ostream for << chaining. + /// \note Developer is expected to add newlines. static std::ostream& warn(std::string topic) { return slic3r_log->warn(topic); } + /// Logs an informational message with Slic3r. + /// \param topic [in] file or heading for message + /// \return reference to output ostream for << chaining. + /// \note Developer is expected to add newlines. static std::ostream& info(std::string topic) { return slic3r_log->info(topic); } From 37f4497450f7fe9beed653cec1788b4202542044 Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Thu, 22 Nov 2018 23:30:22 -0600 Subject: [PATCH 6/7] Allow for filtering additionally on topic name. --- src/test/libslic3r/test_log.cpp | 47 +++++++++++++++++++++++++++++++++ xs/src/libslic3r/Log.cpp | 22 +++++++++++---- xs/src/libslic3r/Log.hpp | 18 +++++++++++++ 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/src/test/libslic3r/test_log.cpp b/src/test/libslic3r/test_log.cpp index 33d250331..bfe26eb36 100644 --- a/src/test/libslic3r/test_log.cpp +++ b/src/test/libslic3r/test_log.cpp @@ -588,3 +588,50 @@ SCENARIO( "_Log output set filtering with std::string methods" ) { } } } + +SCENARIO( "_Log output filtering on topic name" ) { + std::stringstream log; + std::unique_ptr<_Log> cut { _Log::make_log(log) }; + cut->set_inclusive(true); + cut->set_level(log_t::ALL); + WHEN("Topic is \"t1\"") { + cut->add_topic("t1"); + cut->debug("t1") << "TEXT FOR T1 "; + cut->debug("t2") << "TEXT FOR T2 "; + cut->debug("t3") << "TEXT FOR T3"; + THEN("Log text is \"TEXT FOR T1 \"") { + REQUIRE(log.str() == "t1 DEBUG: TEXT FOR T1 "); + } + } + + WHEN("Topic is \"t2\"") { + cut->add_topic("t2"); + cut->debug("t1") << "TEXT FOR T1 "; + cut->debug("t2") << "TEXT FOR T2 "; + cut->debug("t3") << "TEXT FOR T3"; + THEN("Log text is \"TEXT FOR T2 \"") { + REQUIRE(log.str() == "t2 DEBUG: TEXT FOR T2 "); + } + } + + WHEN("Topic is \"t3\"") { + cut->add_topic("t3"); + cut->debug("t1") << "TEXT FOR T1 "; + cut->debug("t2") << "TEXT FOR T2 "; + cut->debug("t3") << "TEXT FOR T3"; + THEN("Log text is \"TEXT FOR T3\"") { + REQUIRE(log.str() == "t3 DEBUG: TEXT FOR T3"); + } + } + + WHEN("Topic is \"t3\" and \"t2\"") { + cut->add_topic("t2"); + cut->add_topic("t3"); + cut->debug("t1") << "TEXT FOR T1 "; + cut->debug("t2") << "TEXT FOR T2 "; + cut->debug("t3") << "TEXT FOR T3"; + THEN("Log text is \"TEXT FOR T2 TEXT FOR T3\"") { + REQUIRE(log.str() == "t2 DEBUG: TEXT FOR T2 t3 DEBUG: TEXT FOR T3"); + } + } +} diff --git a/xs/src/libslic3r/Log.cpp b/xs/src/libslic3r/Log.cpp index f2548efd9..9e117d5f3 100644 --- a/xs/src/libslic3r/Log.cpp +++ b/xs/src/libslic3r/Log.cpp @@ -34,6 +34,10 @@ bool _Log::_has_log_level(log_t lvl) { return false; } +bool _Log::_has_topic(const std::string& topic) { + return this->_topics.find(topic) != this->_topics.end() || this->_topics.size() == 0; +} + void _Log::fatal_error(const std::string& topic, const std::wstring& message) { this->fatal_error(topic, this->converter.to_bytes(message)); } void _Log::error(const std::string& topic, const std::wstring& message) { this->error(topic, this->converter.to_bytes(message)); } void _Log::warn(const std::string& topic, const std::wstring& message) { this->warn(topic, this->converter.to_bytes(message)); } @@ -44,7 +48,7 @@ void _Log::fatal_error(const std::string& topic, const std::string& message) { this->fatal_error(topic) << message << std::endl; } std::ostream& _Log::fatal_error(const std::string& topic) { - if (this->_has_log_level(log_t::FERR)) { + if (this->_has_log_level(log_t::FERR) && this->_has_topic(topic)) { _out << topic << std::setfill(' ') << std::setw(6) << "FERR" << ": "; return _out; } @@ -55,7 +59,7 @@ void _Log::error(const std::string& topic, const std::string& message) { this->error(topic) << message << std::endl; } std::ostream& _Log::error(const std::string& topic) { - if (this->_has_log_level(log_t::ERR)) { + if (this->_has_log_level(log_t::ERR) && this->_has_topic(topic)) { _out << topic << std::setfill(' ') << std::setw(6) << "ERR" << ": "; return _out; } @@ -67,7 +71,7 @@ void _Log::info(const std::string& topic, const std::string& message) { } std::ostream& _Log::info(const std::string& topic) { - if (this->_has_log_level(log_t::INFO)) { + if (this->_has_log_level(log_t::INFO) && this->_has_topic(topic)) { _out << topic << std::setfill(' ') << std::setw(6) << "INFO" << ": "; return _out; } @@ -79,7 +83,7 @@ void _Log::warn(const std::string& topic, const std::string& message) { } std::ostream& _Log::warn(const std::string& topic) { - if (this->_has_log_level(log_t::WARN)) { + if (this->_has_log_level(log_t::WARN) && this->_has_topic(topic)) { _out << topic << std::setfill(' ') << std::setw(6) << "WARN" << ": "; return _out; } @@ -91,7 +95,7 @@ void _Log::debug(const std::string& topic, const std::string& message) { } std::ostream& _Log::debug(const std::string& topic) { - if (this->_has_log_level(log_t::DEBUG)) { + if (this->_has_log_level(log_t::DEBUG) && this->_has_topic(topic)) { _out << topic << std::setfill(' ') << std::setw(6) << "DEBUG" << ": "; return _out; } @@ -131,4 +135,12 @@ void _Log::clear_level(log_t level) { } } +void _Log::clear_topic(const std::string& topic) { + if (topic == "") { + this->_topics.clear(); + } else { + if (this->_topics.find(topic) != this->_topics.end()) this->_topics.erase(topic); + } +} + } // Slic3r diff --git a/xs/src/libslic3r/Log.hpp b/xs/src/libslic3r/Log.hpp index 0f0040c5a..48e309297 100644 --- a/xs/src/libslic3r/Log.hpp +++ b/xs/src/libslic3r/Log.hpp @@ -63,6 +63,8 @@ public: void set_level(log_t level); void clear_level(log_t level); void set_inclusive(bool v) { this->_inclusive_levels = v; } + void add_topic(const std::string& topic) { this->_topics.insert(topic); } + void clear_topic(const std::string& topic); // _Log(_Log const&) = delete; // void operator=(_Log const&) = delete; @@ -72,10 +74,12 @@ private: _Log(std::ostream& out); bool _inclusive_levels { true }; std::set _log_level { }; + std::set _topics { }; std::wstring_convert> converter; bool _has_log_level(log_t lvl); + bool _has_topic(const std::string& topic); }; @@ -183,6 +187,20 @@ public: static std::ostream& raw() { return slic3r_log->raw(); } + + /// Adds a topic to filter on with Slic3r's debug system. + /// \param topic [in] name of topic to filter on. + /// Only shows registered topics. + static void add_topic(const std::string& topic) { + slic3r_log->add_topic(topic); + } + + /// Removes a topic from the filter list with Slic3r's debug system. + /// \param topic [in] name of topic to remove from filter. + /// \note Default option removes all filters. + static void clear_topic(const std::string& topic = "") { + slic3r_log->clear_topic(topic); + } }; /// Utility debug function to transform a std::vector of anything that From 93518c95458ac52e2c1ee05fdb4991e6059aa333 Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Fri, 23 Nov 2018 08:07:50 -0600 Subject: [PATCH 7/7] Include STL algorithm --- xs/src/libslic3r/Log.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/xs/src/libslic3r/Log.cpp b/xs/src/libslic3r/Log.cpp index 9e117d5f3..da2d2af42 100644 --- a/xs/src/libslic3r/Log.cpp +++ b/xs/src/libslic3r/Log.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "Log.hpp"