Documentation
¶
Index ¶
- func BuildTrackedEndpoints(paths []string) map[string]bool
- func Middleware(cfg MiddlewareConfig) fiber.Handler
- type Aggregator
- type AggregatorStorage
- type BufferStats
- type Collector
- type Config
- type DailyStats
- type Flusher
- type FlusherStats
- type GeoIPLookup
- type GeoIPProvider
- type Interval
- type LatencyStats
- type MiddlewareConfig
- type NoOpGeoIPLookup
- type RequestLog
- type RingBuffer
- type StorageBackend
- type Summary
- type TimeSeriesPoint
- type TopEntry
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BuildTrackedEndpoints ¶
BuildTrackedEndpoints converts a list of endpoint path patterns to a map of endpoint names.
func Middleware ¶
func Middleware(cfg MiddlewareConfig) fiber.Handler
Middleware creates a Fiber middleware that captures request statistics. The middleware runs after the handler to capture response status and timing.
Types ¶
type Aggregator ¶
type Aggregator struct {
// contains filtered or unexported fields
}
Aggregator handles daily aggregation and data retention.
func NewAggregator ¶
func NewAggregator(storage AggregatorStorage, detailedRetention, aggregatedRetention time.Duration) *Aggregator
NewAggregator creates a new aggregator instance.
func (*Aggregator) LastAggregation ¶
func (a *Aggregator) LastAggregation() time.Time
LastAggregation returns the date of the last successful aggregation.
func (*Aggregator) Purge ¶
func (a *Aggregator) Purge() (detailed int64, aggregated int64, err error)
Purge manually purges data older than the retention periods.
type AggregatorStorage ¶
type AggregatorStorage interface {
AggregateDailyStats(date time.Time) error
PurgeDetailedLogs(before time.Time) (int64, error)
PurgeAggregatedStats(before time.Time) (int64, error)
}
AggregatorStorage is the interface for aggregation storage operations.
type BufferStats ¶
type BufferStats struct {
Size int `json:"size"`
Capacity int `json:"capacity"`
FillPercentage float64 `json:"fill_percentage"`
}
BufferStats holds buffer operational statistics.
type Collector ¶
type Collector struct {
// contains filtered or unexported fields
}
Collector manages statistics collection for federation endpoints.
func NewCollector ¶
func NewCollector(cfg Config, storage StorageBackend) (*Collector, error)
NewCollector creates a new statistics collector.
func (*Collector) BufferStats ¶
func (c *Collector) BufferStats() BufferStats
BufferStats returns current buffer statistics.
func (*Collector) FlusherStats ¶
func (c *Collector) FlusherStats() FlusherStats
FlusherStats returns current flusher statistics.
func (*Collector) Middleware ¶
Middleware returns a Fiber middleware handler for collecting statistics.
func (*Collector) Record ¶
func (c *Collector) Record(entry *RequestLog)
Record manually records a request log entry. This is useful for testing or custom integrations.
type Config ¶
type Config struct {
// Enabled controls whether statistics collection is active.
Enabled bool
// Buffer configuration
BufferSize int
FlushInterval time.Duration
FlushThreshold float64
// Capture options
CaptureClientIP bool
CaptureUserAgent bool
CaptureQueryParams bool
// GeoIP configuration
GeoIPEnabled bool
GeoIPDBPath string
// Retention
DetailedRetention time.Duration
AggregatedRetention time.Duration
// Endpoints to track (empty = all federation endpoints)
Endpoints []string
}
Config holds configuration for the stats collector.
type DailyStats ¶
type DailyStats struct {
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
// Primary key fields for grouping
Date time.Time `gorm:"type:date;uniqueIndex:idx_ds_date_endpoint_status;not null" json:"date"`
Endpoint string `gorm:"size:100;uniqueIndex:idx_ds_date_endpoint_status;not null" json:"endpoint"`
StatusCode int `gorm:"type:smallint;uniqueIndex:idx_ds_date_endpoint_status;not null" json:"status_code"`
// Counts
RequestCount int64 `gorm:"not null;default:0" json:"request_count"`
ErrorCount int64 `gorm:"not null;default:0" json:"error_count"`
// Duration statistics (in milliseconds)
DurationP50Ms int `gorm:"default:0" json:"duration_p50_ms"`
DurationP95Ms int `gorm:"default:0" json:"duration_p95_ms"`
DurationP99Ms int `gorm:"default:0" json:"duration_p99_ms"`
DurationAvgMs int `gorm:"default:0" json:"duration_avg_ms"`
DurationMinMs int `gorm:"default:0" json:"duration_min_ms"`
DurationMaxMs int `gorm:"default:0" json:"duration_max_ms"`
// Top entries as JSON arrays
TopUserAgents json.RawMessage `gorm:"type:json" json:"top_user_agents,omitempty"`
TopCountries json.RawMessage `gorm:"type:json" json:"top_countries,omitempty"`
TopClientIPs json.RawMessage `gorm:"type:json" json:"top_client_ips,omitempty"`
TopParams json.RawMessage `gorm:"type:json" json:"top_params,omitempty"`
}
DailyStats represents aggregated statistics for a single day. This is used for long-term retention with smaller storage footprint.
func (*DailyStats) BeforeCreate ¶
func (d *DailyStats) BeforeCreate(_ *gorm.DB) error
BeforeCreate sets the date to midnight UTC.
func (DailyStats) TableName ¶
func (DailyStats) TableName() string
TableName returns the table name for DailyStats.
type Flusher ¶
type Flusher struct {
// contains filtered or unexported fields
}
Flusher handles periodic flushing of the ring buffer to the database.
func NewFlusher ¶
func NewFlusher(buffer *RingBuffer, storage StorageBackend, interval time.Duration) *Flusher
NewFlusher creates a new flusher instance.
type FlusherStats ¶
type FlusherStats struct {
TotalFlushed int64 `json:"total_flushed"`
TotalDropped int64 `json:"total_dropped"`
LastFlushTime time.Time `json:"last_flush_time"`
LastFlushSize int `json:"last_flush_size"`
BufferSize int `json:"buffer_size"`
BufferFill float64 `json:"buffer_fill"`
}
FlusherStats holds flusher operational statistics.
type GeoIPLookup ¶
type GeoIPLookup struct {
// contains filtered or unexported fields
}
GeoIPLookup provides country code lookup from IP addresses using MaxMind GeoLite2 database.
func NewGeoIPLookup ¶
func NewGeoIPLookup(dbPath string) (*GeoIPLookup, error)
NewGeoIPLookup creates a new GeoIP lookup instance from a MaxMind database file. The database file should be a GeoLite2-Country.mmdb or GeoIP2-Country.mmdb file.
func (*GeoIPLookup) Close ¶
func (g *GeoIPLookup) Close() error
Close closes the MaxMind database reader.
func (*GeoIPLookup) LookupCountry ¶
func (g *GeoIPLookup) LookupCountry(ipStr string) string
LookupCountry returns the ISO 3166-1 alpha-2 country code for the given IP address. Returns an empty string if the lookup fails or the IP is not found.
type GeoIPProvider ¶
GeoIPProvider is the interface for GeoIP lookups.
type LatencyStats ¶
type LatencyStats struct {
P50Ms int `json:"p50_ms"`
P75Ms int `json:"p75_ms"`
P90Ms int `json:"p90_ms"`
P95Ms int `json:"p95_ms"`
P99Ms int `json:"p99_ms"`
AvgMs float64 `json:"avg_ms"`
MinMs int `json:"min_ms"`
MaxMs int `json:"max_ms"`
}
LatencyStats holds latency percentile statistics.
type MiddlewareConfig ¶
type MiddlewareConfig struct {
// CaptureClientIP enables capturing the client IP address.
CaptureClientIP bool
// CaptureUserAgent enables capturing the User-Agent header.
CaptureUserAgent bool
// CaptureQueryParams enables capturing URL query parameters.
CaptureQueryParams bool
// GeoIP provides country lookup from IP addresses. Can be nil.
GeoIP GeoIPProvider
// TrackedEndpoints is a map of endpoints to track. If empty, all requests are tracked.
// Keys should be normalized endpoint names (e.g., "well-known", "fetch", "resolve").
TrackedEndpoints map[string]bool
// Buffer is the ring buffer to write entries to.
Buffer *RingBuffer
}
MiddlewareConfig contains configuration for the stats middleware.
type NoOpGeoIPLookup ¶
type NoOpGeoIPLookup struct{}
NoOpGeoIPLookup is a no-op implementation that always returns empty strings. Used when GeoIP is disabled.
func (NoOpGeoIPLookup) LookupCountry ¶
func (NoOpGeoIPLookup) LookupCountry(string) string
LookupCountry always returns an empty string.
type RequestLog ¶
type RequestLog struct {
ID uint64 `gorm:"primaryKey;autoIncrement" json:"id"`
Timestamp time.Time `gorm:"index:idx_rl_ts;not null" json:"timestamp"`
// Request info
Endpoint string `gorm:"size:100;index:idx_rl_endpoint;not null" json:"endpoint"`
Method string `gorm:"size:10;not null" json:"method"`
StatusCode int `gorm:"type:smallint;not null" json:"status_code"`
DurationMs int `gorm:"not null" json:"duration_ms"`
// Client info
ClientIP string `gorm:"size:45;index:idx_rl_ip" json:"client_ip,omitempty"`
CountryCode string `gorm:"size:2" json:"country_code,omitempty"`
UserAgent string `gorm:"type:text" json:"user_agent,omitempty"`
UserAgentHash uint32 `gorm:"index:idx_rl_ua_hash" json:"user_agent_hash,omitempty"`
// Request details
QueryParams json.RawMessage `gorm:"type:json" json:"query_params,omitempty"`
RequestSize int `gorm:"default:0" json:"request_size"`
ResponseSize int `gorm:"default:0" json:"response_size"`
// Error info
ErrorType string `gorm:"size:100" json:"error_type,omitempty"`
}
RequestLog represents a single request to a federation endpoint. This is stored in the database for detailed analytics.
func (RequestLog) TableName ¶
func (RequestLog) TableName() string
TableName returns the table name for RequestLog.
type RingBuffer ¶
type RingBuffer struct {
// NotifyThreshold is signaled when the buffer reaches the threshold percentage.
// It's a buffered channel (size 1) so sends never block.
NotifyThreshold chan struct{}
// contains filtered or unexported fields
}
RingBuffer is a thread-safe circular buffer for storing RequestLog entries. It provides non-blocking writes that never fail - if the buffer is full, the oldest entries are overwritten.
func NewRingBuffer ¶
func NewRingBuffer(capacity int, threshold float64) *RingBuffer
NewRingBuffer creates a new ring buffer with the given capacity and flush threshold. The threshold (0.0 to 1.0) determines when NotifyThreshold is signaled.
func (*RingBuffer) Capacity ¶
func (b *RingBuffer) Capacity() int
Capacity returns the maximum capacity of the buffer.
func (*RingBuffer) Drain ¶
func (b *RingBuffer) Drain() []*RequestLog
Drain removes and returns all entries from the buffer. The buffer is empty after this call.
func (*RingBuffer) FillPercentage ¶
func (b *RingBuffer) FillPercentage() float64
FillPercentage returns the current fill level as a percentage (0.0 to 1.0).
func (*RingBuffer) IsFull ¶
func (b *RingBuffer) IsFull() bool
IsFull returns true if the buffer is at capacity.
func (*RingBuffer) Size ¶
func (b *RingBuffer) Size() int
Size returns the current number of entries in the buffer.
func (*RingBuffer) Write ¶
func (b *RingBuffer) Write(entry *RequestLog) bool
Write adds an entry to the buffer. This operation is non-blocking and always succeeds. If the buffer is full, the oldest entry is overwritten. Returns true if the threshold was reached (caller may want to trigger a flush).
type StorageBackend ¶
type StorageBackend interface {
InsertBatch(entries []*RequestLog) error
}
StorageBackend is the interface that storage must implement for the flusher.
type Summary ¶
type Summary struct {
TotalRequests int64 `json:"total_requests"`
TotalErrors int64 `json:"total_errors"`
ErrorRate float64 `json:"error_rate"`
AvgLatencyMs float64 `json:"avg_latency_ms"`
P50LatencyMs int `json:"p50_latency_ms"`
P95LatencyMs int `json:"p95_latency_ms"`
P99LatencyMs int `json:"p99_latency_ms"`
UniqueClients int64 `json:"unique_clients"`
UniqueUserAgents int64 `json:"unique_user_agents"`
RequestsByStatus map[int]int64 `json:"requests_by_status"`
RequestsByEndpoint map[string]int64 `json:"requests_by_endpoint"`
}
Summary represents an overall statistics summary.