mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
feat(data): 废弃 usage 表 HTTP/结算列,迁移至 settlement_snapshots 与 http_audits
- 新增迁移 20260413030000:标记 billing_status、finalized_at、request_headers 等列为 DEPRECATED - 更新 baseline_v2.sql 同步废弃注释,BASELINE_V2_CUTOFF_VERSION 升至 20260413030000 - usage/sql.rs:inline body 阈值归零,强制所有 body 走 blob 存储;upsert 时清空 legacy header/output_price 列 - 查询层优先读 usage_settlement_snapshots 的 billing_status、finalized_at、output_price_per_1m - runtime.rs:stale usage 处理同步写入 usage_settlement_snapshots;SELECT FOR UPDATE 改为 FOR UPDATE OF usage - 前端:PerformanceAnalysis 页面重构为实时面板,新增 prometheus 工具函数与 monitoring API
This commit is contained in:
@@ -183,6 +183,18 @@ export interface RequestDetail {
|
||||
has_response_body?: boolean
|
||||
has_client_response_body?: boolean
|
||||
metadata?: Record<string, unknown>
|
||||
settlement?: {
|
||||
billing_snapshot?: Record<string, unknown>
|
||||
billing_snapshot_schema_version?: string
|
||||
billing_snapshot_status?: string
|
||||
rate_multiplier?: number
|
||||
is_free_tier?: boolean
|
||||
input_price_per_1m?: number
|
||||
output_price_per_1m?: number
|
||||
cache_creation_price_per_1m?: number
|
||||
cache_read_price_per_1m?: number
|
||||
price_per_request?: number
|
||||
} | null
|
||||
// 阶梯计费信息
|
||||
tiered_pricing?: {
|
||||
total_input_context: number // 总输入上下文 (input + cache_read)
|
||||
|
||||
208
frontend/src/api/monitoring.ts
Normal file
208
frontend/src/api/monitoring.ts
Normal file
@@ -0,0 +1,208 @@
|
||||
import apiClient from './client'
|
||||
import {
|
||||
findMetricValueNumber,
|
||||
parsePrometheusSamples,
|
||||
sumMetricValues,
|
||||
} from '@/utils/prometheus'
|
||||
|
||||
export interface AdminMonitoringSystemStatus {
|
||||
timestamp: string
|
||||
users: {
|
||||
total: number
|
||||
active: number
|
||||
}
|
||||
providers: {
|
||||
total: number
|
||||
active: number
|
||||
}
|
||||
api_keys: {
|
||||
total: number
|
||||
active: number
|
||||
}
|
||||
today_stats: {
|
||||
requests: number
|
||||
tokens: number
|
||||
cost_usd: string
|
||||
}
|
||||
tunnel: {
|
||||
proxy_connections: number
|
||||
nodes: number
|
||||
active_streams: number
|
||||
}
|
||||
internal_gateway: {
|
||||
status: string
|
||||
path_prefixes: string[]
|
||||
}
|
||||
recent_errors: number
|
||||
}
|
||||
|
||||
export interface AdminMonitoringCircuitBreakerSummary {
|
||||
state: string
|
||||
provider_id?: string
|
||||
provider_name?: string | null
|
||||
key_name?: string | null
|
||||
health_score?: number
|
||||
consecutive_failures?: number
|
||||
last_failure_at?: string | null
|
||||
open_formats?: string[]
|
||||
}
|
||||
|
||||
export interface AdminMonitoringErrorStatistics {
|
||||
total_errors: number
|
||||
active_keys: number
|
||||
degraded_keys: number
|
||||
unhealthy_keys: number
|
||||
open_circuit_breakers: number
|
||||
circuit_breakers: Record<string, AdminMonitoringCircuitBreakerSummary>
|
||||
}
|
||||
|
||||
export interface AdminMonitoringRecentError {
|
||||
error_id: string
|
||||
error_type: string
|
||||
operation: string
|
||||
timestamp: string | null
|
||||
context: {
|
||||
request_id?: string | null
|
||||
provider_id?: string | null
|
||||
provider_name?: string | null
|
||||
model?: string | null
|
||||
api_format?: string | null
|
||||
status_code?: number | null
|
||||
error_message?: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface AdminMonitoringResilienceStatus {
|
||||
timestamp: string
|
||||
health_score: number
|
||||
status: 'healthy' | 'degraded' | 'critical' | string
|
||||
error_statistics: AdminMonitoringErrorStatistics
|
||||
recent_errors: AdminMonitoringRecentError[]
|
||||
recommendations: string[]
|
||||
}
|
||||
|
||||
export interface AdminMonitoringCircuitHistoryItem {
|
||||
event: string
|
||||
key_id: string
|
||||
provider_id: string
|
||||
provider_name?: string | null
|
||||
key_name?: string | null
|
||||
api_format?: string | null
|
||||
reason?: string | null
|
||||
recovery_seconds?: number | null
|
||||
timestamp?: string | null
|
||||
}
|
||||
|
||||
export interface AdminMonitoringCircuitHistoryResponse {
|
||||
items: AdminMonitoringCircuitHistoryItem[]
|
||||
count: number
|
||||
}
|
||||
|
||||
export interface GatewayGateMetrics {
|
||||
inFlight: number | null
|
||||
availablePermits: number | null
|
||||
highWatermark: number | null
|
||||
rejectedTotal: number | null
|
||||
unavailable: boolean
|
||||
}
|
||||
|
||||
export interface GatewayFallbackMetricSummary {
|
||||
name: string
|
||||
label: string
|
||||
total: number
|
||||
}
|
||||
|
||||
export interface GatewayMetricsSummary {
|
||||
serviceUp: number | null
|
||||
local: GatewayGateMetrics
|
||||
distributed: GatewayGateMetrics
|
||||
tunnel: {
|
||||
proxyConnections: number | null
|
||||
nodes: number | null
|
||||
activeStreams: number | null
|
||||
}
|
||||
fallbackTotal: number
|
||||
fallbacks: GatewayFallbackMetricSummary[]
|
||||
}
|
||||
|
||||
const FALLBACK_METRICS: Array<{ name: string; label: string }> = [
|
||||
{ name: 'decision_remote_total', label: '远端决策回退' },
|
||||
{ name: 'plan_fallback_total', label: 'Plan 回退' },
|
||||
{ name: 'control_execute_fallback_total', label: '控制执行回退' },
|
||||
{ name: 'remote_execute_emergency_total', label: '紧急远端执行' },
|
||||
{ name: 'local_execution_runtime_miss_total', label: '本地运行时缺失' },
|
||||
]
|
||||
|
||||
function buildGateMetrics(
|
||||
samples: ReturnType<typeof parsePrometheusSamples>,
|
||||
gate: string
|
||||
): GatewayGateMetrics {
|
||||
return {
|
||||
inFlight: findMetricValueNumber(samples, 'concurrency_in_flight', { gate }),
|
||||
availablePermits: findMetricValueNumber(samples, 'concurrency_available_permits', { gate }),
|
||||
highWatermark: findMetricValueNumber(samples, 'concurrency_high_watermark', { gate }),
|
||||
rejectedTotal: findMetricValueNumber(samples, 'concurrency_rejected_total', { gate }),
|
||||
unavailable: findMetricValueNumber(samples, 'concurrency_unavailable', { gate }) === 1,
|
||||
}
|
||||
}
|
||||
|
||||
export function buildGatewayMetricsSummary(text: string): GatewayMetricsSummary {
|
||||
const samples = parsePrometheusSamples(text)
|
||||
const fallbacks = FALLBACK_METRICS.map(item => ({
|
||||
...item,
|
||||
total: sumMetricValues(samples, item.name),
|
||||
}))
|
||||
|
||||
return {
|
||||
serviceUp: findMetricValueNumber(samples, 'service_up', { service: 'aether-gateway' }),
|
||||
local: buildGateMetrics(samples, 'gateway_requests'),
|
||||
distributed: buildGateMetrics(samples, 'gateway_requests_distributed'),
|
||||
tunnel: {
|
||||
proxyConnections: findMetricValueNumber(samples, 'tunnel_proxy_connections'),
|
||||
nodes: findMetricValueNumber(samples, 'tunnel_nodes'),
|
||||
activeStreams: findMetricValueNumber(samples, 'tunnel_active_streams'),
|
||||
},
|
||||
fallbackTotal: fallbacks.reduce((total, item) => total + item.total, 0),
|
||||
fallbacks,
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchGatewayMetricsText(): Promise<string> {
|
||||
const response = await apiClient.get<string>('/_gateway/metrics', {
|
||||
responseType: 'text',
|
||||
transformResponse: [(data: string) => data],
|
||||
})
|
||||
return typeof response.data === 'string' ? response.data : String(response.data ?? '')
|
||||
}
|
||||
|
||||
export const monitoringApi = {
|
||||
async getSystemStatus(): Promise<AdminMonitoringSystemStatus> {
|
||||
const response = await apiClient.get<AdminMonitoringSystemStatus>(
|
||||
'/api/admin/monitoring/system-status'
|
||||
)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async getResilienceStatus(): Promise<AdminMonitoringResilienceStatus> {
|
||||
const response = await apiClient.get<AdminMonitoringResilienceStatus>(
|
||||
'/api/admin/monitoring/resilience-status'
|
||||
)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async getCircuitHistory(limit = 10): Promise<AdminMonitoringCircuitHistoryResponse> {
|
||||
const response = await apiClient.get<AdminMonitoringCircuitHistoryResponse>(
|
||||
'/api/admin/monitoring/resilience/circuit-history',
|
||||
{ params: { limit } }
|
||||
)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async getGatewayMetricsText(): Promise<string> {
|
||||
return fetchGatewayMetricsText()
|
||||
},
|
||||
|
||||
async getGatewayMetricsSummary(): Promise<GatewayMetricsSummary> {
|
||||
return buildGatewayMetricsSummary(await fetchGatewayMetricsText())
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user