Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
647d07d
Add Logger class and give one to nodes
dhood Nov 29, 2017
2decda3
Try to improve compiler errors when non-Logger is passed to macros
dhood Nov 29, 2017
31d687f
Add define for 'disabling' loggers
dhood Nov 29, 2017
6ef5970
Add/update tests
dhood Nov 29, 2017
bb67d17
Linter fix
dhood Nov 29, 2017
f7a1e66
Documentation
dhood Nov 29, 2017
d92b7ce
Windows fix
dhood Nov 29, 2017
d47cb79
Move free functions to source file (windows was upset)
dhood Nov 29, 2017
be6cd99
Fix windows by changing prototype ordering
dhood Nov 29, 2017
2002852
Store node logger in NodeBase
dhood Nov 29, 2017
d9d3886
Windows is not happy with this EXPECT_ANY_THROW
dhood Nov 29, 2017
4600014
Move get_logger to a NodeLogger interface
dhood Nov 30, 2017
1566cd8
Move Logger into 'logger' namespace
dhood Nov 30, 2017
70f5bbd
Move helper function for macro errors into macro header
dhood Nov 30, 2017
05c8bc7
Remove 'logger' namespace
dhood Nov 30, 2017
c80ac85
Return type on separate line
dhood Nov 30, 2017
8d91bf3
Update copyright year
dhood Nov 30, 2017
a9c0ef7
Give lifecycle nodes a logger
dhood Nov 30, 2017
ab695af
Add test for lifecycle node logger
dhood Nov 30, 2017
a519b72
Switch to static_assert for logger check
dhood Dec 1, 2017
c3960b7
global ns scope in macro calls
dhood Dec 1, 2017
5142bab
Revert "Add test for lifecycle node logger" (make diff smaller)
dhood Dec 4, 2017
af66f6c
Update for rcutils function name change
dhood Dec 4, 2017
05d86cf
Add reference to Node::get_logger() in doxygen
dhood Dec 4, 2017
7769fb4
Rename NodeLoggerInterface to NodeLoggingInterface
dhood Dec 4, 2017
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
5 changes: 5 additions & 0 deletions rclcpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/graph_listener.cpp
src/rclcpp/intra_process_manager.cpp
src/rclcpp/intra_process_manager_impl.cpp
src/rclcpp/logger.cpp
src/rclcpp/memory_strategies.cpp
src/rclcpp/memory_strategy.cpp
src/rclcpp/node.cpp
src/rclcpp/node_interfaces/node_base.cpp
src/rclcpp/node_interfaces/node_clock.cpp
src/rclcpp/node_interfaces/node_graph.cpp
src/rclcpp/node_interfaces/node_logging.cpp
src/rclcpp/node_interfaces/node_parameters.cpp
src/rclcpp/node_interfaces/node_services.cpp
src/rclcpp/node_interfaces/node_timers.cpp
Expand Down Expand Up @@ -297,6 +299,9 @@ if(BUILD_TESTING)
target_link_libraries(test_executor ${PROJECT_NAME})
endif()

ament_add_gtest(test_logger test/test_logger.cpp)
target_link_libraries(test_logger ${PROJECT_NAME})

ament_add_gmock(test_logging test/test_logging.cpp)
target_link_libraries(test_logging ${PROJECT_NAME})

Expand Down
131 changes: 131 additions & 0 deletions rclcpp/include/rclcpp/logger.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright 2017 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef RCLCPP__LOGGER_HPP_
#define RCLCPP__LOGGER_HPP_

#include <memory>
#include <string>

#include "rclcpp/visibility_control.hpp"

/**
* \def RCLCPP_LOGGING_ENABLED
* When this define evaluates to true (default), logger factory functions will
* behave normally.
* When false, logger factory functions will create dummy loggers to avoid
* computational expense in manipulating objects.
* This should be used in combination with `RCLCPP_LOG_MIN_SEVERITY` to compile
* out logging macros.
*/
// TODO(dhood): determine this automatically from `RCLCPP_LOG_MIN_SEVERITY`
#ifndef RCLCPP_LOGGING_ENABLED
#define RCLCPP_LOGGING_ENABLED 1
#endif

