Skip to content

Commit 804d242

Browse files
committed
[logger] Add option to plug an external logger
1 parent 339c5e5 commit 804d242

File tree

4 files changed

+178
-15
lines changed

4 files changed

+178
-15
lines changed

CMakeLists_Options.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ if(NOT DEFINED LOG_LEVEL)
88
endif()
99
add_compile_definitions(LOG_LEVEL=${LOG_LEVEL})
1010

11+
# Logger
12+
option(EXTERNAL_LOGGER "Use an external logger" OFF)
13+
if(EXTERNAL_LOGGER)
14+
add_compile_definitions(EXTERNAL_LOGGER=1)
15+
endif()
16+
1117
# Static library
1218
option(BUILD_STATIC_LIBRARY "Build Open OCPP as a static library" ON)
1319

src/tools/log/Logger.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,47 @@ void Logger::registerLogger(ocpp::database::Database& database, const std::strin
103103
}
104104
}
105105

106+
/** @brief External logging function */
107+
std::function<void(unsigned int, const std::string&)> ExtLogger::m_log_function = [](unsigned int level, const std::string& log_line)
108+
{
109+
// Default function if no external logger has been registered
110+
static std::mutex mutex;
111+
112+
std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
113+
std::lock_guard<std::mutex> lock(mutex);
114+
115+
std::tm now_tm;
116+
localtime_r(&now, &now_tm);
117+
LOG_OUTPUT << level << " - [" << std::put_time(&now_tm, "%Y-%m-%dT%T") << "] - " << log_line << std::endl;
118+
};
119+
120+
/** @brief Constructor */
121+
ExtLogger::ExtLogger(const char* level_str, unsigned int level, const char* filename, const char* line) : m_log_output(), m_level(level)
122+
{
123+
(void)level_str;
124+
m_log_output << filename << ":" << line << " - ";
125+
}
126+
127+
/** @brief Constructor */
128+
ExtLogger::ExtLogger(const char* name, const char* level_str, unsigned int level, const char* filename, const char* line)
129+
: m_log_output(), m_level(level)
130+
{
131+
(void)name;
132+
(void)level_str;
133+
m_log_output << filename << ":" << line << " - ";
134+
}
135+
136+
/** @brief Destructor */
137+
ExtLogger::~ExtLogger()
138+
{
139+
m_log_function(m_level, m_log_output.str());
140+
}
141+
142+
/** @brief Register an external logging function */
143+
void ExtLogger::registerLogFunction(std::function<void(unsigned int, const std::string&)> log_function)
144+
{
145+
m_log_function = log_function;
146+
}
147+
106148
} // namespace log
107149
} // namespace ocpp

src/tools/log/Logger.h

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
2121

2222
#include "FilenameMacro.h"
2323

24+
#include <functional>
2425
#include <map>
2526
#include <memory>
2627
#include <sstream>
@@ -61,6 +62,23 @@ class LogDatabase;
6162
#define LOG_LEVEL 2
6263
#endif // LOG_LEVEL
6364

65+
#ifdef EXTERNAL_LOGGER
66+
/** @brief Log level is set to 0 to generate all the logs
67+
* The leve filtering will be done by the external logger
68+
*/
69+
#undef LOG_LEVEL
70+
#define LOG_LEVEL 0
71+
72+
// Use the external logger
73+
#define OPENOCPP_LOGGER ocpp::log::ExtLogger
74+
75+
#else
76+
77+
// Use the standard logger
78+
#define OPENOCPP_LOGGER ocpp::log::Logger
79+
80+
#endif // EXTERNAL_LOGGER
81+
6482
/** @brief Default log name */
6583
#define DEFAULT_LOG_NAME "Logs"
6684

@@ -71,36 +89,36 @@ class LogDatabase;
7189

