mirror of
https://github.com/chubin/wttr.in
synced 2024-11-15 00:27:09 +00:00
Add /:stats support
This commit is contained in:
parent
8fd712f790
commit
ec264850a4
2 changed files with 116 additions and 40 deletions
|
@ -28,6 +28,8 @@ type RequestProcessor struct {
|
||||||
peakRequest30 sync.Map
|
peakRequest30 sync.Map
|
||||||
peakRequest60 sync.Map
|
peakRequest60 sync.Map
|
||||||
lruCache *lru.Cache
|
lruCache *lru.Cache
|
||||||
|
stats *Stats
|
||||||
|
router Router
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRequestProcessor returns new RequestProcessor.
|
// NewRequestProcessor returns new RequestProcessor.
|
||||||
|
@ -37,9 +39,15 @@ func NewRequestProcessor() (*RequestProcessor, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &RequestProcessor{
|
rp := &RequestProcessor{
|
||||||
lruCache: lruCache,
|
lruCache: lruCache,
|
||||||
}, nil
|
stats: NewStats(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize routes.
|
||||||
|
rp.router.AddPath("/:stats", rp.stats)
|
||||||
|
|
||||||
|
return rp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start starts async request processor jobs, such as peak handling.
|
// Start starts async request processor jobs, such as peak handling.
|
||||||
|
@ -53,11 +61,23 @@ func (rp *RequestProcessor) ProcessRequest(r *http.Request) (*ResponseWithHeader
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
rp.stats.Inc("total")
|
||||||
|
|
||||||
|
// Main routing logic.
|
||||||
|
if rh := rp.router.Route(r); rh != nil {
|
||||||
|
result := rh.Response(r)
|
||||||
|
if result != nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if resp, ok := redirectInsecure(r); ok {
|
if resp, ok := redirectInsecure(r); ok {
|
||||||
|
rp.stats.Inc("redirects")
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if dontCache(r) {
|
if dontCache(r) {
|
||||||
|
rp.stats.Inc("uncached")
|
||||||
return get(r)
|
return get(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +89,7 @@ func (rp *RequestProcessor) ProcessRequest(r *http.Request) (*ResponseWithHeader
|
||||||
|
|
||||||
cacheBody, ok := rp.lruCache.Get(cacheDigest)
|
cacheBody, ok := rp.lruCache.Get(cacheDigest)
|
||||||
if ok {
|
if ok {
|
||||||
|
rp.stats.Inc("cache1")
|
||||||
cacheEntry := cacheBody.(ResponseWithHeader)
|
cacheEntry := cacheBody.(ResponseWithHeader)
|
||||||
|
|
||||||
// if after all attempts we still have no answer,
|
// if after all attempts we still have no answer,
|
||||||
|
@ -93,7 +114,17 @@ func (rp *RequestProcessor) ProcessRequest(r *http.Request) (*ResponseWithHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
if !foundInCache {
|
if !foundInCache {
|
||||||
|
// Handling query.
|
||||||
|
format := r.URL.Query().Get("format")
|
||||||
|
if len(format) != 0 {
|
||||||
|
rp.stats.Inc("format")
|
||||||
|
if format == "j1" {
|
||||||
|
rp.stats.Inc("format=j1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rp.lruCache.Add(cacheDigest, ResponseWithHeader{InProgress: true})
|
rp.lruCache.Add(cacheDigest, ResponseWithHeader{InProgress: true})
|
||||||
|
|
||||||
response, err = get(r)
|
response, err = get(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
121
cmd/stat.go
121
cmd/stat.go
|
@ -1,40 +1,85 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
// import (
|
import (
|
||||||
// "log"
|
"bytes"
|
||||||
// "sync"
|
"fmt"
|
||||||
// "time"
|
"net/http"
|
||||||
// )
|
"sync"
|
||||||
//
|
"time"
|
||||||
// type safeCounter struct {
|
)
|
||||||
// v map[int]int
|
|
||||||
// mux sync.Mutex
|
// Stats holds processed requests statistics.
|
||||||
// }
|
type Stats struct {
|
||||||
//
|
m sync.Mutex
|
||||||
// func (c *safeCounter) inc(key int) {
|
v map[string]int
|
||||||
// c.mux.Lock()
|
startTime time.Time
|
||||||
// c.v[key]++
|
}
|
||||||
// c.mux.Unlock()
|
|
||||||
// }
|
// NewStats returns new Stats.
|
||||||
//
|
func NewStats() *Stats {
|
||||||
// // func (c *safeCounter) val(key int) int {
|
return &Stats{
|
||||||
// // c.mux.Lock()
|
v: map[string]int{},
|
||||||
// // defer c.mux.Unlock()
|
startTime: time.Now(),
|
||||||
// // return c.v[key]
|
}
|
||||||
// // }
|
}
|
||||||
// //
|
|
||||||
// // func (c *safeCounter) reset(key int) int {
|
// Inc key by one.
|
||||||
// // c.mux.Lock()
|
func (c *Stats) Inc(key string) {
|
||||||
// // defer c.mux.Unlock()
|
c.m.Lock()
|
||||||
// // result := c.v[key]
|
c.v[key]++
|
||||||
// // c.v[key] = 0
|
c.m.Unlock()
|
||||||
// // return result
|
}
|
||||||
// // }
|
|
||||||
//
|
// Get current key counter value.
|
||||||
// var queriesPerMinute safeCounter
|
func (c *Stats) Get(key string) int {
|
||||||
//
|
c.m.Lock()
|
||||||
// func printStat() {
|
defer c.m.Unlock()
|
||||||
// _, min, _ := time.Now().Clock()
|
return c.v[key]
|
||||||
// queriesPerMinute.inc(min)
|
}
|
||||||
// log.Printf("Processed %d requests\n", min)
|
|
||||||
// }
|
// 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"])
|
||||||
|
|
||||||
|
return b.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Stats) Response(*http.Request) *ResponseWithHeader {
|
||||||
|
return &ResponseWithHeader{
|
||||||
|
Body: c.Show(),
|
||||||
|
StatusCode: 200,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue