From c53346d8069a090ab2731c6aef19e119e71e9ce3 Mon Sep 17 00:00:00 2001 From: Margherita Milani Date: Fri, 3 Oct 2025 17:25:55 +0200 Subject: [PATCH] Add simple header-only logger with macro Introduce log.hpp for enable or disable logging at runtime with the specif macro. Signed-off-by: Margherita Milani --- CMakeLists.txt | 5 ++ examples/CMakeLists.txt | 2 + include/amarula/dbus/gproxy.hpp | 5 +- include/amarula/log.hpp | 50 ++++++++++++ src/dbus/gconnman_agent.cpp | 3 +- src/dbus/gconnman_clock.cpp | 34 ++++---- src/dbus/gconnman_manager.cpp | 5 +- src/dbus/gconnman_service.cpp | 129 +++++++++++++++---------------- src/dbus/gconnman_technology.cpp | 19 ++--- tests/CMakeLists.txt | 6 ++ tests/log_test.cpp | 32 ++++++++ 11 files changed, 195 insertions(+), 95 deletions(-) create mode 100644 include/amarula/log.hpp create mode 100644 tests/log_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 97050af..93080a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,11 @@ if(BUILD_CONNMAN) COMPONENT ${PROJECT_NAME}-dev) endif(BUILD_CONNMAN) +install( + FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/amarula/log.hpp + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amarula + COMPONENT ${PROJECT_NAME}-dev) + if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) if(BUILD_TESTS) include(CTest) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index c0a2070..5c49e5c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,5 @@ +add_compile_definitions(LCM_LOG_DEFAULT_ENABLED=1) + if(BUILD_CONNMAN) add_executable(connmanctl_dbus connmanctl.cpp) target_link_libraries(connmanctl_dbus PRIVATE GConnmanDbus) diff --git a/include/amarula/dbus/gproxy.hpp b/include/amarula/dbus/gproxy.hpp index 54a0bc9..d7a7f77 100644 --- a/include/amarula/dbus/gproxy.hpp +++ b/include/amarula/dbus/gproxy.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -74,7 +75,7 @@ class DBusProxy : public std::enable_shared_from_this> { self->updateProperties(out_properties); g_variant_unref(out_properties); } else { - std::cerr << error->message << '\n'; + LCM_LOG(error->message << '\n'); g_error_free(error); } self->template executeCallBack(counter, @@ -214,7 +215,7 @@ class DBusProxy : public std::enable_shared_from_this> { const auto success = finish(G_DBUS_PROXY(proxy), res, &error); if (!success) { - std::cerr << error->message << '\n'; + LCM_LOG(error->message << '\n'); g_error_free(error); } diff --git a/include/amarula/log.hpp b/include/amarula/log.hpp new file mode 100644 index 0000000..9069a41 --- /dev/null +++ b/include/amarula/log.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include +#include + +namespace Amarula { + +class Log { + public: + static void enable(bool enabled) { + state().store(enabled, std::memory_order_relaxed); + } + + static auto isEnabled() -> bool { + return state().load(std::memory_order_relaxed); + } + + static auto mutex() -> std::mutex& { + static std::mutex mutex; + return mutex; + } + + private: + static auto state() -> std::atomic& { +#ifdef LCM_LOG_DEFAULT_ENABLED + static std::atomic flag{true}; +#else + static std::atomic flag{false}; +#endif + return flag; + } +}; + +} // namespace Amarula + +#ifndef LCM_LOG_STREAM +#define LCM_LOG_STREAM std::cout +#endif + +#define LCM_LOG(...) \ + do { \ + if (::Amarula::Log::isEnabled()) { \ + std::ostringstream _lcm_oss; \ + _lcm_oss << __VA_ARGS__; \ + std::lock_guard _lcm_guard(::Amarula::Log::mutex()); \ + LCM_LOG_STREAM << _lcm_oss.str(); \ + } \ + } while (0) diff --git a/src/dbus/gconnman_agent.cpp b/src/dbus/gconnman_agent.cpp index ec43a70..3cf559a 100644 --- a/src/dbus/gconnman_agent.cpp +++ b/src/dbus/gconnman_agent.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -114,7 +115,7 @@ void Agent::dispatch_method_call(GDBusMethodInvocation *invocation, service = g_variant_get_string(child_service, nullptr); error_str = g_variant_get_string(child_error, nullptr); - std::cerr << "ReportError:" << service << " " << error_str << "\n"; + LCM_LOG("ReportError:" << service << " " << error_str << '\n'); g_variant_unref(child_service); g_variant_unref(child_error); diff --git a/src/dbus/gconnman_clock.cpp b/src/dbus/gconnman_clock.cpp index 9b3bf26..1765413 100644 --- a/src/dbus/gconnman_clock.cpp +++ b/src/dbus/gconnman_clock.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,7 @@ void ClockProperties::update(const gchar* key, GVariant* value) { } else if (g_strcmp0(key, TIMESERVERSYNCED_STR) == 0U) { time_server_synced_ = g_variant_get_boolean(value) == 1U; } else { - std::cerr << "Unknown property for Clock: " << key << '\n'; + LCM_LOG("Unknown property for Clock: " << key << '\n'); } } @@ -97,24 +98,25 @@ void Clock::setTimeServers(const std::vector& servers, } void ClockProperties::print() const { - std::cout << "@@@@@@@@@@ ClockProperties: @@@@@@@@@@@@@@@\n"; - std::cout << TIME_STR << ": " << time_ << " ("; + LCM_LOG("@@@@@@@@@@ ClockProperties: @@@@@@@@@@@@@@@\n"); + LCM_LOG(TIME_STR << ": " << time_ << " ("); const auto time_value = static_cast(time_); - std::cout << std::put_time(std::localtime(&time_value), "%Y-%m-%d %H:%M:%S") - << ")\n"; - std::cout << TIMEUPDATES_STR << ": " - << TIME_UPDATE_MAP.toString(time_updates_) << '\n'; - std::cout << TIMEZONE_STR << ": " << timezone_ << '\n'; - std::cout << TIMEZONEUPDATES_STR << ": " - << TIME_ZONE_UPDATE_MAP.toString(timezone_updates_) << '\n'; - std::cout << TIMESERVERSYNCED_STR << ": " << std::boolalpha - << time_server_synced_ << '\n'; - std::cout << TIMESERVERS_STR << ": "; + LCM_LOG(std::put_time(std::localtime(&time_value), "%Y-%m-%d %H:%M:%S") + << ")\n"); + LCM_LOG(TIMEUPDATES_STR << ": " << TIME_UPDATE_MAP.toString(time_updates_) + << '\n'); + LCM_LOG(TIMEZONE_STR << ": " << timezone_ << '\n'); + LCM_LOG(TIMEZONEUPDATES_STR + << ": " << TIME_ZONE_UPDATE_MAP.toString(timezone_updates_) + << '\n'); + LCM_LOG(TIMESERVERSYNCED_STR << ": " << std::boolalpha + << time_server_synced_ << '\n'); + LCM_LOG(TIMESERVERS_STR << ": "); for (const auto& server : time_servers_) { - std::cout << server << ' '; + LCM_LOG(server << ' '); } - std::cout << '\n'; - std::cout << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"; + LCM_LOG('\n'); + LCM_LOG("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); } } // namespace Amarula::DBus::G::Connman diff --git a/src/dbus/gconnman_manager.cpp b/src/dbus/gconnman_manager.cpp index 82bebc4..f6ad993 100644 --- a/src/dbus/gconnman_manager.cpp +++ b/src/dbus/gconnman_manager.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,7 @@ void ManaProperties::update(const gchar* key, GVariant* value) { } else if (g_strcmp0(key, STATE_STR) == 0U) { state_ = STATE_MAP.fromString(g_variant_get_string(value, nullptr)); } else { - std::cerr << "Unknown property for Manager: " << key << '\n'; + LCM_LOG("Unknown property for Manager: " << key << '\n'); } } @@ -270,7 +271,7 @@ void Manager::get_proxies_cb(GObject* proxy, GAsyncResult* res, } } else { - std::cerr << error->message << '\n'; + LCM_LOG(error->message << '\n'); g_error_free(error); } } diff --git a/src/dbus/gconnman_service.cpp b/src/dbus/gconnman_service.cpp index 7bca6ec..6e5fdf3 100644 --- a/src/dbus/gconnman_service.cpp +++ b/src/dbus/gconnman_service.cpp @@ -1,9 +1,9 @@ - #include #include #include #include +#include #include #include #include @@ -132,7 +132,7 @@ void IPv4::update(const gchar* key, GVariant* value) { } else if (g_strcmp0(key, GATEWAY_STR) == 0U) { gateway_ = g_variant_get_string(value, nullptr); } else { - std::cerr << "Unknown property for IPv4: " << key << '\n'; + LCM_LOG("Unknown property for IPv4: " << key << '\n'); } } @@ -150,7 +150,7 @@ void IPv6::update(const gchar* key, GVariant* value) { } else if (g_strcmp0(key, PREFIXLENGTH_STR) == 0U) { prefix_length_ = static_cast(g_variant_get_byte(value)); } else { - std::cerr << "Unknown property for IPv6: " << key << '\n'; + LCM_LOG("Unknown property for IPv6: " << key << '\n'); } } @@ -185,7 +185,7 @@ void Ethernet::update(const gchar* key, GVariant* value) { } else if (g_strcmp0(key, MTU_STR) == 0U) { mtu_ = static_cast(g_variant_get_uint16(value)); } else { - std::cerr << "Unknown property for Ethernet: " << key << '\n'; + LCM_LOG("Unknown property for Ethernet: " << key << '\n'); } } @@ -199,7 +199,7 @@ void Provider::update(const gchar* key, GVariant* value) { } else if (g_strcmp0(key, TYPE_STR) == 0U) { type_ = g_variant_get_string(value, nullptr); } else { - std::cerr << "Unknown property for Provider: " << key << '\n'; + LCM_LOG("Unknown property for Provider: " << key << '\n'); } } @@ -214,7 +214,7 @@ void Proxy::update(const gchar* key, GVariant* value) { } else if (g_strcmp0(key, EXCLUDES_STR) == 0U) { excludes_ = as_to_vector(value); } else { - std::cerr << "Unknown property for Proxy: " << key << '\n'; + LCM_LOG("Unknown property for Proxy: " << key << '\n'); } } @@ -283,64 +283,64 @@ void ServProperties::update(const gchar* key, GVariant* value) { ? std::optional>(as_to_vector(value)) : std::nullopt; } else { - std::cerr << "Unknown or empty property for Service: " << key << '\n'; + LCM_LOG("Unknown or empty property for Service: " << key << '\n'); } } void ServProperties::print() const { - std::cout << "@@@@@@@@@@ ServProperties: @@@@@@@@@@@@@@@\n"; - std::cout << "State: " << STATE_MAP.toString(state_) << '\n'; + LCM_LOG("@@@@@@@@@@ ServProperties: @@@@@@@@@@@@@@@\n"); + LCM_LOG("State: " << STATE_MAP.toString(state_) << '\n'); if (error_ != Error::None) { - std::cout << "Error: " << ERROR_MAP.toString(error_) << '\n'; + LCM_LOG("Error: " << ERROR_MAP.toString(error_) << '\n'); } - std::cout << "Name: " << name_ << '\n'; - std::cout << "Type: " << TYPE_MAP.toString(type_) << '\n'; - std::cout << "Strength: " << static_cast(strength_) << '\n'; - std::cout << "AutoConnect: " << std::boolalpha << autoconnect_ << '\n'; - std::cout << "mDNS: " << mdns_ << '\n'; - std::cout << "Favorite: " << favorite_ << '\n'; - std::cout << "Immutable: " << immutable_ << '\n'; - std::cout << "Roaming: " << roaming_ << '\n'; + LCM_LOG("Name: " << name_ << '\n'); + LCM_LOG("Type: " << TYPE_MAP.toString(type_) << '\n'); + LCM_LOG("Strength: " << static_cast(strength_) << '\n'); + LCM_LOG("AutoConnect: " << std::boolalpha << autoconnect_ << '\n'); + LCM_LOG("mDNS: " << mdns_ << '\n'); + LCM_LOG("Favorite: " << favorite_ << '\n'); + LCM_LOG("Immutable: " << immutable_ << '\n'); + LCM_LOG("Roaming: " << roaming_ << '\n'); if (security_) { - std::cout << "Security: "; + LCM_LOG("Security: "); for (const auto& sec : security_.value()) { - std::cout << SECURITY_MAP.toString(sec) << ' '; + LCM_LOG(SECURITY_MAP.toString(sec) << ' '); } - std::cout << '\n'; + LCM_LOG('\n'); } if (name_servers_) { - std::cout << "Nameservers: "; + LCM_LOG("Nameservers: "); for (const auto& nserver : name_servers_.value()) { - std::cout << nserver << ' '; + LCM_LOG(nserver << ' '); } - std::cout << '\n'; + LCM_LOG('\n'); } if (name_servers_conf_) { - std::cout << "Nameservers.Configuration: "; + LCM_LOG("Nameservers.Configuration: "); for (const auto& nserver : name_servers_conf_.value()) { - std::cout << nserver << ' '; + LCM_LOG(nserver << ' '); } - std::cout << '\n'; + LCM_LOG('\n'); } if (domains_) { - std::cout << "Domains: "; + LCM_LOG("Domains: "); for (const auto& domain : domains_.value()) { - std::cout << domain << ' '; + LCM_LOG(domain << ' '); } - std::cout << '\n'; + LCM_LOG('\n'); } if (time_servers_) { - std::cout << "TimeServers: "; + LCM_LOG("TimeServers: "); for (const auto& tserver : time_servers_.value()) { - std::cout << tserver << ' '; + LCM_LOG(tserver << ' '); } - std::cout << '\n'; + LCM_LOG('\n'); } if (ipv4_) { @@ -363,57 +363,56 @@ void ServProperties::print() const { proxy_.value().print(); } - std::cout << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"; + LCM_LOG("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); } void Ethernet::print() const { - std::cout << "Ethernet:\n"; - std::cout << " Method: " << ETHERNET_METHOD_MAP.toString(method_) << '\n'; - std::cout << " Interface: " << interface_ << '\n'; - std::cout << " Address: " << address_ << '\n'; - std::cout << " MTU: " << mtu_ << '\n'; + LCM_LOG("Ethernet:\n"); + LCM_LOG(" Method: " << ETHERNET_METHOD_MAP.toString(method_) << '\n'); + LCM_LOG(" Interface: " << interface_ << '\n'); + LCM_LOG(" Address: " << address_ << '\n'); + LCM_LOG(" MTU: " << mtu_ << '\n'); } void IPv4::print() const { - std::cout << "IPv4:\n"; - std::cout << " Method: " << IPV4_METHOD_MAP.toString(method_) << '\n'; - std::cout << " Address: " << address_ << '\n'; - std::cout << " Netmask: " << netmask_ << '\n'; - std::cout << " Gateway: " << gateway_ << '\n'; + LCM_LOG("IPv4:\n"); + LCM_LOG(" Method: " << IPV4_METHOD_MAP.toString(method_) << '\n'); + LCM_LOG(" Address: " << address_ << '\n'); + LCM_LOG(" Netmask: " << netmask_ << '\n'); + LCM_LOG(" Gateway: " << gateway_ << '\n'); } void Provider::print() const { - std::cout << "Provider:\n"; - std::cout << " Host: " << host_ << '\n'; - std::cout << " Domain: " << domain_ << '\n'; - std::cout << " Name: " << name_ << '\n'; - std::cout << " Type: " << type_ << '\n'; + LCM_LOG("Provider:\n"); + LCM_LOG(" Host: " << host_ << '\n'); + LCM_LOG(" Domain: " << domain_ << '\n'); + LCM_LOG(" Name: " << name_ << '\n'); + LCM_LOG(" Type: " << type_ << '\n'); } void IPv6::print() const { - std::cout << "IPv6:\n"; - std::cout << " Method: " << IPV6_METHOD_MAP.toString(method_) << '\n'; - std::cout << " Address: " << address_ << '\n'; - std::cout << " Gateway: " << gateway_ << '\n'; - std::cout << " Privacy: " << static_cast(privacy_) << '\n'; - std::cout << " Prefix Length: " << static_cast(prefix_length_) - << '\n'; + LCM_LOG("IPv6:\n"); + LCM_LOG(" Method: " << IPV6_METHOD_MAP.toString(method_) << '\n'); + LCM_LOG(" Address: " << address_ << '\n'); + LCM_LOG(" Gateway: " << gateway_ << '\n'); + LCM_LOG(" Privacy: " << static_cast(privacy_) << '\n'); + LCM_LOG(" Prefix Length: " << static_cast(prefix_length_) << '\n'); } void Proxy::print() const { - std::cout << "Proxy:\n"; - std::cout << " Method: " << PROXY_METHOD_MAP.toString(method_) << '\n'; - std::cout << " URL: " << url_ << '\n'; - std::cout << " Servers: "; + LCM_LOG("Proxy:\n"); + LCM_LOG(" Method: " << PROXY_METHOD_MAP.toString(method_) << '\n'); + LCM_LOG(" URL: " << url_ << '\n'); + LCM_LOG(" Servers: "); for (const auto& server : servers_) { - std::cout << server << ' '; + LCM_LOG(server << ' '); } - std::cout << '\n'; + LCM_LOG('\n'); - std::cout << " Excludes: "; + LCM_LOG(" Excludes: "); for (const auto& exclude : excludes_) { - std::cout << exclude << ' '; + LCM_LOG(exclude << ' '); } - std::cout << '\n'; + LCM_LOG('\n'); } } // namespace Amarula::DBus::G::Connman diff --git a/src/dbus/gconnman_technology.cpp b/src/dbus/gconnman_technology.cpp index d210117..ea1fbd8 100644 --- a/src/dbus/gconnman_technology.cpp +++ b/src/dbus/gconnman_technology.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -55,19 +56,19 @@ void TechProperties::update(const gchar* key, GVariant* value) { } else if (g_strcmp0(key, TETHERINGFREQ_STR) == 0U) { tethering_freq_ = g_variant_get_int32(value); } else { - std::cerr << "Unknown property for Technology: " << key << '\n'; + LCM_LOG("Unknown property for Technology: " << key << '\n'); } } void TechProperties::print() const { - std::cout << "@@@@@@@@@@ TechProperties: @@@@@@@@@@@@@@@\n"; - std::cout << NAME_STR << ": " << name_ << "\n"; - std::cout << TYPE_STR << ": " << TYPE_MAP.toString(type_) << "\n"; - std::cout << POWERED_STR << ": " << std::boolalpha << powered_ << "\n"; - std::cout << CONNECTED_STR << ": " << std::boolalpha << connected_ << "\n"; - std::cout << TETHERING_STR << ": " << std::boolalpha << tethering_ << "\n"; - std::cout << TETHERINGFREQ_STR << ": " << tethering_freq_ << " \n"; - std::cout << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"; + LCM_LOG("@@@@@@@@@@ TechProperties: @@@@@@@@@@@@@@@\n"); + LCM_LOG(NAME_STR << ": " << name_ << '\n'); + LCM_LOG(TYPE_STR << ": " << TYPE_MAP.toString(type_) << '\n'); + LCM_LOG(POWERED_STR << ": " << std::boolalpha << powered_ << '\n'); + LCM_LOG(CONNECTED_STR << ": " << std::boolalpha << connected_ << '\n'); + LCM_LOG(TETHERING_STR << ": " << std::boolalpha << tethering_ << '\n'); + LCM_LOG(TETHERINGFREQ_STR << ": " << tethering_freq_ << " \n"); + LCM_LOG("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); } } // namespace Amarula::DBus::G::Connman diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0a9116d..d2af96b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,3 +1,5 @@ +add_compile_definitions(LCM_LOG_DEFAULT_ENABLED=1) + include(FetchContent) FetchContent_Declare( googletest @@ -31,3 +33,7 @@ if(BUILD_CONNMAN) EXPORT ${PROJECT_NAME}-config COMPONENT ${PROJECT_NAME}-dev) endif(BUILD_CONNMAN) + + +add_executable(log_test log_test.cpp) +target_link_libraries(log_test PRIVATE GDbusProxy gtest_main) diff --git a/tests/log_test.cpp b/tests/log_test.cpp new file mode 100644 index 0000000..55fffde --- /dev/null +++ b/tests/log_test.cpp @@ -0,0 +1,32 @@ +#include + +#include +#include +#include +#include + +TEST(Logger, EnableThenDisable) { + std::stringstream buffer; + std::streambuf* old = std::cout.rdbuf(buffer.rdbuf()); + + Amarula::Log::enable(true); + EXPECT_TRUE(Amarula::Log::isEnabled()); + + LCM_LOG("first message"); + LCM_LOG("second " << "message"); + std::cout.flush(); + + const std::string out1 = buffer.str(); + EXPECT_NE(out1.find("first message"), std::string::npos); + EXPECT_NE(out1.find("second message"), std::string::npos); + + Amarula::Log::enable(false); + buffer.str(""); + buffer.clear(); + + LCM_LOG("should not appear"); + std::cout.flush(); + + EXPECT_TRUE(buffer.str().empty()); + std::cout.rdbuf(old); +}