Change the log time to China
Build and Push CodeReview / build (push) Waiting to run
Details
Build and Push CodeReview / build (push) Waiting to run
Details
This commit is contained in:
parent
5166027e2f
commit
3ce3767938
|
|
@ -0,0 +1,21 @@
|
|||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
# 中国标准时间 (UTC+8)
|
||||
CHINA_TZ = timezone(timedelta(hours=8))
|
||||
|
||||
def get_now():
|
||||
"""获取当前的中国时间 (UTC+8)"""
|
||||
return datetime.now(CHINA_TZ)
|
||||
|
||||
def get_now_iso():
|
||||
"""获取当前中国时间的 ISO 格式字符串"""
|
||||
return get_now().isoformat()
|
||||
|
||||
def beijing_time(*args):
|
||||
"""
|
||||
用于 logging.Formatter.converter 的转换函数
|
||||
"""
|
||||
if args:
|
||||
# args[0] 是 timestamp
|
||||
return datetime.fromtimestamp(args[0], CHINA_TZ).timetuple()
|
||||
return get_now().timetuple()
|
||||
|
|
@ -8,9 +8,12 @@ from app.api.v1.api import api_router
|
|||
from app.db.session import AsyncSessionLocal
|
||||
from app.db.init_db import init_db
|
||||
|
||||
from app.core.timezone import beijing_time
|
||||
|
||||
# 配置日志
|
||||
logging.Formatter.converter = beijing_time
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
level=logging.DEBUG,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import asyncio
|
|||
import json
|
||||
import logging
|
||||
from typing import Optional, Dict, Any, List, AsyncGenerator, Callable
|
||||
from datetime import datetime, timezone
|
||||
from app.core.timezone import get_now, get_now_iso
|
||||
from dataclasses import dataclass
|
||||
import uuid
|
||||
|
||||
|
|
@ -281,7 +281,7 @@ class EventManager:
|
|||
):
|
||||
"""添加事件"""
|
||||
event_id = str(uuid.uuid4())
|
||||
timestamp = datetime.now(timezone.utc)
|
||||
timestamp = get_now()
|
||||
|
||||
event_data = {
|
||||
"id": event_id,
|
||||
|
|
@ -379,6 +379,7 @@ class EventManager:
|
|||
finding_id=event_data["finding_id"],
|
||||
tokens_used=event_data["tokens_used"],
|
||||
event_metadata=sanitize_dict(event_data["metadata"]), # 🔥 清理元数据
|
||||
created_at=get_now(),
|
||||
)
|
||||
db.add(event)
|
||||
await db.commit()
|
||||
|
|
@ -523,7 +524,7 @@ class EventManager:
|
|||
|
||||
except asyncio.TimeoutError:
|
||||
# 发送心跳
|
||||
yield {"event_type": "heartbeat", "timestamp": datetime.now(timezone.utc).isoformat()}
|
||||
yield {"event_type": "heartbeat", "timestamp": get_now_iso()}
|
||||
|
||||
except GeneratorExit:
|
||||
# SSE 连接断开
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import logging
|
|||
from enum import Enum
|
||||
from typing import Any, Dict, Optional, AsyncGenerator, List
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timezone
|
||||
from app.core.timezone import get_now_iso
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ class StreamEvent:
|
|||
"""流式事件"""
|
||||
event_type: StreamEventType
|
||||
data: Dict[str, Any] = field(default_factory=dict)
|
||||
timestamp: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
|
||||
timestamp: str = field(default_factory=get_now_iso)
|
||||
sequence: int = 0
|
||||
|
||||
# 可选字段
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ Tracer - 审计追踪器
|
|||
import csv
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
from app.core.timezone import get_now, get_now_iso
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, List, Optional
|
||||
from uuid import uuid4
|
||||
|
|
@ -53,7 +53,7 @@ class Tracer:
|
|||
# 运行标识
|
||||
self.run_name = run_name
|
||||
self.run_id = run_name or f"run-{uuid4().hex[:8]}"
|
||||
self.start_time = datetime.now(timezone.utc).isoformat()
|
||||
self.start_time = get_now_iso()
|
||||
self.end_time: Optional[str] = None
|
||||
|
||||
# 追踪数据
|
||||
|
|
@ -148,8 +148,8 @@ class Tracer:
|
|||
"type": agent_type,
|
||||
"status": "running",
|
||||
"parent_id": parent_id,
|
||||
"created_at": datetime.now(timezone.utc).isoformat(),
|
||||
"updated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"created_at": get_now_iso(),
|
||||
"updated_at": get_now_iso(),
|
||||
"tool_executions": [],
|
||||
"findings_count": 0,
|
||||
}
|
||||
|
|
@ -166,13 +166,13 @@ class Tracer:
|
|||
"""更新 Agent 状态"""
|
||||
if agent_id in self.agents:
|
||||
self.agents[agent_id]["status"] = status
|
||||
self.agents[agent_id]["updated_at"] = datetime.now(timezone.utc).isoformat()
|
||||
self.agents[agent_id]["updated_at"] = get_now_iso()
|
||||
|
||||
if error_message:
|
||||
self.agents[agent_id]["error_message"] = error_message
|
||||
|
||||
if status in ["completed", "failed", "stopped"]:
|
||||
self.agents[agent_id]["finished_at"] = datetime.now(timezone.utc).isoformat()
|
||||
self.agents[agent_id]["finished_at"] = get_now_iso()
|
||||
|
||||
# 触发回调
|
||||
if self.agent_status_callback:
|
||||
|
|
@ -193,7 +193,7 @@ class Tracer:
|
|||
execution_id = self._next_execution_id
|
||||
self._next_execution_id += 1
|
||||
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
now = get_now_iso()
|
||||
|
||||
# 清理过大的参数
|
||||
cleaned_args = self._clean_args(args)
|
||||
|
|
@ -226,7 +226,7 @@ class Tracer:
|
|||
"""更新工具执行状态"""
|
||||
if execution_id in self.tool_executions:
|
||||
self.tool_executions[execution_id]["status"] = status
|
||||
self.tool_executions[execution_id]["completed_at"] = datetime.now(timezone.utc).isoformat()
|
||||
self.tool_executions[execution_id]["completed_at"] = get_now_iso()
|
||||
|
||||
# 清理过大的结果
|
||||
if result is not None:
|
||||
|
|
@ -295,7 +295,7 @@ class Tracer:
|
|||
"content": content,
|
||||
"role": role,
|
||||
"agent_id": agent_id,
|
||||
"timestamp": datetime.now(timezone.utc).isoformat(),
|
||||
"timestamp": get_now_iso(),
|
||||
"metadata": metadata or {},
|
||||
}
|
||||
|
||||
|
|
@ -324,7 +324,7 @@ class Tracer:
|
|||
"vulnerability_type": vulnerability_type,
|
||||
"file_path": file_path,
|
||||
"agent_id": agent_id,
|
||||
"timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC"),
|
||||
"timestamp": get_now().strftime("%Y-%m-%d %H:%M:%S") + " CST",
|
||||
}
|
||||
|
||||
self.vulnerability_reports.append(report)
|
||||
|
|
@ -365,12 +365,12 @@ class Tracer:
|
|||
"scan_completed": True,
|
||||
"content": content,
|
||||
"success": success,
|
||||
"completed_at": datetime.now(timezone.utc).isoformat(),
|
||||
"completed_at": get_now_iso(),
|
||||
"total_vulnerabilities": len(self.vulnerability_reports),
|
||||
}
|
||||
|
||||
self.run_metadata["status"] = "completed" if success else "failed"
|
||||
self.end_time = datetime.now(timezone.utc).isoformat()
|
||||
self.end_time = get_now_iso()
|
||||
self.run_metadata["end_time"] = self.end_time
|
||||
|
||||
logger.info(f"Tracer: Final scan result set, success={success}")
|
||||
|
|
@ -386,7 +386,7 @@ class Tracer:
|
|||
run_dir = self.get_run_dir()
|
||||
|
||||
if mark_complete:
|
||||
self.end_time = datetime.now(timezone.utc).isoformat()
|
||||
self.end_time = get_now_iso()
|
||||
self.run_metadata["end_time"] = self.end_time
|
||||
|
||||
# 保存最终报告
|
||||
|
|
@ -410,7 +410,7 @@ class Tracer:
|
|||
|
||||
with report_file.open("w", encoding="utf-8") as f:
|
||||
f.write("# 安全审计报告\n\n")
|
||||
f.write(f"**生成时间:** {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')}\n")
|
||||
f.write(f"**生成时间:** {get_now().strftime('%Y-%m-%d %H:%M:%S')} CST\n")
|
||||
f.write(f"**运行ID:** {self.run_id}\n\n")
|
||||
|
||||
# 统计信息
|
||||
|
|
@ -518,11 +518,11 @@ class Tracer:
|
|||
def _calculate_duration(self) -> float:
|
||||
"""计算运行时长"""
|
||||
try:
|
||||
start = datetime.fromisoformat(self.start_time.replace("Z", "+00:00"))
|
||||
start = datetime.fromisoformat(self.start_time)
|
||||
if self.end_time:
|
||||
end = datetime.fromisoformat(self.end_time.replace("Z", "+00:00"))
|
||||
end = datetime.fromisoformat(self.end_time)
|
||||
else:
|
||||
end = datetime.now(timezone.utc)
|
||||
end = get_now()
|
||||
return (end - start).total_seconds()
|
||||
except (ValueError, TypeError):
|
||||
return 0.0
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ PDF 报告生成服务 - 专业审计版 (WeasyPrint)
|
|||
import io
|
||||
import html
|
||||
from datetime import datetime
|
||||
from app.core.timezone import get_now
|
||||
from typing import List, Dict, Any
|
||||
import math
|
||||
import os
|
||||
|
|
@ -475,8 +476,8 @@ class ReportGenerator:
|
|||
context = {
|
||||
'title': '代码审计报告',
|
||||
'subtitle': f'即时分析 | 语言: {language.capitalize()}',
|
||||
'generated_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'report_id': f"INST-{int(datetime.now().timestamp())}",
|
||||
'generated_at': get_now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'report_id': f"INST-{int(get_now().timestamp())}",
|
||||
'score': score,
|
||||
'stats': [
|
||||
('问题总数', len(issues)),
|
||||
|
|
@ -493,7 +494,7 @@ class ReportGenerator:
|
|||
context = {
|
||||
'title': '项目代码审计报告',
|
||||
'subtitle': f"项目: {project} | 分支: {task.get('branch_name', 'default')}",
|
||||
'generated_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'generated_at': get_now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'report_id': f"TASK-{task.get('id', '')[:8]}",
|
||||
'score': score,
|
||||
'stats': [
|
||||
|
|
|
|||
|
|
@ -59,10 +59,7 @@ function agentAuditReducer(state: AgentAuditState, action: AgentAuditAction): Ag
|
|||
return { ...state, logs: action.payload };
|
||||
|
||||
case 'ADD_LOG': {
|
||||
const { id: providedId, ...logData } = action.payload;
|
||||
const newLog = providedId
|
||||
? { ...createLogItem(logData), id: providedId }
|
||||
: createLogItem(logData);
|
||||
const newLog = createLogItem(action.payload);
|
||||
return { ...state, logs: [...state.logs, newLog] };
|
||||
}
|
||||
|
||||
|
|
@ -194,11 +191,11 @@ export function useAgentAuditState() {
|
|||
dispatch({ type: 'SET_AGENT_TREE', payload: tree });
|
||||
}, []);
|
||||
|
||||
const addLog = useCallback((log: Omit<LogItem, 'id' | 'time'>): string => {
|
||||
const addLog = useCallback((log: Omit<LogItem, 'id' | 'time'> & { id?: string; time?: string }): string => {
|
||||
const newLog = createLogItem(log);
|
||||
dispatch({ type: 'SET_LOGS', payload: [...state.logs, newLog] });
|
||||
dispatch({ type: 'ADD_LOG', payload: newLog });
|
||||
return newLog.id;
|
||||
}, [state.logs]);
|
||||
}, []);
|
||||
|
||||
const updateLog = useCallback((id: string, updates: Partial<LogItem>) => {
|
||||
dispatch({ type: 'UPDATE_LOG', payload: { id, updates } });
|
||||
|
|
|
|||
|
|
@ -199,6 +199,7 @@ function AgentAuditPageContent() {
|
|||
title: event.message?.slice(0, 100) + (event.message && event.message.length > 100 ? '...' : '') || 'Thinking...',
|
||||
content: event.message || (event.metadata?.thought as string) || '',
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
processedCount++;
|
||||
|
|
@ -217,6 +218,7 @@ function AgentAuditPageContent() {
|
|||
status: 'running' as const,
|
||||
},
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
processedCount++;
|
||||
|
|
@ -237,6 +239,7 @@ function AgentAuditPageContent() {
|
|||
status: 'completed' as const,
|
||||
},
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
processedCount++;
|
||||
|
|
@ -253,6 +256,7 @@ function AgentAuditPageContent() {
|
|||
title: event.message || (event.metadata?.title as string) || 'Vulnerability found',
|
||||
severity: (event.metadata?.severity as string) || 'medium',
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
processedCount++;
|
||||
|
|
@ -271,6 +275,7 @@ function AgentAuditPageContent() {
|
|||
type: 'dispatch',
|
||||
title: event.message || `Event: ${event.event_type}`,
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
processedCount++;
|
||||
|
|
@ -284,6 +289,7 @@ function AgentAuditPageContent() {
|
|||
type: 'info',
|
||||
title: event.message || 'Task completed',
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
processedCount++;
|
||||
|
|
@ -297,6 +303,7 @@ function AgentAuditPageContent() {
|
|||
type: 'error',
|
||||
title: event.message || 'Task error',
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
processedCount++;
|
||||
|
|
@ -310,6 +317,7 @@ function AgentAuditPageContent() {
|
|||
type: 'info',
|
||||
title: event.message || 'Task cancelled',
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
processedCount++;
|
||||
|
|
@ -335,6 +343,7 @@ function AgentAuditPageContent() {
|
|||
progressKey: matchedProgress.key,
|
||||
title: event.message,
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
|
@ -344,6 +353,7 @@ function AgentAuditPageContent() {
|
|||
type: 'info',
|
||||
title: event.message,
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -374,6 +384,7 @@ function AgentAuditPageContent() {
|
|||
progressKey: matchedProgress.key,
|
||||
title: message,
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
|
@ -383,6 +394,7 @@ function AgentAuditPageContent() {
|
|||
type: event.event_type === 'error' ? 'error' : 'info',
|
||||
title: message,
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -406,6 +418,7 @@ function AgentAuditPageContent() {
|
|||
type: 'info',
|
||||
title: event.message,
|
||||
agentName,
|
||||
time: event.timestamp,
|
||||
}
|
||||
});
|
||||
processedCount++;
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ export type AgentAuditAction =
|
|||
| { type: 'ADD_FINDING'; payload: Partial<AgentFinding> & { id: string } }
|
||||
| { type: 'SET_AGENT_TREE'; payload: AgentTreeResponse }
|
||||
| { type: 'SET_LOGS'; payload: LogItem[] }
|
||||
| { type: 'ADD_LOG'; payload: Omit<LogItem, 'id' | 'time'> & { id?: string } }
|
||||
| { type: 'ADD_LOG'; payload: Omit<LogItem, 'id' | 'time'> & { id?: string; time?: string } }
|
||||
| { type: 'UPDATE_LOG'; payload: { id: string; updates: Partial<LogItem> } }
|
||||
| { type: 'UPDATE_OR_ADD_PROGRESS_LOG'; payload: { progressKey: string; title: string; agentName?: string } }
|
||||
| { type: 'COMPLETE_TOOL_LOG'; payload: { toolName: string; output: string; duration: number } }
|
||||
|
|
|
|||
|
|
@ -73,7 +73,18 @@ export function resetLogIdCounter(): void {
|
|||
* Get current time string for logs
|
||||
*/
|
||||
export function getTimeString(): string {
|
||||
return new Date().toLocaleTimeString('en-US', {
|
||||
return formatTimestamp(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* Format timestamp (date or string) to HH:mm:ss
|
||||
*/
|
||||
export function formatTimestamp(time?: string | Date | number): string {
|
||||
if (!time) return getTimeString();
|
||||
const date = new Date(time);
|
||||
if (isNaN(date.getTime())) return getTimeString();
|
||||
|
||||
return date.toLocaleTimeString('en-US', {
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
|
|
@ -84,12 +95,12 @@ export function getTimeString(): string {
|
|||
/**
|
||||
* Create a log item
|
||||
*/
|
||||
export function createLogItem(item: Omit<LogItem, 'id' | 'time'>): LogItem {
|
||||
export function createLogItem(item: Omit<LogItem, 'id' | 'time'> & { id?: string; time?: string }): LogItem {
|
||||
return {
|
||||
...item,
|
||||
id: generateLogId(),
|
||||
time: getTimeString(),
|
||||
};
|
||||
id: item.id || generateLogId(),
|
||||
time: item.time ? formatTimestamp(item.time) : getTimeString(),
|
||||
} as LogItem;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue