diff --git a/opm/common/OpmLog/CounterLog.cpp b/opm/common/OpmLog/CounterLog.cpp index e3b45770a..8e066486c 100644 --- a/opm/common/OpmLog/CounterLog.cpp +++ b/opm/common/OpmLog/CounterLog.cpp @@ -48,8 +48,8 @@ size_t CounterLog::numMessages(int64_t messageType) const { -void CounterLog::addMessage(int64_t messageType , const std::string& ) { - if (includeMessage( messageType )) +void CounterLog::addTaggedMessage(int64_t messageType, const std::string& messageTag, const std::string& ) { + if (includeMessage( messageType, messageTag )) m_count[messageType]++; } diff --git a/opm/common/OpmLog/CounterLog.hpp b/opm/common/OpmLog/CounterLog.hpp index 6313759e1..f9843558c 100644 --- a/opm/common/OpmLog/CounterLog.hpp +++ b/opm/common/OpmLog/CounterLog.hpp @@ -39,8 +39,9 @@ public: size_t numMessages(int64_t messageType) const; - void addMessage(int64_t messageFlag , - const std::string& message); + void addTaggedMessage(int64_t messageFlag, + const std::string& messageTag, + const std::string& message); void clear(); diff --git a/opm/common/OpmLog/EclipsePRTLog.cpp b/opm/common/OpmLog/EclipsePRTLog.cpp index 92ee7b8a9..db726e67b 100644 --- a/opm/common/OpmLog/EclipsePRTLog.cpp +++ b/opm/common/OpmLog/EclipsePRTLog.cpp @@ -23,9 +23,9 @@ namespace Opm { - void EclipsePRTLog::addMessage(int64_t messageType, const std::string& message) + void EclipsePRTLog::addTaggedMessage(int64_t messageType, const std::string& messageTag, const std::string& message) { - StreamLog::addMessage(messageType, message); + StreamLog::addTaggedMessage(messageType, messageTag, message); m_count[messageType]++; } @@ -53,7 +53,7 @@ namespace Opm { std::string("\nBugs " + std::to_string(numMessages(Log::MessageType::Bug))) + std::string("\nDebug " + std::to_string(numMessages(Log::MessageType::Debug))) + std::string("\nProblems " + std::to_string(numMessages(Log::MessageType::Problem))) +"\n"; - addMessage(Log::MessageType::Info, summary_msg); + StreamLog::addTaggedMessage(Log::MessageType::Info, "", summary_msg); } } diff --git a/opm/common/OpmLog/EclipsePRTLog.hpp b/opm/common/OpmLog/EclipsePRTLog.hpp index 5fbcba070..d4a7e42d3 100644 --- a/opm/common/OpmLog/EclipsePRTLog.hpp +++ b/opm/common/OpmLog/EclipsePRTLog.hpp @@ -31,7 +31,7 @@ class EclipsePRTLog : public StreamLog { public: using StreamLog::StreamLog; - void addMessage(int64_t messageType, const std::string& message); + void addTaggedMessage(int64_t messageType, const std::string& messageTag, const std::string& message); size_t numMessages(int64_t messageType) const; diff --git a/opm/common/OpmLog/LogBackend.cpp b/opm/common/OpmLog/LogBackend.cpp index e0e2c89eb..e8a5180d3 100644 --- a/opm/common/OpmLog/LogBackend.cpp +++ b/opm/common/OpmLog/LogBackend.cpp @@ -36,14 +36,40 @@ namespace Opm { m_formatter = formatter; } + void LogBackend::configureMessageLimiter(std::shared_ptr limiter) + { + m_limiter = limiter; + } + + void LogBackend::addMessage(int64_t messageFlag, const std::string& message) + { + // Forward the call to the tagged version. + addTaggedMessage(messageFlag, "", message); + } + int64_t LogBackend::getMask() const { return m_mask; } - bool LogBackend::includeMessage(int64_t messageFlag) + bool LogBackend::includeMessage(int64_t messageFlag, const std::string& messageTag) { - return ((messageFlag & m_mask) == messageFlag) && (messageFlag > 0); + // Check mask. + const bool included = ((messageFlag & m_mask) == messageFlag) && (messageFlag > 0); + if (!included) { + return false; + } + + // Use the message limiter (if any). + MessageLimiter::Response res = m_limiter + ? m_limiter->encounteredMessage(messageTag) + : MessageLimiter::Response::PrintMessage; + if (res == MessageLimiter::Response::JustOverLimit) { + // Special case: add a message to this backend about limit being reached. + std::string msg = "Message limit reached for message tag: " + messageTag; + addTaggedMessage(messageFlag, "", msg); + } + return res == MessageLimiter::Response::PrintMessage; } std::string LogBackend::decorateMessage(int64_t messageFlag, const std::string& message) diff --git a/opm/common/OpmLog/LogBackend.hpp b/opm/common/OpmLog/LogBackend.hpp index 5d4036e03..9a6888ae4 100644 --- a/opm/common/OpmLog/LogBackend.hpp +++ b/opm/common/OpmLog/LogBackend.hpp @@ -43,11 +43,22 @@ namespace Opm /// Configure how decorateMessage() will modify message strings. void configureDecoration(std::shared_ptr formatter); + /// Configure how message tags will be used to limit messages. + void configureMessageLimiter(std::shared_ptr limiter); + /// Add a message to the backend. /// /// Typically a subclass may filter, change, and output /// messages based on configuration and the messageFlag. - virtual void addMessage(int64_t messageFlag, const std::string& message) = 0; + void addMessage(int64_t messageFlag, const std::string& message); + + /// Add a tagged message to the backend. + /// + /// Typically a subclass may filter, change, and output + /// messages based on configuration and the messageFlag. + virtual void addTaggedMessage(int64_t messageFlag, + const std::string& messageTag, + const std::string& message) = 0; /// The message mask types are specified in the /// Opm::Log::MessageType namespace, in file LogUtils.hpp. @@ -55,7 +66,7 @@ namespace Opm protected: /// Return true if all bits of messageFlag are also set in our mask. - bool includeMessage(int64_t messageFlag); + bool includeMessage(int64_t messageFlag, const std::string& messageTag); /// Return decorated version of message depending on configureDecoration() arguments. std::string decorateMessage(int64_t messageFlag, const std::string& message); @@ -63,6 +74,7 @@ namespace Opm private: int64_t m_mask; std::shared_ptr m_formatter; + std::shared_ptr m_limiter; }; } // namespace LogBackend diff --git a/opm/common/OpmLog/Logger.cpp b/opm/common/OpmLog/Logger.cpp index 9a5d96ee7..e7cd511f6 100644 --- a/opm/common/OpmLog/Logger.cpp +++ b/opm/common/OpmLog/Logger.cpp @@ -38,6 +38,18 @@ namespace Opm { addMessageType( Log::MessageType::Bug , "bug"); } + void Logger::addTaggedMessage(int64_t messageType, const std::string& tag, const std::string& message) const { + if ((m_enabledTypes & messageType) == 0) + throw std::invalid_argument("Tried to issue message with unrecognized message ID"); + + if (m_globalMask & messageType) { + for (auto iter = m_backends.begin(); iter != m_backends.end(); ++iter) { + std::shared_ptr backend = (*iter).second; + backend->addTaggedMessage( messageType, tag, message ); + } + } + } + void Logger::addMessage(int64_t messageType , const std::string& message) const { if ((m_enabledTypes & messageType) == 0) throw std::invalid_argument("Tried to issue message with unrecognized message ID"); diff --git a/opm/common/OpmLog/Logger.hpp b/opm/common/OpmLog/Logger.hpp index cce33de02..341a4f4c5 100644 --- a/opm/common/OpmLog/Logger.hpp +++ b/opm/common/OpmLog/Logger.hpp @@ -35,6 +35,7 @@ class Logger { public: Logger(); void addMessage(int64_t messageType , const std::string& message) const; + void addTaggedMessage(int64_t messageType, const std::string& tag, const std::string& message) const; static bool enabledDefaultMessageType( int64_t messageType); bool enabledMessageType( int64_t messageType) const; diff --git a/opm/common/OpmLog/OpmLog.cpp b/opm/common/OpmLog/OpmLog.cpp index dd17b0ba4..5b110ed7a 100644 --- a/opm/common/OpmLog/OpmLog.cpp +++ b/opm/common/OpmLog/OpmLog.cpp @@ -37,6 +37,12 @@ namespace Opm { } + void OpmLog::addTaggedMessage(int64_t messageFlag, const std::string& tag, const std::string& message) { + if (m_logger) + m_logger->addTaggedMessage( messageFlag, tag, message ); + } + + void OpmLog::info(const std::string& message) { addMessage(Log::MessageType::Info, message); @@ -73,6 +79,45 @@ namespace Opm { } + + void OpmLog::info(const std::string& tag, const std::string& message) + { + addTaggedMessage(Log::MessageType::Info, tag, message); + } + + + void OpmLog::warning(const std::string& tag, const std::string& message) + { + addTaggedMessage(Log::MessageType::Warning, tag, message); + } + + + void OpmLog::problem(const std::string& tag, const std::string& message) + { + addTaggedMessage(Log::MessageType::Problem, tag, message); + } + + + void OpmLog::error(const std::string& tag, const std::string& message) + { + addTaggedMessage(Log::MessageType::Error, tag, message); + } + + + void OpmLog::bug(const std::string& tag, const std::string& message) + { + addTaggedMessage(Log::MessageType::Bug, tag, message); + } + + + void OpmLog::debug(const std::string& tag, const std::string& message) + { + addTaggedMessage(Log::MessageType::Debug, tag, message); + } + + + + bool OpmLog::enabledMessageType( int64_t messageType ) { if (m_logger) return m_logger->enabledMessageType( messageType ); diff --git a/opm/common/OpmLog/OpmLog.hpp b/opm/common/OpmLog/OpmLog.hpp index 15ffbd291..a0abe3cf2 100644 --- a/opm/common/OpmLog/OpmLog.hpp +++ b/opm/common/OpmLog/OpmLog.hpp @@ -40,6 +40,7 @@ class OpmLog { public: static void addMessage(int64_t messageFlag , const std::string& message); + static void addTaggedMessage(int64_t messageFlag, const std::string& tag, const std::string& message); static void info(const std::string& message); static void warning(const std::string& message); @@ -47,6 +48,14 @@ public: static void problem(const std::string& message); static void bug(const std::string& message); static void debug(const std::string& message); + + static void info(const std::string& tag, const std::string& message); + static void warning(const std::string& tag, const std::string& message); + static void error(const std::string& tag, const std::string& message); + static void problem(const std::string& tag, const std::string& message); + static void bug(const std::string& tag, const std::string& message); + static void debug(const std::string& tag, const std::string& message); + static bool hasBackend( const std::string& backendName ); static void addBackend(const std::string& name , std::shared_ptr backend); static bool removeBackend(const std::string& name); diff --git a/opm/common/OpmLog/StreamLog.cpp b/opm/common/OpmLog/StreamLog.cpp index eee7d25fe..fb1809a6e 100644 --- a/opm/common/OpmLog/StreamLog.cpp +++ b/opm/common/OpmLog/StreamLog.cpp @@ -44,12 +44,12 @@ void StreamLog::close() { } } -void StreamLog::addMessage(int64_t messageType , const std::string& message) { - if (includeMessage( messageType )) { +void StreamLog::addTaggedMessage(int64_t messageType, const std::string& messageTag, const std::string& message) { + if (includeMessage( messageType, messageTag )) { (*m_ostream) << decorateMessage(messageType, message) << std::endl; - - if (m_ofstream.is_open()) + if (m_ofstream.is_open()) { m_ofstream.flush(); + } } } diff --git a/opm/common/OpmLog/StreamLog.hpp b/opm/common/OpmLog/StreamLog.hpp index 378d337a1..fc6c5467f 100644 --- a/opm/common/OpmLog/StreamLog.hpp +++ b/opm/common/OpmLog/StreamLog.hpp @@ -33,7 +33,7 @@ class StreamLog : public LogBackend { public: StreamLog(const std::string& logFile , int64_t messageMask); StreamLog(std::ostream& os , int64_t messageMask); - void addMessage(int64_t messageType , const std::string& message); + virtual void addTaggedMessage(int64_t messageType, const std::string& messageTag, const std::string& message) override; ~StreamLog(); private: diff --git a/opm/common/OpmLog/TimerLog.cpp b/opm/common/OpmLog/TimerLog.cpp index c011ce801..8faf279b5 100644 --- a/opm/common/OpmLog/TimerLog.cpp +++ b/opm/common/OpmLog/TimerLog.cpp @@ -41,14 +41,14 @@ TimerLog::TimerLog(std::ostream& os) : StreamLog( os , StopTimer | StartTimer ) -void TimerLog::addMessage(int64_t messageType , const std::string& msg ) { +void TimerLog::addTaggedMessage(int64_t messageType, const std::string& messageTag, const std::string& msg ) { if (messageType == StopTimer) { clock_t stop = clock(); double secondsElapsed = 1.0 * (m_start - stop) / CLOCKS_PER_SEC ; m_work.str(""); m_work << std::fixed << msg << ": " << secondsElapsed << " seconds "; - StreamLog::addMessage( messageType , m_work.str()); + StreamLog::addTaggedMessage( messageType, messageTag, m_work.str()); } else { if (messageType == StartTimer) m_start = clock(); diff --git a/opm/common/OpmLog/TimerLog.hpp b/opm/common/OpmLog/TimerLog.hpp index cc1a65162..bfbf5fe8e 100644 --- a/opm/common/OpmLog/TimerLog.hpp +++ b/opm/common/OpmLog/TimerLog.hpp @@ -42,8 +42,9 @@ public: TimerLog(const std::string& logFile); TimerLog(std::ostream& os); - void addMessage(int64_t messageFlag , - const std::string& message); + void addTaggedMessage(int64_t messageFlag, + const std::string& messageTag, + const std::string& message) override; void clear(); ~TimerLog() {}; diff --git a/tests/test_OpmLog.cpp b/tests/test_OpmLog.cpp index abb009832..be63479c7 100644 --- a/tests/test_OpmLog.cpp +++ b/tests/test_OpmLog.cpp @@ -118,7 +118,7 @@ public: m_specialMessages = 0; } - void addMessage(int64_t messageType , const std::string& /* message */) { + void addTaggedMessage(int64_t messageType , const std::string& /* messageTag */, const std::string& /* message */) { if (messageType & Log::DefaultMessageTypes) m_defaultMessages +=1; else @@ -303,3 +303,59 @@ BOOST_AUTO_TEST_CASE(TestOpmLogWithColors) std::cout << log_stream.str() << std::endl; } + + + + +BOOST_AUTO_TEST_CASE(TestOpmLogWithLimits) +{ + OpmLog::removeAllBackends(); + + std::ostringstream log_stream1; + std::ostringstream log_stream2; + + { + std::shared_ptr streamLog1 = std::make_shared(log_stream1, Log::DefaultMessageTypes); + std::shared_ptr streamLog2 = std::make_shared(log_stream2, Log::DefaultMessageTypes); + OpmLog::addBackend("STREAM1" , streamLog1); + OpmLog::addBackend("STREAM2" , streamLog2); + BOOST_CHECK_EQUAL( true , OpmLog::hasBackend("STREAM1")); + BOOST_CHECK_EQUAL( true , OpmLog::hasBackend("STREAM2")); + + streamLog1->configureDecoration(std::make_shared(false, true)); + streamLog1->configureMessageLimiter(std::make_shared(2)); + streamLog2->configureDecoration(std::make_shared(false, true)); + streamLog2->configureMessageLimiter(std::make_shared()); // no limit + } + + const std::string tag = "ExampleTag"; + OpmLog::warning(tag, "Warning"); + OpmLog::error("Error"); + OpmLog::info("Info"); + OpmLog::bug("Bug"); + OpmLog::warning(tag, "Warning"); + OpmLog::warning(tag, "Warning"); + OpmLog::warning(tag, "Warning"); + + const std::string expected1 = Log::colorCodeMessage(Log::MessageType::Warning, "Warning") + "\n" + + Log::colorCodeMessage(Log::MessageType::Error, "Error") + "\n" + + Log::colorCodeMessage(Log::MessageType::Info, "Info") + "\n" + + Log::colorCodeMessage(Log::MessageType::Bug, "Bug") + "\n" + + Log::colorCodeMessage(Log::MessageType::Warning, "Warning") + "\n" + + Log::colorCodeMessage(Log::MessageType::Warning, "Message limit reached for message tag: " + tag) + "\n"; + + BOOST_CHECK_EQUAL(log_stream1.str(), expected1); + + const std::string expected2 = Log::colorCodeMessage(Log::MessageType::Warning, "Warning") + "\n" + + Log::colorCodeMessage(Log::MessageType::Error, "Error") + "\n" + + Log::colorCodeMessage(Log::MessageType::Info, "Info") + "\n" + + Log::colorCodeMessage(Log::MessageType::Bug, "Bug") + "\n" + + Log::colorCodeMessage(Log::MessageType::Warning, "Warning") + "\n" + + Log::colorCodeMessage(Log::MessageType::Warning, "Warning") + "\n" + + Log::colorCodeMessage(Log::MessageType::Warning, "Warning") + "\n"; + + BOOST_CHECK_EQUAL(log_stream2.str(), expected2); + + std::cout << log_stream1.str() << std::endl; + std::cout << log_stream2.str() << std::endl; +}