7290
// Log macros
7391
#if (LOG_LEVEL == 0)
74-
#define LOG_DEBUG ocpp::log::Logger("\x1b[32m[ DEBUG ]\x1b[0m", 0, __FILENAME__, LINE_TOSTRING(__LINE__))
75-
#define LOG_DEBUG2(logger_name) ocpp::log::Logger(logger_name, "\x1b[32m[ DEBUG ]\x1b[0m", 0, __FILENAME__, LINE_TOSTRING(__LINE__))
92+
#define LOG_DEBUG OPENOCPP_LOGGER("\x1b[32m[ DEBUG ]\x1b[0m", 0, __FILENAME__, LINE_TOSTRING(__LINE__))
93+
#define LOG_DEBUG2(logger_name) OPENOCPP_LOGGER(logger_name, "\x1b[32m[ DEBUG ]\x1b[0m", 0, __FILENAME__, LINE_TOSTRING(__LINE__))
7694
#else
7795
#define LOG_DEBUG ocpp::log::NullLogger()
7896
#define LOG_DEBUG2(logger_name) ocpp::log::NullLogger()
7997
#endif
8098
#if (LOG_LEVEL <= 1)
81-
#define LOG_COM ocpp::log::Logger("\x1b[34m[ COM ]\x1b[0m", 1, __FILENAME__, LINE_TOSTRING(__LINE__))
82-
#define LOG_COM2(logger_name) ocpp::log::Logger(logger_name, "\x1b[34m[ COM ]\x1b[0m", 1, __FILENAME__, LINE_TOSTRING(__LINE__))
99+
#define LOG_COM OPENOCPP_LOGGER("\x1b[34m[ COM ]\x1b[0m", 1, __FILENAME__, LINE_TOSTRING(__LINE__))
100+
#define LOG_COM2(logger_name) OPENOCPP_LOGGER(logger_name, "\x1b[34m[ COM ]\x1b[0m", 1, __FILENAME__, LINE_TOSTRING(__LINE__))
83101
#else
84102
#define LOG_COM ocpp::log::NullLogger()
85103
#define LOG_COM2(logger_name) ocpp::log::NullLogger()
86104
#endif
87105
#if (LOG_LEVEL <= 2)
88-
#define LOG_INFO ocpp::log::Logger("\x1b[30m[ INFO ]\x1b[0m", 2, __FILENAME__, LINE_TOSTRING(__LINE__))
89-
#define LOG_INFO2(logger_name) ocpp::log::Logger(logger_name, "\x1b[30m[ INFO ]\x1b[0m", 2, __FILENAME__, LINE_TOSTRING(__LINE__))
106+
#define LOG_INFO OPENOCPP_LOGGER("\x1b[30m[ INFO ]\x1b[0m", 2, __FILENAME__, LINE_TOSTRING(__LINE__))
107+
#define LOG_INFO2(logger_name) OPENOCPP_LOGGER(logger_name, "\x1b[30m[ INFO ]\x1b[0m", 2, __FILENAME__, LINE_TOSTRING(__LINE__))
90108
#else
91109
#define LOG_INFO ocpp::log::NullLogger()
92110
#define LOG_INFO2(logger_name) ocpp::log::NullLogger()
93111
#endif
94112
#if (LOG_LEVEL <= 3)
95-
#define LOG_WARNING ocpp::log::Logger("\x1b[33m[WARNING]\x1b[0m", 3, __FILENAME__, LINE_TOSTRING(__LINE__))
96-
#define LOG_WARNING2(logger_name) ocpp::log::Logger(logger_name, "\x1b[33m[WARNING]\x1b[0m", 3, __FILENAME__, LINE_TOSTRING(__LINE__))
113+
#define LOG_WARNING OPENOCPP_LOGGER("\x1b[33m[WARNING]\x1b[0m", 3, __FILENAME__, LINE_TOSTRING(__LINE__))
114+
#define LOG_WARNING2(logger_name) OPENOCPP_LOGGER(logger_name, "\x1b[33m[WARNING]\x1b[0m", 3, __FILENAME__, LINE_TOSTRING(__LINE__))
97115
#else
98116
#define LOG_WARNING ocpp::log::NullLogger()
99117
#define LOG_WARNING2(logger_name) ocpp::log::NullLogger()
100118
#endif
101119
#if (LOG_LEVEL <= 4)
102-
#define LOG_ERROR ocpp::log::Logger("\x1b[31m[ ERROR ]\x1b[0m", 4, __FILENAME__, LINE_TOSTRING(__LINE__))
103-
#define LOG_ERROR2(logger_name) ocpp::log::Logger(logger_name, "\x1b[31m[ ERROR ]\x1b[0m", 4, __FILENAME__, LINE_TOSTRING(__LINE__))
120+
#define LOG_ERROR OPENOCPP_LOGGER("\x1b[31m[ ERROR ]\x1b[0m", 4, __FILENAME__, LINE_TOSTRING(__LINE__))
121+
#define LOG_ERROR2(logger_name) OPENOCPP_LOGGER(logger_name, "\x1b[31m[ ERROR ]\x1b[0m", 4, __FILENAME__, LINE_TOSTRING(__LINE__))
104122
#else
105123
#define LOG_ERROR ocpp::log::NullLogger()
106124
#define LOG_ERROR2(logger_name) ocpp::log::NullLogger()
@@ -187,6 +205,55 @@ class NullLogger
187205
}
188206
};
189207

