Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store logger name associated with node #212

Merged
merged 11 commits into from
Feb 26, 2018
Merged
Show file tree
Hide file tree
Changes from 10 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
27 changes: 27 additions & 0 deletions rcl/include/rcl/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,33 @@ RCL_WARN_UNUSED
const struct rcl_guard_condition_t *
rcl_node_get_graph_guard_condition(const rcl_node_t * node);

/// Return the logger name of the node.
/**
* This function returns the node's internal logger name string.
* This function can fail, and therefore return `NULL`, if:
* - node is `NULL`
* - node has not been initialized (the implementation is invalid)
*
* The returned string is only valid as long as the given rcl_node_t is valid.
* The value of the string may change if the value in the rcl_node_t changes,
* and therefore copying the string is recommended if this is a concern.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] node pointer to the node
* \return logger_name string if successful, otherwise `NULL`
*/
RCL_PUBLIC
RCL_WARN_UNUSED
const char *
rcl_node_get_logger_name(const rcl_node_t * node);

#if __cplusplus
}
#endif
Expand Down
64 changes: 64 additions & 0 deletions rcl/src/rcl/node.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ extern "C"
#include "rcl/error_handling.h"
#include "rcl/rcl.h"
#include "rcutils/filesystem.h"
#include "rcutils/find.h"
#include "rcutils/format_string.h"
#include "rcutils/get_env.h"
#include "rcutils/logging_macros.h"
#include "rcutils/macros.h"
#include "rcutils/repl_str.h"
#include "rcutils/snprintf.h"
#include "rcutils/strdup.h"
#include "rmw/error_handling.h"
#include "rmw/node_security_options.h"
#include "rmw/rmw.h"
Expand All @@ -52,9 +55,51 @@ typedef struct rcl_node_impl_t
rmw_node_t * rmw_node_handle;
uint64_t rcl_instance_id;
rcl_guard_condition_t * graph_guard_condition;
const char * logger_name;
} rcl_node_impl_t;


/// Return the logger name associated with a node given the validated node name and namespace.
/**
* E.g. for a node named "c" in namespace "/a/b", the logger name will be
* "a.b.c", assuming logger name separator of ".".
*
* \param[in] node_name validated node name (a single token)
* \param[in] node_namespace validated, absolute namespace (starting with "/")
* \param[in] allocator the allocator to use for allocation
* \returns duplicated string or null if there is an error
*/
const char * rcl_create_node_logger_name(
const char * node_name,
const char * node_namespace,
const rcl_allocator_t * allocator)
{
// If the namespace is the root namespace ("/"), the logger name is just the node name.
if (strlen(node_namespace) == 1) {
return rcutils_strdup(node_name, *allocator);
}

// Convert the forward slashes in the namespace to the separator used for logger names.
// The input namespace has already been expanded and therefore will always be absolute,
// i.e. it will start with a forward slash, which we want to ignore.
const char * ns_with_separators = rcutils_repl_str(
node_namespace + 1, // Ignore the leading forward slash.
"/", RCUTILS_LOGGING_SEPARATOR_STRING,
(rcl_allocator_t *)allocator); // TODO(dhood): remove need for casting away const
Copy link
Contributor

Choose a reason for hiding this comment

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

is that comment still valid?

Copy link
Member Author

Choose a reason for hiding this comment

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

valid until ros2/rcutils#89 is merged

if (NULL == ns_with_separators) {
return NULL;
}

// Join the namespace and node name to create the logger name.
char * node_logger_name = rcutils_format_string(
*allocator, "%s%s%s", ns_with_separators, RCUTILS_LOGGING_SEPARATOR_STRING, node_name);
if (NULL == node_logger_name) {
allocator->deallocate((char *)ns_with_separators, allocator->state);
return NULL;
}
return node_logger_name;
}