namespace rclcpp
{

// Forward declaration is used for friend statement.
namespace node_interfaces
{
class NodeLogging;
}

class Logger;

/// Return a named logger.
/**
* The returned logger's name will include any naming conventions, such as a
* name prefix.
* Currently there are no such naming conventions but they may be introduced in
* the future.
*
* \param[in] name the name of the logger
* \return a logger with the fully-qualified name including naming conventions, or
* \return a dummy logger if logging is disabled.
*/
RCLCPP_PUBLIC
Logger
get_logger(const std::string & name);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

do we think this should return a shared ptr as log4cxx does or leave it up to callers to call make_shared or similar?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In our discussion it sounded like it might make sense to return a shared_ptr here. In particular this would allow us to implement the actual Logger with a specialized subclass that potentially overrides the get_name or other capabilities and keeps a weak backlink to the node and can output a warning if node goes out of scope and the backlink is broken. And although the current logger is trivially copyable right now we wouldn't need to keep it that way looking forward if we return the pointer instead of an instance.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We talked about this off-line (@dhood and I) and I pointed out that if we want to do what you describe @tfoote we don't have swap the return type to a shared pointer, instead we could have the Logger class store a shared pointer and forward all methods calls to the shared pointer. Basically we could accomplish the same thing without inheritance.

That being said, if @dhood wanted to switch this to a pointer, that's fine by me too.

Also, if we really want to return a shared pointer we can do that in the future with an API break.


class Logger
{
private:
friend Logger rclcpp::get_logger(const std::string & name);
friend ::rclcpp::node_interfaces::NodeLogging;

/// Constructor of a dummy logger.
/**
* This is used when logging is disabled: see `RCLCPP_LOGGING_ENABLED`.
* This cannot be called directly, see `rclcpp::get_logger` instead.
*/
Logger()
: name_(nullptr) {}

/// Constructor of a named logger.
/**
* This cannot be called directly, see `rclcpp::get_logger` instead.
*/
explicit Logger(const std::string & name)
: name_(new std::string(name)) {}

std::shared_ptr<const std::string> name_;

public:
RCLCPP_PUBLIC
Logger(const Logger &) = default;

/// Get the name of this logger.
/**
* \return the full name of the logger including any prefixes, or
* \return `nullptr` if this logger is invalid (e.g. because logging is
* disabled).
*/
RCLCPP_PUBLIC
const char *
get_name() const
{
if (!name_) {
return nullptr;
}
return name_->c_str();
}

/// Return a logger that is a descendant of this logger.
/**
* The child logger's full name will include any hierarchy conventions that
* indicate it is a descendant of this logger.
* For example, ```get_logger('abc').get_child('def')``` will return a logger

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nitpick: which use triple back tick here but single elsewhere?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

it wasn't rendering the full expression without the triple (the others are simpler)

* with name `abc.def`.
*
* \param[in] suffix the child logger's suffix
* \return a logger with the fully-qualified name including the suffix, or
* \return a dummy logger if this logger is invalid (e.g. because logging is
* disabled).
*/
RCLCPP_PUBLIC
Logger
get_child(const std::string & suffix)
{
if (!name_) {
return Logger();
}
return Logger(*name_ + "." + suffix);
}
};

} // namespace rclcpp

#endif // RCLCPP__LOGGER_HPP_
9 changes: 9 additions & 0 deletions rclcpp/include/rclcpp/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@
#include "rclcpp/client.hpp"
#include "rclcpp/context.hpp"
#include "rclcpp/event.hpp"
#include "rclcpp/logger.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/message_memory_strategy.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_clock_interface.hpp"
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
#include "rclcpp/node_interfaces/node_logging_interface.hpp"
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
#include "rclcpp/node_interfaces/node_services_interface.hpp"
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
Expand Down Expand Up @@ -108,6 +110,12 @@ class Node : public std::enable_shared_from_this<Node>
const char *
get_namespace() const;

/// Get the logger of the node.
/** \return The logger of the node. */
RCLCPP_PUBLIC
rclcpp::Logger
get_logger() const;

/// Create and return a callback group.
RCLCPP_PUBLIC
rclcpp::callback_group::CallbackGroup::SharedPtr
Expand Down Expand Up @@ -412,6 +420,7 @@ class Node : public std::enable_shared_from_this<Node>

rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_;
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_;
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging_;
rclcpp::node_interfaces::NodeTimersInterface::SharedPtr node_timers_;
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_;
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_;
Expand Down
61 changes: 61 additions & 0 deletions rclcpp/include/rclcpp/node_interfaces/node_logging.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2017 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef RCLCPP__NODE_INTERFACES__NODE_LOGGING_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_LOGGING_HPP_

#include <memory>

#include "rclcpp/logger.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_logging_interface.hpp"
#include "rclcpp/visibility_control.hpp"

namespace rclcpp
{
namespace node_interfaces
{

/// Implementation of the NodeLogging part of the Node API.
class NodeLogging : public NodeLoggingInterface
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeLoggingInterface)

RCLCPP_PUBLIC
explicit NodeLogging(rclcpp::node_interfaces::NodeBaseInterface * node_base);

RCLCPP_PUBLIC
virtual
~NodeLogging();

RCLCPP_PUBLIC
virtual
rclcpp::Logger
get_logger() const;

private:
RCLCPP_DISABLE_COPY(NodeLogging)

/// Handle to the NodeBaseInterface given in the constructor.
rclcpp::node_interfaces::NodeBaseInterface * node_base_;

rclcpp::Logger logger_;
};

} // namespace node_interfaces
} // namespace rclcpp

