syncthing/cmd/strelaysrv/status.go

128 lines
3.3 KiB
Go
Raw Normal View History

2016-06-02 12:16:02 +00:00
// Copyright (C) 2015 Audrius Butkevicius and Contributors.
2015-08-20 10:59:44 +00:00
package main
import (
"encoding/json"
"log"
"net/http"
"net/http/pprof"
2015-08-20 10:59:44 +00:00
"runtime"
"sync/atomic"
2015-08-20 12:02:52 +00:00
"time"
2015-08-20 10:59:44 +00:00
)
2015-08-20 12:02:52 +00:00
var rc *rateCalculator
2015-08-20 10:59:44 +00:00
func statusService(addr string) {
2015-08-20 12:02:52 +00:00
rc = newRateCalculator(360, 10*time.Second, &bytesProxied)
handler := http.NewServeMux()
handler.HandleFunc("/status", getStatus)
if pprofEnabled {
handler.HandleFunc("/debug/pprof/", pprof.Index)
}
srv := http.Server{
Addr: addr,
Handler: handler,
ReadTimeout: 15 * time.Second,
}
srv.SetKeepAlivesEnabled(false)
if err := srv.ListenAndServe(); err != nil {
2015-08-20 10:59:44 +00:00
log.Fatal(err)
}
}
func getStatus(w http.ResponseWriter, r *http.Request) {
2015-10-22 20:44:29 +00:00
w.Header().Set("Access-Control-Allow-Origin", "*")
2015-08-20 10:59:44 +00:00
status := make(map[string]interface{})
sessionMut.Lock()
// This can potentially be double the number of pending sessions, as each session has two keys, one for each side.
status["version"] = Version
status["buildHost"] = BuildHost
status["buildUser"] = BuildUser
status["buildDate"] = BuildDate
2015-10-10 10:43:07 +00:00
status["startTime"] = rc.startTime
2015-10-22 20:40:36 +00:00
status["uptimeSeconds"] = time.Since(rc.startTime) / time.Second
status["numPendingSessionKeys"] = len(pendingSessions)
status["numActiveSessions"] = len(activeSessions)
2015-08-20 10:59:44 +00:00
sessionMut.Unlock()
2015-08-20 12:02:52 +00:00
status["numConnections"] = atomic.LoadInt64(&numConnections)
2015-08-20 10:59:44 +00:00
status["numProxies"] = atomic.LoadInt64(&numProxies)
status["bytesProxied"] = atomic.LoadInt64(&bytesProxied)
status["goVersion"] = runtime.Version()
status["goOS"] = runtime.GOOS
2015-11-21 18:58:52 +00:00
status["goArch"] = runtime.GOARCH
2015-08-20 10:59:44 +00:00
status["goMaxProcs"] = runtime.GOMAXPROCS(-1)
2016-02-10 21:24:57 +00:00
status["goNumRoutine"] = runtime.NumGoroutine()
2015-08-20 12:02:52 +00:00
status["kbps10s1m5m15m30m60m"] = []int64{
rc.rate(1) * 8 / 1000, // each interval is 10s
2015-08-20 12:02:52 +00:00
rc.rate(60/10) * 8 / 1000,
rc.rate(5*60/10) * 8 / 1000,
rc.rate(15*60/10) * 8 / 1000,
rc.rate(30*60/10) * 8 / 1000,
rc.rate(60*60/10) * 8 / 1000,
}
2015-10-10 10:49:34 +00:00
status["options"] = map[string]interface{}{
2015-10-22 20:40:36 +00:00
"network-timeout": networkTimeout / time.Second,
"ping-interval": pingInterval / time.Second,
"message-timeout": messageTimeout / time.Second,
2015-10-10 10:49:34 +00:00
"per-session-rate": sessionLimitBps,
"global-rate": globalLimitBps,
2015-10-22 20:40:36 +00:00
"pools": pools,
2015-10-18 22:15:01 +00:00
"provided-by": providedBy,
2015-10-10 10:49:34 +00:00
}
2015-08-20 10:59:44 +00:00
bs, err := json.MarshalIndent(status, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(bs)
}
2015-08-20 12:02:52 +00:00
type rateCalculator struct {
counter *int64 // atomic, must remain 64-bit aligned
2015-10-10 10:43:07 +00:00
rates []int64
prev int64
startTime time.Time
2015-08-20 12:02:52 +00:00
}
func newRateCalculator(keepIntervals int, interval time.Duration, counter *int64) *rateCalculator {
r := &rateCalculator{
2015-10-10 10:43:07 +00:00
rates: make([]int64, keepIntervals),
counter: counter,
startTime: time.Now(),
2015-08-20 12:02:52 +00:00
}
go r.updateRates(interval)
return r
}
func (r *rateCalculator) updateRates(interval time.Duration) {
for {
now := time.Now()
next := now.Truncate(interval).Add(interval)
time.Sleep(next.Sub(now))
cur := atomic.LoadInt64(r.counter)
rate := int64(float64(cur-r.prev) / interval.Seconds())
copy(r.rates[1:], r.rates)
r.rates[0] = rate
r.prev = cur
}
}
func (r *rateCalculator) rate(periods int) int64 {
var tot int64
for i := 0; i < periods; i++ {
tot += r.rates[i]
}
return tot / int64(periods)
}