const char * rcl_get_secure_root(const char * node_name)
{
const char * ros_secure_root_env = NULL;
Expand Down Expand Up @@ -187,6 +232,12 @@ rcl_node_init(
// Initialize node impl.
// node options (assume it is trivially copyable)
node->impl->options = *options;

// node logger name
node->impl->logger_name = rcl_create_node_logger_name(name, local_namespace_, allocator);
RCL_CHECK_FOR_NULL_WITH_MSG(
node->impl->logger_name, "creating logger name failed", goto fail, *allocator);

// node rmw_node_handle
if (node->impl->options.domain_id == RCL_NODE_OPTIONS_DEFAULT_DOMAIN_ID) {
// Find the domain ID set by the environment.
Expand Down Expand Up @@ -300,6 +351,9 @@ rcl_node_init(
return RCL_RET_OK;
fail:
if (node->impl) {
if (node->impl->logger_name) {
allocator->deallocate((char *)node->impl->logger_name, allocator->state);
}
if (node->impl->rmw_node_handle) {
ret = rmw_destroy_node(node->impl->rmw_node_handle);
if (ret != RMW_RET_OK) {
Expand Down Expand Up @@ -353,6 +407,7 @@ rcl_node_fini(rcl_node_t * node)
}
allocator.deallocate(node->impl->graph_guard_condition, allocator.state);
// assuming that allocate and deallocate are ok since they are checked in init
allocator.deallocate((char *)node->impl->logger_name, allocator.state);
allocator.deallocate(node->impl, allocator.state);
node->impl = NULL;
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Node finalized")
Expand Down Expand Up @@ -456,6 +511,15 @@ rcl_node_get_graph_guard_condition(const rcl_node_t * node)
return node->impl->graph_guard_condition;
}

const char *
rcl_node_get_logger_name(const rcl_node_t * node)
{
if (!rcl_node_is_valid(node, NULL)) {
return NULL;
}
return node->impl->logger_name;
}

#if __cplusplus
}
#endif
114 changes: 114 additions & 0 deletions rcl/test/rcl/test_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,30 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
if (actual_node_namespace) {
EXPECT_EQ(std::string(namespace_), std::string(actual_node_namespace));
}
// Test rcl_node_get_logger_name().
const char * actual_node_logger_name;
actual_node_logger_name = rcl_node_get_logger_name(nullptr);
EXPECT_EQ(nullptr, actual_node_logger_name);
rcl_reset_error();
actual_node_logger_name = rcl_node_get_logger_name(&zero_node);
EXPECT_EQ(nullptr, actual_node_logger_name);
rcl_reset_error();
actual_node_logger_name = rcl_node_get_logger_name(&invalid_node);
EXPECT_EQ(nullptr, actual_node_logger_name);
rcl_reset_error();
start_memory_checking();
assert_no_malloc_begin();
assert_no_realloc_begin();
assert_no_free_begin();
actual_node_logger_name = rcl_node_get_logger_name(&node);
assert_no_malloc_end();
assert_no_realloc_end();
assert_no_free_end();
stop_memory_checking();
EXPECT_TRUE(actual_node_logger_name ? true : false);
if (actual_node_logger_name) {
EXPECT_EQ("ns." + std::string(name), std::string(actual_node_logger_name));
}
// Test rcl_node_get_options().
const rcl_node_options_t * actual_options;
actual_options = rcl_node_get_options(nullptr);
Expand Down Expand Up @@ -555,3 +579,93 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_namespace_r
EXPECT_EQ(RCL_RET_OK, ret);
}
}

/* Tests the logger name associated with the node.
*/
TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_logger_name) {
stop_memory_checking();
rcl_ret_t ret;

// Initialize rcl with rcl_init().
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret);
auto rcl_shutdown_exit = make_scope_exit(
[]() {
rcl_ret_t ret = rcl_shutdown();
ASSERT_EQ(RCL_RET_OK, ret);
});

const char * name = "node";
const char * actual_node_logger_name;
rcl_node_options_t default_options = rcl_node_get_default_options();

// First do a normal node namespace.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "/ns", &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
actual_node_logger_name = rcl_node_get_logger_name(&node);
EXPECT_TRUE(actual_node_logger_name ? true : false);
if (actual_node_logger_name) {
EXPECT_EQ("ns." + std::string(name), std::string(actual_node_logger_name));
}
rcl_ret_t ret = rcl_node_fini(&node);
EXPECT_EQ(RCL_RET_OK, ret);
}

// Node namespace that is an empty string.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "", &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
actual_node_logger_name = rcl_node_get_logger_name(&node);
EXPECT_TRUE(actual_node_logger_name ? true : false);
if (actual_node_logger_name) {
EXPECT_EQ(std::string(name), std::string(actual_node_logger_name));
}
rcl_ret_t ret = rcl_node_fini(&node);
EXPECT_EQ(RCL_RET_OK, ret);
}

// Node namespace that is just a forward slash.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "/", &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
actual_node_logger_name = rcl_node_get_logger_name(&node);
EXPECT_TRUE(actual_node_logger_name ? true : false);
if (actual_node_logger_name) {
EXPECT_EQ(std::string(name), std::string(actual_node_logger_name));
}
rcl_ret_t ret = rcl_node_fini(&node);
EXPECT_EQ(RCL_RET_OK, ret);
}

// Node namespace that is not absolute.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "ns", &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
actual_node_logger_name = rcl_node_get_logger_name(&node);
EXPECT_TRUE(actual_node_logger_name ? true : false);
if (actual_node_logger_name) {
EXPECT_EQ("ns." + std::string(name), std::string(actual_node_logger_name));
}
rcl_ret_t ret = rcl_node_fini(&node);
EXPECT_EQ(RCL_RET_OK, ret);
}

// Nested namespace.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "/ns/sub_1/sub_2", &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
actual_node_logger_name = rcl_node_get_logger_name(&node);
EXPECT_TRUE(actual_node_logger_name ? true : false);
if (actual_node_logger_name) {
EXPECT_EQ("ns.sub_1.sub_2." + std::string(name), std::string(actual_node_logger_name));
}
rcl_ret_t ret = rcl_node_fini(&node);
EXPECT_EQ(RCL_RET_OK, ret);
}
}