Task · MDE-0066

Repair the MS per-device port-usage fallback after ID-only labels

Description

The post-v2 live soak confirmed that the per-device port-usage fallback fails before its API call. collect_device_port_usage_metrics() builds an ID-only device-label map and then reads device_labels["name"] for LogContext (src/meraki_dashboard_exporter/collectors/devices/ms.py:1272-1284), while the label helper deliberately removed display-name keys (src/meraki_dashboard_exporter/core/label_helpers.py:21-65). DeviceCollector invokes this helper when the organization usage path fails or is unavailable (src/meraki_dashboard_exporter/collectors/device.py:981-1005). The concrete result is one swallowed KeyError("name") per switch, counted as unknown, before getDeviceSwitchPortsStatuses runs; the live soak observed four such errors while top-level DeviceCollector failures remained zero. Tests exercise ms_collector.collect() but never call this fallback helper directly (tests/unit/collectors/test_ms_collector.py:1470-1499). This is a live medium-severity defect: when status bulk collection succeeds but usage bulk collection fails, the intended usage fallback emits nothing, and the top-level success counter masks it.

Acceptance Criteria

Definition of Done

Implementation Notes

2026-09-04 main thread. Failing-first evidence: driving collect_device_port_usage_metrics directly raised KeyError: ‘name’ at ms.py:1279 inside the LogContext construction, before getDeviceSwitchPortsStatuses ran — exactly the reported mechanism. After sourcing the display name from the device input with device.get(‘name’, ‘’), the same regression showed the API call completing, the response validating with name=sw1 in the log context, and meraki_ms_port_traffic_bytes_per_second emitted with ID-only labels and no name label.

Metric labels are unchanged: create_device_labels still omits the display name per #534, and only the logging context reads it. Focused result: 49 passed for the MS module. Full gate: just check 2945 passed, 5 deselected, 91.49% coverage. CodeRabbit reported 0 findings.

Final Summary

Fixed in 84aa7e8. The per-device port-usage fallback now takes its logging display name from the device input rather than the ID-only Prometheus label map, so it no longer raises KeyError before its API call. Verified by a focused regression driven directly against collect_device_port_usage_metrics, watched failing with KeyError: ‘name’ at the LogContext line and passing afterwards with the API call made and meraki_ms_port_traffic_bytes_per_second emitted under ID-only labels. MS module 49 passed; just check 2945 passed at 91.49% coverage; CodeRabbit 0 findings. DoD2: the generated-drift gate passed with no declaration change. DoD3: metric labels are unchanged and remain ID-only, so no Grafana query needed updating.

View the source file on GitHub