status.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Copyright (C) 2015 Audrius Butkevicius and Contributors.
  2. package main
  3. import (
  4. "encoding/json"
  5. "log"
  6. "net/http"
  7. "net/http/pprof"
  8. "runtime"
  9. "sync/atomic"
  10. "time"
  11. "github.com/syncthing/syncthing/lib/build"
  12. )
  13. var rc *rateCalculator
  14. func statusService(addr string) {
  15. rc = newRateCalculator(360, 10*time.Second, &bytesProxied)
  16. handler := http.NewServeMux()
  17. handler.HandleFunc("/status", getStatus)
  18. if pprofEnabled {
  19. handler.HandleFunc("/debug/pprof/", pprof.Index)
  20. }
  21. srv := http.Server{
  22. Addr: addr,
  23. Handler: handler,
  24. ReadTimeout: 15 * time.Second,
  25. }
  26. srv.SetKeepAlivesEnabled(false)
  27. if err := srv.ListenAndServe(); err != nil {
  28. log.Fatal(err)
  29. }
  30. }
  31. func getStatus(w http.ResponseWriter, r *http.Request) {
  32. w.Header().Set("Access-Control-Allow-Origin", "*")
  33. status := make(map[string]interface{})
  34. sessionMut.Lock()
  35. // This can potentially be double the number of pending sessions, as each session has two keys, one for each side.
  36. status["version"] = build.Version
  37. status["buildHost"] = build.Host
  38. status["buildUser"] = build.User
  39. status["buildDate"] = build.Date
  40. status["startTime"] = rc.startTime
  41. status["uptimeSeconds"] = time.Since(rc.startTime) / time.Second
  42. status["numPendingSessionKeys"] = len(pendingSessions)
  43. status["numActiveSessions"] = len(activeSessions)
  44. sessionMut.Unlock()
  45. status["numConnections"] = atomic.LoadInt64(&numConnections)
  46. status["numProxies"] = atomic.LoadInt64(&numProxies)
  47. status["bytesProxied"] = atomic.LoadInt64(&bytesProxied)
  48. status["goVersion"] = runtime.Version()
  49. status["goOS"] = runtime.GOOS
  50. status["goArch"] = runtime.GOARCH
  51. status["goMaxProcs"] = runtime.GOMAXPROCS(-1)
  52. status["goNumRoutine"] = runtime.NumGoroutine()
  53. status["kbps10s1m5m15m30m60m"] = []int64{
  54. rc.rate(1) * 8 / 1000, // each interval is 10s
  55. rc.rate(60/10) * 8 / 1000,
  56. rc.rate(5*60/10) * 8 / 1000,
  57. rc.rate(15*60/10) * 8 / 1000,
  58. rc.rate(30*60/10) * 8 / 1000,
  59. rc.rate(60*60/10) * 8 / 1000,
  60. }
  61. status["options"] = map[string]interface{}{
  62. "network-timeout": networkTimeout / time.Second,
  63. "ping-interval": pingInterval / time.Second,
  64. "message-timeout": messageTimeout / time.Second,
  65. "per-session-rate": sessionLimitBps,
  66. "global-rate": globalLimitBps,
  67. "pools": pools,
  68. "provided-by": providedBy,
  69. }
  70. bs, err := json.MarshalIndent(status, "", " ")
  71. if err != nil {
  72. http.Error(w, err.Error(), http.StatusInternalServerError)
  73. return
  74. }
  75. w.Header().Set("Content-Type", "application/json")
  76. w.Write(bs)
  77. }
  78. type rateCalculator struct {
  79. counter *int64 // atomic, must remain 64-bit aligned
  80. rates []int64
  81. prev int64
  82. startTime time.Time
  83. }
  84. func newRateCalculator(keepIntervals int, interval time.Duration, counter *int64) *rateCalculator {
  85. r := &rateCalculator{
  86. rates: make([]int64, keepIntervals),
  87. counter: counter,
  88. startTime: time.Now(),
  89. }
  90. go r.updateRates(interval)
  91. return r
  92. }
  93. func (r *rateCalculator) updateRates(interval time.Duration) {
  94. for {
  95. now := time.Now()
  96. next := now.Truncate(interval).Add(interval)
  97. time.Sleep(next.Sub(now))
  98. cur := atomic.LoadInt64(r.counter)
  99. rate := int64(float64(cur-r.prev) / interval.Seconds())
  100. copy(r.rates[1:], r.rates)
  101. r.rates[0] = rate
  102. r.prev = cur
  103. }
  104. }
  105. func (r *rateCalculator) rate(periods int) int64 {
  106. var tot int64
  107. for i := 0; i < periods; i++ {
  108. tot += r.rates[i]
  109. }
  110. return tot / int64(periods)
  111. }