diff --git a/rclpy/rclpy/client.py b/rclpy/rclpy/client.py index d4d7e5124..e0fa355be 100644 --- a/rclpy/rclpy/client.py +++ b/rclpy/rclpy/client.py @@ -216,6 +216,12 @@ def service_name(self) -> str: with self.handle: return self.__client.service_name + @property + def logger_name(self) -> str: + """Get the name of the logger associated with the node of the client.""" + with self.handle: + return self.__client.get_logger_name() + def destroy(self): """ Destroy a container for a ROS service client. diff --git a/rclpy/rclpy/publisher.py b/rclpy/rclpy/publisher.py index 2570461fd..3edd99e81 100644 --- a/rclpy/rclpy/publisher.py +++ b/rclpy/rclpy/publisher.py @@ -87,6 +87,12 @@ def topic_name(self) -> str: def handle(self): return self.__publisher + @property + def logger_name(self) -> str: + """Get the name of the logger associated with the node of the publisher.""" + with self.handle: + return self.__publisher.get_logger_name() + def destroy(self): """ Destroy a container for a ROS publisher. diff --git a/rclpy/rclpy/service.py b/rclpy/rclpy/service.py index ba890576e..17515b4ef 100644 --- a/rclpy/rclpy/service.py +++ b/rclpy/rclpy/service.py @@ -107,6 +107,12 @@ def service_name(self) -> str: with self.handle: return self.__service.name + @property + def logger_name(self) -> str: + """Get the name of the logger associated with the node of the service.""" + with self.handle: + return self.__service.get_logger_name() + def destroy(self): """ Destroy a container for a ROS service server. diff --git a/rclpy/rclpy/subscription.py b/rclpy/rclpy/subscription.py index 9f993a147..996f94a1a 100644 --- a/rclpy/rclpy/subscription.py +++ b/rclpy/rclpy/subscription.py @@ -123,3 +123,9 @@ def callback(self, value): raise RuntimeError( 'Subscription.__init__(): callback should be either be callable with one argument' '(to get only the message) or two (to get message and message info)') + + @property + def logger_name(self) -> str: + """Get the name of the logger associated with the node of the subscription.""" + with self.handle: + return self.__subscription.get_logger_name() diff --git a/rclpy/src/rclpy/client.cpp b/rclpy/src/rclpy/client.cpp index c25a70a55..ccbddfd6a 100644 --- a/rclpy/src/rclpy/client.cpp +++ b/rclpy/src/rclpy/client.cpp @@ -170,6 +170,17 @@ Client::get_service_name() return rcl_client_get_service_name(rcl_client_.get()); } +const char * +Client::get_logger_name() const +{ + const char * node_logger_name = rcl_node_get_logger_name(node_.rcl_ptr()); + if (!node_logger_name) { + throw RCLError("Node logger name not set"); + } + + return node_logger_name; +} + void define_client(py::object module) { @@ -194,6 +205,9 @@ define_client(py::object module) "Take a received response from an earlier request") .def( "configure_introspection", &Client::configure_introspection, - "Configure whether introspection is enabled"); + "Configure whether introspection is enabled") + .def( + "get_logger_name", &Client::get_logger_name, + "Get the name of the logger associated with the node of the client."); } } // namespace rclpy diff --git a/rclpy/src/rclpy/client.hpp b/rclpy/src/rclpy/client.hpp index 9cef3400c..9113dd52c 100644 --- a/rclpy/src/rclpy/client.hpp +++ b/rclpy/src/rclpy/client.hpp @@ -109,6 +109,15 @@ class Client : public Destroyable, public std::enable_shared_from_this const char * get_service_name(); + /// Get the name of the logger associated with the node of the client. + /** + * + * \return logger_name, or + * \return None on failure + */ + const char * + get_logger_name() const; + private: Node node_; std::shared_ptr rcl_client_; diff --git a/rclpy/src/rclpy/service.cpp b/rclpy/src/rclpy/service.cpp index ec3ad1cfe..e24d07b97 100644 --- a/rclpy/src/rclpy/service.cpp +++ b/rclpy/src/rclpy/service.cpp @@ -155,6 +155,17 @@ Service::get_qos_profile() return rclpy::convert_to_qos_dict(&options->qos); } +const char * +Service::get_logger_name() const +{ + const char * node_logger_name = rcl_node_get_logger_name(node_.rcl_ptr()); + if (!node_logger_name) { + throw RCLError("Node logger name not set"); + } + + return node_logger_name; +} + void Service::configure_introspection( Clock & clock, py::object pyqos_service_event_pub, @@ -197,6 +208,9 @@ define_service(py::object module) "Take a request from a given service") .def( "configure_introspection", &Service::configure_introspection, - "Configure whether introspection is enabled"); + "Configure whether introspection is enabled") + .def( + "get_logger_name", &Service::get_logger_name, + "Get the name of the logger associated with the node of the service."); } } // namespace rclpy diff --git a/rclpy/src/rclpy/service.hpp b/rclpy/src/rclpy/service.hpp index 278cad097..495c23225 100644 --- a/rclpy/src/rclpy/service.hpp +++ b/rclpy/src/rclpy/service.hpp @@ -95,6 +95,15 @@ class Service : public Destroyable, public std::enable_shared_from_this const char * get_service_name(); + /// Get the name of the logger associated with the node of the service. + /** + * + * \return logger_name, or + * \return None on failure + */ + const char * + get_logger_name() const; + /// Get the QoS profile for this service. py::dict get_qos_profile(); diff --git a/rclpy/test/test_client.py b/rclpy/test/test_client.py index c18021a0d..b17635c91 100644 --- a/rclpy/test/test_client.py +++ b/rclpy/test/test_client.py @@ -242,6 +242,11 @@ def _service(request, response): self.node.destroy_client(cli) self.node.destroy_service(srv) + def test_logger_name_is_equal_to_node_name(self): + cli = self.node.create_client(GetParameters, 'get/parameters') + self.assertEqual(cli.logger_name, 'TestClient') + self.node.destroy_client(cli) + if __name__ == '__main__': unittest.main() diff --git a/rclpy/test/test_publisher.py b/rclpy/test/test_publisher.py index aef28d384..ecb367307 100644 --- a/rclpy/test/test_publisher.py +++ b/rclpy/test/test_publisher.py @@ -125,6 +125,11 @@ def test_wait_for_all_acked(self): pub.destroy() sub.destroy() + def test_logger_name_is_equal_to_node_name(self) -> None: + pub = self.node.create_publisher(BasicTypes, TEST_TOPIC, 10) + self.assertEqual(pub.logger_name, 'node') + pub.destroy() + if __name__ == '__main__': unittest.main() diff --git a/rclpy/test/test_service.py b/rclpy/test/test_service.py index c620afb11..eee62b376 100644 --- a/rclpy/test/test_service.py +++ b/rclpy/test/test_service.py @@ -20,6 +20,9 @@ from test_msgs.srv import Empty +NODE_NAME = 'test_node' + + @pytest.fixture(autouse=True) def default_context(): rclpy.init() @@ -27,6 +30,23 @@ def default_context(): rclpy.shutdown() +@pytest.fixture +def test_node(): + node = Node(NODE_NAME) + yield node + node.destroy_node() + + +def test_logger_name_is_equal_to_node_name(test_node): + srv = test_node.create_service( + srv_type=Empty, + srv_name='test_srv', + callback=lambda _: None + ) + + assert srv.logger_name == NODE_NAME + + @pytest.mark.parametrize('service_name, namespace, expected', [ # No namespaces ('service', None, '/service'), diff --git a/rclpy/test/test_subscription.py b/rclpy/test/test_subscription.py index 8a873f4be..83e14f8b2 100644 --- a/rclpy/test/test_subscription.py +++ b/rclpy/test/test_subscription.py @@ -23,11 +23,21 @@ from test_msgs.msg import Empty +NODE_NAME = 'test_node' + + @pytest.fixture(scope='session', autouse=True) def setup_ros(): rclpy.init() +@pytest.fixture +def test_node(): + node = Node(NODE_NAME) + yield node + node.destroy_node() + + @pytest.mark.parametrize('topic_name, namespace, expected', [ # No namespaces ('topic', None, '/topic'), @@ -56,6 +66,17 @@ def test_get_subscription_topic_name(topic_name, namespace, expected): node.destroy_node() +def test_logger_name_is_equal_to_node_name(test_node): + sub = test_node.create_subscription( + msg_type=Empty, + topic='topic', + callback=lambda _: None, + qos_profile=10, + ) + + assert sub.logger_name == NODE_NAME + + @pytest.mark.parametrize('topic_name, namespace, cli_args, expected', [ ('topic', None, ['--ros-args', '--remap', 'topic:=new_topic'], '/new_topic'), ('topic', 'ns', ['--ros-args', '--remap', 'topic:=new_topic'], '/ns/new_topic'),