From 416376e03c8ac2f5fa990956fbebcada5704c666 Mon Sep 17 00:00:00 2001 From: Felipe Magno de Almeida Date: Mon, 10 Mar 2014 12:25:20 +0900 Subject: [PATCH] eina-cxx: Added eina_log support for C++, using IOStreams syntax Summary: Added eina_log support for C++ using the following macros: For logging into a domain: EINA_CXX_DOM_LOG EINA_CXX_DOM_LOG_CRIT EINA_CXX_DOM_LOG_ERR EINA_CXX_DOM_LOG_INFO EINA_CXX_DOM_LOG_DBG EINA_CXX_DOM_LOG_WARN And for logging into the default domain: EINA_CXX_LOG EINA_CXX_LOG_CRIT EINA_CXX_LOG_ERR EINA_CXX_LOG_INFO EINA_CXX_LOG_DBG EINA_CXX_LOG_WARN The usage is simple as can be seen in the tests: efl::eina::log_domain domain("error_domain_name"); domain.set_level(efl::eina::log_level::critical); EINA_CXX_DOM_LOG_CRIT(domain, "something went wrong with the following error: " << error); @feature Reviewers: cedric CC: raster, savio, cedric, sanjeev Differential Revision: https://phab.enlightenment.org/D605 --- src/Makefile_Eina_Cxx.am | 1 + src/bindings/eina_cxx/Eina.hh | 1 + src/bindings/eina_cxx/eina_log.hh | 122 ++++++++++++++++++++++++ src/lib/eina/eina_log.c | 14 +++ src/lib/eina/eina_log.h | 12 +++ src/tests/eina_cxx/eina_cxx_suite.cc | 2 + src/tests/eina_cxx/eina_cxx_test_log.cc | 102 ++++++++++++++++++++ 7 files changed, 254 insertions(+) create mode 100644 src/bindings/eina_cxx/eina_log.hh create mode 100644 src/tests/eina_cxx/eina_cxx_test_log.cc diff --git a/src/Makefile_Eina_Cxx.am b/src/Makefile_Eina_Cxx.am index 60fead4124..69ae679010 100644 --- a/src/Makefile_Eina_Cxx.am +++ b/src/Makefile_Eina_Cxx.am @@ -33,6 +33,7 @@ TESTS += tests/eina_cxx/eina_cxx_suite tests_eina_cxx_eina_cxx_suite_SOURCES = \ tests/eina_cxx/eina_cxx_suite.cc \ tests/eina_cxx/eina_cxx_test_inlist.cc \ +tests/eina_cxx/eina_cxx_test_log.cc \ tests/eina_cxx/eina_cxx_test_inarray.cc \ tests/eina_cxx/eina_cxx_test_iterator.cc \ tests/eina_cxx/eina_cxx_test_ptrarray.cc \ diff --git a/src/bindings/eina_cxx/Eina.hh b/src/bindings/eina_cxx/Eina.hh index 7e7e985c16..37741b642f 100644 --- a/src/bindings/eina_cxx/Eina.hh +++ b/src/bindings/eina_cxx/Eina.hh @@ -12,6 +12,7 @@ #include #include #include +#include namespace efl { namespace eina { diff --git a/src/bindings/eina_cxx/eina_log.hh b/src/bindings/eina_cxx/eina_log.hh new file mode 100644 index 0000000000..aec9b2ef62 --- /dev/null +++ b/src/bindings/eina_cxx/eina_log.hh @@ -0,0 +1,122 @@ +#ifndef EFL_EINA_LOG_HH +#define EFL_EINA_LOG_HH + +#include + +namespace efl { namespace eina { + +namespace log_level { + +struct critical_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_CRITICAL; }; +critical_t const critical = {}; + +struct error_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_ERR; }; +error_t const error = {}; + +struct info_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_INFO; }; +info_t const info = {}; + +struct debug_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_DBG; }; +debug_t const debug = {}; + +struct warn_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_WARN; }; +warn_t const warning = {}; + +} + +template +struct _domain_base +{ + void set_level(log_level::critical_t l) { set_level(l.value); } + void set_level(log_level::error_t l) { set_level(l.value); } + void set_level(log_level::info_t l) { set_level(l.value); } + void set_level(log_level::debug_t l) { set_level(l.value); } + void set_level(log_level::warn_t l) { set_level(l.value); } + void set_level( ::Eina_Log_Level l) + { + ::eina_log_domain_registered_level_set(static_cast(*this).domain_raw(), l); + } + ::Eina_Log_Level get_level() const + { + return static_cast< ::Eina_Log_Level> + (::eina_log_domain_registered_level_get(static_cast(*this).domain_raw())); + } +}; + +const struct global_domain : _domain_base +{ + int domain_raw() const { return EINA_LOG_DOMAIN_GLOBAL; } +} global_domain; + +const struct default_domain : _domain_base +{ + int domain_raw() const { return EINA_LOG_DOMAIN_DEFAULT; } +} default_domain; + +struct log_domain : _domain_base +{ + log_domain(char const* name, char const* color = "black") + : _domain( ::eina_log_domain_register(name, color)) + { + } + ~log_domain() + { + ::eina_log_domain_unregister(_domain); + } + int domain_raw() const { return _domain; } +private: + int _domain; +}; + +inline void _log(std::stringstream const& stream, int domain, ::Eina_Log_Level level + , const char* file, const char* function, int line) +{ + ::eina_log_print(domain, level, file, function, line + , "%s", stream.str().c_str()); +} + +#define EINA_CXX_DOM_LOG(DOMAIN, LEVEL, EXPR) \ + if( ::eina_log_domain_level_check((DOMAIN), LEVEL)) \ + { \ + std::stringstream stream; \ + stream << EXPR; \ + ::efl::eina::_log(std::move(stream), (DOMAIN), LEVEL \ + , __FILE__, __FUNCTION__, __LINE__); \ + } + +#define EINA_CXX_DOM_LOG_CRIT(DOMAIN, EXPR) \ + EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_CRITICAL, EXPR) + +#define EINA_CXX_DOM_LOG_ERR(DOMAIN, EXPR) \ + EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_ERR, EXPR) + +#define EINA_CXX_DOM_LOG_INFO(DOMAIN, EXPR) \ + EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_INFO, EXPR) + +#define EINA_CXX_DOM_LOG_DBG(DOMAIN, EXPR) \ + EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_DBG, EXPR) + +#define EINA_CXX_DOM_LOG_WARN(DOMAIN, EXPR) \ + EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_WARN, EXPR) + +#define EINA_CXX_LOG(LEVEL, EXPR) \ + EINA_CXX_DOM_LOG(EINA_LOG_DOMAIN_DEFAULT, LEVEL, EXPR) + +#define EINA_CXX_LOG_CRIT(EXPR) \ + EINA_CXX_LOG(EINA_LOG_LEVEL_CRITICAL, EXPR) + +#define EINA_CXX_LOG_ERR(EXPR) \ + EINA_CXX_LOG(EINA_LOG_LEVEL_ERR, EXPR) + +#define EINA_CXX_LOG_INFO(EXPR) \ + EINA_CXX_LOG(EINA_LOG_LEVEL_INFO, EXPR) + +#define EINA_CXX_LOG_DBG(EXPR) \ + EINA_CXX_LOG(EINA_LOG_LEVEL_DBG, EXPR) + +#define EINA_CXX_LOG_WARN(EXPR) \ + EINA_CXX_LOG(EINA_LOG_LEVEL_WARN, EXPR) + +} } + +#endif diff --git a/src/lib/eina/eina_log.c b/src/lib/eina/eina_log.c index e225e345b8..140816d989 100644 --- a/src/lib/eina/eina_log.c +++ b/src/lib/eina/eina_log.c @@ -1837,6 +1837,20 @@ eina_log_domain_registered_level_get(int domain) #endif } +EAPI void +eina_log_domain_registered_level_set(int domain, int level) +{ +#ifdef EINA_ENABLE_LOG + EINA_SAFETY_ON_FALSE_RETURN(domain >= 0); + EINA_SAFETY_ON_FALSE_RETURN((unsigned int)domain < _log_domains_count); + EINA_SAFETY_ON_TRUE_RETURN(_log_domains[domain].deleted); + _log_domains[domain].level = level; +#else + (void) domain; + (void) level; +#endif +} + #ifdef EINA_LOG_BACKTRACE # define DISPLAY_BACKTRACE(File, Level) \ if (EINA_UNLIKELY(Level < _backtrace_level)) \ diff --git a/src/lib/eina/eina_log.h b/src/lib/eina/eina_log.h index bc59d785e8..70f9b408ea 100644 --- a/src/lib/eina/eina_log.h +++ b/src/lib/eina/eina_log.h @@ -695,6 +695,18 @@ EAPI int eina_log_domain_level_get(const char *domain_name) EINA_ */ EAPI int eina_log_domain_registered_level_get(int domain) EINA_WARN_UNUSED_RESULT; +/** + * Set the domain level given its identifier. + * + * @param domain identifier, so it must be previously registered with + * eina_log_domain_register(). It's a much faster version of + * eina_log_domain_level_get(), but relies on domain being + * present. + * @param level level to use to limit eina_log_print() for given domain. + * @since 1.10 + */ +EAPI void eina_log_domain_registered_level_set(int domain, int level); + static inline Eina_Bool eina_log_domain_level_check(int domain, int level); /* diff --git a/src/tests/eina_cxx/eina_cxx_suite.cc b/src/tests/eina_cxx/eina_cxx_suite.cc index a842e00f07..4ef8a9f45d 100644 --- a/src/tests/eina_cxx/eina_cxx_suite.cc +++ b/src/tests/eina_cxx/eina_cxx_suite.cc @@ -16,6 +16,7 @@ void eina_test_error(TCase* tc); void eina_test_accessor(TCase* tc); void eina_test_thread(TCase* tc); void eina_test_value(TCase* tc); +void eina_test_log(TCase* tc); typedef struct _Eina_Test_Case Eina_Test_Case; struct _Eina_Test_Case @@ -35,6 +36,7 @@ static const Eina_Test_Case etc[] = { { "Accessor", eina_test_accessor }, { "Thread", eina_test_thread }, { "Value", eina_test_value }, + { "Log", eina_test_log }, { NULL, NULL } }; diff --git a/src/tests/eina_cxx/eina_cxx_test_log.cc b/src/tests/eina_cxx/eina_cxx_test_log.cc new file mode 100644 index 0000000000..52c8ccdc61 --- /dev/null +++ b/src/tests/eina_cxx/eina_cxx_test_log.cc @@ -0,0 +1,102 @@ + +#include "Eina.hh" + +#include + +#include + +bool expensive_called = false; + +int expensive_call() +{ + expensive_called = true; + return 11; +} + +START_TEST(eina_cxx_level_log) +{ + efl::eina::eina_init init; + + efl::eina::log_domain domain("level_error_domain"); + + domain.set_level(efl::eina::log_level::critical); + ck_assert(domain.get_level() == ::EINA_LOG_LEVEL_CRITICAL); + domain.set_level(efl::eina::log_level::warning); + ck_assert(domain.get_level() == ::EINA_LOG_LEVEL_WARN); + domain.set_level(efl::eina::log_level::debug); + ck_assert(domain.get_level() == ::EINA_LOG_LEVEL_DBG); + domain.set_level(efl::eina::log_level::info); + ck_assert(domain.get_level() == ::EINA_LOG_LEVEL_INFO); + domain.set_level(efl::eina::log_level::error); + ck_assert(domain.get_level() == ::EINA_LOG_LEVEL_ERR); +} +END_TEST + +START_TEST(eina_cxx_expensive_log) +{ + efl::eina::eina_init init; + + efl::eina::log_domain domain("expensive_call_error_domain"); + + domain.set_level(EINA_LOG_LEVEL_CRITICAL); + + EINA_CXX_DOM_LOG_ERR(domain, "foo " << ::expensive_call()); + ck_assert(!expensive_called); +} +END_TEST + +START_TEST(eina_cxx_domain_log) +{ + efl::eina::eina_init init; + + efl::eina::log_domain domain("error_domain"); + + EINA_CXX_DOM_LOG_CRIT(domain, "foo 0x" << std::hex << 10); + EINA_CXX_DOM_LOG_ERR(domain, "foo " << 5); + EINA_CXX_DOM_LOG_INFO(domain, "foo " << 5); + EINA_CXX_DOM_LOG_DBG(domain, "foo " << 5); + EINA_CXX_DOM_LOG_WARN(domain, "foo " << 5); + + EINA_CXX_LOG_CRIT("foo " << 5); + EINA_CXX_LOG_ERR("foo " << 5); + EINA_CXX_LOG_INFO("foo " << 5); + EINA_CXX_LOG_DBG("foo " << 5); + EINA_CXX_LOG_WARN("foo " << 5); +} +END_TEST + +START_TEST(eina_cxx_default_domain_log) +{ + efl::eina::eina_init init; + + EINA_CXX_DOM_LOG_CRIT(efl::eina::default_domain, "foo " << 5); + EINA_CXX_DOM_LOG_ERR(efl::eina::default_domain, "foo " << 5); + EINA_CXX_DOM_LOG_INFO(efl::eina::default_domain, "foo " << 5); + EINA_CXX_DOM_LOG_DBG(efl::eina::default_domain, "foo " << 5); + EINA_CXX_DOM_LOG_WARN(efl::eina::default_domain, "foo " << 5); +} +END_TEST + +START_TEST(eina_cxx_global_domain_log) +{ + efl::eina::eina_init init; + + efl::eina::log_domain domain("domain"); + + EINA_CXX_DOM_LOG_CRIT(efl::eina::global_domain, "foo " << 5); + EINA_CXX_DOM_LOG_ERR(efl::eina::global_domain, "foo " << 5); + EINA_CXX_DOM_LOG_INFO(efl::eina::global_domain, "foo " << 5); + EINA_CXX_DOM_LOG_DBG(efl::eina::global_domain, "foo " << 5); + EINA_CXX_DOM_LOG_WARN(efl::eina::global_domain, "foo " << 5); +} +END_TEST + +void +eina_test_log(TCase* tc) +{ + tcase_add_test(tc, eina_cxx_domain_log); + tcase_add_test(tc, eina_cxx_default_domain_log); + tcase_add_test(tc, eina_cxx_global_domain_log); + tcase_add_test(tc, eina_cxx_expensive_log); + tcase_add_test(tc, eina_cxx_level_log); +}