refactor(logging): implement get_logger and set_logger functions

- Add get_logger and set_logger functions to manage global logger
- Update Logger class to use unique_ptr for child loggers
- Modify get_child method to use template and transfer ownership
- Update logging initialization and shutdown processes
- Adjust test cases to use new logger management functions
This commit is contained in:
ovizro 2024-12-10 15:53:48 +08:00
parent 610a7e4008
commit ccaa4908b5
12 changed files with 129 additions and 95 deletions

View File

@ -31,38 +31,17 @@ if (CMAKE_CROSSCOMPILING)
message(STATUS "CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")
endif()
include_directories(./include)
include_directories(${CMAKE_SOURCE_DIR}/include)
aux_source_directory(${CMAKE_SOURCE_DIR}/src SRC_LIST)
aux_source_directory(./src SRC_LIST)
add_library(exint_static STATIC ${SRC_LIST})
add_library(exint SHARED ${SRC_LIST})
add_library(exint_static STATIC ${SRC_LIST})
set_target_properties(exint_static PROPERTIES OUTPUT_NAME exint)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(exint PRIVATE -Wno-nonnull -fvisibility=hidden)
endif()
#
set(TESTS_DIR "${CMAKE_SOURCE_DIR}/tests")
set(TEST_COMMON_SOURCE "${TESTS_DIR}/c_testcase.cpp")
link_libraries(pthread)
# test_
file(GLOB_RECURSE TEST_FILES "${TESTS_DIR}/test_*.cpp")
#
foreach(TEST_FILE ${TEST_FILES})
#
get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE)
#
add_executable(${TEST_NAME} ${TEST_FILE} ${TEST_COMMON_SOURCE} ${SRC_LIST})
#
list(APPEND TEST_EXECUTABLES "${EXECUTABLE_OUTPUT_PATH}/${TEST_NAME}")
endforeach()
enable_testing()
add_test(NAME test
COMMAND ${CMAKE_SOURCE_DIR}/scripts/unittest.py ${TEST_EXECUTABLES}
)
subdirs(tests)

View File

@ -12,7 +12,7 @@ cmake . -B build
cmake --build build -j6
```
使用cmake及ctest进行测试:
使用cmake调用测试脚本进行测试:
```bash
cmake . -B build

View File

