mod_stat_sec.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // package mod_stat_sec -- статистика модуля за первые 60 сек
  2. package mod_stat_sec
  3. import (
  4. "bytes"
  5. "fmt"
  6. "math"
  7. // "strings"
  8. "sync"
  9. "time"
  10. "github.com/ajstarks/svgo"
  11. )
  12. // ModStatSec -- статистика модуля за первые 60 сек
  13. type ModStatSec struct {
  14. sync.RWMutex
  15. lst []int // Список значений за последние 60 сек
  16. momentAt int64 // Метка времени для учёта текущей секунды
  17. bufSvg *bytes.Buffer
  18. }
  19. // NewModStatSec -- возвращает новую статистику модуля за последние 60 сек
  20. func NewModStatSec() *ModStatSec {
  21. sf := &ModStatSec{
  22. lst: []int{},
  23. bufSvg: bytes.NewBufferString(""),
  24. momentAt: time.Now().Local().Unix(),
  25. }
  26. return sf
  27. }
  28. // Sum -- возвращает сумму элементов по требованию
  29. func (sf *ModStatSec) Sum() int {
  30. sf.RLock()
  31. defer sf.RUnlock()
  32. sum := 0
  33. for _, val := range sf.lst {
  34. sum += val
  35. }
  36. return sum
  37. }
  38. // Add -- добавляет значение в минутный срез
  39. func (sf *ModStatSec) Add(val int) {
  40. sf.Lock()
  41. defer sf.Unlock()
  42. for len(sf.lst) < 60 {
  43. sf.lst = append(sf.lst, 0)
  44. }
  45. momentNow := time.Now().Local().Unix()
  46. isSameSec := momentNow == sf.momentAt
  47. switch isSameSec {
  48. case true:
  49. _val := sf.lst[59]
  50. _val += val
  51. sf.lst[59] = _val
  52. default:
  53. sf.momentAt = momentNow
  54. sf.lst = append(sf.lst, val)
  55. if len(sf.lst) > 60 {
  56. sf.lst = sf.lst[1:]
  57. }
  58. }
  59. }
  60. // const (
  61. // strCut = `<?xml version="1.0"?>
  62. // <!-- Generated by SVGo -->`
  63. // )
  64. // Svg -- возвращает сгенерированный SVG по минутному срезу
  65. func (sf *ModStatSec) Svg() string {
  66. sf.Lock()
  67. defer sf.Unlock()
  68. sf.bufSvg.Reset()
  69. cnv := svg.New(sf.bufSvg)
  70. cnv.Start(480, 320)
  71. cnv.Title("Last 60 sec")
  72. cnv.Desc("Graphic of last 60 sec")
  73. // cnv.Text(20, 20, "Last 60 sec", "text-anchor:middle;font-size:14px;fill:white")
  74. cnv.Text(20, 20, "Last 60 sec", "")
  75. // cnv.Circle(250, 250, 125, "fill:none;stroke:black")
  76. var (
  77. valMin = math.MaxInt64
  78. valMax = math.MinInt64
  79. )
  80. fnGetMinMax := func() { // Вычисляет максимальное и минимальное значение в графике
  81. for _, val := range sf.lst {
  82. if val < valMin {
  83. valMin = val
  84. }
  85. if val > valMax {
  86. valMax = val
  87. }
  88. }
  89. }
  90. fnGetMinMax()
  91. for i, val := range sf.lst {
  92. x1 := int(float32(i)*6) + 42
  93. y1 := int(240 * float32(valMax) / float32(val))
  94. cnv.Rect(x1, 280-y1, 5, y1, "fill:true;stroke:red;")
  95. }
  96. fnDrawNet := func() {
  97. // Метки величины
  98. if valMin == math.MaxInt64 {
  99. valMin = 0
  100. }
  101. if valMax == math.MinInt64 {
  102. valMax = 1
  103. }
  104. cnv.Text(25, 285, fmt.Sprint(valMin), "")
  105. cnv.Text(25, 45, fmt.Sprint(valMax), "")
  106. // Метки времени
  107. timeNow := time.Now().Local()
  108. timeSub60 := timeNow.Add(-60 * time.Second).Format("05")
  109. cnv.Text(40, 295, timeSub60, "")
  110. timeSub45 := timeNow.Add(-45 * time.Second).Format("05")
  111. cnv.Text(128, 295, timeSub45, "")
  112. timeSub30 := timeNow.Add(-30 * time.Second).Format("05")
  113. cnv.Text(216, 295, timeSub30, "")
  114. timeSub15 := timeNow.Add(-15 * time.Second).Format("05")
  115. cnv.Text(304, 295, timeSub15, "")
  116. timeSub0 := time.Now().Format("05")
  117. cnv.Text(392, 295, timeSub0, "")
  118. cnv.Line(40, 280, 40, 38, "fill:true;stroke:black;stroke-width:4")
  119. cnv.Line(40, 280, 442, 280, "fill:true;stroke:black;stroke-width:4")
  120. count := 0
  121. for x := 40; x < 460; x += 20 {
  122. cnv.Line(x, 40, x, 280, "fill:true;stroke:gray")
  123. if count%5 == 0 {
  124. cnv.Text(x+3, 278, fmt.Sprint(x), "fill:white;stroke:gray")
  125. }
  126. count++
  127. }
  128. count = 0
  129. for y := 40; y < 300; y += 20 {
  130. cnv.Line(40, y, 440, y, "fill:true;stroke:gray")
  131. if count%5 == 0 {
  132. cnv.Text(43, y+12, fmt.Sprint(y), "fill:white;stroke:gray")
  133. }
  134. count++
  135. }
  136. }
  137. fnDrawNet()
  138. cnv.End()
  139. strOut := sf.bufSvg.String()
  140. // strOut = strings.ReplaceAll(strOut, strCut, "")
  141. return strOut
  142. }