From 1c4f9dd03096c644081373f7c969c25b30af403a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 28 Feb 2024 20:56:28 +0100 Subject: [PATCH 01/13] Add gmock dependency to tests #44 --- .circleci/config.yml | 2 +- Tests/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b5756e3..23e13a1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -81,7 +81,7 @@ jobs: name: Install dependencies command: | sudo apt-get update - sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev + sudo apt-get -y install libgtest-dev libgmock-dev libcurl4-openssl-dev libboost-dev - run: name: "Build" command: "make" diff --git a/Tests/Makefile b/Tests/Makefile index d3b30bb..c31eb4c 100644 --- a/Tests/Makefile +++ b/Tests/Makefile @@ -3,7 +3,7 @@ OBJS = $(SRCS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) dstargateway_tests: ../VersionInfo/GitVersion.h $(OBJS) ../APRS/APRS.a ../IRCDDB/IRCDDB.a ../DStarBase/DStarBase.a ../BaseCommon/BaseCommon.a ../Common/Common.a - $(CC) $(CPPFLAGS) -o dstargateway_tests $(OBJS) ../Common/Common.a ../APRS/APRS.a ../DStarBase/DStarBase.a ../IRCDDB/IRCDDB.a ../BaseCommon/BaseCommon.a $(LDFLAGS) -lgtest -lgtest_main + $(CC) $(CPPFLAGS) -o dstargateway_tests $(OBJS) ../Common/Common.a ../APRS/APRS.a ../DStarBase/DStarBase.a ../IRCDDB/IRCDDB.a ../BaseCommon/BaseCommon.a $(LDFLAGS) -lgtest -lgtest_main -lgmock %.o : %.cpp $(CC) $(CPPFLAGS) -DUNIT_TESTS -I../APRS -I../Common -I../BaseCommon -I../DStarBase -I../IRCDDB -I../VersionInfo -MMD -MD -c $< -o $@ From 72ae922a1ce821f980f96628f6a65b69234c443c Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 28 Feb 2024 20:57:19 +0100 Subject: [PATCH 02/13] change buidl task to tests #44 --- .vscode/tasks.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 6d6532b..9f00615 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -13,10 +13,7 @@ "USE_GPSD=1", "all" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] }, { @@ -94,7 +91,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] } ] From 5fb1c0286622129f9d510a3c28f96b80af11dfd6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 28 Feb 2024 21:02:09 +0100 Subject: [PATCH 03/13] Add log limiting #44 --- BaseCommon/Log.cpp | 3 +++ BaseCommon/Log.h | 41 +++++++++++++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/BaseCommon/Log.cpp b/BaseCommon/Log.cpp index 689e69f..dd702ad 100644 --- a/BaseCommon/Log.cpp +++ b/BaseCommon/Log.cpp @@ -27,6 +27,9 @@ bool CLog::m_addedTargets(false); std::recursive_mutex CLog::m_targetsMutex; std::vector CLog::m_targets = { new CLogConsoleTarget(LOG_DEBUG) }; +std::string CLog::m_prevMsg = ""; +int CLog::m_prevMsgCount = 0; + void CLog::addTarget(CLogTarget* target) { diff --git a/BaseCommon/Log.h b/BaseCommon/Log.h index e2afcc1..82f6313 100644 --- a/BaseCommon/Log.h +++ b/BaseCommon/Log.h @@ -35,6 +35,8 @@ private: static std::vector m_targets; static bool m_addedTargets; static std::recursive_mutex m_targetsMutex; + static std::string m_prevMsg; + static int m_prevMsgCount; static void getTimeStamp(std::string& s); @@ -68,12 +70,9 @@ private: break; } - std::string timestamp; - getTimeStamp(timestamp); - - std::string f2("[%s] [%s] "); + std::string f2("[%s] "); f2.append(f); - CStringUtils::string_format_in_place(output, f2, timestamp.c_str(), severityStr.c_str(), args...); + CStringUtils::string_format_in_place(output, f2, severityStr.c_str(), args...); boost::trim_if(output, [](char c){ return c == '\n' || c == '\r' || c == ' ' || c == '\t'; }); output.push_back('\n'); } @@ -117,15 +116,37 @@ public: { std::lock_guard lockTarget(m_targetsMutex); + if(m_targets.empty()) + return; + + std::string timestamp; + getTimeStamp(timestamp); + std::string msg; - for(auto target : m_targets) { - if(severity >= target->getLevel()) { + formatLogMessage(msg, severity, f, args...); - if(msg.empty()) - formatLogMessage(msg, severity, f, args...); + if(msg.compare(m_prevMsg) == 0) { + m_prevMsgCount++; + return; + } + else if(m_prevMsgCount != 0) { + formatLogMessage(msg, severity, "Previous message repeated %d times", m_prevMsgCount); + } + + m_prevMsg.assign(msg); + + std::string msgts; + CStringUtils::string_format_in_place(msgts, "[%s] %s", timestamp.c_str(), msg.c_str()); - target->printLog(msg); + for(auto target : m_targets) { + if(severity >= target->getLevel()) { + target->printLog(msgts); } } + + if(m_prevMsgCount != 0) { + m_prevMsgCount = 0; + log(severity, f, args ...); + } } }; From 99644004a8461edaf7471f994e0df58a9d3cdc36 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 28 Feb 2024 21:02:29 +0100 Subject: [PATCH 04/13] Add some tests for logging #44 --- Tests/Log/FakeLogTarget.h | 40 +++++++++++++++++ Tests/Log/logError.cpp | 94 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 Tests/Log/FakeLogTarget.h create mode 100644 Tests/Log/logError.cpp diff --git a/Tests/Log/FakeLogTarget.h b/Tests/Log/FakeLogTarget.h new file mode 100644 index 0000000..6e71ad9 --- /dev/null +++ b/Tests/Log/FakeLogTarget.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021-2024 by Geoffrey Merck F4FXL / KC3FRA + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#include "LogTarget.h" + +class CFakeLogTarget : public CLogTarget +{ +public: + CFakeLogTarget(LOG_SEVERITY logLevel) : + CLogTarget(logLevel) + { + + } + + virtual void printLogInt(const std::string& msg) + { + m_messages.push_back(msg); + std::cout << msg; + } + + std::vector m_messages; +}; \ No newline at end of file diff --git a/Tests/Log/logError.cpp b/Tests/Log/logError.cpp new file mode 100644 index 0000000..feda3a5 --- /dev/null +++ b/Tests/Log/logError.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2021-2024 by Geoffrey Merck F4FXL / KC3FRA + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#include "Log.h" +#include "LogSeverity.h" +#include "FakeLogTarget.h" + +using ::testing::EndsWith; + +namespace LogErrorTests +{ + class Log_logError: public ::testing::Test { + protected: + CFakeLogTarget * m_logTarget; + + void SetUp() override + { + m_logTarget = new CFakeLogTarget(LOG_ERROR); + CLog::addTarget((CLogTarget *)m_logTarget); + } + + void TearDown() override + { + CLog::finalise(); + } + }; + + TEST_F(Log_logError, OneMessage) { + CLog::logError("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + } + + TEST_F(Log_logError, WrongLevel) { + CLog::logDebug("One Message"); + + EXPECT_EQ(0, m_logTarget->m_messages.size()) << "There should be no message in the log."; + } + + TEST_F(Log_logError, TwoMessage) { + CLog::logError("One Message"); + CLog::logError("Two Message"); + + EXPECT_EQ(2, m_logTarget->m_messages.size()) << "There should be exactly two message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + EXPECT_THAT(m_logTarget->m_messages[1].c_str(), EndsWith("[ERROR ] Two Message\n")); + } + + TEST_F(Log_logError, ThreeIdenticalMessage) { + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + } + + TEST_F(Log_logError, ThreeIdenticalMessageOneDifferent) { + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("Another Message"); + + EXPECT_EQ(3, m_logTarget->m_messages.size()) << "There should be two message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + EXPECT_THAT(m_logTarget->m_messages[1].c_str(), EndsWith("[ERROR ] Previous message repeated 8 times\n")); + EXPECT_THAT(m_logTarget->m_messages[2].c_str(), EndsWith("[ERROR ] Another Message\n")); + } +} \ No newline at end of file From 0cf1384aea5e5b8b77211cc973a89318bbcc09e0 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 28 Feb 2024 21:08:33 +0100 Subject: [PATCH 05/13] Add missing dependency to CI #44 --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 23e13a1..9fc7ca8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,7 +18,7 @@ jobs: name: Install dependencies command: | sudo apt-get update - sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev libgps-dev + sudo apt-get -y install libgtest-dev libgmock-dev libcurl4-openssl-dev libboost-dev libgps-dev - run: name: "Build" command: "make ENABLE_DEBUG=1 USE_GPSD=1" @@ -39,7 +39,7 @@ jobs: name: Install dependencies command: | sudo apt-get update - sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev libgps-dev + sudo apt-get -y install libgtest-dev libgmock-dev libcurl4-openssl-dev libboost-dev libgps-dev - run: name: "Build" command: "make USE_GPSD=1" @@ -60,7 +60,7 @@ jobs: name: Install dependencies command: | sudo apt-get update - sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev + sudo apt-get -y install libgtest-dev libgmock-dev libcurl4-openssl-dev libboost-dev - run: name: "Build" command: "make ENABLE_DEBUG=1" From d488e51cc8460e1571077eb4f1f106ca918fb525 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 28 Feb 2024 21:13:02 +0100 Subject: [PATCH 06/13] Correct test name #44 --- Tests/Log/logError.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Log/logError.cpp b/Tests/Log/logError.cpp index feda3a5..f2c7da8 100644 --- a/Tests/Log/logError.cpp +++ b/Tests/Log/logError.cpp @@ -74,7 +74,7 @@ namespace LogErrorTests EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); } - TEST_F(Log_logError, ThreeIdenticalMessageOneDifferent) { + TEST_F(Log_logError, NineIdenticalMessageOneDifferent) { CLog::logError("One Message"); CLog::logError("One Message"); CLog::logError("One Message"); From 42d8c1ec1350653b2752ca04cfa641905a4814b7 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 28 Feb 2024 21:26:06 +0100 Subject: [PATCH 07/13] Clean up prev message variables #44 --- BaseCommon/Log.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BaseCommon/Log.cpp b/BaseCommon/Log.cpp index dd702ad..7a91e5f 100644 --- a/BaseCommon/Log.cpp +++ b/BaseCommon/Log.cpp @@ -54,6 +54,8 @@ void CLog::finalise() } m_targets.clear(); + m_prevMsg.clear(); + m_prevMsgCount = 0; } void CLog::getTimeStamp(std::string & s) From fcb4f338313595546fd70fee36546e7f72a7e1b2 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 29 Feb 2024 20:20:06 +0100 Subject: [PATCH 08/13] Reorganize tests #44 --- Tests/Log/logDebug.cpp | 79 +++++++++++++++++++++++++++++++++++++++ Tests/Log/logError.cpp | 40 ++++++-------------- Tests/Log/logInfo.cpp | 78 ++++++++++++++++++++++++++++++++++++++ Tests/Log/logRepeat.cpp | 81 ++++++++++++++++++++++++++++++++++++++++ Tests/Log/logTrace.cpp | 80 +++++++++++++++++++++++++++++++++++++++ Tests/Log/logWarning.cpp | 77 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 406 insertions(+), 29 deletions(-) create mode 100644 Tests/Log/logDebug.cpp create mode 100644 Tests/Log/logInfo.cpp create mode 100644 Tests/Log/logRepeat.cpp create mode 100644 Tests/Log/logTrace.cpp create mode 100644 Tests/Log/logWarning.cpp diff --git a/Tests/Log/logDebug.cpp b/Tests/Log/logDebug.cpp new file mode 100644 index 0000000..2c751e2 --- /dev/null +++ b/Tests/Log/logDebug.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021-2024 by Geoffrey Merck F4FXL / KC3FRA + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#include "Log.h" +#include "LogSeverity.h" +#include "FakeLogTarget.h" + +using ::testing::EndsWith; + +namespace LogDebugTests +{ + class Log_logDebug: public ::testing::Test { + protected: + CFakeLogTarget * m_logTarget; + + void SetUp() override + { + m_logTarget = new CFakeLogTarget(LOG_DEBUG); + CLog::addTarget((CLogTarget *)m_logTarget); + } + + void TearDown() override + { + CLog::finalise(); + } + }; + + TEST_F(Log_logDebug, PutError) { + CLog::logError("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + } + + TEST_F(Log_logDebug, PutDebug) { + CLog::logDebug("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be no message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[DEBUG ] One Message\n")); + } + + TEST_F(Log_logDebug, PutInfo) { + CLog::logInfo("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be no message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[INFO ] One Message\n")); + } + + TEST_F(Log_logDebug, PutWarning) { + CLog::logWarning("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[WARNING] One Message\n")); + } + + TEST_F(Log_logDebug, PutTrace) { + CLog::logTrace("One Message"); + + EXPECT_EQ(0, m_logTarget->m_messages.size()) << "There should be no message in the log."; + } +} \ No newline at end of file diff --git a/Tests/Log/logError.cpp b/Tests/Log/logError.cpp index f2c7da8..2c5fa3e 100644 --- a/Tests/Log/logError.cpp +++ b/Tests/Log/logError.cpp @@ -43,52 +43,34 @@ namespace LogErrorTests } }; - TEST_F(Log_logError, OneMessage) { + TEST_F(Log_logError, PutError) { CLog::logError("One Message"); EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); } - TEST_F(Log_logError, WrongLevel) { + TEST_F(Log_logError, PutDebug) { CLog::logDebug("One Message"); EXPECT_EQ(0, m_logTarget->m_messages.size()) << "There should be no message in the log."; } - TEST_F(Log_logError, TwoMessage) { - CLog::logError("One Message"); - CLog::logError("Two Message"); + TEST_F(Log_logError, PutInfo) { + CLog::logInfo("One Message"); - EXPECT_EQ(2, m_logTarget->m_messages.size()) << "There should be exactly two message in the log."; - EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); - EXPECT_THAT(m_logTarget->m_messages[1].c_str(), EndsWith("[ERROR ] Two Message\n")); + EXPECT_EQ(0, m_logTarget->m_messages.size()) << "There should be no message in the log."; } - TEST_F(Log_logError, ThreeIdenticalMessage) { - CLog::logError("One Message"); - CLog::logError("One Message"); - CLog::logError("One Message"); + TEST_F(Log_logError, PutWarning) { + CLog::logWarning("One Message"); - EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; - EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + EXPECT_EQ(0, m_logTarget->m_messages.size()) << "There should be no message in the log."; } - TEST_F(Log_logError, NineIdenticalMessageOneDifferent) { - CLog::logError("One Message"); - CLog::logError("One Message"); - CLog::logError("One Message"); - CLog::logError("One Message"); - CLog::logError("One Message"); - CLog::logError("One Message"); - CLog::logError("One Message"); - CLog::logError("One Message"); - CLog::logError("One Message"); - CLog::logError("Another Message"); + TEST_F(Log_logError, PutTrace) { + CLog::logTrace("One Message"); - EXPECT_EQ(3, m_logTarget->m_messages.size()) << "There should be two message in the log."; - EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); - EXPECT_THAT(m_logTarget->m_messages[1].c_str(), EndsWith("[ERROR ] Previous message repeated 8 times\n")); - EXPECT_THAT(m_logTarget->m_messages[2].c_str(), EndsWith("[ERROR ] Another Message\n")); + EXPECT_EQ(0, m_logTarget->m_messages.size()) << "There should be no message in the log."; } } \ No newline at end of file diff --git a/Tests/Log/logInfo.cpp b/Tests/Log/logInfo.cpp new file mode 100644 index 0000000..96f28fd --- /dev/null +++ b/Tests/Log/logInfo.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2021-2024 by Geoffrey Merck F4FXL / KC3FRA + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#include "Log.h" +#include "LogSeverity.h" +#include "FakeLogTarget.h" + +using ::testing::EndsWith; + +namespace LogInfoTests +{ + class Log_logInfo: public ::testing::Test { + protected: + CFakeLogTarget * m_logTarget; + + void SetUp() override + { + m_logTarget = new CFakeLogTarget(LOG_INFO); + CLog::addTarget((CLogTarget *)m_logTarget); + } + + void TearDown() override + { + CLog::finalise(); + } + }; + + TEST_F(Log_logInfo, PutError) { + CLog::logError("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + } + + TEST_F(Log_logInfo, PutDebug) { + CLog::logDebug("One Message"); + + EXPECT_EQ(0, m_logTarget->m_messages.size()) << "There should be no message in the log."; + } + + TEST_F(Log_logInfo, PutInfo) { + CLog::logInfo("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[INFO ] One Message\n")); + } + + TEST_F(Log_logInfo, PutWarning) { + CLog::logWarning("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[WARNING] One Message\n")); + } + + TEST_F(Log_logInfo, PutTrace) { + CLog::logTrace("One Message"); + + EXPECT_EQ(0, m_logTarget->m_messages.size()) << "There should be no message in the log."; + } +} \ No newline at end of file diff --git a/Tests/Log/logRepeat.cpp b/Tests/Log/logRepeat.cpp new file mode 100644 index 0000000..23ec4c9 --- /dev/null +++ b/Tests/Log/logRepeat.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021-2024 by Geoffrey Merck F4FXL / KC3FRA + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#include "Log.h" +#include "LogSeverity.h" +#include "FakeLogTarget.h" + +using ::testing::EndsWith; + +namespace LogRepeatTests +{ + class LogRepeat: public ::testing::Test { + protected: + CFakeLogTarget * m_logTarget; + + void SetUp() override + { + m_logTarget = new CFakeLogTarget(LOG_ERROR); + CLog::addTarget((CLogTarget *)m_logTarget); + } + + void TearDown() override + { + CLog::finalise(); + } + }; + + TEST_F(LogRepeat, TwoMessage) { + CLog::logError("One Message"); + CLog::logError("Two Message"); + + EXPECT_EQ(2, m_logTarget->m_messages.size()) << "There should be exactly two message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + EXPECT_THAT(m_logTarget->m_messages[1].c_str(), EndsWith("[ERROR ] Two Message\n")); + } + + TEST_F(LogRepeat, ThreeIdenticalMessage) { + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + } + + TEST_F(LogRepeat, NineIdenticalMessageOneDifferent) { + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("Another Message"); + + EXPECT_EQ(3, m_logTarget->m_messages.size()) << "There should be two message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + EXPECT_THAT(m_logTarget->m_messages[1].c_str(), EndsWith("[ERROR ] Previous message repeated 8 times\n")); + EXPECT_THAT(m_logTarget->m_messages[2].c_str(), EndsWith("[ERROR ] Another Message\n")); + } +} \ No newline at end of file diff --git a/Tests/Log/logTrace.cpp b/Tests/Log/logTrace.cpp new file mode 100644 index 0000000..4b725bb --- /dev/null +++ b/Tests/Log/logTrace.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021-2024 by Geoffrey Merck F4FXL / KC3FRA + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#include "Log.h" +#include "LogSeverity.h" +#include "FakeLogTarget.h" + +using ::testing::EndsWith; + +namespace LogTraceTests +{ + class Log_logTrace: public ::testing::Test { + protected: + CFakeLogTarget * m_logTarget; + + void SetUp() override + { + m_logTarget = new CFakeLogTarget(LOG_TRACE); + CLog::addTarget((CLogTarget *)m_logTarget); + } + + void TearDown() override + { + CLog::finalise(); + } + }; + + TEST_F(Log_logTrace, PutError) { + CLog::logError("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + } + + TEST_F(Log_logTrace, PutDebug) { + CLog::logDebug("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[DEBUG ] One Message\n")); + } + + TEST_F(Log_logTrace, PutInfo) { + CLog::logInfo("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[INFO ] One Message\n")); + } + + TEST_F(Log_logTrace, PutWarning) { + CLog::logWarning("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[WARNING] One Message\n")); + } + + TEST_F(Log_logTrace, PutTrace) { + CLog::logTrace("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[TRACE ] One Message\n")); + } +} \ No newline at end of file diff --git a/Tests/Log/logWarning.cpp b/Tests/Log/logWarning.cpp new file mode 100644 index 0000000..62938d0 --- /dev/null +++ b/Tests/Log/logWarning.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2021-2024 by Geoffrey Merck F4FXL / KC3FRA + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#include "Log.h" +#include "LogSeverity.h" +#include "FakeLogTarget.h" + +using ::testing::EndsWith; + +namespace LogWarningTests +{ + class Log_logWarning: public ::testing::Test { + protected: + CFakeLogTarget * m_logTarget; + + void SetUp() override + { + m_logTarget = new CFakeLogTarget(LOG_WARNING); + CLog::addTarget((CLogTarget *)m_logTarget); + } + + void TearDown() override + { + CLog::finalise(); + } + }; + + TEST_F(Log_logWarning, PutError) { + CLog::logError("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + } + + TEST_F(Log_logWarning, PutDebug) { + CLog::logDebug("One Message"); + + EXPECT_EQ(0, m_logTarget->m_messages.size()) << "There should be no message in the log."; + } + + TEST_F(Log_logWarning, PutInfo) { + CLog::logInfo("One Message"); + + EXPECT_EQ(0, m_logTarget->m_messages.size()) << "There should be no message in the log."; + } + + TEST_F(Log_logWarning, PutWarning) { + CLog::logWarning("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be one message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[WARNING] One Message\n")); + } + + TEST_F(Log_logWarning, PutTrace) { + CLog::logTrace("One Message"); + + EXPECT_EQ(0, m_logTarget->m_messages.size()) << "There should be no message in the log."; + } +} \ No newline at end of file From 6f7a65ee612a10f56aae2e3e71ffeb22a56f7204 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 3 Mar 2024 18:47:08 +0100 Subject: [PATCH 09/13] Made repeat thrshold settable #44 --- BaseCommon/Log.cpp | 8 ++++++- BaseCommon/Log.h | 29 ++++++++++++++----------- Tests/Log/logRepeat.cpp | 48 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 67 insertions(+), 18 deletions(-) diff --git a/BaseCommon/Log.cpp b/BaseCommon/Log.cpp index 7a91e5f..2007d7f 100644 --- a/BaseCommon/Log.cpp +++ b/BaseCommon/Log.cpp @@ -28,7 +28,8 @@ bool CLog::m_addedTargets(false); std::recursive_mutex CLog::m_targetsMutex; std::vector CLog::m_targets = { new CLogConsoleTarget(LOG_DEBUG) }; std::string CLog::m_prevMsg = ""; -int CLog::m_prevMsgCount = 0; +uint CLog::m_prevMsgCount = 0U; +uint CLog::m_repeatThreshold = 1U; void CLog::addTarget(CLogTarget* target) @@ -58,6 +59,11 @@ void CLog::finalise() m_prevMsgCount = 0; } +uint& CLog::getRepeatThreshold() +{ + return CLog::m_repeatThreshold; +} + void CLog::getTimeStamp(std::string & s) { std::time_t now= std::time(0); diff --git a/BaseCommon/Log.h b/BaseCommon/Log.h index 82f6313..7bf9638 100644 --- a/BaseCommon/Log.h +++ b/BaseCommon/Log.h @@ -36,7 +36,8 @@ private: static bool m_addedTargets; static std::recursive_mutex m_targetsMutex; static std::string m_prevMsg; - static int m_prevMsgCount; + static uint m_prevMsgCount; + static uint m_repeatThreshold; static void getTimeStamp(std::string& s); @@ -78,9 +79,9 @@ private: } public: - static void addTarget(CLogTarget * target); static void finalise(); + static uint& getRepeatThreshold(); template static void logTrace(const std::string & f, Args... args) { @@ -119,22 +120,26 @@ public: if(m_targets.empty()) return; - std::string timestamp; - getTimeStamp(timestamp); - std::string msg; formatLogMessage(msg, severity, f, args...); - if(msg.compare(m_prevMsg) == 0) { + bool repeatedMsg = (msg.compare(m_prevMsg) == 0); + + if(repeatedMsg && m_repeatThreshold > 0U) { m_prevMsgCount++; - return; - } - else if(m_prevMsgCount != 0) { - formatLogMessage(msg, severity, "Previous message repeated %d times", m_prevMsgCount); + if(m_prevMsgCount >= m_repeatThreshold) + return; } - + m_prevMsg.assign(msg); + if(m_prevMsgCount >= m_repeatThreshold && !repeatedMsg && m_repeatThreshold > 0U) { + formatLogMessage(msg, severity, "Previous message repeated %d times", m_prevMsgCount - m_repeatThreshold + 1); + m_prevMsg.clear(); + } + + std::string timestamp; + getTimeStamp(timestamp); std::string msgts; CStringUtils::string_format_in_place(msgts, "[%s] %s", timestamp.c_str(), msg.c_str()); @@ -144,7 +149,7 @@ public: } } - if(m_prevMsgCount != 0) { + if(m_prevMsgCount != 0 && !repeatedMsg) { m_prevMsgCount = 0; log(severity, f, args ...); } diff --git a/Tests/Log/logRepeat.cpp b/Tests/Log/logRepeat.cpp index 23ec4c9..c67d459 100644 --- a/Tests/Log/logRepeat.cpp +++ b/Tests/Log/logRepeat.cpp @@ -43,16 +43,17 @@ namespace LogRepeatTests } }; - TEST_F(LogRepeat, TwoMessage) { + TEST_F(LogRepeat, TwoMessage) { CLog::logError("One Message"); CLog::logError("Two Message"); - EXPECT_EQ(2, m_logTarget->m_messages.size()) << "There should be exactly two message in the log."; + EXPECT_EQ(2, m_logTarget->m_messages.size()) << "There should be exactly two messages in the log."; EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); EXPECT_THAT(m_logTarget->m_messages[1].c_str(), EndsWith("[ERROR ] Two Message\n")); } - TEST_F(LogRepeat, ThreeIdenticalMessage) { + TEST_F(LogRepeat, ThreeIdenticalMessageThreshold1) { + CLog::getRepeatThreshold() = 1U; CLog::logError("One Message"); CLog::logError("One Message"); CLog::logError("One Message"); @@ -61,7 +62,8 @@ namespace LogRepeatTests EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); } - TEST_F(LogRepeat, NineIdenticalMessageOneDifferent) { + TEST_F(LogRepeat, NineIdenticalMessageTwoDifferentThreshold1) { + CLog::getRepeatThreshold() = 1U; CLog::logError("One Message"); CLog::logError("One Message"); CLog::logError("One Message"); @@ -72,10 +74,46 @@ namespace LogRepeatTests CLog::logError("One Message"); CLog::logError("One Message"); CLog::logError("Another Message"); + CLog::logError("And here is another Message"); - EXPECT_EQ(3, m_logTarget->m_messages.size()) << "There should be two message in the log."; + EXPECT_EQ(4, m_logTarget->m_messages.size()) << "There should be two message in the log."; EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); EXPECT_THAT(m_logTarget->m_messages[1].c_str(), EndsWith("[ERROR ] Previous message repeated 8 times\n")); EXPECT_THAT(m_logTarget->m_messages[2].c_str(), EndsWith("[ERROR ] Another Message\n")); + EXPECT_THAT(m_logTarget->m_messages[3].c_str(), EndsWith("[ERROR ] And here is another Message\n")); + } + + + TEST_F(LogRepeat, ThreeIdenticalMessageThreshold2) { + CLog::getRepeatThreshold() = 2U; + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + + EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be two messages in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + EXPECT_THAT(m_logTarget->m_messages[1].c_str(), EndsWith("[ERROR ] One Message\n")); + } + + TEST_F(LogRepeat, NineIdenticalMessageTwoDifferentThreshold2) { + CLog::getRepeatThreshold() = 2U; + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("One Message"); + CLog::logError("Another Message"); + CLog::logError("And here is another Message"); + + EXPECT_EQ(4, m_logTarget->m_messages.size()) << "There should be two message in the log."; + EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); + EXPECT_THAT(m_logTarget->m_messages[1].c_str(), EndsWith("[ERROR ] One Message\n")); + EXPECT_THAT(m_logTarget->m_messages[2].c_str(), EndsWith("[ERROR ] Previous message repeated 7 times\n")); + EXPECT_THAT(m_logTarget->m_messages[3].c_str(), EndsWith("[ERROR ] Another Message\n")); + EXPECT_THAT(m_logTarget->m_messages[4].c_str(), EndsWith("[ERROR ] And here is another Message\n")); } } \ No newline at end of file From 870ede0379d0a7fa6b1e63de00a4b202293d04ca Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 3 Mar 2024 20:23:11 +0100 Subject: [PATCH 10/13] change initial threshold to 2 #44 --- BaseCommon/Log.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BaseCommon/Log.cpp b/BaseCommon/Log.cpp index 2007d7f..6f749e1 100644 --- a/BaseCommon/Log.cpp +++ b/BaseCommon/Log.cpp @@ -29,7 +29,7 @@ std::recursive_mutex CLog::m_targetsMutex; std::vector CLog::m_targets = { new CLogConsoleTarget(LOG_DEBUG) }; std::string CLog::m_prevMsg = ""; uint CLog::m_prevMsgCount = 0U; -uint CLog::m_repeatThreshold = 1U; +uint CLog::m_repeatThreshold = 2U; void CLog::addTarget(CLogTarget* target) From dea92a20767d0515d1e98c7f669461402fb720f4 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 3 Mar 2024 20:26:29 +0100 Subject: [PATCH 11/13] Fix broken test #44 --- Tests/Log/logRepeat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Log/logRepeat.cpp b/Tests/Log/logRepeat.cpp index c67d459..99a6b8a 100644 --- a/Tests/Log/logRepeat.cpp +++ b/Tests/Log/logRepeat.cpp @@ -90,7 +90,7 @@ namespace LogRepeatTests CLog::logError("One Message"); CLog::logError("One Message"); - EXPECT_EQ(1, m_logTarget->m_messages.size()) << "There should be two messages in the log."; + EXPECT_EQ(2, m_logTarget->m_messages.size()) << "There should be two messages in the log."; EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); EXPECT_THAT(m_logTarget->m_messages[1].c_str(), EndsWith("[ERROR ] One Message\n")); } @@ -109,7 +109,7 @@ namespace LogRepeatTests CLog::logError("Another Message"); CLog::logError("And here is another Message"); - EXPECT_EQ(4, m_logTarget->m_messages.size()) << "There should be two message in the log."; + EXPECT_EQ(5, m_logTarget->m_messages.size()) << "There should be two message in the log."; EXPECT_THAT(m_logTarget->m_messages[0].c_str(), EndsWith("[ERROR ] One Message\n")); EXPECT_THAT(m_logTarget->m_messages[1].c_str(), EndsWith("[ERROR ] One Message\n")); EXPECT_THAT(m_logTarget->m_messages[2].c_str(), EndsWith("[ERROR ] Previous message repeated 7 times\n")); From b69c0e5fcb112a241e91c97e3aa49163356c79f6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 3 Mar 2024 20:27:40 +0100 Subject: [PATCH 12/13] Add repeat thrshold to log configuration #44 --- DStarGateway/DStarGatewayConfig.cpp | 5 +++++ DStarGateway/DStarGatewayConfig.h | 1 + DStarGateway/example.cfg | 1 + 3 files changed, 7 insertions(+) diff --git a/DStarGateway/DStarGatewayConfig.cpp b/DStarGateway/DStarGatewayConfig.cpp index 15b2028..da334be 100644 --- a/DStarGateway/DStarGatewayConfig.cpp +++ b/DStarGateway/DStarGatewayConfig.cpp @@ -181,6 +181,11 @@ bool CDStarGatewayConfig::loadLog(const CConfig & cfg) else if(levelStr == "none") m_log.displayLevel = LOG_NONE; } + std::string thresholdStr; + ret = cfg.getValue("log", "repeatthreshold", thresholdStr, "2", {"disabled", "1", "2", "3", "4","5", "6", "7", "8", "9", "10"}) && ret; + if(thresholdStr == "disabled") m_log.repeatThreshold = 0; + else m_log.repeatThreshold = ::atoi(thresholdStr.c_str()); + return ret; } diff --git a/DStarGateway/DStarGatewayConfig.h b/DStarGateway/DStarGatewayConfig.h index d148987..1a15d65 100644 --- a/DStarGateway/DStarGatewayConfig.h +++ b/DStarGateway/DStarGatewayConfig.h @@ -88,6 +88,7 @@ typedef struct { LOG_SEVERITY fileLevel; std::string fileRoot; bool fileRotate; + uint repeatThreshold; } TLog; typedef struct { diff --git a/DStarGateway/example.cfg b/DStarGateway/example.cfg index 731da4e..73d7b09 100644 --- a/DStarGateway/example.cfg +++ b/DStarGateway/example.cfg @@ -152,6 +152,7 @@ fileRoot= # defaults to dstarGateway fileRotate= # rotate log files daily, defaults to true fileLevel= # defaults to info, valid values are trace, debug, info, warning, error, fatal, none displayLevel= # defaults to info, valid values are trace, debug, info, warning, error, fatal, none +repeatThreshold=#defaults to 2, valid values are disbaled and 1 to 10. Prevents flooding of logs from repeated log messages. [Paths] data=/usr/local/share/dstargateway.d/ #Path where the data (hostfiles, audio files etc) can be found From 2b2fbfc7f608074d182079ab743ed68b00b72340 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 3 Mar 2024 20:34:42 +0100 Subject: [PATCH 13/13] Update readme #44 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b0470af..45fd43e 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ The testing framwework used is Google Test. # 5. Version History ## 5.1. Version 1.0 +- [**Improvement**] Limit log reporting ([#44](https://github.com/F4FXL/DStarGateway/issues/44)) - [**Improvement**] Improve CI to include all variants of build configurations ([#40](https://github.com/F4FXL/DStarGateway/issues/40)) - [**Bugfix**] Fix #43 Cache not updated when answering ircddb gateway is only conected to one network ([#43](https://github.com/F4FXL/DStarGateway/issues/43)) - [**Bugfix**] Fix #37 Unable to transmit multiple files (DGWVoiceTransmit) ([#37](https://github.com/F4FXL/DStarGateway/issues/37))