Files
microdao-daarion/services/monitor-agent-service/app/monitor_logger.py
Apple fca48b3eb0 feat(node2): Complete NODE2 setup - guardian, agents, swapper models
- Node-guardian running on MacBook and updating metrics
- NODE2 agents (Atlas, Greeter, Oracle, Builder Bot) assigned to node-2-macbook-m4max
- Swapper models displaying correctly (8 models)
- DAGI Router agents showing with correct status (3 active, 1 stale)
- Router health check using node_cache for remote nodes
2025-12-02 07:07:58 -08:00

234 lines
8.6 KiB
Python

"""
Monitor Agent Logger - Автоматичне створення MD файлів та Jupyter Notebook
для кожного Monitor Agent з усіма змінами та подіями
"""
import os
import json
from datetime import datetime
from typing import Dict, Any, Optional
from pathlib import Path
import logging
logger = logging.getLogger(__name__)
# Базовий шлях для збереження логів Monitor Agent
MONITOR_LOGS_DIR = Path(os.getenv("MONITOR_LOGS_DIR", "docs/monitor_agents"))
MONITOR_LOGS_DIR.mkdir(parents=True, exist_ok=True)
def get_monitor_agent_file_paths(agent_id: str) -> Dict[str, Path]:
"""
Отримати шляхи до MD файлу та Jupyter Notebook для Monitor Agent
Args:
agent_id: ID Monitor Agent (monitor, monitor-node-{node_id}, monitor-microdao-{microdao_id})
Returns:
Dict з шляхами до MD файлу та Jupyter Notebook
"""
# Нормалізуємо agent_id для використання в іменах файлів
safe_id = agent_id.replace('/', '_').replace(':', '_')
return {
'md': MONITOR_LOGS_DIR / f"{safe_id}_changes.md",
'ipynb': MONITOR_LOGS_DIR / f"{safe_id}_changes.ipynb",
}
def append_to_markdown(agent_id: str, change: Dict[str, Any], message: str) -> None:
"""
Додати зміну до MD файлу Monitor Agent
Args:
agent_id: ID Monitor Agent
change: Дані про зміну
message: Повідомлення від Monitor Agent
"""
try:
file_paths = get_monitor_agent_file_paths(agent_id)
md_path = file_paths['md']
# Створюємо файл, якщо його немає
if not md_path.exists():
md_path.parent.mkdir(parents=True, exist_ok=True)
with open(md_path, 'w', encoding='utf-8') as f:
f.write(f"# 📊 Monitor Agent: {agent_id}\n\n")
f.write(f"**Автоматично створено:** {datetime.now().isoformat()}\n\n")
f.write("---\n\n")
f.write("## 📝 Історія змін\n\n")
# Додаємо нову зміну
timestamp = change.get('timestamp', datetime.now().isoformat())
change_type = change.get('type', 'unknown')
change_action = change.get('action', 'unknown')
path = change.get('path', 'unknown')
description = change.get('description', '')
with open(md_path, 'a', encoding='utf-8') as f:
f.write(f"### {timestamp}\n\n")
f.write(f"**Тип:** {change_type} | **Дія:** {change_action}\n\n")
f.write(f"**Шлях:** `{path}`\n\n")
if description:
f.write(f"**Опис:** {description}\n\n")
f.write(f"**Повідомлення від Monitor Agent:**\n\n")
f.write(f"{message}\n\n")
f.write("---\n\n")
logger.debug(f"✅ Appended change to {md_path}")
except Exception as e:
logger.error(f"❌ Error appending to markdown: {e}")
def append_to_notebook(agent_id: str, change: Dict[str, Any], message: str) -> None:
"""
Додати зміну до Jupyter Notebook Monitor Agent
Args:
agent_id: ID Monitor Agent
change: Дані про зміну
message: Повідомлення від Monitor Agent
"""
try:
file_paths = get_monitor_agent_file_paths(agent_id)
ipynb_path = file_paths['ipynb']
# Створюємо notebook, якщо його немає
if not ipynb_path.exists():
notebook = {
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
f"# 📊 Monitor Agent: {agent_id}\n",
f"\n",
f"**Автоматично створено:** {datetime.now().isoformat()}\n",
f"\n",
f"---\n",
f"\n",
f"## 📝 Історія змін\n",
f"\n",
f"Цей notebook автоматично оновлюється при кожній зміні в проєкті."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3.11"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
else:
# Читаємо існуючий notebook
with open(ipynb_path, 'r', encoding='utf-8') as f:
notebook = json.load(f)
# Додаємо нову комірку зі зміною
timestamp = change.get('timestamp', datetime.now().isoformat())
change_type = change.get('type', 'unknown')
change_action = change.get('action', 'unknown')
path = change.get('path', 'unknown')
description = change.get('description', '')
new_cell = {
"cell_type": "markdown",
"metadata": {
"timestamp": timestamp,
"change_type": change_type,
"change_action": change_action,
"path": path
},
"source": [
f"### {timestamp}\n",
f"\n",
f"**Тип:** {change_type} | **Дія:** {change_action}\n",
f"\n",
f"**Шлях:** `{path}`\n",
f"\n",
f"**Опис:** {description}\n",
f"\n",
f"**Повідомлення від Monitor Agent:**\n",
f"\n",
f"{message}\n",
f"\n",
f"---\n"
]
}
# Додаємо комірку на початок (нові зміни зверху)
notebook['cells'].insert(1, new_cell)
# Зберігаємо максимум 200 комірок (крім першої заголовної)
if len(notebook['cells']) > 201:
notebook['cells'] = [notebook['cells'][0]] + notebook['cells'][1:201]
# Зберігаємо notebook
with open(ipynb_path, 'w', encoding='utf-8') as f:
json.dump(notebook, f, indent=2, ensure_ascii=False)
logger.debug(f"✅ Appended change to {ipynb_path}")
except Exception as e:
logger.error(f"❌ Error appending to notebook: {e}")
def log_monitor_change(agent_id: str, change: Dict[str, Any], message: str) -> None:
"""
Зберегти зміну в MD файл та Jupyter Notebook для Monitor Agent
Args:
agent_id: ID Monitor Agent
change: Дані про зміну
message: Повідомлення від Monitor Agent
"""
try:
# Додаємо до MD файлу
append_to_markdown(agent_id, change, message)
# Додаємо до Jupyter Notebook
append_to_notebook(agent_id, change, message)
logger.info(f"✅ Logged change to files for {agent_id}")
except Exception as e:
logger.error(f"❌ Error logging change: {e}")
def get_monitor_agent_file_urls(agent_id: str, base_url: str = "/") -> Dict[str, str]:
"""
Отримати URL для MD файлу та Jupyter Notebook Monitor Agent
Args:
agent_id: ID Monitor Agent
base_url: Базовий URL для посилань
Returns:
Dict з URL до MD файлу та Jupyter Notebook
"""
file_paths = get_monitor_agent_file_paths(agent_id)
# Конвертуємо абсолютні шляхи в відносні від кореня проєкту
project_root = Path.cwd()
md_relative = file_paths['md'].relative_to(project_root) if file_paths['md'].is_relative_to(project_root) else file_paths['md']
ipynb_relative = file_paths['ipynb'].relative_to(project_root) if file_paths['ipynb'].is_relative_to(project_root) else file_paths['ipynb']
return {
'md': f"{base_url}{md_relative.as_posix()}",
'ipynb': f"{base_url}{ipynb_relative.as_posix()}",
}