scraper.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package httpcheckreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver"
  4. import (
  5. "context"
  6. "errors"
  7. "net/http"
  8. "sync"
  9. "time"
  10. "go.opentelemetry.io/collector/component"
  11. "go.opentelemetry.io/collector/pdata/pcommon"
  12. "go.opentelemetry.io/collector/pdata/pmetric"
  13. "go.opentelemetry.io/collector/receiver"
  14. "go.uber.org/multierr"
  15. "go.uber.org/zap"
  16. "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver/internal/metadata"
  17. )
  18. var (
  19. errClientNotInit = errors.New("client not initialized")
  20. httpResponseClasses = map[string]int{"1xx": 1, "2xx": 2, "3xx": 3, "4xx": 4, "5xx": 5}
  21. )
  22. type httpcheckScraper struct {
  23. clients []*http.Client
  24. cfg *Config
  25. settings component.TelemetrySettings
  26. mb *metadata.MetricsBuilder
  27. }
  28. // start starts the scraper by creating a new HTTP Client on the scraper
  29. func (h *httpcheckScraper) start(_ context.Context, host component.Host) (err error) {
  30. for _, target := range h.cfg.Targets {
  31. client, clentErr := target.ToClient(host, h.settings)
  32. if clentErr != nil {
  33. err = multierr.Append(err, clentErr)
  34. }
  35. h.clients = append(h.clients, client)
  36. }
  37. return
  38. }
  39. // scrape connects to the endpoint and produces metrics based on the response
  40. func (h *httpcheckScraper) scrape(ctx context.Context) (pmetric.Metrics, error) {
  41. if h.clients == nil || len(h.clients) == 0 {
  42. return pmetric.NewMetrics(), errClientNotInit
  43. }
  44. var wg sync.WaitGroup
  45. wg.Add(len(h.clients))
  46. var mux sync.Mutex
  47. for idx, client := range h.clients {
  48. go func(targetClient *http.Client, targetIndex int) {
  49. defer wg.Done()
  50. now := pcommon.NewTimestampFromTime(time.Now())
  51. req, err := http.NewRequestWithContext(ctx, h.cfg.Targets[targetIndex].Method, h.cfg.Targets[targetIndex].Endpoint, http.NoBody)
  52. if err != nil {
  53. h.settings.Logger.Error("failed to create request", zap.Error(err))
  54. return
  55. }
  56. start := time.Now()
  57. resp, err := targetClient.Do(req)
  58. mux.Lock()
  59. h.mb.RecordHttpcheckDurationDataPoint(now, time.Since(start).Milliseconds(), h.cfg.Targets[targetIndex].Endpoint)
  60. statusCode := 0
  61. if err != nil {
  62. h.mb.RecordHttpcheckErrorDataPoint(now, int64(1), h.cfg.Targets[targetIndex].Endpoint, err.Error())
  63. } else {
  64. statusCode = resp.StatusCode
  65. }
  66. for class, intVal := range httpResponseClasses {
  67. if statusCode/100 == intVal {
  68. h.mb.RecordHttpcheckStatusDataPoint(now, int64(1), h.cfg.Targets[targetIndex].Endpoint, int64(statusCode), req.Method, class)
  69. } else {
  70. h.mb.RecordHttpcheckStatusDataPoint(now, int64(0), h.cfg.Targets[targetIndex].Endpoint, int64(statusCode), req.Method, class)
  71. }
  72. }
  73. mux.Unlock()
  74. }(client, idx)
  75. }
  76. wg.Wait()
  77. return h.mb.Emit(), nil
  78. }
  79. func newScraper(conf *Config, settings receiver.CreateSettings) *httpcheckScraper {
  80. return &httpcheckScraper{
  81. cfg: conf,
  82. settings: settings.TelemetrySettings,
  83. mb: metadata.NewMetricsBuilder(conf.MetricsBuilderConfig, settings),
  84. }
  85. }