Skip to content

Commit 9bcd61b

Browse files
committed
Add Basler acquisition stats debug logging
Adds rate-limited debug logging of Basler acquisition and stream-grabber buffer statistics to help diagnose frame retrieval issues. The backend now logs these stats after successful frame reads and after frame read errors, with new helper methods to collect camera and stream-grabber counters.
1 parent b9feabd commit 9bcd61b

1 file changed

Lines changed: 52 additions & 0 deletions

File tree

‎dlclivegui/cameras/backends/basler_backend.py‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def __init__(self, settings):
5151
)
5252
self._camera_pixel_format: str | None = None
5353
self._logged_first_frame: bool = False
54+
self._debug_last_acquis_stats_log: float = 0.0
5455

5556
# Optional fast-start hint for probe workers
5657
# (may skip StartGrabbing and converter setup for faster capability probing; not suitable for normal capture)
@@ -723,6 +724,8 @@ def read(self) -> tuple[np.ndarray, float]:
723724
grab_result.Release()
724725
grab_result = None
725726

727+
self._debug_log_acquisition_stats(context="after frame read")
728+
726729
if self._actual_width is None or self._actual_height is None:
727730
h, w = frame.shape[:2]
728731
self._actual_width = int(w)
@@ -747,6 +750,8 @@ def read(self) -> tuple[np.ndarray, float]:
747750

748751
self._timing.note_error()
749752
self._timing.maybe_log()
753+
self._debug_log_acquisition_stats(context=f"after frame read error: {type(exc).__name__}")
754+
750755
raise RuntimeError("Failed to retrieve image from Basler camera.") from exc
751756

752757
def close(self) -> None:
@@ -958,6 +963,53 @@ def _set_numeric_feature(self, name: str, value, *, strict: bool = False) -> boo
958963
LOG.warning("Failed to set Basler feature '%s' to '%s': %s", name, value, exc)
959964
return False
960965

966+
def _debug_log_acquisition_stats(
967+
self,
968+
*,
969+
context: str,
970+
force: bool = False,
971+
) -> None:
972+
if not BASLER_DO_LOG_TIMING or not LOG.isEnabledFor(logging.DEBUG):
973+
return
974+
975+
now = time.monotonic()
976+
if not force and now - self._debug_last_acquisition_stats_log < 1.0:
977+
return
978+
979+
self._debug_last_acquisition_stats_log = now
980+
stats = self._debug_read_acquisition_stats()
981+
if stats:
982+
LOG.debug(
983+
"[Basler] acquisition stats context=%s values=%s",
984+
context,
985+
stats,
986+
)
987+
988+
def _debug_read_acquisition_stats(self) -> dict[str, int]:
989+
cam = self._camera
990+
if cam is None or not cam.IsGrabbing():
991+
return {}
992+
993+
stats: dict[str, int] = {}
994+
for name in ("NumReadyBuffers", "NumQueuedBuffers", "MaxNumBuffer"):
995+
try:
996+
stats[name] = int(getattr(cam, name).GetValue())
997+
except Exception:
998+
pass
999+
1000+
try:
1001+
sg = cam.StreamGrabber
1002+
for name in (
1003+
"Statistic_Buffer_Underrun_Count",
1004+
"Statistic_Missed_Frame_Count",
1005+
"Statistic_Failed_Buffer_Count",
1006+
):
1007+
stats[name] = int(getattr(sg, name).GetValue())
1008+
except Exception:
1009+
pass
1010+
1011+
return stats
1012+
9611013
def _debug_trigger_nodes(self, *, context: str = "") -> None:
9621014
if not LOG.isEnabledFor(logging.DEBUG) or not DEBUG_TRIGGER_LOGS:
9631015
return

0 commit comments

Comments
 (0)