Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions include/rcutils/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,30 @@ extern "C"
RCUTILS_PUBLIC
extern bool g_rcutils_logging_initialized;

/// Initialize the logging allocator.
/**
* This function is called automatically when using the logging macros.
* Initialize the logging allocator only if it is not initialized yet.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
*
* \return #RCUTILS_RET_OK if successful initialized, or
* \return #RCUTILS_RET_INVALID_ARGUMENT if the allocator is invalid.
*/
RCUTILS_PUBLIC
RCUTILS_WARN_UNUSED
rcutils_ret_t rcutils_logging_allocator_initialize(
const rcutils_allocator_t * allocator);

/// Initialize the logging system using the specified allocator.
/**
* Call rcutils_logging_allocator_initialize() using allocator argument.
* Initialize the logging system only if it was not in an initialized state.
*
* If an invalid allocator is passed, the initialization will fail.
Expand Down
45 changes: 41 additions & 4 deletions src/logging.c
Original file line number Diff line number Diff line change
Expand Up @@ -626,20 +626,56 @@ static void parse_and_create_handlers_list(void)
}
}

rcutils_ret_t rcutils_logging_allocator_initialize(
const rcutils_allocator_t * allocator)
{
RCUTILS_CHECK_ALLOCATOR_WITH_MSG(
allocator, "invalid allocator", return RCUTILS_RET_INVALID_ARGUMENT);

if (rcutils_allocator_is_valid(&g_rcutils_logging_allocator)) {
return RCUTILS_RET_OK;
}
g_rcutils_logging_allocator = *allocator;

return RCUTILS_RET_OK;
}

rcutils_ret_t rcutils_logging_initialize_with_allocator(rcutils_allocator_t allocator)
{
if (g_rcutils_logging_initialized) {
return RCUTILS_RET_OK;
}

if (!rcutils_allocator_is_valid(&allocator)) {
RCUTILS_SET_ERROR_MSG("Provided allocator is invalid.");
if (rcutils_logging_allocator_initialize(&allocator) != RCUTILS_RET_OK) {
return RCUTILS_RET_INVALID_ARGUMENT;
}
g_rcutils_logging_allocator = allocator;

g_rcutils_logging_output_handler = &rcutils_logging_console_output_handler;
g_rcutils_logging_default_logger_level = RCUTILS_DEFAULT_LOGGER_DEFAULT_LEVEL;
// Check for the environment variable for default logger level
const char * env_default_level;
const char * ret_str_level =
rcutils_get_env("RCUTILS_DEFAULT_LOGGER_DEFAULT_LEVEL", &env_default_level);
if (NULL != ret_str_level) {
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING(
"Error getting environment variable RCUTILS_DEFAULT_LOGGER_DEFAULT_LEVEL: %s", ret_str_level);
g_rcutils_logging_default_logger_level = RCUTILS_DEFAULT_LOGGER_DEFAULT_LEVEL;
} else if (strcmp(env_default_level, "") == 0) {
// Environment variable is empty, use default
g_rcutils_logging_default_logger_level = RCUTILS_DEFAULT_LOGGER_DEFAULT_LEVEL;
} else {
// Try to convert the environment variable value to a severity level
int env_severity;
rcutils_ret_t severity_ret = rcutils_logging_severity_level_from_string(
env_default_level, g_rcutils_logging_allocator, &env_severity);
if (severity_ret == RCUTILS_RET_OK) {
g_rcutils_logging_default_logger_level = env_severity;
} else {
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING(
"Invalid severity level '%s' in RCUTILS_DEFAULT_LOGGER_DEFAULT_LEVEL. Using default.",
env_default_level);
g_rcutils_logging_default_logger_level = RCUTILS_DEFAULT_LOGGER_DEFAULT_LEVEL;
}
}
Comment on lines +654 to +678
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is new behavior we introduce with this PR.

before, the default global log level is fixed as RCUTILS_DEFAULT_LOGGER_DEFAULT_LEVEL statically, that leads the situation if the initialization of context is not finished, there is no way to print the debug log message unless rebuild the system with changing RCUTILS_DEFAULT_LOGGER_DEFAULT_LEVEL.
but now, user application can set RCUTILS_DEFAULT_LOGGER_DEFAULT_LEVEL environmental variable to change the default global log level at runtime without any code change. this gives more flexibility to debug the initialization process for ROS 2 system libraries.


const char * line_buffered = NULL;
const char * ret_str = rcutils_get_env("RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED", &line_buffered);
Expand Down Expand Up @@ -802,6 +838,7 @@ rcutils_ret_t rcutils_logging_shutdown(void)
g_rcutils_logging_severities_map_valid = false;
}
g_num_log_msg_handlers = 0;
g_rcutils_logging_allocator = rcutils_get_zero_initialized_allocator();
g_rcutils_logging_initialized = false;

#ifdef _WIN32
Expand Down
12 changes: 12 additions & 0 deletions test/test_logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@
#include "rcutils/logging.h"
#include "rcutils/strdup.h"

TEST(TestLogging, test_logging_allocator_initialization) {
rcutils_allocator_t allocator = rcutils_get_default_allocator();
rcutils_allocator_t invalid_allocator = rcutils_get_zero_initialized_allocator();

ASSERT_EQ(RCUTILS_RET_INVALID_ARGUMENT, rcutils_logging_allocator_initialize(NULL));
ASSERT_EQ(RCUTILS_RET_INVALID_ARGUMENT, rcutils_logging_allocator_initialize(&invalid_allocator));

ASSERT_EQ(RCUTILS_RET_OK, rcutils_logging_allocator_initialize(&allocator));
// 2nd time will also succeed.
ASSERT_EQ(RCUTILS_RET_OK, rcutils_logging_allocator_initialize(&allocator));
}

TEST(TestLogging, test_logging_initialization) {
EXPECT_FALSE(g_rcutils_logging_initialized);
ASSERT_EQ(RCUTILS_RET_OK, rcutils_logging_initialize());
Expand Down