@ -158,11 +158,11 @@ extern "C"{
if (memcmp((expr1), (expr2), (size)) != 0) { \
printf("assertion failed: %s == %s\n", #expr1, #expr2); \
printf("\t#0: "); \
for (int i = 0; i < (size); i++) { \
for (size_t i = 0; i < (size); i++) { \
printf("%02X", ((uint8_t*)(expr1))[i]); \
} \
printf("\n\t#1: "); \
for (int i = 0; i < (size); i++) { \
for (size_t i = 0; i < (size); i++) { \
printf("%02X", ((uint8_t*)(expr2))[i]); \
} \
printf("\nfile: \"%s\", line %d, in %s\n", __FILE__, __LINE__, __ASSERT_FUNCTION);\

View File

@ -74,7 +74,38 @@ public:
LoggerOStream operator[](Level level);
LoggerOStream operator[](int level);
Logger* get_child(const std::string& name, Level level = Level::UNKNOWN);
void move_children_to(Logger& other);
template<class T_Logger = Logger>
Logger* get_child(const std::string& name, Level level)
{
Logger* logger;
auto sep_pos = name.find(namesep);
do {
if (name.empty() || sep_pos == 0) {
logger = this;
break;
}
std::string base_name;
if (sep_pos == std::string::npos) {
base_name = name;
} else {
base_name = name.substr(0, sep_pos);
}
auto iter = logger_cache.find(base_name);
if (iter != logger_cache.end()) {
logger = iter->second.get();
break;
}
logger = new T_Logger(base_name, level, this);
logger_cache[base_name] = std::unique_ptr<Logger>(logger);
} while (0);
auto seqlen = strlen(namesep);
if (sep_pos == std::string::npos || sep_pos + seqlen >= name.size())
return logger;
return logger->get_child(name.substr(sep_pos + seqlen), level);
}
protected:
explicit Logger(const std::string& name, Level level = Level::INFO, Logger* parent = nullptr);
@ -132,16 +163,18 @@ struct Record
Record(const std::string& name, Logger::Level level, const std::string& msg);
};
std::ostream& operator<<(std::ostream& os, const Logger::Level level);
Logger::Level str2level(const char* level);
extern std::unique_ptr<Logger> global_logger;
using LogLevel = Logger::Level;
std::ostream& operator<<(std::ostream& os, const Logger::Level level);
Logger::Level str2level(const char* level);
std::unique_ptr<Logger>& _get_global_logger();
Logger& get_global_logger();
void set_global_logger(std::unique_ptr<Logger>&& logger);
template<class T_Logger = Logger>
static inline Logger* get_logger(const std::string& name, LogLevel level = LogLevel::UNKNOWN)
{
return global_logger->get_child(name, level);
return _get_global_logger()->get_child<T_Logger>(name, level);
}
}

View File

@ -2,4 +2,4 @@
mkdir -p dist
zip -r "dist/exint-build-$(date +%Y%m%d-%H%M%S).zip" bin/ lib/ config/\
scripts/ README.md
scripts/ README.md include/external_interface.h

View File

@ -2,4 +2,4 @@
mkdir -p dist
tar -czvf "dist/exint-$(date +%Y%m%d-%H%M%S).tar.gz" src/ include/ tests/ config/\
scripts/ toolchains/ tools/ README.md CMakeLists.txt mak .gitignore
scripts/ toolchains/ README.md CMakeLists.txt mak .gitignore

View File

@ -70,7 +70,7 @@ void exint_send(uint32_t type, size_t len, void* data) {
event_name = "send_audio";
break;
default:
break;
return;
}
exint_event(event_name, len, data);
}

View File

@ -10,8 +10,23 @@
using namespace logging;
__attribute__((__init_priority__(8192)))
std::unique_ptr<Logger> logging::global_logger(new Logger(LogLevel::WARN));
std::unique_ptr<Logger>& logging::_get_global_logger()
{
static std::unique_ptr<Logger> global_logger(new Logger(LogLevel::WARN));
return global_logger;
}
Logger& logging::get_global_logger()
{
return *_get_global_logger();
}
void logging::set_global_logger(std::unique_ptr<Logger>&& logger)
{
auto& global_logger = _get_global_logger();
global_logger->move_children_to(*logger);
global_logger = std::move(logger);
}
Logger::Logger(Level level) : _parent(nullptr), _level(level)
{}
@ -186,35 +201,15 @@ LoggerOStream Logger::operator[](int level)
return (*this)[static_cast<Logger::Level>(level)];
}
Logger* Logger::get_child(const std::string& name, Level level)
void Logger::move_children_to(Logger& target_logger)
{
Logger* logger;
auto sep_pos = name.find(namesep);
do {
if (name.empty() || sep_pos == 0) {
logger = this;
break;
if (logger_cache.empty()) return;
for (auto it = logger_cache.begin(); it != logger_cache.end(); ) {
// Transfer ownership of the child logger to the target_logger
it->second->_parent = &target_logger;
target_logger.logger_cache.insert(std::move(*it));
it = logger_cache.erase(it); // Remove from current logger's cache
}
std::string base_name;
if (sep_pos == std::string::npos) {
base_name = name;
} else {
base_name = name.substr(0, sep_pos);
}
auto iter = logger_cache.find(base_name);
if (iter != logger_cache.end()) {
logger = iter->second.get();
break;
}
logger = new Logger(base_name, level, this);
(*global_logger)[Level::DEBUG] << "created logger" << logger->_name << std::endl;
logger_cache[base_name] = std::unique_ptr<Logger>(logger);
} while (0);
auto seqlen = strlen(namesep);
if (sep_pos == std::string::npos || sep_pos + seqlen >= name.size())
return logger;
return logger->get_child(name.substr(sep_pos + seqlen), level);
}
LoggerOStream::LoggerOStream(Logger& logger, Logger::Level level)
@ -311,20 +306,17 @@ void log_init(const char* level)
} else if (strcasecmp(level, "env") == 0 || strcasecmp(level, "auto") == 0) {
level = getenv("LOG_LEVEL");
}
if (global_logger->children_count()) {
global_logger->warn("reseting logger with children");
}
global_logger = std::unique_ptr<Logger>(new Logger(str2level(level)));
set_global_logger(std::unique_ptr<Logger>(new Logger(str2level(level))));
}
int log_level()
{
return static_cast<int>(global_logger->level());
return static_cast<int>(_get_global_logger()->level());
}
void log_set_level(int level)
{
global_logger->set_level(static_cast<Logger::Level>(level));
_get_global_logger()->set_level(static_cast<Logger::Level>(level));
}
void log_log(int level, const char* fmt, ...)
@ -337,10 +329,5 @@ void log_log(int level, const char* fmt, ...)
void log_vlog(int level, const char* fmt, va_list args)
{
if (!global_logger) {
vfprintf(stderr, fmt, args);
fputc('\n', stderr);
return;
}
global_logger->vlog(static_cast<Logger::Level>(level), fmt, args);
_get_global_logger()->vlog(static_cast<Logger::Level>(level), fmt, args);
}

18
tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.15)
project(test)
set(TESTS_DIR .)
set(TEST_COMMON_SOURCE "${TESTS_DIR}/c_testcase.cpp")
file(GLOB_RECURSE TEST_FILES "${TESTS_DIR}/test_*.cpp")
foreach(TEST_FILE ${TEST_FILES})
get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE)
add_executable(${TEST_NAME} ${TEST_FILE} ${TEST_COMMON_SOURCE} ${SRC_LIST})
list(APPEND TEST_EXECUTABLES "${EXECUTABLE_OUTPUT_PATH}/${TEST_NAME}")
endforeach()
add_custom_target(test
COMMAND ${CMAKE_SOURCE_DIR}/scripts/unittest.py ${TEST_EXECUTABLES}
DEPENDS ${TEST_EXECUTABLES}
)

