graphite_test.go 12 KB

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