mrs_lib
Various reusable classes, functions and utilities for use in MRS projects
Loading...
Searching...
No Matches
logger.hpp
1#ifndef MRS_LIB_LOGGER_HPP_
2#define MRS_LIB_LOGGER_HPP_
3
4#include <chrono>
5#include <format>
6#include <utility>
7
8#include <rclcpp/clock.hpp>
9#include <rclcpp/logger.hpp>
10#include <rclcpp/logging.hpp>
11#include <rclcpp/node_interfaces/node_clock_interface.hpp>
12#include <rclcpp/node_interfaces/node_interfaces.hpp>
13#include <rclcpp/node_interfaces/node_logging_interface.hpp>
14
15// Macro to expand the tokens further.
16// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
17#define MRS_LIB_GENERATE_FOR_ALL_LEVELS_EXPAND(...) __VA_ARGS__
18
19// Macro to generate methods of the logger without repeating them manually for all levels.
20// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
21#define MRS_LIB_GENERATE_FOR_ALL_LEVELS(MACRO) \
22 MRS_LIB_GENERATE_FOR_ALL_LEVELS_EXPAND(MACRO(debug, DEBUG)) \
23 MRS_LIB_GENERATE_FOR_ALL_LEVELS_EXPAND(MACRO(info, INFO)) \
24 MRS_LIB_GENERATE_FOR_ALL_LEVELS_EXPAND(MACRO(warning, WARN)) \
25 MRS_LIB_GENERATE_FOR_ALL_LEVELS_EXPAND(MACRO(error, ERROR)) \
26 MRS_LIB_GENERATE_FOR_ALL_LEVELS_EXPAND(MACRO(fatal, FATAL)) \
27 static_assert(true)
28
29// Hide the lambda from Doxygen, because it breaks Sphinx rendering.
30#define MRS_LIB_LOGGER_UNIQUE_TAG [] {}
31
32namespace mrs_lib
33{
34
44 class Logger
45 {
46 using NodeInterfaces = rclcpp::node_interfaces::NodeInterfaces<rclcpp::node_interfaces::NodeLoggingInterface, rclcpp::node_interfaces::NodeClockInterface>;
47
48 public:
49 using Level = rclcpp::Logger::Level;
50
54 explicit Logger(NodeInterfaces node) : node_interfaces_(std::move(node))
55 {
56 }
57
64 void set_level(Level level)
65 {
66 node_interfaces_.get_node_logging_interface()->get_logger().set_level(level);
67 }
68
69// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
70#define MRS_LIB_GEN_LOG(level, LEVEL) \
71 \
72 \
73 \
74 template <typename... Args> \
75 void level(std::format_string<Args...> fmt, Args&&... args) \
76 { \
77 RCLCPP_##LEVEL(get_logger(), "%s", std::format(fmt, std::forward<Args>(args)...).c_str()); \
78 }
79
80 MRS_LIB_GENERATE_FOR_ALL_LEVELS(MRS_LIB_GEN_LOG);
81#undef MRS_LIB_GEN_LOG
82
83// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
84#define MRS_LIB_GEN_LOG_ONCE(level, LEVEL) \
85 \
86 \
87 \
88 \
89 template <auto LocTag = MRS_LIB_LOGGER_UNIQUE_TAG, typename... Args> \
90 void level##_once(std::format_string<Args...> fmt, Args&&... args) \
91 { \
92 RCLCPP_##LEVEL##_ONCE(get_logger(), "%s", std::format(fmt, std::forward<Args>(args)...).c_str()); \
93 }
94
95 MRS_LIB_GENERATE_FOR_ALL_LEVELS(MRS_LIB_GEN_LOG_ONCE);
96#undef MRS_LIB_GEN_LOG_ONCE
97
98// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
99#define MRS_LIB_GEN_LOG_THROTTLE(level, LEVEL) \
100 \
101 \
102 \
103 \
104 template <auto LocTag = MRS_LIB_LOGGER_UNIQUE_TAG, typename... Args> \
105 void level##_throttle(std::chrono::milliseconds duration, std::format_string<Args...> fmt, Args&&... args) \
106 { \
107 RCLCPP_##LEVEL##_THROTTLE(get_logger(), get_clock(), duration.count(), "%s", std::format(fmt, std::forward<Args>(args)...).c_str()); \
108 }
109
110 MRS_LIB_GENERATE_FOR_ALL_LEVELS(MRS_LIB_GEN_LOG_THROTTLE);
111#undef MRS_LIB_GEN_LOG_THROTTLE
112
113 private:
114 rclcpp::Logger get_logger()
115 {
116 return node_interfaces_.get_node_logging_interface()->get_logger();
117 }
118
119 rclcpp::Clock& get_clock()
120 {
121 return *node_interfaces_.get_node_clock_interface()->get_clock();
122 }
123
124 NodeInterfaces node_interfaces_;
125 };
126
127} // namespace mrs_lib
128
129#undef MRS_LIB_LOGGER_UNIQUE_TAG
130#undef MRS_LIB_GENERATE_FOR_ALL_LEVELS
131#undef MRS_LIB_GENERATE_FOR_ALL_LEVELS_EXPAND
132
133#endif // MRS_LIB_LOGGER_HPP_
Logger(NodeInterfaces node)
Construct from node like object with the required interfaces.
Definition logger.hpp:54
void set_level(Level level)
Set output level of the stored logger.
Definition logger.hpp:64
All mrs_lib functions, classes, variables and definitions are contained in this namespace.
Definition attitude_converter.h:24