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
1 change: 1 addition & 0 deletions src/ros2_medkit_log_bridge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ ros2 launch ros2_medkit_log_bridge log_bridge.launch.py
| `include_only_nodes` | `[]` | if set, only promote nodes whose FQN matches |
| `max_tracked_nodes` | `512` | cap on per-node reporters; least-recently-used nodes evicted past this |
| `report_cooldown_sec` | `5.0` | per-fault_code forward debounce; `0.0` disables |
| `exclude_medkit_stack` | `true` | skip medkit's own infrastructure nodes (`fault_manager`, gateway, the other bridges) so their logs do not feed back as faults; set `false` to debug medkit's own logs |

`exclude_nodes` / `include_only_nodes` match as **unanchored substrings**
against the node FQN: `planner` matches `/planner_server` and
Expand Down
4 changes: 4 additions & 0 deletions src/ros2_medkit_log_bridge/config/log_bridge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ log_bridge:
# forwarded immediately; the same code within the window is suppressed.
# 0.0 disables. Tames ERROR/FATAL floods, which bypass the per-node filter.
report_cooldown_sec: 5.0
# Skip the medkit stack's own infrastructure nodes (fault_manager, gateway,
# the other bridges). Their /rosout lines would otherwise feed back as
# faults about medkit itself. Set false only to debug medkit's own logs.
exclude_medkit_stack: true
Comment thread
mfaferek93 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ class LogBridgeNode : public rclcpp::Node {
/// include/exclude lists. Exposed for unit testing.
bool node_is_eligible(const std::string & source_id) const;

/// Whether a logger name belongs to the medkit stack's own infrastructure
/// (fault_manager, gateway, the other bridges). Matched on the raw logger
/// name so namespaced nodes are caught. Exposed for unit testing.
static bool is_medkit_stack_logger(const std::string & logger_name);

/// Map an rcl_interfaces/msg/Log.name (a logger name, e.g. "bt_navigator" or
/// "controller_manager.resource_manager") to the originating node's
/// fully-qualified name ("/bt_navigator", "/controller_manager"). The gateway
Expand Down Expand Up @@ -121,6 +126,10 @@ class LogBridgeNode : public rclcpp::Node {
int max_tracked_nodes_;
double report_cooldown_sec_;
std::string own_node_name_;
// When true (default), never promote logs from the medkit stack's own
// infrastructure nodes (fault_manager, gateway, the other bridges) - else
// their /rosout lines feed back into faults about medkit itself.
bool exclude_medkit_stack_;
};

} // namespace ros2_medkit_log_bridge
16 changes: 16 additions & 0 deletions src/ros2_medkit_log_bridge/src/log_bridge_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ void LogBridgeNode::load_parameters() {
if (report_cooldown_sec_ < 0.0) {
report_cooldown_sec_ = 0.0;
}
exclude_medkit_stack_ = declare_parameter<bool>("exclude_medkit_stack", true);
}

void LogBridgeNode::log_callback(const rcl_interfaces::msg::Log::ConstSharedPtr & msg) {
Expand All @@ -99,6 +100,12 @@ void LogBridgeNode::log_callback(const rcl_interfaces::msg::Log::ConstSharedPtr
if (source_id == own_node_name_ || source_id == "/log_bridge") {
return;
}
// Skip the medkit stack's own infrastructure nodes (else fault_manager's own
// /rosout lines feed back as faults about medkit). Matched on the raw logger
// name, which keeps the namespace (node_source_id collapses it to the ns).
if (exclude_medkit_stack_ && is_medkit_stack_logger(msg->name)) {
return;
}
if (!node_is_eligible(source_id)) {
return;
}
Expand Down Expand Up @@ -147,6 +154,15 @@ std::string LogBridgeNode::node_source_id(const std::string & log_name) {
return node;
}

bool LogBridgeNode::is_medkit_stack_logger(const std::string & logger_name) {
// Match medkit's own infrastructure against the raw logger name so a
// namespaced node (e.g. "robot1.fault_manager") is still caught, even though
// node_source_id would collapse its FQN to the namespace.
static const std::vector<std::string> kMedkitStack = {"fault_manager", "ros2_medkit_gateway", "diagnostic_bridge",
"action_status_bridge"};
return contains_substr(kMedkitStack, logger_name);
}

bool LogBridgeNode::node_is_eligible(const std::string & source_id) const {
if (!include_only_nodes_.empty() && !contains_substr(include_only_nodes_, source_id)) {
return false;
Expand Down
17 changes: 17 additions & 0 deletions src/ros2_medkit_log_bridge/test/test_log_bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,23 @@ TEST_F(LogBridgeTest, NodeEligibility_IncludeOnlySubstring) {
EXPECT_FALSE(node->node_is_eligible("/amcl"));
}

// Matched on the raw logger name (msg->name), which is what log_callback feeds
// it - including the namespaced form "robot1.fault_manager" that node_source_id
// would otherwise collapse to "/robot1".
TEST_F(LogBridgeTest, MedkitStackLogger_MatchesOwnInfra) {
EXPECT_TRUE(LogBridgeNode::is_medkit_stack_logger("fault_manager"));
EXPECT_TRUE(LogBridgeNode::is_medkit_stack_logger("robot1.fault_manager"));
EXPECT_TRUE(LogBridgeNode::is_medkit_stack_logger("ros2_medkit_gateway"));
EXPECT_TRUE(LogBridgeNode::is_medkit_stack_logger("diagnostic_bridge"));
EXPECT_TRUE(LogBridgeNode::is_medkit_stack_logger("action_status_bridge"));
}

TEST_F(LogBridgeTest, MedkitStackLogger_AllowsApplicationNodes) {
EXPECT_FALSE(LogBridgeNode::is_medkit_stack_logger("bt_navigator"));
EXPECT_FALSE(LogBridgeNode::is_medkit_stack_logger("robot1.controller_server"));
EXPECT_FALSE(LogBridgeNode::is_medkit_stack_logger("amcl"));
}

// --- source_id normalization to node FQN (entity association) ---

TEST_F(LogBridgeTest, NodeSourceId_PrependsLeadingSlash) {
Expand Down
Loading