package obs
import "time"
// TrafficRange is one of the windows the traffic page offers: how far
// back it reads, and how wide each point of its chart is.
type TrafficRange struct {
Name string
Span time.Duration
Step time.Duration
}
// TrafficRanges are the windows, shortest first. Each is drawn in 60 to
// 168 points: fine enough that a burst of a few minutes shows as one,
// few enough that the chart stays a line rather than noise. The month
// is as far as the request log reaches (see obsduck.HitsKept).
var TrafficRanges = []TrafficRange{
{"1h", time.Hour, time.Minute},
{"24h", 24 * time.Hour, 10 * time.Minute},
{"7d", 7 * 24 * time.Hour, time.Hour},
{"30d", 30 * 24 * time.Hour, 6 * time.Hour},
}
// RangeNamed is the window by its name, the day for anything else.
func RangeNamed(name string) TrafficRange {
for _, r := range TrafficRanges {
if r.Name == name {
return r
}
}
return TrafficRanges[1]
}
// TrafficFilters are the page's filter chips. Every one narrows every
// panel; an empty one narrows nothing.
var TrafficFilters = []string{"repo", "kind", "network", "country", "path", "client", "crawler", "door"}
// TrafficQuery is what the page asks for.
type TrafficQuery struct {
Range TrafficRange
Filters map[string]string
// Now is the end of the window; zero is the present.
Now time.Time
}
// TrafficTotals are the summary strip's numbers for one window.
type TrafficTotals struct {
Visitors, Requests, Bytes, ServerMs, Errors int64
// Automated is the share of requests from crawlers and scripts, 0..1.
Automated float64
}
// TrafficPoint is one point of the chart.
type TrafficPoint struct {
At time.Time
// ByKind is requests by reader kind, in TrafficKinds order.
ByKind [4]int64
Visitors int64
Bytes int64
ServerMs int64
Errors int64
}
// TrafficKinds is the order ByKind and every kind breakdown use.
var TrafficKinds = [4]string{KindPerson, KindCrawler, KindAutomated, KindUnsure}
// Count is one bar of a breakdown.
type Count struct {
Label string
Note string // the muted text beside the label
N int64
// Key is what a filter chip set from this row filters on, when the
// label is not it (an AS number behind a network's name).
Key string
// Flag marks a row worth a reader's eye: an impostor.
Flag bool
}
// Latency is a path's or a kind's response times.
type Latency struct {
Label string
N int64
P50Ms, P95Ms int64
}
// Download is one repository's reading by sync and archive.
type Download struct {
Repo string
Clones, Fetches, Archive int64
Bytes int64
// Mix is downloads by reader kind, in TrafficKinds order.
Mix [4]int64
// Zit, Fossil and Other split the sync rounds and archives by
// client.
Zit, Fossil, Other int64
SignedIn int64 // distinct verified accounts
}
// Source is one reader of downloads, grouped by who it appears to be.
type Source struct {
Name string
Kind string
Took string // what it read: repositories and how
N int64
Why string // the evidence for Kind, in a sentence
}
// Traffic is everything the traffic page shows for one query.
type Traffic struct {
Range TrafficRange
From, To time.Time
Totals TrafficTotals
Prev TrafficTotals
Points []TrafficPoint
PrevPoints []TrafficPoint
Kinds []Count
Crawlers []Count
Networks []Count
Countries []Count
Paths []Count
Slowest []Latency
Repos []Count
Served []Count // bytes by what was served
Status []Count
Referrers []Count
Refused []Count
// Histogram counts responses by time: the edges are HistEdgesMs,
// the last bucket everything past the last edge.
Histogram []int64
P50, P95, P99 int64
ByKind []Latency
// TimeSplit is where the server's time went, in milliseconds:
// reading stores, the forge's own work around them, and rendering
// and writing the response.
StoreMs, LogicMs, RenderMs int64
Downloads []Download
How []Count
Sources []Source
}
// HistEdgesMs are the response-time histogram's bucket edges.
var HistEdgesMs = []int64{5, 10, 20, 35, 50, 75, 100, 150, 200, 350, 500, 1000, 2000, 5000}
// Traffic reads the request log back for the traffic page. A forge with
// history switched off has none to read, and says so with a nil.
func (r *Recorder) Traffic(q TrafficQuery) (*Traffic, error) {
r.mu.Lock()
sink := r.sink
r.mu.Unlock()
t, ok := sink.(interface {
Traffic(TrafficQuery) (*Traffic, error)
})
if !ok {
return nil, nil
}
return t.Traffic(q)
}