graphite_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  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 TestSanitizePrefix(t *testing.T) {
  86. testCases := []struct {
  87. in, out string
  88. }{
  89. {in: "service.prod.", out: "service.prod."},
  90. {in: "service.prod", out: "service.prod"},
  91. }
  92. var buf bytes.Buffer
  93. w := bufio.NewWriter(&buf)
  94. for i, tc := range testCases {
  95. if err := writePrefix(w, tc.in); err != nil {
  96. t.Fatalf("write failed: %v", err)
  97. }
  98. if err := w.Flush(); err != nil {
  99. t.Fatalf("flush failed: %v", err)
  100. }
  101. if want, got := tc.out, buf.String(); want != got {
  102. t.Fatalf("test case index %d: got sanitized string %s, want %s", i, got, want)
  103. }
  104. buf.Reset()
  105. }
  106. }
  107. func TestWriteSummary(t *testing.T) {
  108. sumVec := prometheus.NewSummaryVec(
  109. prometheus.SummaryOpts{
  110. Name: "name",
  111. Help: "docstring",
  112. Namespace: "grafana",
  113. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  114. Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
  115. },
  116. []string{"labelname"},
  117. )
  118. reg := prometheus.NewRegistry()
  119. reg.MustRegister(sumVec)
  120. b, err := NewBridge(&Config{
  121. URL: "localhost:8080",
  122. Gatherer: reg,
  123. CountersAsDelta: true,
  124. })
  125. if err != nil {
  126. t.Fatalf("cannot create bridge. err: %v", err)
  127. }
  128. sumVec.WithLabelValues("val1").Observe(float64(10))
  129. sumVec.WithLabelValues("val1").Observe(float64(20))
  130. sumVec.WithLabelValues("val1").Observe(float64(30))
  131. sumVec.WithLabelValues("val2").Observe(float64(20))
  132. sumVec.WithLabelValues("val2").Observe(float64(30))
  133. sumVec.WithLabelValues("val2").Observe(float64(40))
  134. mfs, err := reg.Gather()
  135. if err != nil {
  136. t.Fatalf("error: %v", err)
  137. }
  138. now := model.Time(1477043083)
  139. var buf bytes.Buffer
  140. err = b.writeMetrics(&buf, mfs, "prefix.", now)
  141. if err != nil {
  142. t.Fatalf("error: %v", err)
  143. }
  144. want := `prefix.name.constname.constvalue.labelname.val1.quantile.0_5 20 1477043
  145. prefix.name.constname.constvalue.labelname.val1.quantile.0_9 30 1477043
  146. prefix.name.constname.constvalue.labelname.val1.quantile.0_99 30 1477043
  147. prefix.name_sum.constname.constvalue.labelname.val1 60 1477043
  148. prefix.name_count.constname.constvalue.labelname.val1.count 3 1477043
  149. prefix.name.constname.constvalue.labelname.val2.quantile.0_5 30 1477043
  150. prefix.name.constname.constvalue.labelname.val2.quantile.0_9 40 1477043
  151. prefix.name.constname.constvalue.labelname.val2.quantile.0_99 40 1477043
  152. prefix.name_sum.constname.constvalue.labelname.val2 90 1477043
  153. prefix.name_count.constname.constvalue.labelname.val2.count 3 1477043
  154. `
  155. if got := buf.String(); want != got {
  156. t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
  157. }
  158. }
  159. func TestWriteHistogram(t *testing.T) {
  160. histVec := prometheus.NewHistogramVec(
  161. prometheus.HistogramOpts{
  162. Name: "name",
  163. Help: "docstring",
  164. Namespace: "grafana",
  165. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  166. Buckets: []float64{0.01, 0.02, 0.05, 0.1},
  167. },
  168. []string{"labelname"},
  169. )
  170. reg := prometheus.NewRegistry()
  171. reg.MustRegister(histVec)
  172. b, err := NewBridge(&Config{
  173. URL: "localhost:8080",
  174. Gatherer: reg,
  175. CountersAsDelta: true,
  176. })
  177. if err != nil {
  178. t.Fatalf("error creating bridge: %v", err)
  179. }
  180. histVec.WithLabelValues("val1").Observe(float64(10))
  181. histVec.WithLabelValues("val1").Observe(float64(20))
  182. histVec.WithLabelValues("val1").Observe(float64(30))
  183. histVec.WithLabelValues("val2").Observe(float64(20))
  184. histVec.WithLabelValues("val2").Observe(float64(30))
  185. histVec.WithLabelValues("val2").Observe(float64(40))
  186. mfs, err := reg.Gather()
  187. if err != nil {
  188. t.Fatalf("error: %v", err)
  189. }
  190. now := model.Time(1477043083)
  191. var buf bytes.Buffer
  192. err = b.writeMetrics(&buf, mfs, "prefix.", now)
  193. if err != nil {
  194. t.Fatalf("error: %v", err)
  195. }
  196. want := `prefix.name_bucket.constname.constvalue.labelname.val1.le.0_01 0 1477043
  197. prefix.name_bucket.constname.constvalue.labelname.val1.le.0_02 0 1477043
  198. prefix.name_bucket.constname.constvalue.labelname.val1.le.0_05 0 1477043
  199. prefix.name_bucket.constname.constvalue.labelname.val1.le.0_1 0 1477043
  200. prefix.name_sum.constname.constvalue.labelname.val1.sum 60 1477043
  201. prefix.name_count.constname.constvalue.labelname.val1.count 3 1477043
  202. prefix.name_bucket.constname.constvalue.labelname.val1.le._Inf 3 1477043
  203. prefix.name_bucket.constname.constvalue.labelname.val2.le.0_01 0 1477043
  204. prefix.name_bucket.constname.constvalue.labelname.val2.le.0_02 0 1477043
  205. prefix.name_bucket.constname.constvalue.labelname.val2.le.0_05 0 1477043
  206. prefix.name_bucket.constname.constvalue.labelname.val2.le.0_1 0 1477043
  207. prefix.name_sum.constname.constvalue.labelname.val2.sum 90 1477043
  208. prefix.name_count.constname.constvalue.labelname.val2.count 3 1477043
  209. prefix.name_bucket.constname.constvalue.labelname.val2.le._Inf 3 1477043
  210. `
  211. if got := buf.String(); want != got {
  212. t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
  213. }
  214. }
  215. func TestCounterVec(t *testing.T) {
  216. cntVec := prometheus.NewCounterVec(
  217. prometheus.CounterOpts{
  218. Name: "page_response",
  219. Namespace: "grafana",
  220. Help: "docstring",
  221. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  222. },
  223. []string{"labelname"},
  224. )
  225. apicntVec := prometheus.NewCounterVec(
  226. prometheus.CounterOpts{
  227. Name: "api_response",
  228. Namespace: "grafana",
  229. Help: "docstring",
  230. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  231. },
  232. []string{"labelname"},
  233. )
  234. reg := prometheus.NewRegistry()
  235. reg.MustRegister(cntVec)
  236. reg.MustRegister(apicntVec)
  237. cntVec.WithLabelValues("val1").Inc()
  238. cntVec.WithLabelValues("val2").Inc()
  239. apicntVec.WithLabelValues("val1").Inc()
  240. apicntVec.WithLabelValues("val2").Inc()
  241. b, err := NewBridge(&Config{
  242. URL: "localhost:8080",
  243. Gatherer: reg,
  244. CountersAsDelta: true,
  245. })
  246. if err != nil {
  247. t.Fatalf("error creating bridge: %v", err)
  248. }
  249. // first collect
  250. mfs, err := reg.Gather()
  251. if err != nil {
  252. t.Fatalf("error: %v", err)
  253. }
  254. var buf bytes.Buffer
  255. err = b.writeMetrics(&buf, mfs, "prefix.", model.Time(1477043083))
  256. if err != nil {
  257. t.Fatalf("error: %v", err)
  258. }
  259. want := `prefix.api.response.constname.constvalue.labelname.val1.count 1 1477043
  260. prefix.api.response.constname.constvalue.labelname.val2.count 1 1477043
  261. prefix.page.response.constname.constvalue.labelname.val1.count 1 1477043
  262. prefix.page.response.constname.constvalue.labelname.val2.count 1 1477043
  263. `
  264. if got := buf.String(); want != got {
  265. t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
  266. }
  267. //next collect
  268. cntVec.WithLabelValues("val1").Inc()
  269. cntVec.WithLabelValues("val2").Inc()
  270. apicntVec.WithLabelValues("val1").Inc()
  271. apicntVec.WithLabelValues("val2").Inc()
  272. mfs, err = reg.Gather()
  273. if err != nil {
  274. t.Fatalf("error: %v", err)
  275. }
  276. buf = bytes.Buffer{}
  277. err = b.writeMetrics(&buf, mfs, "prefix.", model.Time(1477053083))
  278. if err != nil {
  279. t.Fatalf("error: %v", err)
  280. }
  281. want2 := `prefix.api.response.constname.constvalue.labelname.val1.count 1 1477053
  282. prefix.api.response.constname.constvalue.labelname.val2.count 1 1477053
  283. prefix.page.response.constname.constvalue.labelname.val1.count 1 1477053
  284. prefix.page.response.constname.constvalue.labelname.val2.count 1 1477053
  285. `
  286. if got := buf.String(); want2 != got {
  287. t.Fatalf("wanted \n%s\n, got \n%s\n", want2, got)
  288. }
  289. }
  290. func TestCounter(t *testing.T) {
  291. cntVec := prometheus.NewCounter(
  292. prometheus.CounterOpts{
  293. Name: "page_response",
  294. Help: "docstring",
  295. Namespace: "grafana",
  296. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  297. })
  298. reg := prometheus.NewRegistry()
  299. reg.MustRegister(cntVec)
  300. cntVec.Inc()
  301. b, err := NewBridge(&Config{
  302. URL: "localhost:8080",
  303. Gatherer: reg,
  304. CountersAsDelta: true,
  305. })
  306. if err != nil {
  307. t.Fatalf("error creating bridge: %v", err)
  308. }
  309. // first collect
  310. mfs, err := reg.Gather()
  311. if err != nil {
  312. t.Fatalf("error: %v", err)
  313. }
  314. var buf bytes.Buffer
  315. err = b.writeMetrics(&buf, mfs, "prefix.", model.Time(1477043083))
  316. if err != nil {
  317. t.Fatalf("error: %v", err)
  318. }
  319. want := "prefix.page.response.constname.constvalue.count 1 1477043\n"
  320. if got := buf.String(); want != got {
  321. t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
  322. }
  323. //next collect
  324. cntVec.Inc()
  325. mfs, err = reg.Gather()
  326. if err != nil {
  327. t.Fatalf("error: %v", err)
  328. }
  329. buf = bytes.Buffer{}
  330. err = b.writeMetrics(&buf, mfs, "prefix.", model.Time(1477053083))
  331. if err != nil {
  332. t.Fatalf("error: %v", err)
  333. }
  334. want2 := "prefix.page.response.constname.constvalue.count 1 1477053\n"
  335. if got := buf.String(); want2 != got {
  336. t.Fatalf("wanted \n%s\n, got \n%s\n", want2, got)
  337. }
  338. }
  339. func TestTrimGrafanaNamespace(t *testing.T) {
  340. cntVec := prometheus.NewCounter(
  341. prometheus.CounterOpts{
  342. Name: "http_request_total",
  343. Help: "docstring",
  344. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  345. })
  346. reg := prometheus.NewRegistry()
  347. reg.MustRegister(cntVec)
  348. cntVec.Inc()
  349. b, err := NewBridge(&Config{
  350. URL: "localhost:8080",
  351. Gatherer: reg,
  352. CountersAsDelta: true,
  353. })
  354. if err != nil {
  355. t.Fatalf("error creating bridge: %v", err)
  356. }
  357. // first collect
  358. mfs, err := reg.Gather()
  359. if err != nil {
  360. t.Fatalf("error: %v", err)
  361. }
  362. var buf bytes.Buffer
  363. err = b.writeMetrics(&buf, mfs, "prefix.", model.Time(1477043083))
  364. if err != nil {
  365. t.Fatalf("error: %v", err)
  366. }
  367. want := "prefix.http_request_total.constname.constvalue.count 1 1477043\n"
  368. if got := buf.String(); want != got {
  369. t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
  370. }
  371. }
  372. func TestSkipNanValues(t *testing.T) {
  373. cntVec := prometheus.NewSummary(
  374. prometheus.SummaryOpts{
  375. Name: "http_request_total",
  376. Help: "docstring",
  377. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  378. })
  379. reg := prometheus.NewRegistry()
  380. reg.MustRegister(cntVec)
  381. b, err := NewBridge(&Config{
  382. URL: "localhost:8080",
  383. Gatherer: reg,
  384. CountersAsDelta: true,
  385. })
  386. if err != nil {
  387. t.Fatalf("error creating bridge: %v", err)
  388. }
  389. // first collect
  390. mfs, err := reg.Gather()
  391. if err != nil {
  392. t.Fatalf("error: %v", err)
  393. }
  394. var buf bytes.Buffer
  395. err = b.writeMetrics(&buf, mfs, "prefix.", model.Time(1477043083))
  396. if err != nil {
  397. t.Fatalf("error: %v", err)
  398. }
  399. want := `prefix.http_request_total_sum.constname.constvalue 0 1477043
  400. prefix.http_request_total_count.constname.constvalue.count 0 1477043
  401. `
  402. if got := buf.String(); want != got {
  403. t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
  404. }
  405. }
  406. func TestPush(t *testing.T) {
  407. reg := prometheus.NewRegistry()
  408. cntVec := prometheus.NewCounterVec(
  409. prometheus.CounterOpts{
  410. Name: "name",
  411. Help: "docstring",
  412. Namespace: "grafana",
  413. ConstLabels: prometheus.Labels{"constname": "constvalue"},
  414. },
  415. []string{"labelname"},
  416. )
  417. cntVec.WithLabelValues("val1").Inc()
  418. cntVec.WithLabelValues("val2").Inc()
  419. reg.MustRegister(cntVec)
  420. host := "localhost"
  421. port := ":56789"
  422. b, err := NewBridge(&Config{
  423. URL: host + port,
  424. Gatherer: reg,
  425. Prefix: "prefix.",
  426. })
  427. if err != nil {
  428. t.Fatalf("error creating bridge: %v", err)
  429. }
  430. nmg, err := newMockGraphite(port)
  431. if err != nil {
  432. t.Fatalf("error creating mock graphite: %v", err)
  433. }
  434. defer nmg.Close()
  435. err = b.Push()
  436. if err != nil {
  437. t.Fatalf("error pushing: %v", err)
  438. }
  439. wants := []string{
  440. "prefix.name.constname.constvalue.labelname.val1.count 1",
  441. "prefix.name.constname.constvalue.labelname.val2.count 1",
  442. }
  443. select {
  444. case got := <-nmg.readc:
  445. for _, want := range wants {
  446. matched, err := regexp.MatchString(want, got)
  447. if err != nil {
  448. t.Fatalf("error pushing: %v", err)
  449. }
  450. if !matched {
  451. t.Fatalf("missing metric:\nno match for %s received by server:\n%s", want, got)
  452. }
  453. }
  454. return
  455. case err := <-nmg.errc:
  456. t.Fatalf("error reading push: %v", err)
  457. case <-time.After(50 * time.Millisecond):
  458. t.Fatalf("no result from graphite server")
  459. }
  460. }
  461. func newMockGraphite(port string) (*mockGraphite, error) {
  462. readc := make(chan string)
  463. errc := make(chan error)
  464. ln, err := net.Listen("tcp", port)
  465. if err != nil {
  466. return nil, err
  467. }
  468. go func() {
  469. conn, err := ln.Accept()
  470. if err != nil {
  471. errc <- err
  472. }
  473. var b bytes.Buffer
  474. io.Copy(&b, conn)
  475. readc <- b.String()
  476. }()
  477. return &mockGraphite{
  478. readc: readc,
  479. errc: errc,
  480. Listener: ln,
  481. }, nil
  482. }
  483. type mockGraphite struct {
  484. readc chan string
  485. errc chan error
  486. net.Listener
  487. }