github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/metric/emitter/prometheus_test.go (about)

     1  package emitter_test
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  
     8  	. "github.com/onsi/ginkgo"
     9  	. "github.com/onsi/gomega"
    10  
    11  	"code.cloudfoundry.org/lager/lagertest"
    12  	"github.com/prometheus/client_golang/prometheus"
    13  
    14  	"github.com/pf-qiu/concourse/v6/atc/metric"
    15  	"github.com/pf-qiu/concourse/v6/atc/metric/emitter"
    16  	"github.com/pf-qiu/concourse/v6/atc/metric/emitter/emitterfakes"
    17  )
    18  
    19  var _ = Describe("PrometheusEmitter garbage collector", func() {
    20  	var (
    21  		fake emitterfakes.FakePrometheusGarbageCollectable
    22  
    23  		labelsLong  prometheus.Labels
    24  		labelsShort prometheus.Labels
    25  
    26  		workerContainers *prometheus.GaugeVec
    27  		workerVolumes    *prometheus.GaugeVec
    28  		workerTasks      *prometheus.GaugeVec
    29  
    30  		workerContainersLabels map[string]map[string]prometheus.Labels
    31  		workerVolumesLabels    map[string]map[string]prometheus.Labels
    32  		workerTasksLabels      map[string]map[string]prometheus.Labels
    33  	)
    34  
    35  	BeforeEach(func() {
    36  		workerContainers = prometheus.NewGaugeVec(
    37  			prometheus.GaugeOpts{
    38  				Namespace: "concourse",
    39  				Subsystem: "workers",
    40  				Name:      "containers",
    41  				Help:      "Number of containers per worker",
    42  			},
    43  			[]string{"worker", "platform", "team", "tags"},
    44  		)
    45  		prometheus.Register(workerContainers)
    46  
    47  		workerVolumes = prometheus.NewGaugeVec(
    48  			prometheus.GaugeOpts{
    49  				Namespace: "concourse",
    50  				Subsystem: "workers",
    51  				Name:      "volumes",
    52  				Help:      "Number of volumes per worker",
    53  			},
    54  			[]string{"worker", "platform", "team", "tags"},
    55  		)
    56  		prometheus.Register(workerVolumes)
    57  
    58  		workerTasks = prometheus.NewGaugeVec(
    59  			prometheus.GaugeOpts{
    60  				Namespace: "concourse",
    61  				Subsystem: "workers",
    62  				Name:      "tasks",
    63  				Help:      "Number of active tasks per worker",
    64  			},
    65  			[]string{"worker", "platform"},
    66  		)
    67  		prometheus.Register(workerTasks)
    68  
    69  		workerContainersLabels = map[string]map[string]prometheus.Labels{}
    70  		workerVolumesLabels = map[string]map[string]prometheus.Labels{}
    71  		workerTasksLabels = map[string]map[string]prometheus.Labels{}
    72  
    73  		labelsLong = prometheus.Labels{
    74  			"worker":   "foo",
    75  			"platform": "linux",
    76  			"team":     "main",
    77  			"tags":     "",
    78  		}
    79  
    80  		labelsShort = prometheus.Labels{
    81  			"worker":   "foo",
    82  			"platform": "linux",
    83  		}
    84  	})
    85  	JustBeforeEach(func() {
    86  		fake = emitterfakes.FakePrometheusGarbageCollectable{
    87  			WorkerContainersStub: func() *prometheus.GaugeVec { return workerContainers },
    88  			WorkerVolumesStub:    func() *prometheus.GaugeVec { return workerVolumes },
    89  			WorkerTasksStub:      func() *prometheus.GaugeVec { return workerTasks },
    90  
    91  			WorkerContainersLabelsStub: func() map[string]map[string]prometheus.Labels {
    92  				return workerContainersLabels
    93  			},
    94  			WorkerVolumesLabelsStub: func() map[string]map[string]prometheus.Labels {
    95  				return workerVolumesLabels
    96  			},
    97  			WorkerTasksLabelsStub: func() map[string]map[string]prometheus.Labels {
    98  				return workerTasksLabels
    99  			},
   100  		}
   101  
   102  		// Deep copy the labels so we can use them to verify the test results later
   103  		labels := make(prometheus.Labels)
   104  		for k, v := range labelsLong {
   105  			labels[k] = v
   106  		}
   107  		fake.WorkerContainers().With(labels).Set(42.0)
   108  		fake.WorkerContainersLabels()["foo"] = make(map[string]prometheus.Labels)
   109  		fake.WorkerContainersLabels()["foo"]["foo_linux_main__"] = labels
   110  
   111  		fake.WorkerVolumes().With(labels).Set(42.0)
   112  		fake.WorkerVolumesLabels()["foo"] = make(map[string]prometheus.Labels)
   113  		fake.WorkerVolumesLabels()["foo"]["foo_linux_main__"] = labels
   114  
   115  		labels = make(prometheus.Labels)
   116  		for k, v := range labelsShort {
   117  			labels[k] = v
   118  		}
   119  		fake.WorkerTasks().With(labels).Set(42.0)
   120  		fake.WorkerTasksLabels()["foo"] = make(map[string]prometheus.Labels)
   121  		fake.WorkerTasksLabels()["foo"]["foo_linux"] = labels
   122  	})
   123  
   124  	It("should remove all metrics from the emitter", func() {
   125  		Expect(fake.WorkerContainersLabels()).To(HaveLen(1))
   126  		Expect(fake.WorkerVolumesLabels()).To(HaveLen(1))
   127  		Expect(fake.WorkerTasksLabels()).To(HaveLen(1))
   128  
   129  		emitter.DoGarbageCollection(&fake, "foo")
   130  
   131  		Expect(fake.WorkerContainersLabels()).To(HaveLen(0))
   132  		Expect(fake.WorkerVolumesLabels()).To(HaveLen(0))
   133  		Expect(fake.WorkerTasksLabels()).To(HaveLen(0))
   134  
   135  		// Delete should return false if the metrics no longer exist
   136  		Expect(fake.WorkerContainers().Delete(labelsLong)).To(Equal(false))
   137  		Expect(fake.WorkerVolumes().Delete(labelsLong)).To(Equal(false))
   138  		Expect(fake.WorkerTasks().Delete(labelsShort)).To(Equal(false))
   139  	})
   140  
   141  	// There is no easy way to detect whether metrics are REALLY garbage collected due to the
   142  	// limitations of the Prometheus client library, so here we verify that the metrics that were
   143  	// deleted in the previous spec were actually present from the beginning.
   144  	It("should not do anything if there are no metrics", func() {
   145  		// Delete should return true if the metrics are actually deleted
   146  		Expect(fake.WorkerContainers().Delete(labelsLong)).To(Equal(true))
   147  		Expect(fake.WorkerVolumes().Delete(labelsLong)).To(Equal(true))
   148  		Expect(fake.WorkerTasks().Delete(labelsShort)).To(Equal(true))
   149  
   150  		emitter.DoGarbageCollection(&fake, "foo")
   151  
   152  		// Delete should return false if the metrics no longer exist
   153  		Expect(fake.WorkerContainers().Delete(labelsLong)).To(Equal(false))
   154  		Expect(fake.WorkerVolumes().Delete(labelsLong)).To(Equal(false))
   155  		Expect(fake.WorkerTasks().Delete(labelsShort)).To(Equal(false))
   156  
   157  	})
   158  
   159  	AfterEach(func() {
   160  		workerContainers.Reset()
   161  		workerVolumes.Reset()
   162  		workerTasks.Reset()
   163  
   164  		workerContainersLabels = map[string]map[string]prometheus.Labels{}
   165  		workerVolumesLabels = map[string]map[string]prometheus.Labels{}
   166  		workerTasksLabels = map[string]map[string]prometheus.Labels{}
   167  
   168  		prometheus.Unregister(workerContainers)
   169  		prometheus.Unregister(workerVolumes)
   170  		prometheus.Unregister(workerTasks)
   171  	})
   172  })
   173  
   174  var _ = Describe("PrometheusEmitter", func() {
   175  	var (
   176  		prometheusConfig  *emitter.PrometheusConfig
   177  		prometheusEmitter metric.Emitter
   178  		logger            *lagertest.TestLogger
   179  		err               error
   180  	)
   181  
   182  	BeforeEach(func() {
   183  		logger = lagertest.NewTestLogger("test")
   184  		prometheusConfig = &emitter.PrometheusConfig{
   185  			BindIP:   "localhost",
   186  			BindPort: "9090",
   187  		}
   188  	})
   189  
   190  	JustBeforeEach(func() {
   191  		prometheusEmitter, err = prometheusConfig.NewEmitter()
   192  	})
   193  
   194  	It("emits task waiting metric", func() {
   195  		prometheusEmitter.Emit(logger, metric.Event{
   196  			Name:  "tasks waiting",
   197  			Value: 4,
   198  			Attributes: map[string]string{
   199  				"teamId":     "42",
   200  				"workerTags": "tester",
   201  				"platform":   "darwin",
   202  			},
   203  		})
   204  
   205  		res, _ := http.Get(fmt.Sprintf("http://%s:%s/metrics", prometheusConfig.BindIP, prometheusConfig.BindPort))
   206  		defer res.Body.Close()
   207  		body, _ := ioutil.ReadAll(res.Body)
   208  
   209  		Expect(res.StatusCode).To(Equal(http.StatusOK))
   210  		Expect(string(body)).To(ContainSubstring("concourse_tasks_waiting{platform=\"darwin\",teamId=\"42\",workerTags=\"tester\"} 4"))
   211  		Expect(err).To(BeNil())
   212  	})
   213  })