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
40 changes: 40 additions & 0 deletions routers/bot_orchestration.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,46 @@ async def get_bot_history(
return {"status": "success", "response": response}


@router.get("/{bot_name}/logs")
def get_bot_logs(
bot_name: str,
log_type: str = "all",
limit: int = 100,
bots_manager: BotsOrchestrator = Depends(get_bots_orchestrator)
):
"""
Get recent logs for a specific bot.

Query parameters:
- **log_type**: Filter logs by type (`all`, `general`, `error`)
- **limit**: Maximum number of entries to return per log bucket
"""
if log_type not in {"all", "general", "error"}:
raise HTTPException(
status_code=400,
detail="log_type must be one of: all, general, error",
)

if limit < 1:
raise HTTPException(
status_code=400,
detail="limit must be greater than 0",
)

response = bots_manager.get_bot_logs(
bot_name,
log_type=log_type,
limit=limit,
)
if response is None:
raise HTTPException(status_code=404, detail="Bot not found")

return {
"status": "success",
"data": response,
}


@router.post("/start-bot")
async def start_bot(
action: StartBotAction,
Expand Down
51 changes: 44 additions & 7 deletions services/bots_orchestrator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import asyncio
import logging
from typing import Optional
import re
from typing import Optional

import docker

Expand Down Expand Up @@ -32,7 +32,7 @@ def __init__(self, broker_host, broker_port, broker_username, broker_password):
# Active bots tracking
self.active_bots = {}
self._update_bots_task: Optional[asyncio.Task] = None

# Track bots that are currently being stopped and archived
self.stopping_bots = set()

Expand Down Expand Up @@ -303,7 +303,7 @@ def get_bot_status(self, bot_name):
"general_logs": [],
"recently_active": False,
}

# Get data from MQTT manager
controller_reports = self.mqtt_manager.get_bot_controller_reports(bot_name)
performance = self.determine_controller_performance(controller_reports)
Expand Down Expand Up @@ -331,18 +331,55 @@ def get_bot_status(self, bot_name):
}
except Exception as e:
return {"status": "error", "error": str(e)}


def get_bot_logs(self, bot_name: str, log_type: str = "all", limit: int = 100):
"""Get recent MQTT-backed logs for a specific bot."""
general_logs = self.mqtt_manager.get_bot_logs(bot_name)
error_logs = self.mqtt_manager.get_bot_error_logs(bot_name)

if bot_name not in self.active_bots and not general_logs and not error_logs:
return None

if limit and limit > 0:
general_logs = general_logs[-limit:]
error_logs = error_logs[-limit:]

if log_type == "general":
return {
"bot_name": bot_name,
"log_type": log_type,
"general_logs": general_logs,
"error_logs": [],
"total_count": len(general_logs),
}

if log_type == "error":
return {
"bot_name": bot_name,
"log_type": log_type,
"general_logs": [],
"error_logs": error_logs,
"total_count": len(error_logs),
}

return {
"bot_name": bot_name,
"log_type": "all",
"general_logs": general_logs,
"error_logs": error_logs,
"total_count": len(general_logs) + len(error_logs),
}

def set_bot_stopping(self, bot_name: str):
"""Mark a bot as currently being stopped and archived."""
self.stopping_bots.add(bot_name)
logger.info(f"Marked bot {bot_name} as stopping")

def clear_bot_stopping(self, bot_name: str):
"""Clear the stopping status for a bot."""
self.stopping_bots.discard(bot_name)
logger.info(f"Cleared stopping status for bot {bot_name}")

def is_bot_stopping(self, bot_name: str) -> bool:
"""Check if a bot is currently being stopped."""
return bot_name in self.stopping_bots