208+
/** @brief External logger */
209+
class ExtLogger
210+
{
211+
public:
212+
/** @brief Constructor */
213+
ExtLogger(const char* level_str, unsigned int level, const char* filename, const char* line);
214+
/** @brief Constructor */
215+
ExtLogger(const char* name, const char* level_str, unsigned int level, const char* filename, const char* line);
216+
217+
/** @brief Destructor */
218+
virtual ~ExtLogger();
219+
220+
/**
221+
* @brief Generic log operator
222+
* @param input Data to log
223+
* @return Logger's instance
224+
*/
225+
template <typename T>
226+
ExtLogger& operator<<(const T& input)
227+
{
228+
m_log_output << input;
229+
return (*this);
230+
}
231+
232+
/**
233+
* @brief Log operator for boolean values
234+
* @param input Data to log
235+
* @return Logger's instance
236+
*/
237+
ExtLogger& operator<<(bool input)
238+
{
239+
static const char* BOOL_STRING[] = {"false", "true"};
240+
m_log_output << BOOL_STRING[static_cast<int>(input)];
241+
return (*this);
242+
}
243+
244+
/** @brief Register an external logging function */
245+
static void registerLogFunction(std::function<void(unsigned int, const std::string&)> log_function);
246+
247+
private:
248+
/** @brief Log output */
249+
std::stringstream m_log_output;
250+
/** @brief Log level */
251+
unsigned int m_level;
252+
253+
/** @brief External logging function */
254+
static std::function<void(unsigned int, const std::string&)> m_log_function;
255+
};
256+
190257
} // namespace log
191258
} // namespace ocpp
192259

tests/tools/test_logs.cpp

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,61 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
2020
#undef LOG_LEVEL
2121
#endif
2222
#define LOG_LEVEL 0 // Enable all log levels
23-
#include "Database.h"
24-
#include "LogDatabase.h"
2523
#include "Logger.h"
2624
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
2725
#include "doctest.h"
2826

29-
#include <filesystem>
3027
#include <string>
3128

32-
using namespace ocpp::database;
3329
using namespace ocpp::log;
3430

31+
#ifdef EXTERNAL_LOGGER
32+
33+
TEST_SUITE("External logger class test suite")
34+
{
35+
TEST_CASE("Custom log function")
36+
{
37+
unsigned int log_level = 0;
38+
std::string log_str;
39+
auto log_function = [&](unsigned int level, const std::string& log)
40+
{
41+
log_level = level;
42+
log_str = log;
43+
};
44+
45+
ExtLogger::registerLogFunction(log_function);
46+
47+
LOG_COM << "This one will be saved!";
48+
CHECK_EQ(log_level, 1);
49+
CHECK_NE(log_str.find("This one will be saved!"), std::string::npos);
50+
51+
LOG_DEBUG << "This one too!";
52+
CHECK_EQ(log_level, 0);
53+
CHECK_NE(log_str.find("This one too!"), std::string::npos);
54+
55+
LOG_INFO << "This one either!";
56+
CHECK_EQ(log_level, 2);
57+
CHECK_NE(log_str.find("This one either!"), std::string::npos);
58+
59+
LOG_WARNING << "And also this one!";
60+
CHECK_EQ(log_level, 3);
61+
CHECK_NE(log_str.find("And also this one!"), std::string::npos);
62+
63+
LOG_ERROR << "This is the last one saved!";
64+
CHECK_EQ(log_level, 4);
65+
CHECK_NE(log_str.find("This is the last one saved!"), std::string::npos);
66+
}
67+
}
68+
69+
#else // EXTERNAL_LOGGER
70+
71+
#include "Database.h"
72+
#include "LogDatabase.h"
73+
74+
#include <filesystem>
75+
76+
using namespace ocpp::database;
77+
3578
std::filesystem::path test_database_path;
3679

3780
TEST_SUITE("Database class test suite")
@@ -158,5 +201,10 @@ TEST_SUITE("Database class test suite")
158201
CHECK_FALSE(query->next());
159202
}
160203

161-
TEST_CASE("Cleanup") { std::filesystem::remove(test_database_path); }
204+
TEST_CASE("Cleanup")
205+
{
206+
std::filesystem::remove(test_database_path);
207+
}
162208
}
209+
210+
#endif // EXTERNAL_LOGGER

0 commit comments

Comments
 (0)