package stats import ( "bytes" "fmt" "net/http" "sync" "time" "github.com/chubin/wttr.in/internal/routing" ) // Stats holds processed requests statistics. type Stats struct { m sync.Mutex v map[string]int startTime time.Time } // New returns new Stats. func New() *Stats { return &Stats{ v: map[string]int{}, startTime: time.Now(), } } // Inc key by one. func (c *Stats) Inc(key string) { c.m.Lock() c.v[key]++ c.m.Unlock() } // Get current key counter value. func (c *Stats) Get(key string) int { c.m.Lock() defer c.m.Unlock() return c.v[key] } // Reset key counter. func (c *Stats) Reset(key string) int { c.m.Lock() defer c.m.Unlock() result := c.v[key] c.v[key] = 0 return result } // Show returns current statistics formatted as []byte. func (c *Stats) Show() []byte { var b bytes.Buffer c.m.Lock() defer c.m.Unlock() uptime := time.Since(c.startTime) / time.Second fmt.Fprintf(&b, "%-20s: %v\n", "Running since", c.startTime.Format(time.RFC3339)) fmt.Fprintf(&b, "%-20s: %d\n", "Uptime (min)", uptime/60) fmt.Fprintf(&b, "%-20s: %d\n", "Total queries", c.v["total"]) if uptime != 0 { fmt.Fprintf(&b, "%-20s: %d\n", "Throughput (QpM)", c.v["total"]*60/int(uptime)) } fmt.Fprintf(&b, "%-20s: %d\n", "Cache L1 queries", c.v["cache1"]) if c.v["total"] != 0 { fmt.Fprintf(&b, "%-20s: %d\n", "Cache L1 queries (%)", (100*c.v["cache1"])/c.v["total"]) } fmt.Fprintf(&b, "%-20s: %d\n", "Upstream queries", c.v["total"]-c.v["cache1"]) fmt.Fprintf(&b, "%-20s: %d\n", "Queries with format", c.v["format"]) fmt.Fprintf(&b, "%-20s: %d\n", "Queries with format=j1", c.v["format=j1"]) fmt.Fprintf(&b, "%-20s: %d\n", "Queries with known IP", c.v["geoip"]) return b.Bytes() } func (c *Stats) Response(*http.Request) *routing.Cadre { return &routing.Cadre{ Body: c.Show(), } }