client.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package couchdbreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/couchdbreceiver"
  4. import (
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "net/http"
  9. "strconv"
  10. "go.opentelemetry.io/collector/component"
  11. "go.uber.org/zap"
  12. )
  13. // client defines the basic HTTP client interface.
  14. type client interface {
  15. Get(path string) ([]byte, error)
  16. GetStats(nodeName string) (map[string]any, error)
  17. }
  18. var _ client = (*couchDBClient)(nil)
  19. type couchDBClient struct {
  20. client *http.Client
  21. cfg *Config
  22. logger *zap.Logger
  23. }
  24. // newCouchDBClient creates a new client to make requests for the CouchDB receiver.
  25. func newCouchDBClient(cfg *Config, host component.Host, settings component.TelemetrySettings) (client, error) {
  26. client, err := cfg.ToClient(host, settings)
  27. if err != nil {
  28. return nil, fmt.Errorf("failed to create HTTP Client: %w", err)
  29. }
  30. return &couchDBClient{
  31. client: client,
  32. cfg: cfg,
  33. logger: settings.Logger,
  34. }, nil
  35. }
  36. // Get issues an authorized Get requests to the specified url.
  37. func (c *couchDBClient) Get(path string) ([]byte, error) {
  38. req, err := c.buildReq(path)
  39. if err != nil {
  40. return nil, err
  41. }
  42. resp, err := c.client.Do(req)
  43. if err != nil {
  44. return nil, err
  45. }
  46. defer func() {
  47. if err = resp.Body.Close(); err != nil {
  48. c.logger.Warn("failed to close response body", zap.Error(err))
  49. }
  50. }()
  51. if resp.StatusCode != http.StatusOK {
  52. if resp.StatusCode >= 400 {
  53. c.logger.Error("couchdb", zap.Error(err), zap.String("status_code", strconv.Itoa(resp.StatusCode)))
  54. }
  55. return nil, fmt.Errorf("request GET %s failed - %q", req.URL.String(), resp.Status)
  56. }
  57. body, err := io.ReadAll(resp.Body)
  58. if err != nil {
  59. return nil, fmt.Errorf("failed to read response body %w", err)
  60. }
  61. return body, nil
  62. }
  63. // GetStats gets couchdb stats at a specific node name endpoint.
  64. func (c *couchDBClient) GetStats(nodeName string) (map[string]any, error) {
  65. path := fmt.Sprintf("/_node/%s/_stats/couchdb", nodeName)
  66. body, err := c.Get(path)
  67. if err != nil {
  68. return nil, err
  69. }
  70. var stats map[string]any
  71. err = json.Unmarshal(body, &stats)
  72. if err != nil {
  73. return nil, err
  74. }
  75. return stats, nil
  76. }
  77. func (c *couchDBClient) buildReq(path string) (*http.Request, error) {
  78. url := c.cfg.Endpoint + path
  79. req, err := http.NewRequest(http.MethodGet, url, nil)
  80. if err != nil {
  81. return nil, err
  82. }
  83. req.Header.Set("Content-Type", "application/json")
  84. req.SetBasicAuth(c.cfg.Username, string(c.cfg.Password))
  85. return req, nil
  86. }