metric.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // Copyright 2017 fatedier, fatedier@gmail.com
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package server
  15. import (
  16. "sync"
  17. "time"
  18. "github.com/fatedier/frp/models/config"
  19. "github.com/fatedier/frp/utils/log"
  20. "github.com/fatedier/frp/utils/metric"
  21. )
  22. const (
  23. ReserveDays = 7
  24. )
  25. var globalStats *ServerStatistics
  26. type ServerStatistics struct {
  27. TotalTrafficIn metric.DateCounter
  28. TotalTrafficOut metric.DateCounter
  29. CurConns metric.Counter
  30. // counter for clients
  31. ClientCounts metric.Counter
  32. // counter for proxy types
  33. ProxyTypeCounts map[string]metric.Counter
  34. // statistics for different proxies
  35. // key is proxy name
  36. ProxyStatistics map[string]*ProxyStatistics
  37. mu sync.Mutex
  38. }
  39. type ProxyStatistics struct {
  40. Name string
  41. ProxyType string
  42. TrafficIn metric.DateCounter
  43. TrafficOut metric.DateCounter
  44. CurConns metric.Counter
  45. LastStartTime time.Time
  46. LastCloseTime time.Time
  47. }
  48. func init() {
  49. globalStats = &ServerStatistics{
  50. TotalTrafficIn: metric.NewDateCounter(ReserveDays),
  51. TotalTrafficOut: metric.NewDateCounter(ReserveDays),
  52. CurConns: metric.NewCounter(),
  53. ClientCounts: metric.NewCounter(),
  54. ProxyTypeCounts: make(map[string]metric.Counter),
  55. ProxyStatistics: make(map[string]*ProxyStatistics),
  56. }
  57. go func() {
  58. for {
  59. time.Sleep(12 * time.Hour)
  60. log.Debug("start to clear useless proxy statistics data...")
  61. StatsClearUselessInfo()
  62. log.Debug("finish to clear useless proxy statistics data")
  63. }
  64. }()
  65. }
  66. func StatsClearUselessInfo() {
  67. // To check if there are proxies that closed than 7 days and drop them.
  68. globalStats.mu.Lock()
  69. defer globalStats.mu.Unlock()
  70. for name, data := range globalStats.ProxyStatistics {
  71. if !data.LastCloseTime.IsZero() && time.Since(data.LastCloseTime) > time.Duration(7*24)*time.Hour {
  72. delete(globalStats.ProxyStatistics, name)
  73. log.Trace("clear proxy [%s]'s statistics data, lastCloseTime: [%s]", name, data.LastCloseTime.String())
  74. }
  75. }
  76. }
  77. func StatsNewClient() {
  78. if config.ServerCommonCfg.DashboardPort != 0 {
  79. globalStats.ClientCounts.Inc(1)
  80. }
  81. }
  82. func StatsCloseClient() {
  83. if config.ServerCommonCfg.DashboardPort != 0 {
  84. globalStats.ClientCounts.Dec(1)
  85. }
  86. }
  87. func StatsNewProxy(name string, proxyType string) {
  88. if config.ServerCommonCfg.DashboardPort != 0 {
  89. globalStats.mu.Lock()
  90. defer globalStats.mu.Unlock()
  91. counter, ok := globalStats.ProxyTypeCounts[proxyType]
  92. if !ok {
  93. counter = metric.NewCounter()
  94. }
  95. counter.Inc(1)
  96. globalStats.ProxyTypeCounts[proxyType] = counter
  97. proxyStats, ok := globalStats.ProxyStatistics[name]
  98. if !(ok && proxyStats.ProxyType == proxyType) {
  99. proxyStats = &ProxyStatistics{
  100. Name: name,
  101. ProxyType: proxyType,
  102. CurConns: metric.NewCounter(),
  103. TrafficIn: metric.NewDateCounter(ReserveDays),
  104. TrafficOut: metric.NewDateCounter(ReserveDays),
  105. }
  106. globalStats.ProxyStatistics[name] = proxyStats
  107. }
  108. proxyStats.LastStartTime = time.Now()
  109. }
  110. }
  111. func StatsCloseProxy(proxyName string, proxyType string) {
  112. if config.ServerCommonCfg.DashboardPort != 0 {
  113. globalStats.mu.Lock()
  114. defer globalStats.mu.Unlock()
  115. if counter, ok := globalStats.ProxyTypeCounts[proxyType]; ok {
  116. counter.Dec(1)
  117. }
  118. if proxyStats, ok := globalStats.ProxyStatistics[proxyName]; ok {
  119. proxyStats.LastCloseTime = time.Now()
  120. }
  121. }
  122. }
  123. func StatsOpenConnection(name string) {
  124. if config.ServerCommonCfg.DashboardPort != 0 {
  125. globalStats.CurConns.Inc(1)
  126. globalStats.mu.Lock()
  127. defer globalStats.mu.Unlock()
  128. proxyStats, ok := globalStats.ProxyStatistics[name]
  129. if ok {
  130. proxyStats.CurConns.Inc(1)
  131. globalStats.ProxyStatistics[name] = proxyStats
  132. }
  133. }
  134. }
  135. func StatsCloseConnection(name string) {
  136. if config.ServerCommonCfg.DashboardPort != 0 {
  137. globalStats.CurConns.Dec(1)
  138. globalStats.mu.Lock()
  139. defer globalStats.mu.Unlock()
  140. proxyStats, ok := globalStats.ProxyStatistics[name]
  141. if ok {
  142. proxyStats.CurConns.Dec(1)
  143. globalStats.ProxyStatistics[name] = proxyStats
  144. }
  145. }
  146. }
  147. func StatsAddTrafficIn(name string, trafficIn int64) {
  148. if config.ServerCommonCfg.DashboardPort != 0 {
  149. globalStats.TotalTrafficIn.Inc(trafficIn)
  150. globalStats.mu.Lock()
  151. defer globalStats.mu.Unlock()
  152. proxyStats, ok := globalStats.ProxyStatistics[name]
  153. if ok {
  154. proxyStats.TrafficIn.Inc(trafficIn)
  155. globalStats.ProxyStatistics[name] = proxyStats
  156. }
  157. }
  158. }
  159. func StatsAddTrafficOut(name string, trafficOut int64) {
  160. if config.ServerCommonCfg.DashboardPort != 0 {
  161. globalStats.TotalTrafficOut.Inc(trafficOut)
  162. globalStats.mu.Lock()
  163. defer globalStats.mu.Unlock()
  164. proxyStats, ok := globalStats.ProxyStatistics[name]
  165. if ok {
  166. proxyStats.TrafficOut.Inc(trafficOut)
  167. globalStats.ProxyStatistics[name] = proxyStats
  168. }
  169. }
  170. }
  171. // Functions for getting server stats.
  172. type ServerStats struct {
  173. TotalTrafficIn int64
  174. TotalTrafficOut int64
  175. CurConns int64
  176. ClientCounts int64
  177. ProxyTypeCounts map[string]int64
  178. }
  179. func StatsGetServer() *ServerStats {
  180. globalStats.mu.Lock()
  181. defer globalStats.mu.Unlock()
  182. s := &ServerStats{
  183. TotalTrafficIn: globalStats.TotalTrafficIn.TodayCount(),
  184. TotalTrafficOut: globalStats.TotalTrafficOut.TodayCount(),
  185. CurConns: globalStats.CurConns.Count(),
  186. ClientCounts: globalStats.ClientCounts.Count(),
  187. ProxyTypeCounts: make(map[string]int64),
  188. }
  189. for k, v := range globalStats.ProxyTypeCounts {
  190. s.ProxyTypeCounts[k] = v.Count()
  191. }
  192. return s
  193. }
  194. type ProxyStats struct {
  195. Name string
  196. Type string
  197. TodayTrafficIn int64
  198. TodayTrafficOut int64
  199. LastStartTime string
  200. LastCloseTime string
  201. CurConns int64
  202. }
  203. func StatsGetProxiesByType(proxyType string) []*ProxyStats {
  204. res := make([]*ProxyStats, 0)
  205. globalStats.mu.Lock()
  206. defer globalStats.mu.Unlock()
  207. for name, proxyStats := range globalStats.ProxyStatistics {
  208. if proxyStats.ProxyType != proxyType {
  209. continue
  210. }
  211. ps := &ProxyStats{
  212. Name: name,
  213. Type: proxyStats.ProxyType,
  214. TodayTrafficIn: proxyStats.TrafficIn.TodayCount(),
  215. TodayTrafficOut: proxyStats.TrafficOut.TodayCount(),
  216. CurConns: proxyStats.CurConns.Count(),
  217. }
  218. if !proxyStats.LastStartTime.IsZero() {
  219. ps.LastStartTime = proxyStats.LastStartTime.Format("01-02 15:04:05")
  220. }
  221. if !proxyStats.LastCloseTime.IsZero() {
  222. ps.LastCloseTime = proxyStats.LastCloseTime.Format("01-02 15:04:05")
  223. }
  224. res = append(res, ps)
  225. }
  226. return res
  227. }
  228. type ProxyTrafficInfo struct {
  229. Name string
  230. TrafficIn []int64
  231. TrafficOut []int64
  232. }
  233. func StatsGetProxyTraffic(name string) (res *ProxyTrafficInfo) {
  234. globalStats.mu.Lock()
  235. defer globalStats.mu.Unlock()
  236. proxyStats, ok := globalStats.ProxyStatistics[name]
  237. if ok {
  238. res = &ProxyTrafficInfo{
  239. Name: name,
  240. }
  241. res.TrafficIn = proxyStats.TrafficIn.GetLastDaysCount(ReserveDays)
  242. res.TrafficOut = proxyStats.TrafficOut.GetLastDaysCount(ReserveDays)
  243. }
  244. return
  245. }