statistic.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Copyright 2013 Beego Authors
  2. // Copyright 2014 The Macaron Authors
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  5. // not use this file except in compliance with the License. You may obtain
  6. // a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. // License for the specific language governing permissions and limitations
  14. // under the License.
  15. package toolbox
  16. import (
  17. "encoding/json"
  18. "fmt"
  19. "io"
  20. "strings"
  21. "sync"
  22. "time"
  23. )
  24. // Statistics struct
  25. type Statistics struct {
  26. RequestUrl string
  27. RequestNum int64
  28. MinTime time.Duration
  29. MaxTime time.Duration
  30. TotalTime time.Duration
  31. }
  32. // UrlMap contains several statistics struct to log different data
  33. type UrlMap struct {
  34. lock sync.RWMutex
  35. LengthLimit int // limit the urlmap's length if it's equal to 0 there's no limit
  36. urlmap map[string]map[string]*Statistics
  37. }
  38. // add statistics task.
  39. // it needs request method, request url and statistics time duration
  40. func (m *UrlMap) AddStatistics(requestMethod, requestUrl string, requesttime time.Duration) {
  41. m.lock.Lock()
  42. defer m.lock.Unlock()
  43. if method, ok := m.urlmap[requestUrl]; ok {
  44. if s, ok := method[requestMethod]; ok {
  45. s.RequestNum += 1
  46. if s.MaxTime < requesttime {
  47. s.MaxTime = requesttime
  48. }
  49. if s.MinTime > requesttime {
  50. s.MinTime = requesttime
  51. }
  52. s.TotalTime += requesttime
  53. } else {
  54. nb := &Statistics{
  55. RequestUrl: requestUrl,
  56. RequestNum: 1,
  57. MinTime: requesttime,
  58. MaxTime: requesttime,
  59. TotalTime: requesttime,
  60. }
  61. m.urlmap[requestUrl][requestMethod] = nb
  62. }
  63. } else {
  64. if m.LengthLimit > 0 && m.LengthLimit <= len(m.urlmap) {
  65. return
  66. }
  67. methodmap := make(map[string]*Statistics)
  68. nb := &Statistics{
  69. RequestUrl: requestUrl,
  70. RequestNum: 1,
  71. MinTime: requesttime,
  72. MaxTime: requesttime,
  73. TotalTime: requesttime,
  74. }
  75. methodmap[requestMethod] = nb
  76. m.urlmap[requestUrl] = methodmap
  77. }
  78. }
  79. // put url statistics result in io.Writer
  80. func (m *UrlMap) GetMap(w io.Writer) {
  81. m.lock.RLock()
  82. defer m.lock.RUnlock()
  83. sep := fmt.Sprintf("+%s+%s+%s+%s+%s+%s+%s+\n", strings.Repeat("-", 51), strings.Repeat("-", 12),
  84. strings.Repeat("-", 18), strings.Repeat("-", 18), strings.Repeat("-", 18), strings.Repeat("-", 18), strings.Repeat("-", 18))
  85. fmt.Fprintf(w, sep)
  86. fmt.Fprintf(w, "| % -50s| % -10s | % -16s | % -16s | % -16s | % -16s | % -16s |\n", "Request URL", "Method", "Times", "Total Used(s)", "Max Used(μs)", "Min Used(μs)", "Avg Used(μs)")
  87. fmt.Fprintf(w, sep)
  88. for k, v := range m.urlmap {
  89. for kk, vv := range v {
  90. fmt.Fprintf(w, "| % -50s| % -10s | % 16d | % 16f | % 16.6f | % 16.6f | % 16.6f |\n", k,
  91. kk, vv.RequestNum, vv.TotalTime.Seconds(), float64(vv.MaxTime.Nanoseconds())/1000,
  92. float64(vv.MinTime.Nanoseconds())/1000, float64(time.Duration(int64(vv.TotalTime)/vv.RequestNum).Nanoseconds())/1000,
  93. )
  94. }
  95. }
  96. fmt.Fprintf(w, sep)
  97. }
  98. type URLMapInfo struct {
  99. URL string `json:"url"`
  100. Method string `json:"method"`
  101. Times int64 `json:"times"`
  102. TotalUsed float64 `json:"total_used"`
  103. MaxUsed float64 `json:"max_used"`
  104. MinUsed float64 `json:"min_used"`
  105. AvgUsed float64 `json:"avg_used"`
  106. }
  107. func (m *UrlMap) JSON(w io.Writer) {
  108. infos := make([]*URLMapInfo, 0, len(m.urlmap))
  109. for k, v := range m.urlmap {
  110. for kk, vv := range v {
  111. infos = append(infos, &URLMapInfo{
  112. URL: k,
  113. Method: kk,
  114. Times: vv.RequestNum,
  115. TotalUsed: vv.TotalTime.Seconds(),
  116. MaxUsed: float64(vv.MaxTime.Nanoseconds()) / 1000,
  117. MinUsed: float64(vv.MinTime.Nanoseconds()) / 1000,
  118. AvgUsed: float64(time.Duration(int64(vv.TotalTime)/vv.RequestNum).Nanoseconds()) / 1000,
  119. })
  120. }
  121. }
  122. if err := json.NewEncoder(w).Encode(infos); err != nil {
  123. panic("URLMap.JSON: " + err.Error())
  124. }
  125. }