diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 06e781bc9..9448cd543 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -36,6 +36,7 @@ list (APPEND TEST_SOURCE_FILES tests/test_SimulationDataContainer.cpp tests/test_cmp.cpp tests/test_OpmLog.cpp + tests/test_messagelimiter.cpp ) list (APPEND TEST_DATA_FILES @@ -60,6 +61,7 @@ list( APPEND PUBLIC_HEADER_FILES opm/common/OpmLog/Logger.hpp opm/common/OpmLog/LogUtil.hpp opm/common/OpmLog/MessageFormatter.hpp + opm/common/OpmLog/MessageLimiter.hpp opm/common/OpmLog/OpmLog.hpp opm/common/OpmLog/StreamLog.hpp opm/common/OpmLog/TimerLog.hpp diff --git a/opm/common/OpmLog/LogBackend.hpp b/opm/common/OpmLog/LogBackend.hpp index acccfcf19..5d4036e03 100644 --- a/opm/common/OpmLog/LogBackend.hpp +++ b/opm/common/OpmLog/LogBackend.hpp @@ -22,6 +22,7 @@ #define OPM_LOGBACKEND_HPP #include +#include #include #include #include diff --git a/opm/common/OpmLog/MessageLimiter.hpp b/opm/common/OpmLog/MessageLimiter.hpp new file mode 100644 index 000000000..664f01ff9 --- /dev/null +++ b/opm/common/OpmLog/MessageLimiter.hpp @@ -0,0 +1,111 @@ +/* + Copyright 2016 SINTEF ICT, Applied Mathematics. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ + +#ifndef OPM_MESSAGELIMITER_HEADER_INCLUDED +#define OPM_MESSAGELIMITER_HEADER_INCLUDED + +#include +#include + +namespace Opm +{ + + + /// Handles limiting the number of messages with the same tag. + class MessageLimiter + { + public: + /// Used to indicate no message number limit. + enum { NoLimit = -1 }; + + /// Default constructor, no limit to the number of messages. + MessageLimiter() + : message_limit_(NoLimit) + { + } + + /// Construct with given limit to number of messages with the + /// same tag. + /// + /// Negative limits (including NoLimit) are interpreted as + /// NoLimit, but the default constructor is the preferred way + /// to obtain that behaviour. + explicit MessageLimiter(const int message_limit) + : message_limit_(message_limit < 0 ? NoLimit : message_limit) + { + } + + /// The message limit (same for all tags). + int messageLimit() const + { + return message_limit_; + } + + /// Used for encounteredMessage() return type (see that + /// function). + enum class Response + { + PrintMessage, JustOverLimit, OverLimit + }; + + /// If a tag is empty, there is no message limit or for that + /// tag (count <= limit), respond PrintMessage. + /// If (count == limit + 1), respond JustOverLimit. + /// If (count > limit + 1), respond OverLimit. + Response encounteredMessage(const std::string& tag) + { + if (tag.empty() || message_limit_ == NoLimit) { + return Response::PrintMessage; + } else { + // See if tag already encountered. + auto it = tag_counts_.find(tag); + if (it != tag_counts_.end()) { + // Already encountered this tag. Increment its count. + const int count = ++it->second; + return countBasedResponse(count); + } else { + // First encounter of this tag. Insert 1. + tag_counts_.insert({tag, 1}); + return countBasedResponse(1); + } + } + } + + private: + Response countBasedResponse(const int count) + { + if (count <= message_limit_) { + return Response::PrintMessage; + } else if (count == message_limit_ + 1) { + return Response::JustOverLimit; + } else { + return Response::OverLimit; + } + } + + + int message_limit_; + std::unordered_map tag_counts_; + }; + + + +} // namespace Opm + +#endif // OPM_MESSAGELIMITER_HEADER_INCLUDED diff --git a/tests/test_messagelimiter.cpp b/tests/test_messagelimiter.cpp new file mode 100644 index 000000000..c48048989 --- /dev/null +++ b/tests/test_messagelimiter.cpp @@ -0,0 +1,79 @@ +/* + Copyright 2016 SINTEF ICT, Applied Mathematics. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE MESSAGELIMITER_TESTS + +#include +#include +#include + +#include + + +using namespace Opm; + + +BOOST_AUTO_TEST_CASE(ConstructionAndLimits) +{ + MessageLimiter m1; + BOOST_CHECK_EQUAL(m1.messageLimit(), MessageLimiter::NoLimit); + MessageLimiter m2(0); + BOOST_CHECK_EQUAL(m2.messageLimit(), 0); + MessageLimiter m3(1); + BOOST_CHECK_EQUAL(m3.messageLimit(), 1); + MessageLimiter m4(-4); + BOOST_CHECK_EQUAL(m4.messageLimit(), MessageLimiter::NoLimit); +} + +BOOST_AUTO_TEST_CASE(Response) +{ + { + // No limits. + MessageLimiter m; + BOOST_CHECK(m.encounteredMessage("tag1") == MessageLimiter::Response::PrintMessage); + BOOST_CHECK(m.encounteredMessage("tag2") == MessageLimiter::Response::PrintMessage); + BOOST_CHECK(m.encounteredMessage("tag1") == MessageLimiter::Response::PrintMessage); + BOOST_CHECK(m.encounteredMessage("tag2") == MessageLimiter::Response::PrintMessage); + BOOST_CHECK(m.encounteredMessage("tag1") == MessageLimiter::Response::PrintMessage); + BOOST_CHECK(m.encounteredMessage("tag2") == MessageLimiter::Response::PrintMessage); + } + + { + // Limit == 0. + MessageLimiter m(0); + BOOST_CHECK(m.encounteredMessage("tag1") == MessageLimiter::Response::JustOverLimit); + BOOST_CHECK(m.encounteredMessage("tag2") == MessageLimiter::Response::JustOverLimit); + BOOST_CHECK(m.encounteredMessage("tag1") == MessageLimiter::Response::OverLimit); + BOOST_CHECK(m.encounteredMessage("tag2") == MessageLimiter::Response::OverLimit); + BOOST_CHECK(m.encounteredMessage("tag1") == MessageLimiter::Response::OverLimit); + BOOST_CHECK(m.encounteredMessage("tag2") == MessageLimiter::Response::OverLimit); + } + + { + // Limit == 1. + MessageLimiter m(1); + BOOST_CHECK(m.encounteredMessage("tag1") == MessageLimiter::Response::PrintMessage); + BOOST_CHECK(m.encounteredMessage("tag2") == MessageLimiter::Response::PrintMessage); + BOOST_CHECK(m.encounteredMessage("tag1") == MessageLimiter::Response::JustOverLimit); + BOOST_CHECK(m.encounteredMessage("tag2") == MessageLimiter::Response::JustOverLimit); + BOOST_CHECK(m.encounteredMessage("tag1") == MessageLimiter::Response::OverLimit); + BOOST_CHECK(m.encounteredMessage("tag2") == MessageLimiter::Response::OverLimit); + } +}