graphite_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. package graphitebridge
  2. import (
  3. "bufio"
  4. "bytes"
  5. "io"
  6. "net"
  7. "regexp"
  8. "testing"
  9. "time"
  10. "github.com/prometheus/client_golang/prometheus"
  11. dto "github.com/prometheus/client_model/go"
  12. "github.com/prometheus/common/model"
  13. )
  14. func TestCountersAsDelta(t *testing.T) {
  15. b, _ := NewBridge(&Config{
  16. URL: "localhost:12345",
  17. CountersAsDelta: true,
  18. })
  19. ty := dto.MetricType(0)
  20. mf := &dto.MetricFamily{
  21. Type: &ty,
  22. Metric: []*dto.Metric{},
  23. }
  24. m := model.Metric{}
  25. var want float64
  26. var got float64
  27. want = float64(1)
  28. got = b.replaceCounterWithDelta(mf, m, model.SampleValue(1))
  29. if got != want {
  30. t.Fatalf("want %v got %v", want, got)
  31. }
  32. got = b.replaceCounterWithDelta(mf, m, model.SampleValue(2))
  33. if got != want {
  34. t.Fatalf("want %v got %v", want, got)
  35. }
  36. }
  37. func TestCountersAsDeltaDisabled(t *testing.T) {
  38. b, _ := NewBridge(&Config{
  39. URL: "localhost:12345",
  40. CountersAsDelta: false,
  41. })
  42. ty := dto.MetricType(0)
  43. mf := &dto.MetricFamily{
  44. Type: &ty,
  45. Metric: []*dto.Metric{},
  46. }
  47. m := model.Metric{}
  48. var want float64
  49. var got float64
  50. want = float64(1)
  51. got = b.replaceCounterWithDelta(mf, m, model.SampleValue(1))
  52. if got != want {
  53. t.Fatalf("want %v got %v", want, got)
  54. }
  55. want = float64(2)
  56. got = b.replaceCounterWithDelta(mf, m, model.SampleValue(2))
  57. if got != want {
  58. t.Fatalf("want %v got %v", want, got)
  59. }
  60. }
  61. func TestSanitize(t *testing.T) {
  62. testCases := []struct {
  63. in, out string
  64. }{
  65. {in: "hello", out: "hello"},
  66. {in: "hE/l1o", out: "hE_l1o"},
  67. {in: "he,*ll(.o", out: "he_ll_o"},
  68. {in: "hello_there%^&", out: "hello_there_"},
  69. }
  70. var buf bytes.Buffer
  71. w := bufio.NewWriter(&buf)
  72. for i, tc := range testCases {
  73. if err := writeSanitized(w, tc.in); err != nil {
  74. t.Fatalf("write failed: %v", err)
  75. }
  76. if err := w.Flush(); err != nil {
  77. t.Fatalf("flush failed: %v", err)
  78. }
  79. if want, got := tc.out, buf.String(); want != got {
  80. t.Fatalf("test case index %d: got sanitized string %s, want %s", i, got, want)
  81. }
  82. buf.Reset()
  83. }
  84. }
  85. func TestWriteSummary(t *testing.T) {
  86. sumVec := prometheus.NewSummaryVec(
  87. prometheus.SummaryOpts{
  88. Name: "name",
  89. Help: "docstring",
  90. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  91. Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
  92. },
  93. []string{"labelname"},
  94. )
  95. reg := prometheus.NewRegistry()
  96. reg.MustRegister(sumVec)
  97. b, err := NewBridge(&Config{
  98. URL: "localhost:8080",
  99. Gatherer: reg,
  100. CountersAsDelta: true,
  101. })
  102. if err != nil {
  103. t.Fatalf("cannot create bridge. err: %v", err)
  104. }
  105. sumVec.WithLabelValues("val1").Observe(float64(10))
  106. sumVec.WithLabelValues("val1").Observe(float64(20))
  107. sumVec.WithLabelValues("val1").Observe(float64(30))
  108. sumVec.WithLabelValues("val2").Observe(float64(20))
  109. sumVec.WithLabelValues("val2").Observe(float64(30))
  110. sumVec.WithLabelValues("val2").Observe(float64(40))
  111. mfs, err := reg.Gather()
  112. if err != nil {
  113. t.Fatalf("error: %v", err)
  114. }
  115. now := model.Time(1477043083)
  116. var buf bytes.Buffer
  117. err = b.writeMetrics(&buf, mfs, "prefix", now)
  118. if err != nil {
  119. t.Fatalf("error: %v", err)
  120. }
  121. want := `prefix.name.constname.constvalue.labelname.val1.quantile.0_5 20 1477043
  122. prefix.name.constname.constvalue.labelname.val1.quantile.0_9 30 1477043
  123. prefix.name.constname.constvalue.labelname.val1.quantile.0_99 30 1477043
  124. prefix.name_sum.constname.constvalue.labelname.val1 60 1477043
  125. prefix.name_count.constname.constvalue.labelname.val1.count 3 1477043
  126. prefix.name.constname.constvalue.labelname.val2.quantile.0_5 30 1477043
  127. prefix.name.constname.constvalue.labelname.val2.quantile.0_9 40 1477043
  128. prefix.name.constname.constvalue.labelname.val2.quantile.0_99 40 1477043
  129. prefix.name_sum.constname.constvalue.labelname.val2 90 1477043
  130. prefix.name_count.constname.constvalue.labelname.val2.count 3 1477043
  131. `
  132. if got := buf.String(); want != got {
  133. t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
  134. }
  135. }
  136. func TestWriteHistogram(t *testing.T) {
  137. histVec := prometheus.NewHistogramVec(
  138. prometheus.HistogramOpts{
  139. Name: "name",
  140. Help: "docstring",
  141. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  142. Buckets: []float64{0.01, 0.02, 0.05, 0.1},
  143. },
  144. []string{"labelname"},
  145. )
  146. reg := prometheus.NewRegistry()
  147. reg.MustRegister(histVec)
  148. b, err := NewBridge(&Config{
  149. URL: "localhost:8080",
  150. Gatherer: reg,
  151. CountersAsDelta: true,
  152. })
  153. if err != nil {
  154. t.Fatalf("error creating bridge: %v", err)
  155. }
  156. histVec.WithLabelValues("val1").Observe(float64(10))
  157. histVec.WithLabelValues("val1").Observe(float64(20))
  158. histVec.WithLabelValues("val1").Observe(float64(30))
  159. histVec.WithLabelValues("val2").Observe(float64(20))
  160. histVec.WithLabelValues("val2").Observe(float64(30))
  161. histVec.WithLabelValues("val2").Observe(float64(40))
  162. mfs, err := reg.Gather()
  163. if err != nil {
  164. t.Fatalf("error: %v", err)
  165. }
  166. now := model.Time(1477043083)
  167. var buf bytes.Buffer
  168. err = b.writeMetrics(&buf, mfs, "prefix", now)
  169. if err != nil {
  170. t.Fatalf("error: %v", err)
  171. }
  172. want := `prefix.name_bucket.constname.constvalue.labelname.val1.le.0_01 0 1477043
  173. prefix.name_bucket.constname.constvalue.labelname.val1.le.0_02 0 1477043
  174. prefix.name_bucket.constname.constvalue.labelname.val1.le.0_05 0 1477043
  175. prefix.name_bucket.constname.constvalue.labelname.val1.le.0_1 0 1477043
  176. prefix.name_sum.constname.constvalue.labelname.val1.sum 60 1477043
  177. prefix.name_count.constname.constvalue.labelname.val1.count 3 1477043
  178. prefix.name_bucket.constname.constvalue.labelname.val1.le._Inf 3 1477043
  179. prefix.name_bucket.constname.constvalue.labelname.val2.le.0_01 0 1477043
  180. prefix.name_bucket.constname.constvalue.labelname.val2.le.0_02 0 1477043
  181. prefix.name_bucket.constname.constvalue.labelname.val2.le.0_05 0 1477043
  182. prefix.name_bucket.constname.constvalue.labelname.val2.le.0_1 0 1477043
  183. prefix.name_sum.constname.constvalue.labelname.val2.sum 90 1477043
  184. prefix.name_count.constname.constvalue.labelname.val2.count 3 1477043
  185. prefix.name_bucket.constname.constvalue.labelname.val2.le._Inf 3 1477043
  186. `
  187. if got := buf.String(); want != got {
  188. t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
  189. }
  190. }
  191. func TestCounterVec(t *testing.T) {
  192. cntVec := prometheus.NewCounterVec(
  193. prometheus.CounterOpts{
  194. Name: "page_response",
  195. Help: "docstring",
  196. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  197. },
  198. []string{"labelname"},
  199. )
  200. reg := prometheus.NewRegistry()
  201. reg.MustRegister(cntVec)
  202. cntVec.WithLabelValues("val1").Inc()
  203. cntVec.WithLabelValues("val2").Inc()
  204. b, err := NewBridge(&Config{
  205. URL: "localhost:8080",
  206. Gatherer: reg,
  207. CountersAsDelta: true,
  208. })
  209. if err != nil {
  210. t.Fatalf("error creating bridge: %v", err)
  211. }
  212. // first collect
  213. mfs, err := reg.Gather()
  214. if err != nil {
  215. t.Fatalf("error: %v", err)
  216. }
  217. var buf bytes.Buffer
  218. err = b.writeMetrics(&buf, mfs, "prefix", model.Time(1477043083))
  219. if err != nil {
  220. t.Fatalf("error: %v", err)
  221. }
  222. want := `prefix.page.response.constname.constvalue.labelname.val1.count 1 1477043
  223. prefix.page.response.constname.constvalue.labelname.val2.count 1 1477043
  224. `
  225. if got := buf.String(); want != got {
  226. t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
  227. }
  228. //next collect
  229. cntVec.WithLabelValues("val1").Inc()
  230. cntVec.WithLabelValues("val2").Inc()
  231. mfs, err = reg.Gather()
  232. if err != nil {
  233. t.Fatalf("error: %v", err)
  234. }
  235. buf = bytes.Buffer{}
  236. err = b.writeMetrics(&buf, mfs, "prefix", model.Time(1477053083))
  237. if err != nil {
  238. t.Fatalf("error: %v", err)
  239. }
  240. want2 := `prefix.page.response.constname.constvalue.labelname.val1.count 1 1477053
  241. prefix.page.response.constname.constvalue.labelname.val2.count 1 1477053
  242. `
  243. if got := buf.String(); want2 != got {
  244. t.Fatalf("wanted \n%s\n, got \n%s\n", want2, got)
  245. }
  246. }
  247. func TestCounter(t *testing.T) {
  248. cntVec := prometheus.NewCounter(
  249. prometheus.CounterOpts{
  250. Name: "page_response",
  251. Help: "docstring",
  252. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  253. })
  254. reg := prometheus.NewRegistry()
  255. reg.MustRegister(cntVec)
  256. cntVec.Inc()
  257. b, err := NewBridge(&Config{
  258. URL: "localhost:8080",
  259. Gatherer: reg,
  260. CountersAsDelta: true,
  261. })
  262. if err != nil {
  263. t.Fatalf("error creating bridge: %v", err)
  264. }
  265. // first collect
  266. mfs, err := reg.Gather()
  267. if err != nil {
  268. t.Fatalf("error: %v", err)
  269. }
  270. var buf bytes.Buffer
  271. err = b.writeMetrics(&buf, mfs, "prefix", model.Time(1477043083))
  272. if err != nil {
  273. t.Fatalf("error: %v", err)
  274. }
  275. want := "prefix.page.response.constname.constvalue.count 1 1477043\n"
  276. if got := buf.String(); want != got {
  277. t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
  278. }
  279. //next collect
  280. cntVec.Inc()
  281. mfs, err = reg.Gather()
  282. if err != nil {
  283. t.Fatalf("error: %v", err)
  284. }
  285. buf = bytes.Buffer{}
  286. err = b.writeMetrics(&buf, mfs, "prefix", model.Time(1477053083))
  287. if err != nil {
  288. t.Fatalf("error: %v", err)
  289. }
  290. want2 := "prefix.page.response.constname.constvalue.count 1 1477053\n"
  291. if got := buf.String(); want2 != got {
  292. t.Fatalf("wanted \n%s\n, got \n%s\n", want2, got)
  293. }
  294. }
  295. func TestCanIgnoreSomeMetrics(t *testing.T) {
  296. cntVec := prometheus.NewCounter(
  297. prometheus.CounterOpts{
  298. Name: "http_request_total",
  299. Help: "docstring",
  300. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  301. })
  302. reg := prometheus.NewRegistry()
  303. reg.MustRegister(cntVec)
  304. cntVec.Inc()
  305. b, err := NewBridge(&Config{
  306. URL: "localhost:8080",
  307. Gatherer: reg,
  308. CountersAsDelta: true,
  309. })
  310. if err != nil {
  311. t.Fatalf("error creating bridge: %v", err)
  312. }
  313. // first collect
  314. mfs, err := reg.Gather()
  315. if err != nil {
  316. t.Fatalf("error: %v", err)
  317. }
  318. var buf bytes.Buffer
  319. err = b.writeMetrics(&buf, mfs, "prefix", model.Time(1477043083))
  320. if err != nil {
  321. t.Fatalf("error: %v", err)
  322. }
  323. want := ""
  324. if got := buf.String(); want != got {
  325. t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
  326. }
  327. }
  328. func TestPush(t *testing.T) {
  329. reg := prometheus.NewRegistry()
  330. cntVec := prometheus.NewCounterVec(
  331. prometheus.CounterOpts{
  332. Name: "name",
  333. Help: "docstring",
  334. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  335. },
  336. []string{"labelname"},
  337. )
  338. cntVec.WithLabelValues("val1").Inc()
  339. cntVec.WithLabelValues("val2").Inc()
  340. reg.MustRegister(cntVec)
  341. host := "localhost"
  342. port := ":56789"
  343. b, err := NewBridge(&Config{
  344. URL: host + port,
  345. Gatherer: reg,
  346. Prefix: "prefix",
  347. })
  348. if err != nil {
  349. t.Fatalf("error creating bridge: %v", err)
  350. }
  351. nmg, err := newMockGraphite(port)
  352. if err != nil {
  353. t.Fatalf("error creating mock graphite: %v", err)
  354. }
  355. defer nmg.Close()
  356. err = b.Push()
  357. if err != nil {
  358. t.Fatalf("error pushing: %v", err)
  359. }
  360. wants := []string{
  361. "prefix.name.constname.constvalue.labelname.val1.count 1",
  362. "prefix.name.constname.constvalue.labelname.val2.count 1",
  363. }
  364. select {
  365. case got := <-nmg.readc:
  366. for _, want := range wants {
  367. matched, err := regexp.MatchString(want, got)
  368. if err != nil {
  369. t.Fatalf("error pushing: %v", err)
  370. }
  371. if !matched {
  372. t.Fatalf("missing metric:\nno match for %s received by server:\n%s", want, got)
  373. }
  374. }
  375. return
  376. case err := <-nmg.errc:
  377. t.Fatalf("error reading push: %v", err)
  378. case <-time.After(50 * time.Millisecond):
  379. t.Fatalf("no result from graphite server")
  380. }
  381. }
  382. func newMockGraphite(port string) (*mockGraphite, error) {
  383. readc := make(chan string)
  384. errc := make(chan error)
  385. ln, err := net.Listen("tcp", port)
  386. if err != nil {
  387. return nil, err
  388. }
  389. go func() {
  390. conn, err := ln.Accept()
  391. if err != nil {
  392. errc <- err
  393. }
  394. var b bytes.Buffer
  395. io.Copy(&b, conn)
  396. readc <- b.String()
  397. }()
  398. return &mockGraphite{
  399. readc: readc,
  400. errc: errc,
  401. Listener: ln,
  402. }, nil
  403. }
  404. type mockGraphite struct {
  405. readc chan string
  406. errc chan error
  407. net.Listener
  408. }