diff --git a/bindings/py/cpp_src/bindings/engine/py_Engine.cpp b/bindings/py/cpp_src/bindings/engine/py_Engine.cpp index f4482fcdec..554d8cc8c1 100644 --- a/bindings/py/cpp_src/bindings/engine/py_Engine.cpp +++ b/bindings/py/cpp_src/bindings/engine/py_Engine.cpp @@ -30,8 +30,8 @@ PyBind11 bindings for Engine classes #include #include - #include +#include #include #include @@ -39,6 +39,7 @@ PyBind11 bindings for Engine classes #include #include #include + #include #include @@ -468,13 +469,13 @@ namespace htm_ext , py::arg("srcOutput") = "", py::arg("destInput") = "" , py::arg("propagationDelay") = 0); - py::enum_(m, "LogLevel", py::arithmetic(), "An enumeration of logging levels.") - .value("None", LogLevel::LogLevel_None) // default - .value("Minimal", LogLevel::LogLevel_Minimal) - .value("Normal", LogLevel::LogLevel_Normal) - .value("Verbose", LogLevel::LogLevel_Verbose) + py::enum_(m, "LogLevel", "An enumeration of logging levels.") + .value("None", htm::LogLevel::LogLevel_None) // default + .value("Minimal", htm::LogLevel::LogLevel_Minimal) + .value("Normal", htm::LogLevel::LogLevel_Normal) + .value("Verbose", htm::LogLevel::LogLevel_Verbose) .export_values(); - py_Network.def("setLogLevel", &htm::Network::setLogLevel); + py_Network.def_static("setLogLevel", &htm::Network::setLogLevel, py::arg("level") = htm::LogLevel::LogLevel_None); // plugin registration diff --git a/bindings/py/tests/regions/network_test.py b/bindings/py/tests/regions/network_test.py index f7f6410373..d91b62671f 100644 --- a/bindings/py/tests/regions/network_test.py +++ b/bindings/py/tests/regions/network_test.py @@ -292,10 +292,10 @@ def testBuiltInRegions(self): """ This sets up a network with built-in regions. """ - + import htm net = engine.Network() - net.setLogLevel(engine.Verbose) # Verbose shows data inputs and outputs while executing. - + #net.setLogLevel(htm.bindings.engine_internal.LogLevel.Verbose) # Verbose shows data inputs and outputs while executing. + encoder = net.addRegion("encoder", "ScalarSensor", "{n: 6, w: 2}"); sp = net.addRegion("sp", "SPRegion", "{columnCount: 200}"); tm = net.addRegion("tm", "TMRegion", ""); @@ -316,6 +316,8 @@ def testBuiltInRegions(self): tm_output = tm.getOutputArray("predictedActiveCells") sdr = tm_output.getSDR() + print(sdr.sparse) + print(EXPECTED_RESULT3) self.assertTrue(np.array_equal(sdr.sparse, EXPECTED_RESULT3)) def testExecuteCommand1(self): diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 70ddda21a2..b0ebac06c4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -167,10 +167,6 @@ set(types_files set(utils_files htm/utils/GroupBy.hpp htm/utils/Log.hpp - htm/utils/LoggingException.cpp - htm/utils/LoggingException.hpp - htm/utils/LogItem.cpp - htm/utils/LogItem.hpp htm/utils/MovingAverage.cpp htm/utils/MovingAverage.hpp htm/utils/Random.cpp diff --git a/src/htm/engine/Input.cpp b/src/htm/engine/Input.cpp index 5e74b66225..e1d3772778 100644 --- a/src/htm/engine/Input.cpp +++ b/src/htm/engine/Input.cpp @@ -330,7 +330,7 @@ void Input::uninitialize() { namespace htm { std::ostream &operator<<(std::ostream &f, const Input &d) { - f << "Input: " << d.getRegion()->getName() << "." << d.getName() << " " << d.getData(); + f << "Input: " << d.getRegion()->getName() << "." << d.getName() << " " << d.getData(); return f; } } diff --git a/src/htm/engine/Link.cpp b/src/htm/engine/Link.cpp index 07b23c829d..2355a6384b 100644 --- a/src/htm/engine/Link.cpp +++ b/src/htm/engine/Link.cpp @@ -27,7 +27,7 @@ #include #include -// By calling LogItem::setLogLevel(LogLevel_Verbose) +// By calling Network::setLogLevel(LogLevel_Verbose) // you can enable the NTA_DEBUG macros below. namespace htm { @@ -187,7 +187,7 @@ void Link::compute() { const Array &src = propagationDelay_ ? propagationDelayBuffer_.front() : src_->getData(); Array &dest = dest_->getData(); - NTA_DEBUG << "Link::compute: " << getMoniker() << "; copying to dest input" + NTA_DEBUG << "compute Link: copying " << getMoniker() << "; delay=" << propagationDelay_ << "; size=" << src.getCount() << " type=" << BasicType::getName(src.getType()) << " --> " << BasicType::getName(dest.getType()) << std::endl; diff --git a/src/htm/engine/Network.cpp b/src/htm/engine/Network.cpp index 8d2bf132f4..e14f635dc4 100644 --- a/src/htm/engine/Network.cpp +++ b/src/htm/engine/Network.cpp @@ -40,19 +40,22 @@ namespace htm { class RegisteredRegionImpl; +thread_local LogLevel NTA_LOG_LEVEL; + + Network::Network() { commonInit(); } // move constructor -Network::Network(Network && n) { +Network::Network(Network &&n) noexcept { regions_ = std::move(n.regions_); minEnabledPhase_ = n.minEnabledPhase_; maxEnabledPhase_ = n.maxEnabledPhase_; phaseInfo_ = std::move(n.phaseInfo_); callbacks_ = n.callbacks_; iteration_ = n.iteration_; -} +} Network::Network(const std::string& filename) { commonInit(); diff --git a/src/htm/engine/Network.hpp b/src/htm/engine/Network.hpp index e65c0e51ec..2790981fa2 100644 --- a/src/htm/engine/Network.hpp +++ b/src/htm/engine/Network.hpp @@ -67,7 +67,7 @@ class Link; /** * Cannot copy or assign a Network object. But can be moved. */ - Network(Network&&); // move is allowed + Network(Network &&) noexcept; // move is allowed Network(const Network&) = delete; void operator=(const Network&) = delete; @@ -375,12 +375,14 @@ class Link; */ void resetProfiling(); - /** - * Set one of the debug levels: LogLevel_None = 0, LogLevel_Minimal, LogLevel_Normal, LogLevel_Verbose + /** + * Set one of the debug levels: LogLevel_None = 0, LogLevel_Minimal, LogLevel_Normal, LogLevel_Verbose */ - void setLogLevel(LogLevel level) { - LogItem::setLogLevel(level); - } + static LogLevel setLogLevel(LogLevel level) { + LogLevel prev = NTA_LOG_LEVEL; + NTA_LOG_LEVEL = level; + return prev; + } /** diff --git a/src/htm/engine/Output.cpp b/src/htm/engine/Output.cpp index 0073163361..0aa98d14fb 100644 --- a/src/htm/engine/Output.cpp +++ b/src/htm/engine/Output.cpp @@ -118,7 +118,7 @@ void Output::removeLink(const std::shared_ptr& link) { namespace htm { std::ostream &operator<<(std::ostream &f, const Output &d) { - f << "Output:" << d.getRegion()->getName() << "." << d.getName() << " " << d.getData(); + f << "Output: " << d.getRegion()->getName() << "." << d.getName() << " " << d.getData(); return f; } } diff --git a/src/htm/engine/RegionImpl.cpp b/src/htm/engine/RegionImpl.cpp index 47b85291c3..17f50b14be 100644 --- a/src/htm/engine/RegionImpl.cpp +++ b/src/htm/engine/RegionImpl.cpp @@ -243,7 +243,9 @@ std::shared_ptr RegionImpl::getInput(const std::string &name) const { } std::shared_ptr RegionImpl::getOutput(const std::string &name) const { - return region_->getOutput(name); + auto out = region_->getOutput(name); + NTA_CHECK(out != nullptr) << "Requested output not found: " << name; + return out; } Dimensions RegionImpl::getInputDimensions(const std::string &name) const { return region_->getInputDimensions(name); diff --git a/src/htm/regions/SPRegion.cpp b/src/htm/regions/SPRegion.cpp index d3167b3ad5..18268b4fb0 100644 --- a/src/htm/regions/SPRegion.cpp +++ b/src/htm/regions/SPRegion.cpp @@ -158,7 +158,7 @@ void SPRegion::compute() { // Call SpatialPooler compute sp_->compute(inputBuffer.getSDR(), args_.learningMode, outputBuffer.getSDR()); - + // trace facility NTA_DEBUG << "compute " << *getOutput("bottomUpOut") << "\n"; } diff --git a/src/htm/regions/ScalarSensor.cpp b/src/htm/regions/ScalarSensor.cpp index b40bd0e04b..1e09439099 100644 --- a/src/htm/regions/ScalarSensor.cpp +++ b/src/htm/regions/ScalarSensor.cpp @@ -102,6 +102,9 @@ void ScalarSensor::compute() { SDR &output = getOutput("encoded")->getData().getSDR(); encoder_->encode((Real64)sensedValue_, output); + + // trace facility + NTA_DEBUG << "compute " << getOutput("encoded") << std::endl; } ScalarSensor::~ScalarSensor() {} diff --git a/src/htm/regions/TMRegion.cpp b/src/htm/regions/TMRegion.cpp index 005f3d160b..cef3cd3e11 100644 --- a/src/htm/regions/TMRegion.cpp +++ b/src/htm/regions/TMRegion.cpp @@ -176,6 +176,7 @@ void TMRegion::initialize() { args_.sequencePos = 0; } + void TMRegion::compute() { NTA_ASSERT(tm_) << "TM not initialized"; @@ -209,6 +210,7 @@ void TMRegion::compute() { Array &externalPredictiveInputsWinners = getInput("externalPredictiveInputsWinners")->getData(); SDR& externalPredictiveInputsWinnerCells = (args_.externalPredictiveInputs) ? (externalPredictiveInputsWinners.getSDR()) : nullSDR; + // Trace facility NTA_DEBUG << "compute " << *in << std::endl; // Perform Bottom up compute() @@ -230,36 +232,32 @@ void TMRegion::compute() { // std::shared_ptr out; out = getOutput("bottomUpOut"); - if (out && (out->hasOutgoingLinks() || LogItem::isDebug())) { + //call Network::setLogLevel(LogLevel::LogLevel_Verbose); + // to output the NTA_DEBUG statements below SDR& sdr = out->getData().getSDR(); tm_->getActiveCells(sdr); //active cells if (args_.orColumnOutputs) { //output as columns sdr = tm_->cellsToColumns(sdr); } - NTA_DEBUG << "bottomUpOut " << *out << std::endl; - } + NTA_DEBUG << "compute "<< *out << std::endl; + out = getOutput("activeCells"); - if (out && (out->hasOutgoingLinks() || LogItem::isDebug())) { tm_->getActiveCells(out->getData().getSDR()); - NTA_DEBUG << "active " << *out << std::endl; - } + NTA_DEBUG << "compute "<< *out << std::endl; + out = getOutput("predictedActiveCells"); - if (out && (out->hasOutgoingLinks() || LogItem::isDebug())) { tm_->activateDendrites(); tm_->getWinnerCells(out->getData().getSDR()); - NTA_DEBUG << "winners " << *out << std::endl; - } + NTA_DEBUG << "compute "<< *out << std::endl; + out = getOutput("anomaly"); - if (out && (out->hasOutgoingLinks() || LogItem::isDebug())) { Real32* buffer = reinterpret_cast(out->getData().getBuffer()); - buffer[0] = tm_->anomaly; - NTA_DEBUG << "anomaly " << *out << std::endl; - } + buffer[0] = tm_->anomaly; //only the first field is valid + NTA_DEBUG << "compute "<< *out << std::endl; + out = getOutput("predictiveCells"); - if (out && (out->hasOutgoingLinks() || LogItem::isDebug())) { out->getData().getSDR() = tm_->getPredictiveCells(); - NTA_DEBUG << "predictive " << *out << std::endl; - } + NTA_DEBUG << "compute " << *out << std::endl; } diff --git a/src/htm/regions/TestNode.cpp b/src/htm/regions/TestNode.cpp index 0d8ce81106..38345d6f74 100644 --- a/src/htm/regions/TestNode.cpp +++ b/src/htm/regions/TestNode.cpp @@ -172,6 +172,10 @@ void TestNode::compute() { Array &inputArray = bottomUpIn_->getData(); Real64* inputBuffer = (Real64*)inputArray.getBuffer(); size_t count = inputArray.getCount(); + + // trace facility + NTA_DEBUG << "compute " << bottomUpIn_ << std::endl; + // See TestNode.hpp for description of the computation @@ -198,6 +202,10 @@ void TestNode::compute() { } } + // trace facility + NTA_DEBUG << "compute " << bottomUpOut_ << "\n"; + + iter_++; } diff --git a/src/htm/regions/VectorFileEffector.cpp b/src/htm/regions/VectorFileEffector.cpp index 9ad7515537..51bde38899 100644 --- a/src/htm/regions/VectorFileEffector.cpp +++ b/src/htm/regions/VectorFileEffector.cpp @@ -67,7 +67,8 @@ void VectorFileEffector::initialize() { } void VectorFileEffector::compute() { - NTA_DEBUG << "VectorFileEffector compute() input: " << *region_->getInput("dataIn") << "\n"; + // trace facility + NTA_DEBUG << "compute " << *region_->getInput("dataIn") << "\n"; dataIn_ = region_->getInput("dataIn")->getData(); // It's not necessarily an error to have no inputs. In this case we just // return diff --git a/src/htm/regions/VectorFileSensor.cpp b/src/htm/regions/VectorFileSensor.cpp index 5839208b86..bf67c8a152 100644 --- a/src/htm/regions/VectorFileSensor.cpp +++ b/src/htm/regions/VectorFileSensor.cpp @@ -127,7 +127,9 @@ void VectorFileSensor::compute() { Real *categoryOut = reinterpret_cast(categoryOut_.getBuffer()); vectorFile_.getRawVector((htm::UInt)curVector_, categoryOut, offset, 1); offset++; - NTA_DEBUG << "VectorFileSensor compute() CategoryOut= " << *region_->getOutput("categoryOut") << "\n"; + + // trace facility + NTA_DEBUG << "compute " << region_->getOutput("categoryOut") << std::endl; } if (hasResetOut_) { @@ -135,11 +137,15 @@ void VectorFileSensor::compute() { Real *resetOut = reinterpret_cast(resetOut_.getBuffer()); vectorFile_.getRawVector((htm::UInt)curVector_, resetOut, offset, 1); offset++; - NTA_DEBUG << "VectorFileSensor compute() reset= " << *region_->getOutput("reset") << "\n"; + + // trace facility + NTA_DEBUG << "compute " << *region_->getOutput("reset") << std::endl; } vectorFile_.getScaledVector((htm::UInt)curVector_, out, offset, count); - NTA_DEBUG << "VectorFileSensor compute() dataOut= " << *region_->getOutput("dataOut") << "\n"; + + // trace facility + NTA_DEBUG << "compute " << *region_->getOutput("dataOut") << std::endl; iterations_++; } diff --git a/src/htm/types/Exception.hpp b/src/htm/types/Exception.hpp index cc840c30ac..442f534cf5 100644 --- a/src/htm/types/Exception.hpp +++ b/src/htm/types/Exception.hpp @@ -23,8 +23,10 @@ #define NTA_EXCEPTION_HPP #include + #include #include +#include #include //---------------------------------------------------------------------- @@ -47,22 +49,10 @@ namespace htm { * This class may be used directly by instatiating an instance * and throwing it, but usually you will use the NTA_THROW macro * that makes it much simpler by automatically retreiving the __FILE__ - * and __LINE__ for you and also using a wrapping LogItem that allows - * you to construct the exception message conveniently using the << - * streame operator (see htm/utils/Log.hpp for further details). - * - * @b Notes: - * 1. Exception is a subclass of the standard std::runtime_error. - * This is useful if your code needs to interoperate with other - * code that is not aware of the Exception class, but understands - * std::runtime_error. The what() method will return the exception message - * and the location information will not be avaialable to such code. + * and __LINE__ for you. * - * 2. Source file and line number information is useful of course - * only if you have access to the source code. It is not recommended - * to display this information to users most of the time. */ -class Exception : public std::runtime_error { +class Exception : public std::runtime_error { //TODO rename to NTAException to be less confusing? public: /** * Constructor @@ -77,10 +67,18 @@ class Exception : public std::runtime_error { * * @param message [const std::string &] the description of exception */ - Exception(std::string filename, UInt32 lineno, std::string message, + Exception(std::string filename, + UInt32 lineno, + std::string message = "", std::string stacktrace = "") : std::runtime_error(""), filename_(std::move(filename)), lineno_(lineno), - message_(std::move(message)), stackTrace_(std::move(stacktrace)) {} + message_(std::move(message)), stackTrace_(std::move(stacktrace)),ss_("") {} + + Exception(const Exception& copy): + std::runtime_error("") { + Exception(filename_, lineno_, copy.getMessage(), stackTrace_); + } + /** * Destructor @@ -104,12 +102,8 @@ class Exception : public std::runtime_error { * * @retval [const Byte *] the exception message */ - virtual const char *what() const throw() { - try { + virtual const char *what() const noexcept override { return getMessage(); - } catch (...) { - return "Exception caught in non-throwing Exception::what()"; - } } /** @@ -120,7 +114,7 @@ class Exception : public std::runtime_error { * * @retval [const Byte *] the source filename */ - const char *getFilename() const { return filename_.c_str(); } + const char *getFilename() const noexcept { return filename_.c_str(); } /** * Get the line number in the source file @@ -130,14 +124,17 @@ class Exception : public std::runtime_error { * * @retval [UInt32] the line number in the source file */ - UInt32 getLineNumber() const { return lineno_; } + UInt32 getLineNumber() const noexcept { return lineno_; } /** * Get the error message * * @retval [const char *] the error message */ - virtual const char *getMessage() const { return message_.c_str(); } + virtual const char *getMessage() const noexcept { + message_ += ss_.str(); + ss_.clear(); + return message_.c_str(); } /** * Get the stack trace @@ -147,13 +144,22 @@ class Exception : public std::runtime_error { * * @retval [const Byte *] the stack trace */ - virtual const char *getStackTrace() const { return stackTrace_.c_str(); } + virtual const char *getStackTrace() const noexcept { return stackTrace_.c_str(); } + + + template + Exception &operator<<(const T &obj) { + ss_ << obj; + return *this; + } protected: std::string filename_; UInt32 lineno_; - std::string message_; + mutable std::string message_; //mutable bcs modified in getMessage which is used in what() but that needs be const std::string stackTrace_; +private: + mutable std::stringstream ss_; }; // end class Exception } // end namespace htm diff --git a/src/htm/utils/Log.hpp b/src/htm/utils/Log.hpp index 47546266b0..79e8b8d979 100644 --- a/src/htm/utils/Log.hpp +++ b/src/htm/utils/Log.hpp @@ -23,65 +23,66 @@ #ifndef NTA_LOG2_HPP #define NTA_LOG2_HPP -#include -#include +#include +#include -#define NTA_DEBUG \ - if (htm::LogItem::getLogLevel() < htm::LogLevel_Verbose) { \ - } else \ - htm::LogItem(__FILE__, __LINE__, htm::LogType_debug).stream() +namespace htm { +enum class LogLevel { LogLevel_None = 0, LogLevel_Minimal=1, LogLevel_Normal=2, LogLevel_Verbose=3 }; +// change this in your class to set log level using Network.setLogLevel(level); +extern thread_local LogLevel NTA_LOG_LEVEL; -// Can be used in Loggable classes -// level is one of (LogLevel_None, LogLevel_Minimal, LogLevel_Normal, LogLevel_Verbose) -#define NTA_LDEBUG(level) \ - if (htm::LogItem::getLogLevel() < (level)) { \ - } else \ - htm::LogItem(__FILE__, __LINE__, htm::LogType_debug).stream() +//this code intentionally uses "if() dosomething" instead of "if() { dosomething }" +// as the macro expects another "<< "my clever message"; +// so it eventually becomes: `if() std::cout << "DEBUG:\t" << "users message";` +// +//Expected usage: +//: +//Network::setLogLevel(LogLevel::LogLevel_Verbose); +//NTA_WARN << "Hello World!" << std::endl; //shows +//NTA_DEBUG << "more details how cool this is"; //not showing under "Normal" log level +//NTA_ERR << "You'll always see this, HAHA!"; +//NTA_THROW << "crashing for a good cause"; + +#define NTA_DEBUG \ + if (NTA_LOG_LEVEL >= LogLevel::LogLevel_Verbose) \ + std::cout << "DEBUG:\t" << Path::getBasename(__FILE__) << ":" << __LINE__ << ": " // For informational messages that report status but do not indicate that // anything is wrong #define NTA_INFO \ - if (htm::LogItem::getLogLevel() < htm::LogLevel_Normal) { \ - } else \ - htm::LogItem(__FILE__, __LINE__, htm::LogType_info).stream() + if (NTA_LOG_LEVEL >= LogLevel::LogLevel_Normal) \ + std::cout << "INFO:\t" << Path::getBasename(__FILE__) << ":" << __LINE__ << ": " // For messages that indicate a recoverable error or something else that it may // be important for the end user to know about. #define NTA_WARN \ - if (htm::LogItem::getLogLevel() < htm::LogLevel_Normal) { \ - } else \ - htm::LogItem(__FILE__, __LINE__, htm::LogType_warn).stream() + if (NTA_LOG_LEVEL >= LogLevel::LogLevel_Normal) \ + std::cout << "WARN:\t" << Path::getBasename(__FILE__) << ":" << __LINE__ << ": " // To throw an exception and make sure the exception message is logged // appropriately -#define NTA_THROW throw htm::LoggingException(__FILE__, __LINE__) +#define NTA_THROW throw htm::Exception(__FILE__, __LINE__) // The difference between CHECK and ASSERT is that ASSERT is for // performance critical code and can be disabled in a release // build. Both throw an exception on error (if NTA_ASSERTIONS_ON is set). #define NTA_CHECK(condition) \ - if (condition) { \ - } else \ + if (not (condition) ) \ NTA_THROW << "CHECK FAILED: \"" << #condition << "\" " #ifdef NTA_ASSERTIONS_ON // With NTA_ASSERTIONS_ON, NTA_ASSERT macro throws exception if condition is false. // NTA_ASSERTIONS_ON should be set ON only in debug mode. -#define NTA_ASSERT(condition) \ - if (condition) { \ - } else \ - NTA_THROW << "ASSERTION FAILED: \"" << #condition << "\" " +#define NTA_ASSERT(condition) NTA_CHECK(condition) #else // Without NTA_ASSERTIONS_ON, NTA_ASSERT macro does nothing. -// The second line (with LogItem) should never be executed, or even compiled, but we -// need something that is syntactically compatible with NTA_ASSERT +// The second line (with `if(false)`) should never be executed, or even compiled, but we +// need something that is syntactically compatible with NTA_ASSERT << "msg"; #define NTA_ASSERT(condition) \ - if (1) { \ - } else \ - htm::LogItem(__FILE__, __LINE__, htm::LogType_debug).stream() + if (false) std::cerr << "This line should never happen" #endif // NTA_ASSERTIONS_ON - +} #endif // NTA_LOG2_HPP diff --git a/src/htm/utils/LogItem.cpp b/src/htm/utils/LogItem.cpp deleted file mode 100644 index abb5bbc5f3..0000000000 --- a/src/htm/utils/LogItem.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* --------------------------------------------------------------------- - * HTM Community Edition of NuPIC - * Copyright (C) 2013, Numenta, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero Public License version 3 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Affero Public License for more details. - * - * You should have received a copy of the GNU Affero Public License - * along with this program. If not, see http://www.gnu.org/licenses. - * --------------------------------------------------------------------- */ - -/** @file - * LogItem implementation - */ - -#include // cerr -#include -#include -#include // runtime_error - -using namespace htm; - -// Initialize static members -std::ostream *LogItem::ostream_ = nullptr; -htm::LogLevel LogItem::log_level_ = LogLevel::LogLevel_None; - -// Static functions -void LogItem::setOutputFile(std::ostream &ostream) { ostream_ = &ostream; } -void LogItem::setLogLevel(LogLevel level) { log_level_ = level; } -LogLevel LogItem::getLogLevel() {return log_level_; } - - -// Constructor -// Construct a new instance for each item to be logged. -LogItem::LogItem(const char *filename, int line, htm::LogType type) - : filename_(filename), lineno_(line), type_(type), msg_("") {} - -LogItem::~LogItem() { - std::string slevel; - switch (type_) { - case LogType_debug: - slevel = "DEBUG:"; - break; - case LogType_warn: - slevel = "WARN: "; - break; - case LogType_info: - slevel = "INFO: "; - break; - case LogType_error: - slevel = "ERR:"; - break; - default: - slevel = "Unknown: "; - break; - } - - if (ostream_ == nullptr) - ostream_ = &(std::cerr); - - (*ostream_) << slevel << " " << msg_.str(); - - if (type_ == LogType_error) - (*ostream_) << " [" << filename_ << " line " << lineno_ << "]"; - - (*ostream_) << std::endl; -} - -std::ostringstream &LogItem::stream() { return msg_; } diff --git a/src/htm/utils/LogItem.hpp b/src/htm/utils/LogItem.hpp deleted file mode 100644 index ccb84b287c..0000000000 --- a/src/htm/utils/LogItem.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* --------------------------------------------------------------------- - * HTM Community Edition of NuPIC - * Copyright (C) 2013, Numenta, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero Public License version 3 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Affero Public License for more details. - * - * You should have received a copy of the GNU Affero Public License - * along with this program. If not, see http://www.gnu.org/licenses. - * --------------------------------------------------------------------- */ - -/** @file - * LogItem interface - */ - -#ifndef NTA_LOG_ITEM_HPP -#define NTA_LOG_ITEM_HPP - -#include -#include - -namespace htm { - - /** - * The type of log message. - */ - typedef enum { LogType_debug = 1, LogType_info, LogType_warn, LogType_error } LogType; - - /** - * This enum represents the documented logging level of the debug logger. - * - * Use it like `LDEBUG(htm::LogLevel_XXX)`. - */ - typedef enum { LogLevel_None = 0, LogLevel_Minimal, LogLevel_Normal, LogLevel_Verbose } LogLevel; - -/** - * @b Description - * A LogItem represents a single log entry. It contains a stream that - * accumulates a log message, and its destructor calls the logger. - * - * A LogItem contains an internal stream - * which is used for building up an application message using - * << operators. - * - */ - -class LogItem { -public: - - - /** - * Record information to be logged - */ - LogItem(const char *filename, int line, htm::LogType type); - - /** - * Destructor performs the logging - */ - virtual ~LogItem(); - - /* - * Return the underlying stream object. Caller will use it to construct the - * log message. - */ - std::ostringstream &stream(); - - static void setOutputFile(std::ostream &ostream); - static void setLogLevel(LogLevel level); - static LogLevel getLogLevel(); - static bool isDebug() { return (log_level_ == LogLevel_Verbose); } - -protected: - const char *filename_; // name of file - int lineno_; // line number in file - LogType type_; - std::ostringstream msg_; - -private: - static std::ostream *ostream_; - static htm::LogLevel log_level_; -}; - -} // namespace htm - -#endif // NTA_LOG_ITEM_HPP diff --git a/src/htm/utils/LoggingException.cpp b/src/htm/utils/LoggingException.cpp deleted file mode 100644 index abfdbcba23..0000000000 --- a/src/htm/utils/LoggingException.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* --------------------------------------------------------------------- - * HTM Community Edition of NuPIC - * Copyright (C) 2013, Numenta, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero Public License version 3 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Affero Public License for more details. - * - * You should have received a copy of the GNU Affero Public License - * along with this program. If not, see http://www.gnu.org/licenses. - * --------------------------------------------------------------------- */ - -/** @file */ - -//---------------------------------------------------------------------- - -#include "LoggingException.hpp" -#include "LogItem.hpp" -#include -using namespace htm; - -LoggingException::~LoggingException() throw() { - if (!alreadyLogged_) { - // Let LogItem do the work for us. This code is a bit complex - // because LogItem was designed to be used from a logging macro - LogItem *li = new LogItem(filename_.c_str(), lineno_, LogType::LogType_error); - li->stream() << getMessage(); - delete li; - - alreadyLogged_ = true; - } -} diff --git a/src/htm/utils/LoggingException.hpp b/src/htm/utils/LoggingException.hpp deleted file mode 100644 index f61ffe185f..0000000000 --- a/src/htm/utils/LoggingException.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/* --------------------------------------------------------------------- - * HTM Community Edition of NuPIC - * Copyright (C) 2013, Numenta, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero Public License version 3 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Affero Public License for more details. - * - * You should have received a copy of the GNU Affero Public License - * along with this program. If not, see http://www.gnu.org/licenses. - * --------------------------------------------------------------------- */ - -/** @file */ - -//---------------------------------------------------------------------- - -#ifndef NTA_LOGGING_EXCEPTION_HPP -#define NTA_LOGGING_EXCEPTION_HPP - -#include -#include -#include - -namespace htm { -class LoggingException : public Exception { -public: - LoggingException(const std::string &filename, UInt32 lineno) - : Exception(filename, lineno, std::string()), ss_(std::string()), - lmessageValid_(false), alreadyLogged_(false) {} - - virtual ~LoggingException() throw(); - - const char *getMessage() const override { - // Make sure we use a persistent string. Otherwise the pointer may - // become invalid. - // If the underlying stringstream object hasn't changed, don't regenerate - // lmessage_. This is important because if we catch this exception a second - // call to exception.what() will trash the buffer returned by a first call - // to exception.what() - if (!lmessageValid_) { - lmessage_ = ss_.str(); - lmessageValid_ = true; - } - return lmessage_.c_str(); - } - - - template LoggingException &operator<<(const T &obj) { - // underlying stringstream changes, so let getMessage() know - // to regenerate lmessage_ - lmessageValid_ = false; - ss_ << obj; - return *this; - } - - LoggingException(const LoggingException &l) - : Exception(l), ss_(l.ss_.str()), lmessage_(""), lmessageValid_(false), - alreadyLogged_(true) // copied exception does not log - - { - // make sure message string is up to date for debuggers. - getMessage(); - } - -private: - std::stringstream ss_; - mutable std::string lmessage_; // mutable because getMesssage() modifies it - mutable bool lmessageValid_; - bool alreadyLogged_; -}; // class LoggingException - -} // namespace htm - -#endif // NTA_LOGGING_EXCEPTION_HPP diff --git a/src/test/unit/algorithms/SpatialPoolerTest.cpp b/src/test/unit/algorithms/SpatialPoolerTest.cpp index 6f58c91b07..af3eb03992 100644 --- a/src/test/unit/algorithms/SpatialPoolerTest.cpp +++ b/src/test/unit/algorithms/SpatialPoolerTest.cpp @@ -1206,7 +1206,7 @@ TEST(SpatialPoolerTest, testValidateGlobalInhibitionParameters) { SDR out1( {sp.getNumColumns()} ); //throws EXPECT_ANY_THROW(sp.setLocalAreaDensity(0.02f)); -// EXPECT_THROW(sp.compute(input, false, out1), htm::LoggingException); +// EXPECT_THROW(sp.compute(input, false, out1), htm::Exception); //good parameter EXPECT_NO_THROW(sp.setLocalAreaDensity(0.1f)); EXPECT_NO_THROW(sp.compute(input, false, out1)); diff --git a/src/test/unit/regions/TMRegionTest.cpp b/src/test/unit/regions/TMRegionTest.cpp index fd69978985..89ab022a27 100644 --- a/src/test/unit/regions/TMRegionTest.cpp +++ b/src/test/unit/regions/TMRegionTest.cpp @@ -84,7 +84,7 @@ TEST(TMRegionTest, testSpecAndParameters) { Network net; // Turn on runtime Debug logging. - //if (verbose) LogItem::setLogLevel(LogLevel::LogLevel_Verbose); + //if (verbose) NTA_LOG_LEVEL = LogLevel::LogLevel_Verbose; // create a TM region with default parameters std::set excluded; @@ -240,8 +240,18 @@ TEST(TMRegionTest, testLinking) { ASSERT_EQ(region3->getParameterUInt32("inputWidth"), (UInt32)dataWidth); VERBOSE << "Execute once." << std::endl; + + // turn on trace...for one iteration + LogLevel prev; + VERBOSE << "Turning on Trace =========\n"; + if (verbose) { prev = net.setLogLevel(LogLevel::LogLevel_Verbose); } + net.run(1); + // turn off trace + if (verbose) { net.setLogLevel(prev); } + VERBOSE << "Turned off Trace =========\n"; + VERBOSE << "Checking data after first iteration..." << std::endl; VERBOSE << " VectorFileSensor Output" << std::endl; Array r1OutputArray = region1->getOutputData("dataOut"); @@ -252,7 +262,7 @@ TEST(TMRegionTest, testLinking) { // check anomaly EXPECT_FLOAT_EQ(region3->getParameterReal32("anomaly"), 1.0f); const Real32 *anomalyBuffer = reinterpret_cast(region3->getOutputData("anomaly").getBuffer()); - EXPECT_FLOAT_EQ(anomalyBuffer[0], 0.0f); // Note: it is zero because no links are connected to this output. + EXPECT_FLOAT_EQ(anomalyBuffer[0], 1.0f); VERBOSE << " SPRegion Output " << std::endl; diff --git a/src/test/unit/regions/VectorFileTest.cpp b/src/test/unit/regions/VectorFileTest.cpp index 0045b91599..d847fa6ae4 100644 --- a/src/test/unit/regions/VectorFileTest.cpp +++ b/src/test/unit/regions/VectorFileTest.cpp @@ -49,7 +49,6 @@ #include #include #include -#include #include @@ -184,9 +183,9 @@ namespace testing net.initialize(); VERBOSE << "Execute once." << std::endl; - //LogItem::setLogLevel(LogLevel_Verbose); + //NTA_LOG_LEVEL = LogLevel::LogLevel_Verbose; net.run(1); - //LogItem::setLogLevel(LogLevel_None); + //NTA_LOG_LEVEL = LogLevel::LogLevel_None; VERBOSE << "Checking data after first iteration..." << std::endl; EXPECT_EQ(region1->getParameterInt32("position"), 0); diff --git a/src/test/unit/utils/RandomTest.cpp b/src/test/unit/utils/RandomTest.cpp index 90663ce045..01e7972d06 100644 --- a/src/test/unit/utils/RandomTest.cpp +++ b/src/test/unit/utils/RandomTest.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include @@ -315,7 +315,7 @@ TEST(RandomTest, Sampling) { { // nChoices > nPopulation - EXPECT_THROW(r.sample(population, 5), LoggingException) << "checking for exception from population too small"; + EXPECT_THROW(r.sample(population, 5), Exception) << "checking for exception from population too small"; } }