#endif // RCLCPP__NODE_INTERFACES__NODE_LOGGING_HPP_
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2017 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef RCLCPP__NODE_INTERFACES__NODE_LOGGING_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_LOGGING_INTERFACE_HPP_

#include <memory>

#include "rclcpp/logger.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/visibility_control.hpp"

namespace rclcpp
{
namespace node_interfaces
{

/// Pure virtual interface class for the NodeLogging part of the Node API.
class NodeLoggingInterface
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeLoggingInterface)

/// Return the logger of the node.
/** \return The logger of the node. */
RCLCPP_PUBLIC
virtual
rclcpp::Logger
get_logger() const = 0;
};

} // namespace node_interfaces
} // namespace rclcpp

#endif // RCLCPP__NODE_INTERFACES__NODE_LOGGING_INTERFACE_HPP_
23 changes: 15 additions & 8 deletions rclcpp/include/rclcpp/rclcpp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* `rclcpp` provides the canonical C++ API for interacting with ROS.
* It consists of these main components:
*
* - Nodes
* - Node
* - rclcpp::node::Node
* - rclcpp/node.hpp
* - Publisher
Expand Down Expand Up @@ -93,6 +93,20 @@
* - rclcpp::node::Node::count_publishers()
* - rclcpp::node::Node::count_subscribers()
*
* And components related to logging:
*
* - Logging macros:
* - Some examples (not exhaustive):
* - RCLCPP_DEBUG()
* - RCLCPP_INFO()
* - RCLCPP_WARN_ONCE()
* - RCLCPP_ERROR_SKIPFIRST()
* - rclcpp/logging.hpp
* - Logger:
* - rclcpp::Logger
* - rclcpp/logger.hpp
* - rclcpp::node::Node::get_logger()
*
* Finally, there are many internal API's and utilities:
*
* - Exceptions:
Expand All @@ -110,13 +124,6 @@
* - rclcpp::context::Context
* - rclcpp/context.hpp
* - rclcpp/contexts/default_context.hpp
* - Logging macros:
* - Some examples (not exhaustive):
* - RCLCPP_DEBUG()
* - RCLCPP_INFO()
* - RCLCPP_WARN_ONCE()
* - RCLCPP_ERROR_SKIPFIRST()
* - rclcpp/logging.hpp
* - Various utilities:
* - rclcpp/function_traits.hpp
* - rclcpp/macros.hpp
Expand Down
14 changes: 8 additions & 6 deletions rclcpp/resource/logging.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
#ifndef RCLCPP__LOGGING_HPP_
#define RCLCPP__LOGGING_HPP_

#include <type_traits>

#include "rclcpp/logger.hpp"
#include "rcutils/logging_macros.h"

// These are used for compiling out logging macros lower than a minimum severity.
Expand All @@ -31,13 +34,12 @@
* \def RCLCPP_LOG_MIN_SEVERITY
* Define RCLCPP_LOG_MIN_SEVERITY=RCLCPP_LOG_MIN_SEVERITY_[DEBUG|INFO|WARN|ERROR|FATAL]
* in your build options to compile out anything below that severity.
* Use RCUTILS_LOG_MIN_SEVERITY_NONE to compile out all macros.
* Use RCLCPP_LOG_MIN_SEVERITY_NONE to compile out all macros.
*/
#ifndef RCLCPP_LOG_MIN_SEVERITY
#define RCLCPP_LOG_MIN_SEVERITY RCLCPP_LOG_MIN_SEVERITY_DEBUG
#endif


@{
from rcutils.logging import feature_combinations
from rcutils.logging import get_macro_parameters
Expand Down Expand Up @@ -76,20 +78,20 @@ def is_supported_feature_combination(feature_combination):
@[ for doc_line in feature_combinations[feature_combination].doc_lines]@
* @(doc_line)
@[ end for]@
* \param name The name of the logger
* \param logger The `rclcpp::Logger` to use
@[ for param_name, doc_line in feature_combinations[feature_combination].params.items()]@
* \param @(param_name) @(doc_line)
@[ end for]@
* \param ... The format string, followed by the variable arguments for the format string
*/
// TODO(dhood): Replace the name argument with a logger object.
#define RCLCPP_@(severity)@(suffix)(name, @(''.join([p + ', ' for p in get_macro_parameters(feature_combination).keys()]))...) \
#define RCLCPP_@(severity)@(suffix)(logger, @(''.join([p + ', ' for p in get_macro_parameters(feature_combination).keys()]))...) \
static_assert(::std::is_same<decltype(logger), ::rclcpp::Logger>::value, "First argument to logging macros must be an rclcpp::Logger"); \
RCUTILS_LOG_@(severity)@(suffix)_NAMED( \
@{params = get_macro_parameters(feature_combination).keys()}@
@[ if params]@
@(''.join([' ' + p + ', \\\n' for p in params]))@
@[ end if]@
std::string(name).c_str(), \
logger.get_name(), \
__VA_ARGS__)

@[ end for]@
Expand Down
Loading