prometheus.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package prometheus
  2. import (
  3. "context"
  4. "fmt"
  5. "net/http"
  6. "time"
  7. "github.com/prometheus/client_golang/prometheus"
  8. "github.com/prometheus/client_golang/prometheus/promhttp"
  9. log "github.com/sirupsen/logrus"
  10. "github.com/imgproxy/imgproxy/v3/config"
  11. "github.com/imgproxy/imgproxy/v3/reuseport"
  12. )
  13. var (
  14. enabled = false
  15. requestsTotal prometheus.Counter
  16. errorsTotal *prometheus.CounterVec
  17. requestDuration prometheus.Histogram
  18. downloadDuration prometheus.Histogram
  19. processingDuration prometheus.Histogram
  20. bufferSize *prometheus.HistogramVec
  21. bufferDefaultSize *prometheus.GaugeVec
  22. bufferMaxSize *prometheus.GaugeVec
  23. )
  24. func Init() {
  25. if len(config.PrometheusBind) == 0 {
  26. return
  27. }
  28. requestsTotal = prometheus.NewCounter(prometheus.CounterOpts{
  29. Namespace: config.PrometheusNamespace,
  30. Name: "requests_total",
  31. Help: "A counter of the total number of HTTP requests imgproxy processed.",
  32. })
  33. errorsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
  34. Namespace: config.PrometheusNamespace,
  35. Name: "errors_total",
  36. Help: "A counter of the occurred errors separated by type.",
  37. }, []string{"type"})
  38. requestDuration = prometheus.NewHistogram(prometheus.HistogramOpts{
  39. Namespace: config.PrometheusNamespace,
  40. Name: "request_duration_seconds",
  41. Help: "A histogram of the response latency.",
  42. })
  43. downloadDuration = prometheus.NewHistogram(prometheus.HistogramOpts{
  44. Namespace: config.PrometheusNamespace,
  45. Name: "download_duration_seconds",
  46. Help: "A histogram of the source image downloading latency.",
  47. })
  48. processingDuration = prometheus.NewHistogram(prometheus.HistogramOpts{
  49. Namespace: config.PrometheusNamespace,
  50. Name: "processing_duration_seconds",
  51. Help: "A histogram of the image processing latency.",
  52. })
  53. bufferSize = prometheus.NewHistogramVec(prometheus.HistogramOpts{
  54. Namespace: config.PrometheusNamespace,
  55. Name: "buffer_size_bytes",
  56. Help: "A histogram of the buffer size in bytes.",
  57. Buckets: prometheus.ExponentialBuckets(1024, 2, 14),
  58. }, []string{"type"})
  59. bufferDefaultSize = prometheus.NewGaugeVec(prometheus.GaugeOpts{
  60. Namespace: config.PrometheusNamespace,
  61. Name: "buffer_default_size_bytes",
  62. Help: "A gauge of the buffer default size in bytes.",
  63. }, []string{"type"})
  64. bufferMaxSize = prometheus.NewGaugeVec(prometheus.GaugeOpts{
  65. Namespace: config.PrometheusNamespace,
  66. Name: "buffer_max_size_bytes",
  67. Help: "A gauge of the buffer max size in bytes.",
  68. }, []string{"type"})
  69. prometheus.MustRegister(
  70. requestsTotal,
  71. errorsTotal,
  72. requestDuration,
  73. downloadDuration,
  74. processingDuration,
  75. bufferSize,
  76. bufferDefaultSize,
  77. bufferMaxSize,
  78. )
  79. enabled = true
  80. }
  81. func Enabled() bool {
  82. return enabled
  83. }
  84. func StartServer(cancel context.CancelFunc) error {
  85. if !enabled {
  86. return nil
  87. }
  88. s := http.Server{Handler: promhttp.Handler()}
  89. l, err := reuseport.Listen("tcp", config.PrometheusBind)
  90. if err != nil {
  91. return fmt.Errorf("Can't start Prometheus metrics server: %s", err)
  92. }
  93. go func() {
  94. log.Infof("Starting Prometheus server at %s", config.PrometheusBind)
  95. if err := s.Serve(l); err != nil && err != http.ErrServerClosed {
  96. log.Error(err)
  97. }
  98. cancel()
  99. }()
  100. return nil
  101. }
  102. func StartRequest() context.CancelFunc {
  103. if !enabled {
  104. return func() {}
  105. }
  106. requestsTotal.Inc()
  107. return startDuration(requestDuration)
  108. }
  109. func StartDownloadingSegment() context.CancelFunc {
  110. return startDuration(downloadDuration)
  111. }
  112. func StartProcessingSegment() context.CancelFunc {
  113. return startDuration(processingDuration)
  114. }
  115. func startDuration(m prometheus.Histogram) context.CancelFunc {
  116. if !enabled {
  117. return func() {}
  118. }
  119. t := time.Now()
  120. return func() {
  121. m.Observe(time.Since(t).Seconds())
  122. }
  123. }
  124. func IncrementErrorsTotal(t string) {
  125. if enabled {
  126. errorsTotal.With(prometheus.Labels{"type": t}).Inc()
  127. }
  128. }
  129. func ObserveBufferSize(t string, size int) {
  130. if enabled {
  131. bufferSize.With(prometheus.Labels{"type": t}).Observe(float64(size))
  132. }
  133. }
  134. func SetBufferDefaultSize(t string, size int) {
  135. if enabled {
  136. bufferDefaultSize.With(prometheus.Labels{"type": t}).Set(float64(size))
  137. }
  138. }
  139. func SetBufferMaxSize(t string, size int) {
  140. if enabled {
  141. bufferMaxSize.With(prometheus.Labels{"type": t}).Set(float64(size))
  142. }
  143. }
  144. func AddGaugeFunc(name, help string, f func() float64) {
  145. if !enabled {
  146. return
  147. }
  148. gauge := prometheus.NewGaugeFunc(prometheus.GaugeOpts{
  149. Namespace: config.PrometheusNamespace,
  150. Name: name,
  151. Help: help,
  152. }, f)
  153. prometheus.MustRegister(gauge)
  154. }