end_to_end_test.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package prometheusexporter
  4. import (
  5. "bytes"
  6. "context"
  7. "fmt"
  8. "io"
  9. "net/http"
  10. "net/http/httptest"
  11. "net/url"
  12. "regexp"
  13. "sync"
  14. "testing"
  15. "time"
  16. promconfig "github.com/prometheus/prometheus/config"
  17. "github.com/stretchr/testify/require"
  18. "go.opentelemetry.io/collector/config/confighttp"
  19. "go.opentelemetry.io/collector/exporter/exportertest"
  20. "go.opentelemetry.io/collector/receiver/receivertest"
  21. "gopkg.in/yaml.v2"
  22. "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver"
  23. )
  24. func TestEndToEndSummarySupport(t *testing.T) {
  25. if testing.Short() {
  26. t.Skip("This test can take a couple of seconds")
  27. }
  28. // 1. Create the Prometheus scrape endpoint.
  29. var wg sync.WaitGroup
  30. var currentScrapeIndex = 0
  31. wg.Add(1) // scrape one endpoint
  32. dropWizardServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
  33. // Serve back the metrics as if they were from DropWizard.
  34. _, err := rw.Write([]byte(dropWizardResponse))
  35. require.NoError(t, err)
  36. currentScrapeIndex++
  37. if currentScrapeIndex == 8 { // We shall let the Prometheus receiver scrape the DropWizard mock server, at least 8 times.
  38. wg.Done() // done scraping dropWizardResponse 8 times
  39. }
  40. }))
  41. defer dropWizardServer.Close()
  42. srvURL, err := url.Parse(dropWizardServer.URL)
  43. if err != nil {
  44. t.Fatal(err)
  45. }
  46. ctx, cancel := context.WithCancel(context.Background())
  47. defer cancel()
  48. // 2. Create the Prometheus metrics exporter that'll receive and verify the metrics produced.
  49. exporterCfg := &Config{
  50. Namespace: "test",
  51. HTTPServerSettings: confighttp.HTTPServerSettings{
  52. Endpoint: "localhost:8787",
  53. },
  54. SendTimestamps: true,
  55. MetricExpiration: 2 * time.Hour,
  56. }
  57. exporterFactory := NewFactory()
  58. set := exportertest.NewNopCreateSettings()
  59. exporter, err := exporterFactory.CreateMetricsExporter(ctx, set, exporterCfg)
  60. if err != nil {
  61. t.Fatal(err)
  62. }
  63. if err = exporter.Start(ctx, nil); err != nil {
  64. t.Fatalf("Failed to start the Prometheus exporter: %v", err)
  65. }
  66. t.Cleanup(func() { require.NoError(t, exporter.Shutdown(ctx)) })
  67. // 3. Create the Prometheus receiver scraping from the DropWizard mock server and
  68. // it'll feed scraped and converted metrics then pass them to the Prometheus exporter.
  69. yamlConfig := []byte(fmt.Sprintf(`
  70. global:
  71. scrape_interval: 2ms
  72. scrape_configs:
  73. - job_name: 'otel-collector'
  74. scrape_interval: 50ms
  75. scrape_timeout: 50ms
  76. static_configs:
  77. - targets: ['%s']
  78. `, srvURL.Host))
  79. receiverConfig := new(promconfig.Config)
  80. if err = yaml.Unmarshal(yamlConfig, receiverConfig); err != nil {
  81. t.Fatal(err)
  82. }
  83. receiverFactory := prometheusreceiver.NewFactory()
  84. receiverCreateSet := receivertest.NewNopCreateSettings()
  85. rcvCfg := &prometheusreceiver.Config{
  86. PrometheusConfig: receiverConfig,
  87. }
  88. // 3.5 Create the Prometheus receiver and pass in the previously created Prometheus exporter.
  89. prometheusReceiver, err := receiverFactory.CreateMetricsReceiver(ctx, receiverCreateSet, rcvCfg, exporter)
  90. if err != nil {
  91. t.Fatal(err)
  92. }
  93. if err = prometheusReceiver.Start(ctx, nil); err != nil {
  94. t.Fatalf("Failed to start the Prometheus receiver: %v", err)
  95. }
  96. t.Cleanup(func() { require.NoError(t, prometheusReceiver.Shutdown(ctx)) })
  97. // 4. Scrape from the Prometheus receiver to ensure that we export summary metrics
  98. wg.Wait()
  99. res, err := http.Get("http://" + exporterCfg.Endpoint + "/metrics")
  100. if err != nil {
  101. t.Fatalf("Failed to scrape from the exporter: %v", err)
  102. }
  103. prometheusExporterScrape, err := io.ReadAll(res.Body)
  104. res.Body.Close()
  105. if err != nil {
  106. t.Fatal(err)
  107. }
  108. // 5. Verify that we have the summary metrics and that their values make sense.
  109. wantLineRegexps := []string{
  110. `. HELP test_jvm_gc_collection_seconds Time spent in a given JVM garbage collector in seconds.`,
  111. `. TYPE test_jvm_gc_collection_seconds summary`,
  112. `test_jvm_gc_collection_seconds_sum.gc="G1 Old Generation",instance="127.0.0.1:.*",job="otel-collector". 0.*`,
  113. `test_jvm_gc_collection_seconds_count.gc="G1 Old Generation",instance="127.0.0.1:.*",job="otel-collector". 0.*`,
  114. `test_jvm_gc_collection_seconds_sum.gc="G1 Young Generation",instance="127.0.0.1:.*",job="otel-collector". 0.*`,
  115. `test_jvm_gc_collection_seconds_count.gc="G1 Young Generation",instance="127.0.0.1:.*",job="otel-collector". 9.*`,
  116. `. HELP test_jvm_info JVM version info`,
  117. `. TYPE test_jvm_info gauge`,
  118. `test_jvm_info.instance="127.0.0.1:.*",job="otel-collector",vendor="Oracle Corporation",version="9.0.4.11". 1.*`,
  119. `. HELP test_jvm_memory_pool_bytes_used Used bytes of a given JVM memory pool.`,
  120. `. TYPE test_jvm_memory_pool_bytes_used gauge`,
  121. `test_jvm_memory_pool_bytes_used.instance="127.0.0.1:.*",job="otel-collector",pool="CodeHeap 'non.nmethods'". 1.277952e.06.*`,
  122. `test_jvm_memory_pool_bytes_used.instance="127.0.0.1:.*",job="otel-collector",pool="CodeHeap 'non.profiled nmethods'". 2.869376e.06.*`,
  123. `test_jvm_memory_pool_bytes_used.instance="127.0.0.1:.*",job="otel-collector",pool="CodeHeap 'profiled nmethods'". 6.871168e.06.*`,
  124. `test_jvm_memory_pool_bytes_used.instance="127.0.0.1:.*",job="otel-collector",pool="Compressed Class Space". 2.751312e.06.*`,
  125. `test_jvm_memory_pool_bytes_used.instance="127.0.0.1:.*",job="otel-collector",pool="G1 Eden Space". 4.4040192e.07.*`,
  126. `test_jvm_memory_pool_bytes_used.instance="127.0.0.1:.*",job="otel-collector",pool="G1 Old Gen". 4.385408e.06.*`,
  127. `test_jvm_memory_pool_bytes_used.instance="127.0.0.1:.*",job="otel-collector",pool="G1 Survivor Space". 8.388608e.06.*`,
  128. `test_jvm_memory_pool_bytes_used.instance="127.0.0.1:.*",job="otel-collector",pool="Metaspace". 2.6218176e.07.*`,
  129. `. HELP test_scrape_duration_seconds Duration of the scrape`,
  130. `. TYPE test_scrape_duration_seconds gauge`,
  131. `test_scrape_duration_seconds.instance="127.0.0.1:.*",job="otel-collector". [0-9.e-]+ [0-9]+`,
  132. `. HELP test_scrape_samples_post_metric_relabeling The number of samples remaining after metric relabeling was applied`,
  133. `. TYPE test_scrape_samples_post_metric_relabeling gauge`,
  134. `test_scrape_samples_post_metric_relabeling.instance="127.0.0.1:.*",job="otel-collector". 13 .*`,
  135. `. HELP test_scrape_samples_scraped The number of samples the target exposed`,
  136. `. TYPE test_scrape_samples_scraped gauge`,
  137. `test_scrape_samples_scraped.instance="127.0.0.1:.*",job="otel-collector". 13 .*`,
  138. `. HELP test_scrape_series_added The approximate number of new series in this scrape`,
  139. `. TYPE test_scrape_series_added gauge`,
  140. `test_scrape_series_added.instance="127.0.0.1:.*",job="otel-collector". 13 .*`,
  141. `. HELP test_up The scraping was successful`,
  142. `. TYPE test_up gauge`,
  143. `test_up.instance="127.0.0.1:.*",job="otel-collector". 1 .*`,
  144. `. HELP test_target_info Target metadata`,
  145. `. TYPE test_target_info gauge`,
  146. `test_target_info.http_scheme="http",instance="127.0.0.1:.*",job="otel-collector",net_host_port=".*". 1`,
  147. }
  148. // 5.5: Perform a complete line by line prefix verification to ensure we extract back the inputs
  149. // we'd expect after scraping Prometheus.
  150. for _, wantLineRegexp := range wantLineRegexps {
  151. reg := regexp.MustCompile(wantLineRegexp)
  152. prometheusExporterScrape = reg.ReplaceAll(prometheusExporterScrape, []byte(""))
  153. }
  154. // After this replacement, there should ONLY be newlines present.
  155. prometheusExporterScrape = bytes.ReplaceAll(prometheusExporterScrape, []byte("\n"), []byte(""))
  156. // Now assert that NO output was left over.
  157. if len(prometheusExporterScrape) != 0 {
  158. t.Fatalf("Left-over unmatched Prometheus scrape content: %q\n", prometheusExporterScrape)
  159. }
  160. }
  161. // the following triggers G101: Potential hardcoded credentials
  162. // nolint:gosec
  163. const dropWizardResponse = `
  164. # HELP jvm_memory_pool_bytes_used Used bytes of a given JVM memory pool.
  165. # TYPE jvm_memory_pool_bytes_used gauge
  166. jvm_memory_pool_bytes_used{pool="CodeHeap 'non-nmethods'",} 1277952.0
  167. jvm_memory_pool_bytes_used{pool="Metaspace",} 2.6218176E7
  168. jvm_memory_pool_bytes_used{pool="CodeHeap 'profiled nmethods'",} 6871168.0
  169. jvm_memory_pool_bytes_used{pool="Compressed Class Space",} 2751312.0
  170. jvm_memory_pool_bytes_used{pool="G1 Eden Space",} 4.4040192E7
  171. jvm_memory_pool_bytes_used{pool="G1 Old Gen",} 4385408.0
  172. jvm_memory_pool_bytes_used{pool="G1 Survivor Space",} 8388608.0
  173. jvm_memory_pool_bytes_used{pool="CodeHeap 'non-profiled nmethods'",} 2869376.0
  174. # HELP jvm_info JVM version info
  175. # TYPE jvm_info gauge
  176. jvm_info{version="9.0.4+11",vendor="Oracle Corporation",} 1.0
  177. # HELP jvm_gc_collection_seconds Time spent in a given JVM garbage collector in seconds.
  178. # TYPE jvm_gc_collection_seconds summary
  179. jvm_gc_collection_seconds_count{gc="G1 Young Generation",} 9.0
  180. jvm_gc_collection_seconds_sum{gc="G1 Young Generation",} 0.229
  181. jvm_gc_collection_seconds_count{gc="G1 Old Generation",} 0.0
  182. jvm_gc_collection_seconds_sum{gc="G1 Old Generation",} 0.0`