mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-11 09:46:37 +08:00
fix(openflare): serialize access log snowflake IDs as strings
- Return AccessLogView.id as string to avoid JS Number precision loss - Store OpenFlareAccessLog IDs as uint64 with json id,string - Update frontend AccessLogItem.id type to string
This commit is contained in:
+6
-8
@@ -31,21 +31,19 @@ services:
|
|||||||
postgres:
|
postgres:
|
||||||
image: postgres:17-alpine
|
image: postgres:17-alpine
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-openflare}
|
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
|
||||||
TZ: ${TZ:-Asia/Shanghai}
|
|
||||||
ports:
|
ports:
|
||||||
- "${POSTGRES_PORT:-5432}:5432"
|
- "5432:5432"
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: openflare
|
||||||
|
POSTGRES_USER: openflare
|
||||||
|
POSTGRES_PASSWORD: replace-with-strong-password
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/postgres_data:/var/lib/postgresql/data
|
- ./data/postgres_data:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-openflare}"]
|
test: ["CMD-SHELL", "pg_isready -U openflare -d openflare"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
start_period: 10s
|
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: valkey/valkey:8.0-alpine
|
image: valkey/valkey:8.0-alpine
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ sidebar: false
|
|||||||
- 修复总览看板「24 小时请求趋势」摘要误展示 24 小时累计值的问题:趋势图摘要改为「当前小时」桶数据,顶部 24h 统计改为按小时趋势聚合。
|
- 修复总览看板「24 小时请求趋势」摘要误展示 24 小时累计值的问题:趋势图摘要改为「当前小时」桶数据,顶部 24h 统计改为按小时趋势聚合。
|
||||||
- 修复访问日志 ClickHouse 聚合查询因 `trim(x) AS x` 别名与表列同名导致总览看板地域分布及 IP 统计失败的问题。
|
- 修复访问日志 ClickHouse 聚合查询因 `trim(x) AS x` 别名与表列同名导致总览看板地域分布及 IP 统计失败的问题。
|
||||||
- 修复访问日志页 `count()` 扫描类型不匹配(ClickHouse `UInt64` 写入 `int64`)导致列表计数失败的问题。
|
- 修复访问日志页 `count()` 扫描类型不匹配(ClickHouse `UInt64` 写入 `int64`)导致列表计数失败的问题。
|
||||||
|
- 修复访问日志 Snowflake ID 超出 JS 安全整数范围导致列表 React key 重复告警的问题:API `id` 改为字符串序列化。
|
||||||
|
|
||||||
### 变更
|
### 变更
|
||||||
|
|
||||||
|
|||||||
+1715
-239
File diff suppressed because it is too large
Load Diff
+1715
-239
File diff suppressed because it is too large
Load Diff
+1101
-179
File diff suppressed because it is too large
Load Diff
@@ -523,7 +523,7 @@ export interface AccessLogFilters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface AccessLogItem {
|
export interface AccessLogItem {
|
||||||
id: number;
|
id: string;
|
||||||
node_id: string;
|
node_id: string;
|
||||||
node_name: string;
|
node_name: string;
|
||||||
logged_at: string;
|
logged_at: string;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package observability
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ type AccessLogQuery struct {
|
|||||||
|
|
||||||
// AccessLogView is a single access log row.
|
// AccessLogView is a single access log row.
|
||||||
type AccessLogView struct {
|
type AccessLogView struct {
|
||||||
ID uint `json:"id"`
|
ID string `json:"id"`
|
||||||
NodeID string `json:"node_id"`
|
NodeID string `json:"node_id"`
|
||||||
NodeName string `json:"node_name"`
|
NodeName string `json:"node_name"`
|
||||||
LoggedAt time.Time `json:"logged_at"`
|
LoggedAt time.Time `json:"logged_at"`
|
||||||
@@ -209,7 +210,7 @@ func ListAccessLogs(ctx context.Context, input AccessLogQuery) (*AccessLogList,
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
views = append(views, AccessLogView{
|
views = append(views, AccessLogView{
|
||||||
ID: item.ID,
|
ID: formatAccessLogID(item.ID),
|
||||||
NodeID: item.NodeID,
|
NodeID: item.NodeID,
|
||||||
NodeName: nodeNames[item.NodeID],
|
NodeName: nodeNames[item.NodeID],
|
||||||
LoggedAt: item.LoggedAt,
|
LoggedAt: item.LoggedAt,
|
||||||
@@ -634,3 +635,7 @@ func normalizeFoldMinutes(value int) (int, error) {
|
|||||||
return 0, errors.New("fold_minutes 仅支持 3 或 5")
|
return 0, errors.New("fold_minutes 仅支持 3 或 5")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func formatAccessLogID(id uint64) string {
|
||||||
|
return strconv.FormatUint(id, 10)
|
||||||
|
}
|
||||||
|
|||||||
@@ -476,7 +476,7 @@ func openFlareAccessLogStatusCodeToInt32(code int) int32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func openFlareAccessLogUintToInt64(value uint) int64 {
|
func openFlareAccessLogUintToInt64(value uint64) int64 {
|
||||||
if value > math.MaxInt64 {
|
if value > math.MaxInt64 {
|
||||||
return math.MaxInt64
|
return math.MaxInt64
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ func toNodeAccessLogFilter(query OpenFlareAccessLogQuery) analyticsrepo.NodeAcce
|
|||||||
|
|
||||||
func toAnalyticsNodeAccessLog(record *OpenFlareAccessLog) analyticsmodel.NodeAccessLog {
|
func toAnalyticsNodeAccessLog(record *OpenFlareAccessLog) analyticsmodel.NodeAccessLog {
|
||||||
return analyticsmodel.NodeAccessLog{
|
return analyticsmodel.NodeAccessLog{
|
||||||
ID: uint64(record.ID),
|
ID: record.ID,
|
||||||
NodeID: record.NodeID,
|
NodeID: record.NodeID,
|
||||||
LoggedAt: record.LoggedAt,
|
LoggedAt: record.LoggedAt,
|
||||||
RemoteAddr: record.RemoteAddr,
|
RemoteAddr: record.RemoteAddr,
|
||||||
@@ -232,7 +232,7 @@ func fromAnalyticsNodeAccessLogs(rows []analyticsmodel.NodeAccessLog) []*OpenFla
|
|||||||
result := make([]*OpenFlareAccessLog, len(rows))
|
result := make([]*OpenFlareAccessLog, len(rows))
|
||||||
for index, row := range rows {
|
for index, row := range rows {
|
||||||
result[index] = &OpenFlareAccessLog{
|
result[index] = &OpenFlareAccessLog{
|
||||||
ID: uint(row.ID),
|
ID: row.ID,
|
||||||
NodeID: row.NodeID,
|
NodeID: row.NodeID,
|
||||||
LoggedAt: row.LoggedAt,
|
LoggedAt: row.LoggedAt,
|
||||||
RemoteAddr: row.RemoteAddr,
|
RemoteAddr: row.RemoteAddr,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func (s *memoryAccessLogStore) InsertBatch(_ context.Context, records []*OpenFla
|
|||||||
}
|
}
|
||||||
copyRecord := *record
|
copyRecord := *record
|
||||||
if copyRecord.ID == 0 {
|
if copyRecord.ID == 0 {
|
||||||
copyRecord.ID = uint(idgen.NextUint64ID())
|
copyRecord.ID = idgen.NextUint64ID()
|
||||||
}
|
}
|
||||||
if copyRecord.CreatedAt.IsZero() {
|
if copyRecord.CreatedAt.IsZero() {
|
||||||
copyRecord.CreatedAt = now
|
copyRecord.CreatedAt = now
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func (OpenFlareRequestReport) TableName() string {
|
|||||||
// OpenFlareAccessLog stores a single access log row in ClickHouse (database: openflare, table: of_node_access_logs).
|
// OpenFlareAccessLog stores a single access log row in ClickHouse (database: openflare, table: of_node_access_logs).
|
||||||
// ClickHouse DDL is managed by goose; reads/writes go through internal/repository/analytics.
|
// ClickHouse DDL is managed by goose; reads/writes go through internal/repository/analytics.
|
||||||
type OpenFlareAccessLog struct {
|
type OpenFlareAccessLog struct {
|
||||||
ID uint `json:"id" gorm:"primaryKey;autoIncrement"`
|
ID uint64 `json:"id,string" gorm:"column:id"`
|
||||||
NodeID string `json:"node_id" gorm:"index;size:64;not null"`
|
NodeID string `json:"node_id" gorm:"index;size:64;not null"`
|
||||||
LoggedAt time.Time `json:"logged_at" gorm:"index"`
|
LoggedAt time.Time `json:"logged_at" gorm:"index"`
|
||||||
RemoteAddr string `json:"remote_addr" gorm:"index;size:128"`
|
RemoteAddr string `json:"remote_addr" gorm:"index;size:128"`
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ func sortOpenFlareMetricSnapshots(items []*OpenFlareMetricSnapshot) {
|
|||||||
if compare := openFlareAccessLogCompareInt64(left.CapturedAt.Unix(), right.CapturedAt.Unix()); compare != 0 {
|
if compare := openFlareAccessLogCompareInt64(left.CapturedAt.Unix(), right.CapturedAt.Unix()); compare != 0 {
|
||||||
return compare > 0
|
return compare > 0
|
||||||
}
|
}
|
||||||
return openFlareAccessLogCompareInt64(openFlareAccessLogUintToInt64(left.ID), openFlareAccessLogUintToInt64(right.ID)) > 0
|
return openFlareAccessLogCompareInt64(openFlareAccessLogUintToInt64(uint64(left.ID)), openFlareAccessLogUintToInt64(uint64(right.ID))) > 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,7 +370,7 @@ func sortOpenFlareRequestReports(items []*OpenFlareRequestReport) {
|
|||||||
if compare := openFlareAccessLogCompareInt64(left.WindowEndedAt.Unix(), right.WindowEndedAt.Unix()); compare != 0 {
|
if compare := openFlareAccessLogCompareInt64(left.WindowEndedAt.Unix(), right.WindowEndedAt.Unix()); compare != 0 {
|
||||||
return compare > 0
|
return compare > 0
|
||||||
}
|
}
|
||||||
return openFlareAccessLogCompareInt64(openFlareAccessLogUintToInt64(left.ID), openFlareAccessLogUintToInt64(right.ID)) > 0
|
return openFlareAccessLogCompareInt64(openFlareAccessLogUintToInt64(uint64(left.ID)), openFlareAccessLogUintToInt64(uint64(right.ID))) > 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +384,7 @@ func sortOpenFlareNodeObservationOpenresty(items []*OpenFlareNodeObservationOpen
|
|||||||
if compare := openFlareAccessLogCompareInt64(left.CapturedAt.Unix(), right.CapturedAt.Unix()); compare != 0 {
|
if compare := openFlareAccessLogCompareInt64(left.CapturedAt.Unix(), right.CapturedAt.Unix()); compare != 0 {
|
||||||
return compare > 0
|
return compare > 0
|
||||||
}
|
}
|
||||||
return openFlareAccessLogCompareInt64(openFlareAccessLogUintToInt64(left.ID), openFlareAccessLogUintToInt64(right.ID)) > 0
|
return openFlareAccessLogCompareInt64(openFlareAccessLogUintToInt64(uint64(left.ID)), openFlareAccessLogUintToInt64(uint64(right.ID))) > 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,7 +398,7 @@ func sortOpenFlareNodeObservationFrps(items []*OpenFlareNodeObservationFrps) {
|
|||||||
if compare := openFlareAccessLogCompareInt64(left.CapturedAt.Unix(), right.CapturedAt.Unix()); compare != 0 {
|
if compare := openFlareAccessLogCompareInt64(left.CapturedAt.Unix(), right.CapturedAt.Unix()); compare != 0 {
|
||||||
return compare > 0
|
return compare > 0
|
||||||
}
|
}
|
||||||
return openFlareAccessLogCompareInt64(openFlareAccessLogUintToInt64(left.ID), openFlareAccessLogUintToInt64(right.ID)) > 0
|
return openFlareAccessLogCompareInt64(openFlareAccessLogUintToInt64(uint64(left.ID)), openFlareAccessLogUintToInt64(uint64(right.ID))) > 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +412,7 @@ func sortOpenFlareNodeObservationFrpc(items []*OpenFlareNodeObservationFrpc) {
|
|||||||
if compare := openFlareAccessLogCompareInt64(left.CapturedAt.Unix(), right.CapturedAt.Unix()); compare != 0 {
|
if compare := openFlareAccessLogCompareInt64(left.CapturedAt.Unix(), right.CapturedAt.Unix()); compare != 0 {
|
||||||
return compare > 0
|
return compare > 0
|
||||||
}
|
}
|
||||||
return openFlareAccessLogCompareInt64(openFlareAccessLogUintToInt64(left.ID), openFlareAccessLogUintToInt64(right.ID)) > 0
|
return openFlareAccessLogCompareInt64(openFlareAccessLogUintToInt64(uint64(left.ID)), openFlareAccessLogUintToInt64(uint64(right.ID))) > 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user