277 lines
9.4 KiB
Python
277 lines
9.4 KiB
Python
|
|
"""
|
|||
|
|
系统监控服务
|
|||
|
|
提供系统状态、执行统计、性能指标等监控数据
|
|||
|
|
"""
|
|||
|
|
from sqlalchemy.orm import Session
|
|||
|
|
from sqlalchemy import func, and_, case
|
|||
|
|
from datetime import datetime, timedelta
|
|||
|
|
from typing import Dict, Any, List
|
|||
|
|
from app.models.user import User
|
|||
|
|
from app.models.workflow import Workflow
|
|||
|
|
from app.models.agent import Agent
|
|||
|
|
from app.models.execution import Execution
|
|||
|
|
from app.models.execution_log import ExecutionLog
|
|||
|
|
from app.models.data_source import DataSource
|
|||
|
|
from app.models.model_config import ModelConfig
|
|||
|
|
import logging
|
|||
|
|
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class MonitoringService:
|
|||
|
|
"""系统监控服务"""
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def get_system_overview(db: Session, user_id: str = None) -> Dict[str, Any]:
|
|||
|
|
"""
|
|||
|
|
获取系统概览统计
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
db: 数据库会话
|
|||
|
|
user_id: 用户ID(如果提供,则只统计该用户的数据)
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
系统概览数据
|
|||
|
|
"""
|
|||
|
|
# 构建基础查询条件
|
|||
|
|
user_filter = Workflow.user_id == user_id if user_id else True
|
|||
|
|
|
|||
|
|
# 统计工作流数量
|
|||
|
|
workflow_count = db.query(func.count(Workflow.id)).filter(user_filter).scalar() or 0
|
|||
|
|
|
|||
|
|
# 统计Agent数量
|
|||
|
|
agent_filter = Agent.user_id == user_id if user_id else True
|
|||
|
|
agent_count = db.query(func.count(Agent.id)).filter(agent_filter).scalar() or 0
|
|||
|
|
|
|||
|
|
# 统计执行记录数量
|
|||
|
|
execution_filter = None
|
|||
|
|
if user_id:
|
|||
|
|
execution_filter = Execution.workflow_id.in_(
|
|||
|
|
db.query(Workflow.id).filter(Workflow.user_id == user_id)
|
|||
|
|
)
|
|||
|
|
execution_count = db.query(func.count(Execution.id)).filter(
|
|||
|
|
execution_filter if execution_filter else True
|
|||
|
|
).scalar() or 0
|
|||
|
|
|
|||
|
|
# 统计数据源数量
|
|||
|
|
data_source_filter = DataSource.user_id == user_id if user_id else True
|
|||
|
|
data_source_count = db.query(func.count(DataSource.id)).filter(
|
|||
|
|
data_source_filter
|
|||
|
|
).scalar() or 0
|
|||
|
|
|
|||
|
|
# 统计模型配置数量
|
|||
|
|
model_config_filter = ModelConfig.user_id == user_id if user_id else True
|
|||
|
|
model_config_count = db.query(func.count(ModelConfig.id)).filter(
|
|||
|
|
model_config_filter
|
|||
|
|
).scalar() or 0
|
|||
|
|
|
|||
|
|
# 统计用户数量(仅管理员可见)
|
|||
|
|
user_count = None
|
|||
|
|
if not user_id:
|
|||
|
|
user_count = db.query(func.count(User.id)).scalar() or 0
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
"workflows": workflow_count,
|
|||
|
|
"agents": agent_count,
|
|||
|
|
"executions": execution_count,
|
|||
|
|
"data_sources": data_source_count,
|
|||
|
|
"model_configs": model_config_count,
|
|||
|
|
"users": user_count
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def get_execution_statistics(
|
|||
|
|
db: Session,
|
|||
|
|
user_id: str = None,
|
|||
|
|
days: int = 7
|
|||
|
|
) -> Dict[str, Any]:
|
|||
|
|
"""
|
|||
|
|
获取执行统计信息
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
db: 数据库会话
|
|||
|
|
user_id: 用户ID(如果提供,则只统计该用户的数据)
|
|||
|
|
days: 统计天数(默认7天)
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
执行统计数据
|
|||
|
|
"""
|
|||
|
|
# 构建时间范围
|
|||
|
|
end_time = datetime.utcnow()
|
|||
|
|
start_time = end_time - timedelta(days=days)
|
|||
|
|
|
|||
|
|
# 构建查询条件
|
|||
|
|
execution_filter = Execution.created_at >= start_time
|
|||
|
|
if user_id:
|
|||
|
|
execution_filter = and_(
|
|||
|
|
execution_filter,
|
|||
|
|
Execution.workflow_id.in_(
|
|||
|
|
db.query(Workflow.id).filter(Workflow.user_id == user_id)
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 统计总执行数
|
|||
|
|
total_executions = db.query(func.count(Execution.id)).filter(
|
|||
|
|
execution_filter
|
|||
|
|
).scalar() or 0
|
|||
|
|
|
|||
|
|
# 统计各状态执行数
|
|||
|
|
status_stats = db.query(
|
|||
|
|
Execution.status,
|
|||
|
|
func.count(Execution.id).label('count')
|
|||
|
|
).filter(execution_filter).group_by(Execution.status).all()
|
|||
|
|
|
|||
|
|
status_counts = {status: count for status, count in status_stats}
|
|||
|
|
|
|||
|
|
# 计算成功率
|
|||
|
|
completed = status_counts.get('completed', 0)
|
|||
|
|
failed = status_counts.get('failed', 0)
|
|||
|
|
success_rate = (completed / total_executions * 100) if total_executions > 0 else 0
|
|||
|
|
|
|||
|
|
# 统计平均执行时间
|
|||
|
|
avg_execution_time = db.query(
|
|||
|
|
func.avg(Execution.execution_time)
|
|||
|
|
).filter(
|
|||
|
|
and_(execution_filter, Execution.execution_time.isnot(None))
|
|||
|
|
).scalar() or 0
|
|||
|
|
|
|||
|
|
# 统计最近24小时的执行趋势
|
|||
|
|
hourly_trends = []
|
|||
|
|
for i in range(24):
|
|||
|
|
hour_start = end_time - timedelta(hours=24-i)
|
|||
|
|
hour_end = hour_start + timedelta(hours=1)
|
|||
|
|
hour_filter = and_(
|
|||
|
|
execution_filter,
|
|||
|
|
Execution.created_at >= hour_start,
|
|||
|
|
Execution.created_at < hour_end
|
|||
|
|
)
|
|||
|
|
hour_count = db.query(func.count(Execution.id)).filter(
|
|||
|
|
hour_filter
|
|||
|
|
).scalar() or 0
|
|||
|
|
hourly_trends.append({
|
|||
|
|
"hour": hour_start.strftime("%H:00"),
|
|||
|
|
"count": hour_count
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
"total": total_executions,
|
|||
|
|
"status_counts": status_counts,
|
|||
|
|
"success_rate": round(success_rate, 2),
|
|||
|
|
"avg_execution_time": round(avg_execution_time, 2) if avg_execution_time else 0,
|
|||
|
|
"hourly_trends": hourly_trends
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def get_node_type_statistics(
|
|||
|
|
db: Session,
|
|||
|
|
user_id: str = None,
|
|||
|
|
days: int = 7
|
|||
|
|
) -> List[Dict[str, Any]]:
|
|||
|
|
"""
|
|||
|
|
获取节点类型统计
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
db: 数据库会话
|
|||
|
|
user_id: 用户ID(如果提供,则只统计该用户的数据)
|
|||
|
|
days: 统计天数(默认7天)
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
节点类型统计数据
|
|||
|
|
"""
|
|||
|
|
# 构建时间范围
|
|||
|
|
end_time = datetime.utcnow()
|
|||
|
|
start_time = end_time - timedelta(days=days)
|
|||
|
|
|
|||
|
|
# 构建查询条件
|
|||
|
|
execution_filter = Execution.created_at >= start_time
|
|||
|
|
if user_id:
|
|||
|
|
execution_filter = and_(
|
|||
|
|
execution_filter,
|
|||
|
|
Execution.workflow_id.in_(
|
|||
|
|
db.query(Workflow.id).filter(Workflow.user_id == user_id)
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 获取符合条件的执行ID列表
|
|||
|
|
execution_ids_query = db.query(Execution.id).filter(execution_filter)
|
|||
|
|
execution_ids = [row[0] for row in execution_ids_query.all()]
|
|||
|
|
|
|||
|
|
if not execution_ids:
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
# 统计各节点类型的执行情况
|
|||
|
|
node_stats = db.query(
|
|||
|
|
ExecutionLog.node_type,
|
|||
|
|
func.count(ExecutionLog.id).label('execution_count'),
|
|||
|
|
func.sum(ExecutionLog.duration).label('total_duration'),
|
|||
|
|
func.avg(ExecutionLog.duration).label('avg_duration'),
|
|||
|
|
func.count(
|
|||
|
|
case((ExecutionLog.level == 'ERROR', 1))
|
|||
|
|
).label('error_count')
|
|||
|
|
).filter(
|
|||
|
|
and_(
|
|||
|
|
ExecutionLog.execution_id.in_(execution_ids),
|
|||
|
|
ExecutionLog.node_type.isnot(None),
|
|||
|
|
ExecutionLog.duration.isnot(None)
|
|||
|
|
)
|
|||
|
|
).group_by(ExecutionLog.node_type).all()
|
|||
|
|
|
|||
|
|
result = []
|
|||
|
|
for node_type, exec_count, total_dur, avg_dur, error_count in node_stats:
|
|||
|
|
result.append({
|
|||
|
|
"node_type": node_type,
|
|||
|
|
"execution_count": exec_count,
|
|||
|
|
"total_duration": round(total_dur or 0, 2),
|
|||
|
|
"avg_duration": round(avg_dur or 0, 2),
|
|||
|
|
"error_count": error_count,
|
|||
|
|
"success_rate": round((exec_count - error_count) / exec_count * 100, 2) if exec_count > 0 else 0
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def get_recent_activities(
|
|||
|
|
db: Session,
|
|||
|
|
user_id: str = None,
|
|||
|
|
limit: int = 10
|
|||
|
|
) -> List[Dict[str, Any]]:
|
|||
|
|
"""
|
|||
|
|
获取最近的活动记录
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
db: 数据库会话
|
|||
|
|
user_id: 用户ID(如果提供,则只统计该用户的数据)
|
|||
|
|
limit: 返回数量限制
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
最近活动列表
|
|||
|
|
"""
|
|||
|
|
# 构建查询条件
|
|||
|
|
execution_filter = True
|
|||
|
|
if user_id:
|
|||
|
|
execution_filter = Execution.workflow_id.in_(
|
|||
|
|
db.query(Workflow.id).filter(Workflow.user_id == user_id)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 获取最近的执行记录
|
|||
|
|
recent_executions = db.query(Execution).filter(
|
|||
|
|
execution_filter
|
|||
|
|
).order_by(Execution.created_at.desc()).limit(limit).all()
|
|||
|
|
|
|||
|
|
result = []
|
|||
|
|
for execution in recent_executions:
|
|||
|
|
workflow = db.query(Workflow).filter(
|
|||
|
|
Workflow.id == execution.workflow_id
|
|||
|
|
).first() if execution.workflow_id else None
|
|||
|
|
|
|||
|
|
result.append({
|
|||
|
|
"id": execution.id,
|
|||
|
|
"type": "execution",
|
|||
|
|
"workflow_name": workflow.name if workflow else "未知工作流",
|
|||
|
|
"status": execution.status,
|
|||
|
|
"created_at": execution.created_at.isoformat() if execution.created_at else None,
|
|||
|
|
"execution_time": execution.execution_time
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return result
|