View File

@ -132,9 +132,7 @@ static __inline void print_separator_ex(char lc, const char* str, const char* co
static int collect_testcase() {
for (int i = 0; i < test_case_total; ++i) {
puts(test_cases[i].name);
// putchar(' ');
}
putchar('\n');
return 0;
}
@ -197,6 +195,15 @@ static int unittest_testcase(TestCase* tc) {
int main(int argc, const char** argv) {
for (int i = 1; i < argc; ++i) {
const char* arg = argv[i];
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
printf("usage: %s [-c] [-u NAME] [-h]\n", argv[0]);
printf("\nOptions:\n");
printf(" -i, --interactive: run in interactive mode.\n");
printf(" -c, --collect: list all test cases.\n");
printf(" -u, --unittest: run a single test case.\n");
printf(" -h, --help: show the help text.\n");
return 0;
}
if (strcmp(arg, "-i") == 0 || strcmp(arg, "--interactive") == 0) {
if (interactive)
return interactive(argc, argv);

View File

@ -5,6 +5,8 @@
using namespace logging;
static auto& module_logger = *get_logger("test_logging");
TEST_CASE(test_init) {
log_info("test_init before");
log_init(NULL);
@ -23,10 +25,18 @@ TEST_CASE(test_init) {
END_TEST;
}
TEST_CASE(test_module_logger)
{
module_logger.info("test_module_logger1");
log_init("debug");
module_logger.info("test_module_logger2");
END_TEST;
}
TEST_CASE(test_add_stream) {
std::stringstream ss;
log_init(NULL);
logging::global_logger->add_stream(ss);
get_global_logger().add_stream(ss);
log_info("test_stream");
auto s = ss.str();
@ -60,7 +70,7 @@ TEST_CASE(test_add_stream) {
assert_str_eq(s.c_str() + (s.length() - 26), "[FATAL] test_stream fatal\n");
ss.str("");
logging::global_logger->log<logging::Logger::Level::DEBUG>("test_stream debug");
get_global_logger().log<logging::Logger::Level::DEBUG>("test_stream debug");
s = ss.str();
assert_str_eq(s.c_str() + (s.length() - 26), "[DEBUG] test_stream debug\n");
@ -69,7 +79,7 @@ TEST_CASE(test_add_stream) {
TEST_CASE(test_log_stream) {
log_init(NULL);
auto& logger = *logging::global_logger;
auto& logger = get_global_logger();
std::stringstream ss;
logger.add_stream(ss);
@ -91,7 +101,7 @@ TEST_CASE(test_sub_logger) {
auto sublogger = get_logger("sublogger");
assert_eq(sublogger->level(), LogLevel::INFO);
assert_eq(sublogger->name(), "sublogger");
assert_eq(sublogger->parent(), logging::global_logger.get());
assert_eq(sublogger->parent(), &get_global_logger());
auto subsublogger = get_logger("sublogger::subsublogger");
assert_eq(subsublogger->level(), LogLevel::INFO);
@ -104,11 +114,11 @@ TEST_CASE(test_sub_logger) {
auto sub1logger = get_logger("sublogger1");
assert_eq(sub1logger->level(), LogLevel::INFO);
assert_eq(sub1logger->name(), "sublogger1");
assert_eq(sub1logger->parent(), logging::global_logger.get());
assert_eq(sub1logger->parent(), &get_global_logger());
assert_eq(sub1sub1logger->parent(), sub1logger);
auto root_logger = get_logger("");
assert_eq(root_logger, logging::global_logger.get());
assert_eq(root_logger, &get_global_logger());
auto root_logger1 = get_logger("::");
assert_eq(root_logger1, root_logger);
auto subsublogger1 = get_logger("sublogger::subsublogger");
@ -120,12 +130,12 @@ TEST_CASE(test_sub_logger) {
auto subsublogger4 = get_logger("sublogger::::::subsublogger");
assert_eq(subsublogger4, subsublogger);
global_logger->set_level(LogLevel::DEBUG);
assert_eq(global_logger->level(), LogLevel::DEBUG);
get_global_logger().set_level(LogLevel::DEBUG);
assert_eq(get_global_logger().level(), LogLevel::DEBUG);
assert_eq(sublogger->level(), LogLevel::DEBUG);
assert_eq(subsublogger->level(), LogLevel::DEBUG);
sublogger->set_level(LogLevel::WARN);
assert_eq(global_logger->level(), LogLevel::DEBUG);
assert_eq(get_global_logger().level(), LogLevel::DEBUG);
assert_eq(sublogger->level(), LogLevel::WARN);
assert_eq(subsublogger->level(), LogLevel::WARN);
END_TEST;

View File

@ -1,5 +1,5 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc-9)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++-9)