mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
feat(access-logs): 新增 IP 明细 Tab 并完善日志详情字段
按时间窗聚合 IP 请求数/2xx 比例/入出站流量,支持排序与详情分析; 日志明细详情仅展示请求业务字段,IP 情报迁至独立详情弹窗。
This commit is contained in:
@@ -46,10 +46,16 @@ type NodeAccessLogIPAggregate struct {
|
||||
|
||||
// NodeAccessLogIPSummary is an IP summary row.
|
||||
type NodeAccessLogIPSummary struct {
|
||||
RemoteAddr string `gorm:"column:remote_addr"`
|
||||
TotalRequests int64 `gorm:"column:total_requests"`
|
||||
RecentRequests int64 `gorm:"column:recent_requests"`
|
||||
LastSeenEpoch int64 `gorm:"column:last_seen_epoch"`
|
||||
RemoteAddr string `gorm:"column:remote_addr"`
|
||||
Region string `gorm:"column:region"`
|
||||
TotalRequests int64 `gorm:"column:total_requests"`
|
||||
Success2xxCount int64 `gorm:"column:success_2xx_count"`
|
||||
SuccessRatio float64 `gorm:"column:success_ratio"`
|
||||
BytesReceived int64 `gorm:"column:request_length"`
|
||||
BytesSent int64 `gorm:"column:bytes_sent"`
|
||||
// RecentRequests is deprecated (always 0); kept for wire compatibility.
|
||||
RecentRequests int64 `gorm:"column:recent_requests"`
|
||||
LastSeenEpoch int64 `gorm:"column:last_seen_epoch"`
|
||||
}
|
||||
|
||||
// NodeAccessLogIPTrend is an IP trend bucket row.
|
||||
|
||||
@@ -251,10 +251,15 @@ func buildOpenFlareAccessLogIPSummaryRows(ctx context.Context, query OpenFlareAc
|
||||
continue
|
||||
}
|
||||
rows = append(rows, &OpenFlareAccessLogIPSummaryRow{
|
||||
RemoteAddr: remoteAddr,
|
||||
TotalRequests: partial.TotalRequests,
|
||||
RecentRequests: partial.RecentRequests,
|
||||
LastSeenEpoch: partial.LastSeenEpoch,
|
||||
RemoteAddr: remoteAddr,
|
||||
Region: strings.TrimSpace(partial.Region),
|
||||
TotalRequests: partial.TotalRequests,
|
||||
Success2xxCount: partial.Success2xxCount,
|
||||
SuccessRatio: partial.SuccessRatio,
|
||||
BytesReceived: partial.BytesReceived,
|
||||
BytesSent: partial.BytesSent,
|
||||
RecentRequests: 0,
|
||||
LastSeenEpoch: partial.LastSeenEpoch,
|
||||
})
|
||||
}
|
||||
return rows, nil
|
||||
@@ -305,6 +310,7 @@ func openFlareAccessLogQueryFromIPSummary(query OpenFlareAccessLogIPSummaryQuery
|
||||
RemoteAddr: query.RemoteAddr,
|
||||
Host: query.Host,
|
||||
Since: query.Since,
|
||||
Until: query.Until,
|
||||
Page: query.Page,
|
||||
PageSize: query.PageSize,
|
||||
SortBy: query.SortBy,
|
||||
@@ -377,8 +383,12 @@ func sortOpenFlareAccessLogIPSummaryRows(items []*OpenFlareAccessLogIPSummaryRow
|
||||
}
|
||||
var compare int
|
||||
switch strings.TrimSpace(sortBy) {
|
||||
case "recent_requests":
|
||||
compare = openFlareAccessLogCompareInt64(left.RecentRequests, right.RecentRequests)
|
||||
case "request_length", "bytes_received":
|
||||
compare = openFlareAccessLogCompareInt64(left.BytesReceived, right.BytesReceived)
|
||||
case "bytes_sent":
|
||||
compare = openFlareAccessLogCompareInt64(left.BytesSent, right.BytesSent)
|
||||
case "success_ratio":
|
||||
compare = openFlareAccessLogCompareFloat64(left.SuccessRatio, right.SuccessRatio)
|
||||
case "last_seen_at":
|
||||
compare = openFlareAccessLogCompareInt64(left.LastSeenEpoch, right.LastSeenEpoch)
|
||||
case "remote_addr":
|
||||
@@ -399,6 +409,16 @@ func sortOpenFlareAccessLogIPSummaryRows(items []*OpenFlareAccessLogIPSummaryRow
|
||||
})
|
||||
}
|
||||
|
||||
func openFlareAccessLogCompareFloat64(left, right float64) int {
|
||||
if left < right {
|
||||
return -1
|
||||
}
|
||||
if left > right {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func openFlareAccessLogPaginateBounds(total int, page int, pageSize int) (int, int) {
|
||||
if page < 0 {
|
||||
page = 0
|
||||
|
||||
@@ -274,11 +274,21 @@ func (s *memoryAccessLogStore) IPAggregates(_ context.Context, filter OpenFlareA
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *memoryAccessLogStore) IPSummaries(_ context.Context, filter OpenFlareAccessLogQuery, recentSince time.Time) ([]openFlareAccessLogIPSummaryRow, error) {
|
||||
func (s *memoryAccessLogStore) IPSummaries(_ context.Context, filter OpenFlareAccessLogQuery, _ time.Time) ([]openFlareAccessLogIPSummaryRow, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
rows := s.filterRecords(filter)
|
||||
aggregates := make(map[string]*openFlareAccessLogIPSummaryRow)
|
||||
type aggregate struct {
|
||||
RemoteAddr string
|
||||
Region string
|
||||
RegionEpoch int64
|
||||
TotalRequests int64
|
||||
Success2xxCount int64
|
||||
BytesReceived int64
|
||||
BytesSent int64
|
||||
LastSeenEpoch int64
|
||||
}
|
||||
aggregates := make(map[string]*aggregate)
|
||||
for _, row := range rows {
|
||||
remoteAddr := strings.TrimSpace(row.RemoteAddr)
|
||||
if remoteAddr == "" {
|
||||
@@ -286,25 +296,40 @@ func (s *memoryAccessLogStore) IPSummaries(_ context.Context, filter OpenFlareAc
|
||||
}
|
||||
item := aggregates[remoteAddr]
|
||||
if item == nil {
|
||||
item = &openFlareAccessLogIPSummaryRow{RemoteAddr: remoteAddr}
|
||||
item = &aggregate{RemoteAddr: remoteAddr}
|
||||
aggregates[remoteAddr] = item
|
||||
}
|
||||
item.TotalRequests++
|
||||
if !recentSince.IsZero() && !row.LoggedAt.Before(recentSince) {
|
||||
item.RecentRequests++
|
||||
if row.StatusCode >= 200 && row.StatusCode < 300 {
|
||||
item.Success2xxCount++
|
||||
}
|
||||
item.BytesReceived += row.RequestLength
|
||||
item.BytesSent += row.BytesSent
|
||||
epoch := row.LoggedAt.UTC().Unix()
|
||||
if epoch > item.LastSeenEpoch {
|
||||
item.LastSeenEpoch = epoch
|
||||
}
|
||||
if epoch >= item.RegionEpoch {
|
||||
item.RegionEpoch = epoch
|
||||
item.Region = strings.TrimSpace(row.Region)
|
||||
}
|
||||
}
|
||||
summaryRows := make([]*OpenFlareAccessLogIPSummaryRow, 0, len(aggregates))
|
||||
for _, item := range aggregates {
|
||||
ratio := 0.0
|
||||
if item.TotalRequests > 0 {
|
||||
ratio = float64(item.Success2xxCount) / float64(item.TotalRequests)
|
||||
}
|
||||
summaryRows = append(summaryRows, &OpenFlareAccessLogIPSummaryRow{
|
||||
RemoteAddr: item.RemoteAddr,
|
||||
TotalRequests: item.TotalRequests,
|
||||
RecentRequests: item.RecentRequests,
|
||||
LastSeenEpoch: item.LastSeenEpoch,
|
||||
RemoteAddr: item.RemoteAddr,
|
||||
Region: item.Region,
|
||||
TotalRequests: item.TotalRequests,
|
||||
Success2xxCount: item.Success2xxCount,
|
||||
SuccessRatio: ratio,
|
||||
BytesReceived: item.BytesReceived,
|
||||
BytesSent: item.BytesSent,
|
||||
RecentRequests: 0,
|
||||
LastSeenEpoch: item.LastSeenEpoch,
|
||||
})
|
||||
}
|
||||
sortOpenFlareAccessLogIPSummaryRows(summaryRows, filter.SortBy, filter.SortOrder)
|
||||
@@ -315,10 +340,15 @@ func (s *memoryAccessLogStore) IPSummaries(_ context.Context, filter OpenFlareAc
|
||||
result := make([]openFlareAccessLogIPSummaryRow, len(summaryRows))
|
||||
for index, item := range summaryRows {
|
||||
result[index] = openFlareAccessLogIPSummaryRow{
|
||||
RemoteAddr: item.RemoteAddr,
|
||||
TotalRequests: item.TotalRequests,
|
||||
RecentRequests: item.RecentRequests,
|
||||
LastSeenEpoch: item.LastSeenEpoch,
|
||||
RemoteAddr: item.RemoteAddr,
|
||||
Region: item.Region,
|
||||
TotalRequests: item.TotalRequests,
|
||||
Success2xxCount: item.Success2xxCount,
|
||||
SuccessRatio: item.SuccessRatio,
|
||||
BytesReceived: item.BytesReceived,
|
||||
BytesSent: item.BytesSent,
|
||||
RecentRequests: 0,
|
||||
LastSeenEpoch: item.LastSeenEpoch,
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
|
||||
@@ -237,6 +237,7 @@ type OpenFlareAccessLogIPSummaryQuery struct {
|
||||
RemoteAddr string
|
||||
Host string
|
||||
Since time.Time
|
||||
Until time.Time
|
||||
Page int
|
||||
PageSize int
|
||||
SortBy string
|
||||
@@ -245,10 +246,16 @@ type OpenFlareAccessLogIPSummaryQuery struct {
|
||||
|
||||
// OpenFlareAccessLogIPSummaryRow is an IP summary row (v1 stub).
|
||||
type OpenFlareAccessLogIPSummaryRow struct {
|
||||
RemoteAddr string `json:"remote_addr"`
|
||||
TotalRequests int64 `json:"total_requests"`
|
||||
RecentRequests int64 `json:"recent_requests"`
|
||||
LastSeenEpoch int64 `json:"last_seen_epoch"`
|
||||
RemoteAddr string `json:"remote_addr"`
|
||||
Region string `json:"region"`
|
||||
TotalRequests int64 `json:"total_requests"`
|
||||
Success2xxCount int64 `json:"success_2xx_count"`
|
||||
SuccessRatio float64 `json:"success_ratio"`
|
||||
BytesReceived int64 `json:"bytes_received"`
|
||||
BytesSent int64 `json:"bytes_sent"`
|
||||
// RecentRequests is deprecated and always 0.
|
||||
RecentRequests int64 `json:"recent_requests"`
|
||||
LastSeenEpoch int64 `json:"last_seen_epoch"`
|
||||
}
|
||||
|
||||
// OpenFlareAccessLogIPTrendQuery filters IP trend queries (v1 stub).
|
||||
|
||||
Reference in New Issue
Block a user