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 символов.

prometheus.go 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. package stats
  2. import (
  3. "context"
  4. "net"
  5. "net/http"
  6. "strconv"
  7. "github.com/9seconds/mtg/v2/events"
  8. "github.com/9seconds/mtg/v2/mtglib"
  9. "github.com/prometheus/client_golang/prometheus"
  10. "github.com/prometheus/client_golang/prometheus/promhttp"
  11. )
  12. type prometheusProcessor struct {
  13. streams map[string]streamInfo
  14. factory *PrometheusFactory
  15. }
  16. func (p prometheusProcessor) EventStart(evt mtglib.EventStart) {
  17. info := acquireStreamInfo()
  18. if evt.RemoteIP.To4() != nil {
  19. info[TagIPFamily] = TagIPFamilyIPv4
  20. } else {
  21. info[TagIPFamily] = TagIPFamilyIPv6
  22. }
  23. p.streams[evt.StreamID()] = info
  24. p.factory.metricClientConnections.
  25. WithLabelValues(info[TagIPFamily]).
  26. Inc()
  27. }
  28. func (p prometheusProcessor) EventConnectedToDC(evt mtglib.EventConnectedToDC) {
  29. info, ok := p.streams[evt.StreamID()]
  30. if !ok {
  31. return
  32. }
  33. info[TagTelegramIP] = evt.RemoteIP.String()
  34. info[TagDC] = strconv.Itoa(evt.DC)
  35. p.factory.metricTelegramConnections.
  36. WithLabelValues(info[TagTelegramIP], info[TagDC]).
  37. Inc()
  38. }
  39. func (p prometheusProcessor) EventTraffic(evt mtglib.EventTraffic) {
  40. info, ok := p.streams[evt.StreamID()]
  41. if !ok {
  42. return
  43. }
  44. p.factory.metricTelegramTraffic.
  45. WithLabelValues(info[TagTelegramIP], info[TagDC], getDirection(evt.IsRead)).
  46. Add(float64(evt.Traffic))
  47. }
  48. func (p prometheusProcessor) EventFinish(evt mtglib.EventFinish) {
  49. info, ok := p.streams[evt.StreamID()]
  50. if !ok {
  51. return
  52. }
  53. defer func() {
  54. delete(p.streams, evt.StreamID())
  55. releaseStreamInfo(info)
  56. }()
  57. p.factory.metricClientConnections.
  58. WithLabelValues(info[TagIPFamily]).
  59. Dec()
  60. if telegramIP, ok := info[TagTelegramIP]; ok {
  61. p.factory.metricTelegramConnections.
  62. WithLabelValues(telegramIP, info[TagDC]).
  63. Dec()
  64. }
  65. }
  66. func (p prometheusProcessor) EventConcurrencyLimited(_ mtglib.EventConcurrencyLimited) {
  67. p.factory.metricConcurrencyLimited.Inc()
  68. }
  69. func (p prometheusProcessor) EventIPBlocklisted(evt mtglib.EventIPBlocklisted) {
  70. p.factory.metricIPBlocklisted.Inc()
  71. }
  72. func (p prometheusProcessor) Shutdown() {
  73. p.streams = make(map[string]streamInfo)
  74. }
  75. type PrometheusFactory struct {
  76. httpServer *http.Server
  77. metricClientConnections *prometheus.GaugeVec
  78. metricTelegramConnections *prometheus.GaugeVec
  79. metricDomainFrontingConnections *prometheus.GaugeVec
  80. metricTelegramTraffic *prometheus.CounterVec
  81. metricDomainFrontingTraffic *prometheus.CounterVec
  82. metricDomainFronting prometheus.Counter
  83. metricConcurrencyLimited prometheus.Counter
  84. metricIPBlocklisted prometheus.Counter
  85. metricReplayAttacks prometheus.Counter
  86. }
  87. func (p *PrometheusFactory) Make() events.Observer {
  88. return prometheusProcessor{
  89. streams: make(map[string]streamInfo),
  90. factory: p,
  91. }
  92. }
  93. func (p *PrometheusFactory) Serve(listener net.Listener) error {
  94. return p.httpServer.Serve(listener)
  95. }
  96. func (p *PrometheusFactory) Close() error {
  97. return p.httpServer.Shutdown(context.Background())
  98. }
  99. func NewPrometheus(metricPrefix, httpPath string) *PrometheusFactory { // nolint: funlen
  100. registry := prometheus.NewPedanticRegistry()
  101. httpHandler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{
  102. EnableOpenMetrics: true,
  103. })
  104. mux := http.NewServeMux()
  105. mux.Handle(httpPath, httpHandler)
  106. factory := &PrometheusFactory{
  107. httpServer: &http.Server{
  108. Handler: mux,
  109. },
  110. metricClientConnections: prometheus.NewGaugeVec(prometheus.GaugeOpts{
  111. Namespace: metricPrefix,
  112. Name: MetricClientConnections,
  113. Help: "A number of actively processing client connections.",
  114. }, []string{TagIPFamily}),
  115. metricTelegramConnections: prometheus.NewGaugeVec(prometheus.GaugeOpts{
  116. Namespace: metricPrefix,
  117. Name: MetricTelegramConnections,
  118. Help: "A number of connections to Telegram servers.",
  119. }, []string{TagTelegramIP, TagDC}),
  120. metricDomainFrontingConnections: prometheus.NewGaugeVec(prometheus.GaugeOpts{
  121. Namespace: metricPrefix,
  122. Name: MetricDomainFronting,
  123. Help: "A number of connections which talk with front domain.",
  124. }, []string{TagIPFamily}),
  125. metricTelegramTraffic: prometheus.NewCounterVec(prometheus.CounterOpts{
  126. Namespace: metricPrefix,
  127. Name: MetricTelegramTraffic,
  128. Help: "Traffic which is generated talking with Telegram servers.",
  129. }, []string{TagTelegramIP, TagDC, TagDirection}),
  130. metricDomainFrontingTraffic: prometheus.NewCounterVec(prometheus.CounterOpts{
  131. Namespace: metricPrefix,
  132. Name: MetricDomainFrontingTraffic,
  133. Help: "Traffic which is generated talking with front domain.",
  134. }, []string{TagDirection}),
  135. metricDomainFronting: prometheus.NewCounter(prometheus.CounterOpts{
  136. Namespace: metricPrefix,
  137. Name: MetricDomainFronting,
  138. Help: "A number of routings to front domain.",
  139. }),
  140. metricConcurrencyLimited: prometheus.NewCounter(prometheus.CounterOpts{
  141. Namespace: metricPrefix,
  142. Name: MetricConcurrencyLimited,
  143. Help: "A number of sessions that were rejected by concurrency limiter.",
  144. }),
  145. metricIPBlocklisted: prometheus.NewCounter(prometheus.CounterOpts{
  146. Namespace: metricPrefix,
  147. Name: MetricIPBlocklisted,
  148. Help: "A number of rejected sessions due to ip blocklisting.",
  149. }),
  150. metricReplayAttacks: prometheus.NewCounter(prometheus.CounterOpts{
  151. Namespace: metricPrefix,
  152. Name: MetricReplayAttacks,
  153. Help: "A number of detected replay attacks.",
  154. }),
  155. }
  156. registry.MustRegister(factory.metricClientConnections)
  157. registry.MustRegister(factory.metricTelegramConnections)
  158. registry.MustRegister(factory.metricDomainFrontingConnections)
  159. registry.MustRegister(factory.metricTelegramTraffic)
  160. registry.MustRegister(factory.metricDomainFrontingTraffic)
  161. registry.MustRegister(factory.metricDomainFronting)
  162. registry.MustRegister(factory.metricConcurrencyLimited)
  163. registry.MustRegister(factory.metricIPBlocklisted)
  164. registry.MustRegister(factory.metricReplayAttacks)
  165. return factory
  166. }