main.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // Copyright 2018 The etcd Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package main
  15. import (
  16. "flag"
  17. "fmt"
  18. "io/ioutil"
  19. "net/url"
  20. "os"
  21. "os/exec"
  22. "path/filepath"
  23. "time"
  24. "go.etcd.io/etcd/embed"
  25. "go.uber.org/zap"
  26. )
  27. var lg *zap.Logger
  28. func init() {
  29. var err error
  30. lg, err = zap.NewProduction()
  31. if err != nil {
  32. panic(err)
  33. }
  34. }
  35. func main() {
  36. addr := flag.String("addr", "", "etcd metrics URL to fetch from (empty to use current git branch)")
  37. downloadVer := flag.String("download-ver", "", "etcd binary version to download and fetch metrics from")
  38. debug := flag.Bool("debug", false, "true to enable debug logging")
  39. flag.Parse()
  40. if *addr != "" && *downloadVer != "" {
  41. panic("specify either 'addr' or 'download-ver'")
  42. }
  43. if *debug {
  44. lg = zap.NewExample()
  45. }
  46. ep := *addr
  47. if ep == "" {
  48. if *downloadVer != "" {
  49. ver := *downloadVer
  50. // download release binary to temporary directory
  51. d, err := ioutil.TempDir(os.TempDir(), ver)
  52. if err != nil {
  53. panic(err)
  54. }
  55. defer os.RemoveAll(d)
  56. var bp string
  57. bp, err = install(ver, d)
  58. if err != nil {
  59. panic(err)
  60. }
  61. // set up 2-node cluster locally
  62. ep = "http://localhost:2379/metrics"
  63. cluster := "s1=http://localhost:2380,s2=http://localhost:22380"
  64. d1 := filepath.Join(d, "s1")
  65. d2 := filepath.Join(d, "s2")
  66. os.RemoveAll(d1)
  67. os.RemoveAll(d2)
  68. type run struct {
  69. err error
  70. cmd *exec.Cmd
  71. }
  72. rc := make(chan run)
  73. cs1 := getCommand(bp, "s1", d1, "http://localhost:2379", "http://localhost:2380", cluster)
  74. cmd1 := exec.Command("bash", "-c", cs1)
  75. go func() {
  76. if *debug {
  77. cmd1.Stderr = os.Stderr
  78. }
  79. if cerr := cmd1.Start(); cerr != nil {
  80. lg.Warn("failed to start first process", zap.Error(cerr))
  81. rc <- run{err: cerr}
  82. return
  83. }
  84. lg.Debug("started first process")
  85. rc <- run{cmd: cmd1}
  86. }()
  87. cs2 := getCommand(bp, "s2", d2, "http://localhost:22379", "http://localhost:22380", cluster)
  88. cmd2 := exec.Command("bash", "-c", cs2)
  89. go func() {
  90. if *debug {
  91. cmd2.Stderr = os.Stderr
  92. }
  93. if cerr := cmd2.Start(); cerr != nil {
  94. lg.Warn("failed to start second process", zap.Error(cerr))
  95. rc <- run{err: cerr}
  96. return
  97. }
  98. lg.Debug("started second process")
  99. rc <- run{cmd: cmd2}
  100. }()
  101. rc1 := <-rc
  102. if rc1.err != nil {
  103. panic(rc1.err)
  104. }
  105. rc2 := <-rc
  106. if rc2.err != nil {
  107. panic(rc2.err)
  108. }
  109. defer func() {
  110. lg.Debug("killing processes")
  111. rc1.cmd.Process.Kill()
  112. rc2.cmd.Process.Kill()
  113. rc1.cmd.Wait()
  114. rc2.cmd.Wait()
  115. lg.Debug("killed processes")
  116. }()
  117. // give enough time for peer-to-peer metrics
  118. lg.Debug("waiting")
  119. time.Sleep(7 * time.Second)
  120. lg.Debug("started 2-node etcd cluster")
  121. } else {
  122. // fetch metrics from embedded etcd
  123. uss := newEmbedURLs(4)
  124. ep = uss[0].String() + "/metrics"
  125. cfgs := []*embed.Config{embed.NewConfig(), embed.NewConfig()}
  126. cfgs[0].Name, cfgs[1].Name = "0", "1"
  127. setupEmbedCfg(cfgs[0], []url.URL{uss[0]}, []url.URL{uss[1]}, []url.URL{uss[1], uss[3]})
  128. setupEmbedCfg(cfgs[1], []url.URL{uss[2]}, []url.URL{uss[3]}, []url.URL{uss[1], uss[3]})
  129. type embedAndError struct {
  130. ec *embed.Etcd
  131. err error
  132. }
  133. ech := make(chan embedAndError)
  134. for _, cfg := range cfgs {
  135. go func(c *embed.Config) {
  136. e, err := embed.StartEtcd(c)
  137. if err != nil {
  138. ech <- embedAndError{err: err}
  139. return
  140. }
  141. <-e.Server.ReadyNotify()
  142. ech <- embedAndError{ec: e}
  143. }(cfg)
  144. }
  145. for range cfgs {
  146. ev := <-ech
  147. if ev.err != nil {
  148. lg.Panic("failed to start embedded etcd", zap.Error(ev.err))
  149. }
  150. defer ev.ec.Close()
  151. }
  152. // give enough time for peer-to-peer metrics
  153. lg.Debug("waiting")
  154. time.Sleep(7 * time.Second)
  155. lg.Debug("started 2-node embedded etcd cluster")
  156. }
  157. }
  158. // send client requests to populate gRPC client-side metrics
  159. // TODO: enable default metrics initialization in v3.1 and v3.2
  160. write(ep)
  161. lg.Debug("fetching metrics", zap.String("endpoint", ep))
  162. fmt.Println(getMetrics(ep))
  163. }