You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

168 lines
4.6 KiB

  1. // Copyright 2018, OpenCensus 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. // Command stats implements the stats Quick Start example from:
  15. // https://opencensus.io/quickstart/go/metrics/
  16. package main
  17. import (
  18. "bufio"
  19. "bytes"
  20. "context"
  21. "fmt"
  22. "io"
  23. "log"
  24. "os"
  25. "time"
  26. "net/http"
  27. "go.opencensus.io/exporter/prometheus"
  28. "go.opencensus.io/stats"
  29. "go.opencensus.io/stats/view"
  30. "go.opencensus.io/tag"
  31. "go.opencensus.io/zpages"
  32. )
  33. // Measures for the stats quickstart.
  34. var (
  35. // The latency in milliseconds
  36. mLatencyMs = stats.Float64("repl/latency", "The latency in milliseconds per REPL loop", stats.UnitMilliseconds)
  37. // Counts the number of lines read in from standard input
  38. mLinesIn = stats.Int64("repl/lines_in", "The number of lines read in", stats.UnitNone)
  39. // Encounters the number of non EOF(end-of-file) errors.
  40. mErrors = stats.Int64("repl/errors", "The number of errors encountered", stats.UnitNone)
  41. // Counts/groups the lengths of lines read in.
  42. mLineLengths = stats.Int64("repl/line_lengths", "The distribution of line lengths", stats.UnitBytes)
  43. )
  44. // TagKeys for the stats quickstart.
  45. var (
  46. keyMethod, _ = tag.NewKey("method")
  47. )
  48. // Views for the stats quickstart.
  49. var (
  50. latencyView = &view.View{
  51. Name: "demo/latency",
  52. Measure: mLatencyMs,
  53. Description: "The distribution of the latencies",
  54. // Latency in buckets:
  55. // [>=0ms, >=25ms, >=50ms, >=75ms, >=100ms, >=200ms, >=400ms, >=600ms, >=800ms, >=1s, >=2s, >=4s, >=6s]
  56. Aggregation: view.Distribution(25, 50, 75, 100, 200, 400, 600, 800, 1000, 2000, 4000, 6000),
  57. TagKeys: []tag.Key{keyMethod}}
  58. lineCountView = &view.View{
  59. Name: "demo/lines_in",
  60. Measure: mLinesIn,
  61. Description: "The number of lines from standard input",
  62. Aggregation: view.Count(),
  63. }
  64. errorCountView = &view.View{
  65. Name: "demo/errors",
  66. Measure: mErrors,
  67. Description: "The number of errors encountered",
  68. Aggregation: view.Count(),
  69. }
  70. lineLengthView = &view.View{
  71. Name: "demo/line_lengths",
  72. Description: "Groups the lengths of keys in buckets",
  73. Measure: mLineLengths,
  74. // Lengths: [>=0B, >=5B, >=10B, >=15B, >=20B, >=40B, >=60B, >=80, >=100B, >=200B, >=400, >=600, >=800, >=1000]
  75. Aggregation: view.Distribution(5, 2000, 15, 20, 40, 60, 80, 100, 200, 400, 600, 800, 1000),
  76. }
  77. )
  78. func main() {
  79. zpages.Handle(nil, "/debug")
  80. go http.ListenAndServe("localhost:8080", nil)
  81. // Create that Stackdriver stats exporter
  82. exporter, err := prometheus.NewExporter(prometheus.Options{})
  83. if err != nil {
  84. log.Fatalf("Failed to create the Stackdriver stats exporter: %v", err)
  85. }
  86. http.Handle("/metrics", exporter)
  87. // Register the stats exporter
  88. view.RegisterExporter(exporter)
  89. // Register the views
  90. if err := view.Register(latencyView, lineCountView, errorCountView, lineLengthView); err != nil {
  91. log.Fatalf("Failed to register views: %v", err)
  92. }
  93. // But also we can change the metrics reporting period to 2 seconds
  94. //view.SetReportingPeriod(2 * time.Second)
  95. // In a REPL:
  96. // 1. Read input
  97. // 2. process input
  98. br := bufio.NewReader(os.Stdin)
  99. // repl is the read, evaluate, print, loop
  100. for {
  101. if err := readEvaluateProcess(br); err != nil {
  102. if err == io.EOF {
  103. return
  104. }
  105. log.Fatal(err)
  106. }
  107. }
  108. }
  109. // readEvaluateProcess reads a line from the input reader and
  110. // then processes it. It returns an error if any was encountered.
  111. func readEvaluateProcess(br *bufio.Reader) error {
  112. ctx, err := tag.New(context.Background(), tag.Insert(keyMethod, "repl"))
  113. if err != nil {
  114. return err
  115. }
  116. fmt.Printf("> ")
  117. line, _, err := br.ReadLine()
  118. if err != nil {
  119. if err != io.EOF {
  120. stats.Record(ctx, mErrors.M(1))
  121. }
  122. return err
  123. }
  124. out, err := processLine(ctx, line)
  125. if err != nil {
  126. stats.Record(ctx, mErrors.M(1))
  127. return err
  128. }
  129. fmt.Printf("< %s\n\n", out)
  130. return nil
  131. }
  132. // processLine takes in a line of text and
  133. // transforms it. Currently it just capitalizes it.
  134. func processLine(ctx context.Context, in []byte) (out []byte, err error) {
  135. startTime := time.Now()
  136. defer func() {
  137. ms := float64(time.Since(startTime).Nanoseconds()) / 1e6
  138. stats.Record(ctx, mLinesIn.M(1), mLatencyMs.M(ms), mLineLengths.M(int64(len(in))))
  139. }()
  140. return bytes.ToUpper(in), nil
  141. }