Highly-opinionated (ex-bullshit-free) MTPROTO proxy for Telegram. If you use v1.0 or upgrade broke you proxy, please read the chapter Version 2
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. package stats
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. "github.com/9seconds/mtg/v2/events"
  7. "github.com/9seconds/mtg/v2/logger"
  8. "github.com/9seconds/mtg/v2/mtglib"
  9. statsd "github.com/smira/go-statsd"
  10. )
  11. type statsdProcessor struct {
  12. streams map[string]*streamInfo
  13. client *statsd.Client
  14. }
  15. func (s statsdProcessor) EventStart(evt mtglib.EventStart) {
  16. sInfo := &streamInfo{
  17. createdAt: evt.CreatedAt,
  18. clientIP: evt.RemoteIP,
  19. }
  20. s.streams[evt.StreamID()] = sInfo
  21. s.client.GaugeDelta(MetricClientConnections,
  22. 1,
  23. statsd.StringTag(TagIPType, sInfo.GetClientIPType()))
  24. }
  25. func (s statsdProcessor) EventConnectedToDC(evt mtglib.EventConnectedToDC) {
  26. sInfo, ok := s.streams[evt.StreamID()]
  27. if !ok {
  28. return
  29. }
  30. sInfo.remoteIP = evt.RemoteIP
  31. sInfo.dc = evt.DC
  32. s.client.GaugeDelta(MetricTelegramConnections,
  33. 1,
  34. statsd.StringTag(TagIPType, sInfo.GetRemoteIPType()),
  35. statsd.StringTag(TagTelegramIP, sInfo.remoteIP.String()),
  36. statsd.IntTag(TagDC, sInfo.dc))
  37. }
  38. func (s statsdProcessor) EventTraffic(evt mtglib.EventTraffic) {
  39. sInfo, ok := s.streams[evt.StreamID()]
  40. if !ok {
  41. return
  42. }
  43. tags := []statsd.Tag{
  44. statsd.StringTag(TagIPType, sInfo.GetRemoteIPType()),
  45. statsd.StringTag(TagTelegramIP, sInfo.remoteIP.String()),
  46. statsd.IntTag(TagDC, sInfo.dc),
  47. }
  48. if evt.IsRead {
  49. tags = append(tags, statsd.StringTag(TagDirection, TagDirectionClient))
  50. s.client.Incr(MetricTraffic, int64(evt.Traffic), tags...)
  51. } else {
  52. tags = append(tags, statsd.StringTag(TagDirection, TagDirectionTelegram))
  53. s.client.Incr(MetricTraffic, int64(evt.Traffic), tags...)
  54. }
  55. }
  56. func (s statsdProcessor) EventFinish(evt mtglib.EventFinish) {
  57. sInfo, ok := s.streams[evt.StreamID()]
  58. if !ok {
  59. return
  60. }
  61. defer delete(s.streams, evt.StreamID())
  62. s.client.GaugeDelta(MetricClientConnections,
  63. -1,
  64. statsd.StringTag(TagIPType, sInfo.GetClientIPType()))
  65. s.client.PrecisionTiming(MetricSessionDuration,
  66. evt.CreatedAt.Sub(sInfo.createdAt))
  67. if sInfo.remoteIP != nil {
  68. s.client.GaugeDelta(MetricTelegramConnections,
  69. -1,
  70. statsd.StringTag(TagIPType, sInfo.GetRemoteIPType()),
  71. statsd.StringTag(TagTelegramIP, sInfo.remoteIP.String()),
  72. statsd.IntTag(TagDC, sInfo.dc))
  73. }
  74. }
  75. func (s statsdProcessor) EventConcurrencyLimited(_ mtglib.EventConcurrencyLimited) {
  76. s.client.Incr(MetricConcurrencyLimited, 1)
  77. }
  78. func (s statsdProcessor) EventIPBlocklisted(evt mtglib.EventIPBlocklisted) {
  79. var tag statsd.Tag
  80. if evt.RemoteIP.To4() == nil {
  81. tag = statsd.StringTag(TagIPType, TagIPTypeIPv6)
  82. } else {
  83. tag = statsd.StringTag(TagIPType, TagIPTypeIPv4)
  84. }
  85. s.client.Incr(MetricIPBlocklisted, 1, tag)
  86. }
  87. func (s statsdProcessor) Shutdown() {
  88. now := time.Now()
  89. events := make([]mtglib.EventFinish, 0, len(s.streams))
  90. for k := range s.streams {
  91. events = append(events, mtglib.EventFinish{
  92. CreatedAt: now,
  93. ConnID: k,
  94. })
  95. }
  96. for i := range events {
  97. s.EventFinish(events[i])
  98. }
  99. }
  100. type StatsdFactory struct {
  101. client *statsd.Client
  102. }
  103. func (s StatsdFactory) Close() error {
  104. return s.client.Close()
  105. }
  106. func (s StatsdFactory) Make() events.Observer {
  107. return statsdProcessor{
  108. client: s.client,
  109. streams: make(map[string]*streamInfo),
  110. }
  111. }
  112. func NewStatsd(address string, log logger.StdLikeLogger,
  113. metricPrefix, tagFormat string) (StatsdFactory, error) {
  114. options := []statsd.Option{
  115. statsd.MetricPrefix(metricPrefix),
  116. statsd.Logger(log),
  117. }
  118. switch strings.ToLower(tagFormat) {
  119. case "datadog":
  120. options = append(options, statsd.TagStyle(statsd.TagFormatDatadog))
  121. case "influxdb":
  122. options = append(options, statsd.TagStyle(statsd.TagFormatInfluxDB))
  123. case "graphite":
  124. options = append(options, statsd.TagStyle(statsd.TagFormatGraphite))
  125. default:
  126. return StatsdFactory{}, fmt.Errorf("unknown tag format %s", tagFormat)
  127. }
  128. return StatsdFactory{
  129. client: statsd.NewClient(address, options...),
  130. }, nil
  131. }