class CrewAILoggingEventListener:
"""Logs the CrewAI agent/task/tool lifecycle for dragent observability."""
def setup_listeners(self, crewai_event_bus: CrewAIEventsBus) -> None:
def _register(event_type: Any, render: Any) -> None:
@crewai_event_bus.on(event_type)
def _handler(_: Any, event: Any) -> None:
# CrewAI's bus already isolates handler exceptions; swallow here too so a
# malformed payload logs at DEBUG instead of the bus's error level.
try:
render(event)
except Exception:
logger.debug("CrewAI logging handler error", exc_info=True)
_register(
CrewKickoffStartedEvent,
lambda e: logger.debug("crew kickoff: inputs=%s", _truncate(getattr(e, "inputs", ""))),
)
_register(
AgentExecutionStartedEvent,
lambda e: logger.info("[%s] agent started", _role(e)),
)
_register(
TaskStartedEvent,
lambda e: logger.info("[%s] task started: %s", _role(e), _truncate(_task_name(e))),
)
_register(
TaskCompletedEvent,
lambda e: logger.info(
"[%s] task completed: %s", _role(e), _truncate(getattr(e, "output", ""))
),
)
_register(
TaskFailedEvent,
lambda e: logger.warning(
"[%s] task failed: %s", _role(e), _truncate(getattr(e, "error", ""))
),
)
_register(
ToolUsageStartedEvent,
lambda e: logger.info(
"[%s] tool call: %s(%s) attempt=%s",
_role(e),
getattr(e, "tool_name", ""),
_truncate(getattr(e, "tool_args", "")),
getattr(e, "run_attempts", ""),
),
)
_register(
ToolUsageFinishedEvent,
lambda e: logger.info(
"[%s] tool %s -> %s",
_role(e),
getattr(e, "tool_name", ""),
_truncate(getattr(e, "output", "")),
),
)
_register(
ToolUsageErrorEvent,
lambda e: logger.warning(
"[%s] tool %s error: %s",
_role(e),
getattr(e, "tool_name", ""),
_truncate(getattr(e, "error", "")),
),
)
_register(
AgentReasoningStartedEvent,
lambda e: logger.debug("[%s] reasoning started", _role(e)),
)
_register(
AgentReasoningCompletedEvent,
lambda e: logger.debug("[%s] reasoning completed", _role(e)),
)
_register(
AgentReasoningFailedEvent,
lambda e: logger.debug("[%s] reasoning failed", _role(e)),
)