mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-09-27 19:51:45 +02:00
Add files via upload
This commit is contained in:
@@ -3,6 +3,7 @@ package database
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -500,23 +501,24 @@ type CallsTimelineBucket struct {
|
|||||||
Failed int
|
Failed int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// truncateCallsTimelineBucket 将时间截断到趋势图桶边界(本地时区,与 handler 侧 truncateToBucket 一致)
|
||||||
|
func truncateCallsTimelineBucket(t time.Time, dailyBuckets bool) time.Time {
|
||||||
|
t = t.In(time.Local)
|
||||||
|
if dailyBuckets {
|
||||||
|
y, m, d := t.Date()
|
||||||
|
return time.Date(y, m, d, 0, 0, 0, 0, time.Local)
|
||||||
|
}
|
||||||
|
return t.Truncate(time.Hour)
|
||||||
|
}
|
||||||
|
|
||||||
// LoadCallsTimeline 按时间范围加载调用趋势(since 起至今,含边界)
|
// LoadCallsTimeline 按时间范围加载调用趋势(since 起至今,含边界)
|
||||||
func (db *DB) LoadCallsTimeline(since time.Time, dailyBuckets bool) ([]CallsTimelineBucket, error) {
|
func (db *DB) LoadCallsTimeline(since time.Time, dailyBuckets bool) ([]CallsTimelineBucket, error) {
|
||||||
var bucketExpr string
|
// 在 Go 侧按本地时区分桶,避免 SQLite strftime 对 UTC 存储时间分桶后再误当本地时间解析(差 8h 等问题)
|
||||||
if dailyBuckets {
|
|
||||||
bucketExpr = `strftime('%Y-%m-%d 00:00:00', start_time)`
|
|
||||||
} else {
|
|
||||||
bucketExpr = `strftime('%Y-%m-%d %H:00:00', start_time)`
|
|
||||||
}
|
|
||||||
|
|
||||||
query := `
|
query := `
|
||||||
SELECT ` + bucketExpr + ` AS bucket,
|
SELECT start_time,
|
||||||
COUNT(*) AS total,
|
CASE WHEN status IN ('failed', 'cancelled') THEN 1 ELSE 0 END AS failed
|
||||||
SUM(CASE WHEN status IN ('failed', 'cancelled') THEN 1 ELSE 0 END) AS failed
|
|
||||||
FROM tool_executions
|
FROM tool_executions
|
||||||
WHERE start_time >= ?
|
WHERE start_time >= ?
|
||||||
GROUP BY bucket
|
|
||||||
ORDER BY bucket ASC
|
|
||||||
`
|
`
|
||||||
|
|
||||||
rows, err := db.Query(query, since)
|
rows, err := db.Query(query, since)
|
||||||
@@ -525,28 +527,32 @@ func (db *DB) LoadCallsTimeline(since time.Time, dailyBuckets bool) ([]CallsTime
|
|||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
var buckets []CallsTimelineBucket
|
bucketMap := make(map[time.Time]struct{ total, failed int })
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var bucketStr string
|
var startTime time.Time
|
||||||
var total, failed int
|
var failed int
|
||||||
if err := rows.Scan(&bucketStr, &total, &failed); err != nil {
|
if err := rows.Scan(&startTime, &failed); err != nil {
|
||||||
db.logger.Warn("加载调用趋势失败", zap.Error(err))
|
db.logger.Warn("加载调用趋势失败", zap.Error(err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t, parseErr := time.ParseInLocation("2006-01-02 15:04:05", bucketStr, time.Local)
|
key := truncateCallsTimelineBucket(startTime, dailyBuckets)
|
||||||
if parseErr != nil {
|
entry := bucketMap[key]
|
||||||
t, parseErr = time.Parse("2006-01-02 15:04:05", bucketStr)
|
entry.total++
|
||||||
if parseErr != nil {
|
entry.failed += failed
|
||||||
db.logger.Warn("解析趋势时间桶失败", zap.String("bucket", bucketStr), zap.Error(parseErr))
|
bucketMap[key] = entry
|
||||||
continue
|
}
|
||||||
}
|
|
||||||
}
|
buckets := make([]CallsTimelineBucket, 0, len(bucketMap))
|
||||||
|
for bucketTime, counts := range bucketMap {
|
||||||
buckets = append(buckets, CallsTimelineBucket{
|
buckets = append(buckets, CallsTimelineBucket{
|
||||||
BucketTime: t,
|
BucketTime: bucketTime,
|
||||||
Total: total,
|
Total: counts.total,
|
||||||
Failed: failed,
|
Failed: counts.failed,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
sort.Slice(buckets, func(i, j int) bool {
|
||||||
|
return buckets[i].BucketTime.Before(buckets[j].BucketTime)
|
||||||
|
})
|
||||||
return buckets, nil
|
return buckets, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user