diff --git a/rclcpp/include/rclcpp/logger.hpp b/rclcpp/include/rclcpp/logger.hpp index 622ddd27da..77f7f8d670 100644 --- a/rclcpp/include/rclcpp/logger.hpp +++ b/rclcpp/include/rclcpp/logger.hpp @@ -170,6 +170,24 @@ class Logger RCLCPP_PUBLIC void set_level(Level level); + + /// Get effective level for current logger. + /** + * The effective level is determined as the severity level of + * the logger if it is set, otherwise it is the first specified severity + * level of the logger's ancestors, starting with its closest ancestor. + * The ancestor hierarchy is signified by logger names being separated by dots: + * a logger named `x` is an ancestor of `x.y`, and both `x` and `x.y` are + * ancestors of `x.y.z`, etc. + * If the level has not been set for the logger nor any of its + * ancestors, the default level is used. + * + * \throws rclcpp::exceptions::RCLError if any error happens. + * \return Level for the current logger. + */ + RCLCPP_PUBLIC + Level + get_effective_level() const; }; } // namespace rclcpp diff --git a/rclcpp/src/rclcpp/logger.cpp b/rclcpp/src/rclcpp/logger.cpp index d1a7640215..874858b180 100644 --- a/rclcpp/src/rclcpp/logger.cpp +++ b/rclcpp/src/rclcpp/logger.cpp @@ -125,4 +125,18 @@ Logger::set_level(Level level) } } +Logger::Level +Logger::get_effective_level() const +{ + int logger_level = rcutils_logging_get_logger_effective_level(get_name()); + + if (logger_level < 0) { + exceptions::throw_from_rcl_error( + RCL_RET_ERROR, "Couldn't get logger level", + rcutils_get_error_state(), rcutils_reset_error); + } + + return static_cast(logger_level); +} + } // namespace rclcpp diff --git a/rclcpp/test/rclcpp/test_logger.cpp b/rclcpp/test/rclcpp/test_logger.cpp index 1869b8f478..83d42f0ce8 100644 --- a/rclcpp/test/rclcpp/test_logger.cpp +++ b/rclcpp/test/rclcpp/test_logger.cpp @@ -160,6 +160,50 @@ TEST(TestLogger, set_level) { EXPECT_EQ(RCUTILS_RET_OK, rcutils_logging_shutdown()); } +TEST(TestLogger, get_effective_level) { + ASSERT_EQ(RCUTILS_RET_OK, rcutils_logging_initialize()); + + rclcpp::Logger logger = rclcpp::get_logger("test_logger"); + rclcpp::Logger child_logger = rclcpp::get_logger("test_logger.child"); + + // set child logger level unset to test effective level + child_logger.set_level(rclcpp::Logger::Level::Unset); + + // default + EXPECT_EQ(rclcpp::Logger::Level::Info, logger.get_effective_level()); + EXPECT_EQ(rclcpp::Logger::Level::Info, child_logger.get_effective_level()); + + // unset + logger.set_level(rclcpp::Logger::Level::Unset); + EXPECT_EQ(rclcpp::Logger::Level::Info, logger.get_effective_level()); + EXPECT_EQ(rclcpp::Logger::Level::Info, child_logger.get_effective_level()); + + // debug + logger.set_level(rclcpp::Logger::Level::Debug); + EXPECT_EQ(rclcpp::Logger::Level::Debug, logger.get_effective_level()); + EXPECT_EQ(rclcpp::Logger::Level::Debug, child_logger.get_effective_level()); + + // info + logger.set_level(rclcpp::Logger::Level::Info); + EXPECT_EQ(rclcpp::Logger::Level::Info, logger.get_effective_level()); + EXPECT_EQ(rclcpp::Logger::Level::Info, child_logger.get_effective_level()); + + // warn + logger.set_level(rclcpp::Logger::Level::Warn); + EXPECT_EQ(rclcpp::Logger::Level::Warn, logger.get_effective_level()); + EXPECT_EQ(rclcpp::Logger::Level::Warn, child_logger.get_effective_level()); + + // error + logger.set_level(rclcpp::Logger::Level::Error); + EXPECT_EQ(rclcpp::Logger::Level::Error, logger.get_effective_level()); + EXPECT_EQ(rclcpp::Logger::Level::Error, child_logger.get_effective_level()); + + // fatal + logger.set_level(rclcpp::Logger::Level::Fatal); + EXPECT_EQ(rclcpp::Logger::Level::Fatal, logger.get_effective_level()); + EXPECT_EQ(rclcpp::Logger::Level::Fatal, child_logger.get_effective_level()); +} + TEST(TestLogger, get_logging_directory) { ASSERT_EQ(true, rcutils_set_env("HOME", "/fake_home_dir")); ASSERT_EQ(true, rcutils_set_env("USERPROFILE", nullptr));