status.go 2.9 KB

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