diff --git a/content/quickstart/go/metrics.md b/content/quickstart/go/metrics.md index 0c689e7e..de0dc288 100644 --- a/content/quickstart/go/metrics.md +++ b/content/quickstart/go/metrics.md @@ -80,7 +80,7 @@ touch repl.go Next, put the following code inside of `repl.go`: -{{}} +```go package main import ( @@ -111,7 +111,7 @@ func main() { // readEvaluateProcess reads a line from the input reader and // then processes it. It returns an error if any was encountered. -func readEvaluateProcess(br *bufio.Reader) error { +func readEvaluateProcess(br *bufio.Reader) (terr error) { fmt.Printf("> ") line, _, err := br.ReadLine() if err != nil { @@ -131,7 +131,8 @@ func readEvaluateProcess(br *bufio.Reader) error { func processLine(in []byte) (out []byte, err error) { return bytes.ToUpper(in), nil } -{{}} + +``` You can run the code via `go run repl.go`. @@ -142,8 +143,8 @@ You can run the code via `go run repl.go`. To enable metrics, we’ll import a couple of packages: -{{}} -{{}} +{{% tabs Snippet All %}} +```go import ( "bufio" "bytes" @@ -157,9 +158,9 @@ import ( "go.opencensus.io/stats" "go.opencensus.io/tag" ) -{{}} +``` -{{}} +```go package main import ( @@ -195,7 +196,7 @@ func main() { // readEvaluateProcess reads a line from the input reader and // then processes it. It returns an error if any was encountered. -func readEvaluateProcess(br *bufio.Reader) error { +func readEvaluateProcess(br *bufio.Reader) (terr error) { fmt.Printf("> ") line, _, err := br.ReadLine() if err != nil { @@ -215,29 +216,26 @@ func readEvaluateProcess(br *bufio.Reader) error { func processLine(in []byte) (out []byte, err error) { return bytes.ToUpper(in), nil } -{{}} -{{}} +``` +{{% /tabs %}} ### Create Metrics First, we will create the variables needed to later record our metrics. -{{}} -{{}} +{{% tabs Snippet All %}} +```go var ( // The latency in milliseconds MLatencyMs = stats.Float64("repl/latency", "The latency in milliseconds per REPL loop", "ms") - // Encounters the number of non EOF(end-of-file) errors. - MErrors = stats.Int64("repl/errors", "The number of errors encountered", "1") - // Counts/groups the lengths of lines read in. MLineLengths = stats.Int64("repl/line_lengths", "The distribution of line lengths", "By") ) -{{}} +``` -{{}} +```go package main import ( @@ -258,9 +256,6 @@ var ( // The latency in milliseconds MLatencyMs = stats.Float64("repl/latency", "The latency in milliseconds per REPL loop", "ms") - // Encounters the number of non EOF(end-of-file) errors. - MErrors = stats.Int64("repl/errors", "The number of errors encountered", "1") - // Counts/groups the lengths of lines read in. MLineLengths = stats.Int64("repl/line_lengths", "The distribution of line lengths", "By") ) @@ -284,7 +279,7 @@ func main() { // readEvaluateProcess reads a line from the input reader and // then processes it. It returns an error if any was encountered. -func readEvaluateProcess(br *bufio.Reader) error { +func readEvaluateProcess(br *bufio.Reader) (terr error) { fmt.Printf("> ") line, _, err := br.ReadLine() if err != nil { @@ -304,21 +299,23 @@ func readEvaluateProcess(br *bufio.Reader) error { func processLine(in []byte) (out []byte, err error) { return bytes.ToUpper(in), nil } -{{}} -{{}} +``` +{{% /tabs %}} ### Create Tags Now we will create the variable later needed to add extra text meta-data to our metrics. -{{}} -{{}} +{{% tabs Snippet All %}} +```go var ( KeyMethod, _ = tag.NewKey("method") + KeyStatus, _ = tag.NewKey("status") + KeyError, _ = tag.NewKey("error") ) -{{}} +``` -{{}} +```go package main import ( @@ -339,15 +336,14 @@ var ( // The latency in milliseconds MLatencyMs = stats.Float64("repl/latency", "The latency in milliseconds per REPL loop", "ms") - // Encounters the number of non EOF(end-of-file) errors. - MErrors = stats.Int64("repl/errors", "The number of errors encountered", "1") - // Counts/groups the lengths of lines read in. MLineLengths = stats.Int64("repl/line_lengths", "The distribution of line lengths", "By") ) var ( KeyMethod, _ = tag.NewKey("method") + KeyStatus, _ = tag.NewKey("status") + KeyError, _ = tag.NewKey("error") ) func main() { @@ -369,7 +365,7 @@ func main() { // readEvaluateProcess reads a line from the input reader and // then processes it. It returns an error if any was encountered. -func readEvaluateProcess(br *bufio.Reader) error { +func readEvaluateProcess(br *bufio.Reader) (terr error) { fmt.Printf("> ") line, _, err := br.ReadLine() if err != nil { @@ -389,8 +385,8 @@ func readEvaluateProcess(br *bufio.Reader) error { func processLine(in []byte) (out []byte, err error) { return bytes.ToUpper(in), nil } -{{}} -{{}} +``` +{{% /tabs %}} We will later use this tag, called KeyMethod, to record what method is being invoked. In our scenario, we will only use it to record that "repl" is calling our data. @@ -406,15 +402,15 @@ Now we will insert a specific tag called "repl". It will give us a new `context. For example ```go - ctx, err := tag.New(context.Background(), tag.Insert(KeyMethod, "repl")) +ctx, _ := tag.New(context.Background(), tag.Insert(KeyMethod, "repl"), tag.Insert(KeyStatus, "OK")) ``` and for complete usage: -{{}} -{{}} -func readEvaluateProcess(br *bufio.Reader) error { - ctx, err := tag.New(context.Background(), tag.Insert(KeyMethod, "repl")) +{{% tabs Snippet All %}} +```go +func readEvaluateProcess(br *bufio.Reader) (terr error) { + ctx, _ := tag.New(context.Background(), tag.Insert(KeyMethod, "repl"), tag.Insert(KeyStatus, "OK")) if err != nil { return err } @@ -432,9 +428,9 @@ func readEvaluateProcess(br *bufio.Reader) error { fmt.Printf("< %s\n\n", out) return nil } -{{}} +``` -{{}} +```go package main import ( @@ -455,15 +451,14 @@ var ( // The latency in milliseconds MLatencyMs = stats.Float64("repl/latency", "The latency in milliseconds per REPL loop", "ms") - // Encounters the number of non EOF(end-of-file) errors. - MErrors = stats.Int64("repl/errors", "The number of errors encountered", "1") - // Counts/groups the lengths of lines read in. MLineLengths = stats.Int64("repl/line_lengths", "The distribution of line lengths", "By") ) var ( KeyMethod, _ = tag.NewKey("method") + KeyStatus, _ = tag.NewKey("status") + KeyError, _ = tag.NewKey("error") ) func main() { @@ -485,8 +480,8 @@ func main() { // readEvaluateProcess reads a line from the input reader and // then processes it. It returns an error if any was encountered. -func readEvaluateProcess(br *bufio.Reader) error { - ctx, err := tag.New(context.Background(), tag.Insert(KeyMethod, "repl")) +func readEvaluateProcess(br *bufio.Reader) (terr error) { + ctx, _ := tag.New(context.Background(), tag.Insert(KeyMethod, "repl"), tag.Insert(KeyStatus, "OK")) if err != nil { return err } @@ -510,21 +505,23 @@ func readEvaluateProcess(br *bufio.Reader) error { func processLine(in []byte) (out []byte, err error) { return bytes.ToUpper(in), nil } -{{}} -{{}} +``` +{{% /tabs %}} When recording metrics, we will need the `ctx` from `tag.New`. We will be recording metrics in `processLine`, so let's go ahead and make `ctx` available now. -{{}} -{{}} +{{% tabs Snippet All %}} +```go // ... out, err := processLine(ctx, line) // ... func processLine(ctx context.Context, in []byte) (out []byte, err error) { -{{}} + // ... +} +``` -{{}} +```go package main import ( @@ -545,15 +542,14 @@ var ( // The latency in milliseconds MLatencyMs = stats.Float64("repl/latency", "The latency in milliseconds per REPL loop", "ms") - // Encounters the number of non EOF(end-of-file) errors. - MErrors = stats.Int64("repl/errors", "The number of errors encountered", "1") - // Counts/groups the lengths of lines read in. MLineLengths = stats.Int64("repl/line_lengths", "The distribution of line lengths", "By") ) var ( KeyMethod, _ = tag.NewKey("method") + KeyStatus, _ = tag.NewKey("status") + KeyError, _ = tag.NewKey("error") ) func main() { @@ -575,7 +571,7 @@ func main() { // readEvaluateProcess reads a line from the input reader and // then processes it. It returns an error if any was encountered. -func readEvaluateProcess(br *bufio.Reader) error { +func readEvaluateProcess(br *bufio.Reader) (terr error) { fmt.Printf("> ") line, _, err := br.ReadLine() if err != nil { @@ -596,33 +592,42 @@ func processLine(ctx context.Context, in []byte) (out []byte, err error) { return bytes.ToUpper(in), nil } -{{}} -{{}} + +``` +{{% /tabs %}} ### Recording Metrics Now we will record the desired metrics. To do so, we will use `stats.Record` and pass in our `ctx` and [previously instantiated metrics variables](#create-metrics). -{{}} -{{}} -func readEvaluateProcess(br *bufio.Reader) error { - ctx, err := tag.New(context.Background(), tag.Insert(KeyMethod, "repl")) +{{% tabs Snippet All %}} +```go +func readEvaluateProcess(br *bufio.Reader) (terr error) { + ctx, _ := tag.New(context.Background(), tag.Insert(KeyMethod, "repl"), tag.Insert(KeyStatus, "OK")) if err != nil { return err } + defer func() { + if terr != nil { + ctx, _ = tag.New(ctx, tag.Upsert(KeyStatus, "ERROR"), + tag.Upsert(KeyError, terr.Error())) + } + + stats.Record(ctx, MLatencyMs.M(sinceInMilliseconds(startTime))) + }() + fmt.Printf("> ") line, _, err := br.ReadLine() if err != nil { if err != io.EOF { - stats.Record(ctx, MErrors.M(1)) + return err } - return err + log.Fatal(err) } out, err := processLine(ctx, line) if err != nil { - stats.Record(ctx, MErrors.M(1)) return err } fmt.Printf("< %s\n\n", out) @@ -634,15 +639,19 @@ func readEvaluateProcess(br *bufio.Reader) error { func processLine(ctx context.Context, in []byte) (out []byte, err error) { startTime := time.Now() defer func() { - ms := float64(time.Since(startTime).Nanoseconds()) / 1e6 - stats.Record(ctx, MLatencyMs.M(ms), MLineLengths.M(int64(len(in)))) + stats.Record(ctx, MLatencyMs.M(sinceInMilliseconds(startTime)), + MLineLengths.M(int64(len(in)))) }() return bytes.ToUpper(in), nil } -{{}} -{{}} +func sinceInMilliseconds(startTime time.Time) float64 { + return float64(time.Since(startTime).Nanoseconds()) / 1e6 +} +``` + +```go package main import ( @@ -663,15 +672,14 @@ var ( // The latency in milliseconds MLatencyMs = stats.Float64("repl/latency", "The latency in milliseconds per REPL loop", "ms") - // Encounters the number of non EOF(end-of-file) errors. - MErrors = stats.Int64("repl/errors", "The number of errors encountered", "1") - // Counts/groups the lengths of lines read in. MLineLengths = stats.Int64("repl/line_lengths", "The distribution of line lengths", "By") ) var ( KeyMethod, _ = tag.NewKey("method") + KeyStatus, _ = tag.NewKey("status") + KeyError, _ = tag.NewKey("error") ) func main() { @@ -693,24 +701,32 @@ func main() { // readEvaluateProcess reads a line from the input reader and // then processes it. It returns an error if any was encountered. -func readEvaluateProcess(br *bufio.Reader) error { - ctx, err := tag.New(context.Background(), tag.Insert(KeyMethod, "repl")) +func readEvaluateProcess(br *bufio.Reader) (terr error) { + ctx, _ := tag.New(context.Background(), tag.Insert(KeyMethod, "repl"), tag.Insert(KeyStatus, "OK")) if err != nil { return err } + defer func() { + if terr != nil { + ctx, _ = tag.New(ctx, tag.Upsert(KeyStatus, "ERROR"), + tag.Upsert(KeyError, terr.Error())) + } + + stats.Record(ctx, MLatencyMs.M(sinceInMilliseconds(startTime))) + }() + fmt.Printf("> ") line, _, err := br.ReadLine() if err != nil { if err != io.EOF { - stats.Record(ctx, MErrors.M(1)) + return err } - return err + log.Fatal(err) } out, err := processLine(ctx, line) if err != nil { - stats.Record(ctx, MErrors.M(1)) return err } fmt.Printf("< %s\n\n", out) @@ -722,22 +738,26 @@ func readEvaluateProcess(br *bufio.Reader) error { func processLine(ctx context.Context, in []byte) (out []byte, err error) { startTime := time.Now() defer func() { - ms := float64(time.Since(startTime).Nanoseconds()) / 1e6 - stats.Record(ctx, MLatencyMs.M(ms), MLineLengths.M(int64(len(in)))) + stats.Record(ctx, MLatencyMs.M(sinceInMilliseconds(startTime)), + MLineLengths.M(int64(len(in)))) }() return bytes.ToUpper(in), nil } -{{}} -{{}} + +func sinceInMilliseconds(startTime time.Time) float64 { + return float64(time.Since(startTime).Nanoseconds()) / 1e6 +} +``` +{{% /tabs %}} ## Enable Views We will be adding the View package: `"go.opencensus.io/stats/view"` ### Import Packages -{{}} -{{}} +{{% tabs Snippet All %}} +```go import ( "bufio" "bytes" @@ -752,9 +772,9 @@ import ( "go.opencensus.io/stats/view" "go.opencensus.io/tag" ) -{{}} +``` -{{}} +```go package main import ( @@ -776,15 +796,14 @@ var ( // The latency in milliseconds MLatencyMs = stats.Float64("repl/latency", "The latency in milliseconds per REPL loop", "ms") - // Encounters the number of non EOF(end-of-file) errors. - MErrors = stats.Int64("repl/errors", "The number of errors encountered", "1") - // Counts/groups the lengths of lines read in. MLineLengths = stats.Int64("repl/line_lengths", "The distribution of line lengths", "By") ) var ( KeyMethod, _ = tag.NewKey("method") + KeyStatus, _ = tag.NewKey("status") + KeyError, _ = tag.NewKey("error") ) func main() { @@ -806,24 +825,32 @@ func main() { // readEvaluateProcess reads a line from the input reader and // then processes it. It returns an error if any was encountered. -func readEvaluateProcess(br *bufio.Reader) error { - ctx, err := tag.New(context.Background(), tag.Insert(KeyMethod, "repl")) +func readEvaluateProcess(br *bufio.Reader) (terr error) { + ctx, _ := tag.New(context.Background(), tag.Insert(KeyMethod, "repl"), tag.Insert(KeyStatus, "OK")) if err != nil { return err } + defer func() { + if terr != nil { + ctx, _ = tag.New(ctx, tag.Upsert(KeyStatus, "ERROR"), + tag.Upsert(KeyError, terr.Error())) + } + + stats.Record(ctx, MLatencyMs.M(sinceInMilliseconds(startTime))) + }() + fmt.Printf("> ") line, _, err := br.ReadLine() if err != nil { if err != io.EOF { - stats.Record(ctx, MErrors.M(1)) + return err } - return err + log.Fatal(err) } out, err := processLine(ctx, line) if err != nil { - stats.Record(ctx, MErrors.M(1)) return err } fmt.Printf("< %s\n\n", out) @@ -835,20 +862,24 @@ func readEvaluateProcess(br *bufio.Reader) error { func processLine(ctx context.Context, in []byte) (out []byte, err error) { startTime := time.Now() defer func() { - ms := float64(time.Since(startTime).Nanoseconds()) / 1e6 - stats.Record(ctx, MLatencyMs.M(ms), MLineLengths.M(int64(len(in)))) + stats.Record(ctx, MLatencyMs.M(sinceInMilliseconds(startTime)), + MLineLengths.M(int64(len(in)))) }() return bytes.ToUpper(in), nil } -{{}} -{{}} + +func sinceInMilliseconds(startTime time.Time) float64 { + return float64(time.Since(startTime).Nanoseconds()) / 1e6 +} +``` +{{% /tabs %}} ### Create Views We now determine how our metrics will be organized by creating `Views`. -{{}} -{{}} +{{% tabs Snippet All %}} +```go var ( LatencyView = &view.View{ Name: "demo/latency", @@ -867,13 +898,6 @@ var ( Aggregation: view.Count(), } - ErrorCountView = &view.View{ - Name: "demo/errors", - Measure: MErrors, - Description: "The number of errors encountered", - Aggregation: view.Count(), - } - LineLengthView = &view.View{ Name: "demo/line_lengths", Description: "Groups the lengths of keys in buckets", @@ -882,9 +906,9 @@ var ( Aggregation: view.Distribution(0, 5, 10, 15, 20, 40, 60, 80, 100, 200, 400, 600, 800, 1000), } ) -{{}} +``` -{{}} +```go package main import ( @@ -906,15 +930,14 @@ var ( // The latency in milliseconds MLatencyMs = stats.Float64("repl/latency", "The latency in milliseconds per REPL loop", "ms") - // Encounters the number of non EOF(end-of-file) errors. - MErrors = stats.Int64("repl/errors", "The number of errors encountered", "1") - // Counts/groups the lengths of lines read in. MLineLengths = stats.Int64("repl/line_lengths", "The distribution of line lengths", "By") ) var ( KeyMethod, _ = tag.NewKey("method") + KeyStatus, _ = tag.NewKey("status") + KeyError, _ = tag.NewKey("error") ) var ( @@ -935,13 +958,6 @@ var ( Aggregation: view.Count(), } - ErrorCountView = &view.View{ - Name: "demo/errors", - Measure: MErrors, - Description: "The number of errors encountered", - Aggregation: view.Count(), - } - LineLengthView = &view.View{ Name: "demo/line_lengths", Description: "Groups the lengths of keys in buckets", @@ -970,24 +986,32 @@ func main() { // readEvaluateProcess reads a line from the input reader and // then processes it. It returns an error if any was encountered. -func readEvaluateProcess(br *bufio.Reader) error { - ctx, err := tag.New(context.Background(), tag.Insert(KeyMethod, "repl")) +func readEvaluateProcess(br *bufio.Reader) (terr error) { + ctx, _ := tag.New(context.Background(), tag.Insert(KeyMethod, "repl"), tag.Insert(KeyStatus, "OK")) if err != nil { return err } + defer func() { + if terr != nil { + ctx, _ = tag.New(ctx, tag.Upsert(KeyStatus, "ERROR"), + tag.Upsert(KeyError, terr.Error())) + } + + stats.Record(ctx, MLatencyMs.M(sinceInMilliseconds(startTime))) + }() + fmt.Printf("> ") line, _, err := br.ReadLine() if err != nil { if err != io.EOF { - stats.Record(ctx, MErrors.M(1)) + return err } - return err + log.Fatal(err) } out, err := processLine(ctx, line) if err != nil { - stats.Record(ctx, MErrors.M(1)) return err } fmt.Printf("< %s\n\n", out) @@ -999,20 +1023,24 @@ func readEvaluateProcess(br *bufio.Reader) error { func processLine(ctx context.Context, in []byte) (out []byte, err error) { startTime := time.Now() defer func() { - ms := float64(time.Since(startTime).Nanoseconds()) / 1e6 - stats.Record(ctx, MLatencyMs.M(ms), MLineLengths.M(int64(len(in)))) + stats.Record(ctx, MLatencyMs.M(sinceInMilliseconds(startTime)), + MLineLengths.M(int64(len(in)))) }() return bytes.ToUpper(in), nil } -{{}} -{{}} + +func sinceInMilliseconds(startTime time.Time) float64 { + return float64(time.Since(startTime).Nanoseconds()) / 1e6 +} +``` +{{% /tabs %}} ### Register Views We now register the views and set the reporting period. -{{}} -{{}} +{{% tabs Snippet All %}} +```go func main() { // In a REPL: // 1. Read input @@ -1020,7 +1048,7 @@ func main() { br := bufio.NewReader(os.Stdin) // Register the views - if err := view.Register(LatencyView, LineCountView, ErrorCountView, LineLengthView); err != nil { + if err := view.Register(LatencyView, LineCountView, LineLengthView); err != nil { log.Fatalf("Failed to register views: %v", err) } @@ -1034,9 +1062,9 @@ func main() { } } } -{{}} +``` -{{}} +```go package main import ( @@ -1058,15 +1086,14 @@ var ( // The latency in milliseconds MLatencyMs = stats.Float64("repl/latency", "The latency in milliseconds per REPL loop", "ms") - // Encounters the number of non EOF(end-of-file) errors. - MErrors = stats.Int64("repl/errors", "The number of errors encountered", "1") - // Counts/groups the lengths of lines read in. MLineLengths = stats.Int64("repl/line_lengths", "The distribution of line lengths", "By") ) var ( KeyMethod, _ = tag.NewKey("method") + KeyStatus, _ = tag.NewKey("status") + KeyError, _ = tag.NewKey("error") ) var ( @@ -1087,13 +1114,6 @@ var ( Aggregation: view.Count(), } - ErrorCountView = &view.View{ - Name: "demo/errors", - Measure: MErrors, - Description: "The number of errors encountered", - Aggregation: view.Count(), - } - LineLengthView = &view.View{ Name: "demo/line_lengths", Description: "Groups the lengths of keys in buckets", @@ -1110,7 +1130,7 @@ func main() { br := bufio.NewReader(os.Stdin) // Register the views - if err := view.Register(LatencyView, LineCountView, ErrorCountView, LineLengthView); err != nil { + if err := view.Register(LatencyView, LineCountView, LineLengthView); err != nil { log.Fatalf("Failed to register views: %v", err) } @@ -1127,24 +1147,32 @@ func main() { // readEvaluateProcess reads a line from the input reader and // then processes it. It returns an error if any was encountered. -func readEvaluateProcess(br *bufio.Reader) error { - ctx, err := tag.New(context.Background(), tag.Insert(KeyMethod, "repl")) +func readEvaluateProcess(br *bufio.Reader) (terr error) { + ctx, _ := tag.New(context.Background(), tag.Insert(KeyMethod, "repl"), tag.Insert(KeyStatus, "OK")) if err != nil { return err } + defer func() { + if terr != nil { + ctx, _ = tag.New(ctx, tag.Upsert(KeyStatus, "ERROR"), + tag.Upsert(KeyError, terr.Error())) + } + + stats.Record(ctx, MLatencyMs.M(sinceInMilliseconds(startTime))) + }() + fmt.Printf("> ") line, _, err := br.ReadLine() if err != nil { if err != io.EOF { - stats.Record(ctx, MErrors.M(1)) + return err } - return err + log.Fatal(err) } out, err := processLine(ctx, line) if err != nil { - stats.Record(ctx, MErrors.M(1)) return err } fmt.Printf("< %s\n\n", out) @@ -1156,25 +1184,28 @@ func readEvaluateProcess(br *bufio.Reader) error { func processLine(ctx context.Context, in []byte) (out []byte, err error) { startTime := time.Now() defer func() { - ms := float64(time.Since(startTime).Nanoseconds()) / 1e6 - stats.Record(ctx, MLatencyMs.M(ms), MLineLengths.M(int64(len(in)))) + stats.Record(ctx, MLatencyMs.M(sinceInMilliseconds(startTime)), + MLineLengths.M(int64(len(in)))) }() return bytes.ToUpper(in), nil } -{{}} -{{}} + +func sinceInMilliseconds(startTime time.Time) float64 { + return float64(time.Since(startTime).Nanoseconds()) / 1e6 +} +``` +{{% /tabs %}} ## Exporting stats ### Register the views ```go - // Register the views - if err := view.Register(LatencyView, LineCountView, ErrorCountView, LineLengthView); err != nil { - log.Fatalf("Failed to register views: %v", err) - } - +// Register the views +if err := view.Register(LatencyView, LineCountView, LineLengthView); err != nil { + log.Fatalf("Failed to register views: %v", err) +} ``` @@ -1188,48 +1219,48 @@ to http endpoint "/metrics". ```go import ( - "log" - "net/http" + "log" + "net/http" - "go.opencensus.io/exporter/prometheus" - "go.opencensus.io/stats/view" + "go.opencensus.io/exporter/prometheus" + "go.opencensus.io/stats/view" ) func main() { - pe, err := prometheus.NewExporter(prometheus.Options{ - Namespace: "ocmetricstutorial", - }) - if err != nil { - log.Fatalf("Failed to create the Prometheus stats exporter: %v", err) - } - - // Register the Prometheus exporters as a stats exporter. - view.RegisterExporter(pe) - - // Now finally run the Prometheus exporter as a scrape endpoint. - // We'll run the server on port 8888. - go func() { - mux := http.NewServeMux() - mux.Handle("/metrics", pe) - if err := http.ListenAndServe(":8888", mux); err != nil { - log.Fatalf("Failed to run Prometheus scrape endpoint: %v", err) - } - }() + pe, err := prometheus.NewExporter(prometheus.Options{ + Namespace: "ocmetricstutorial", + }) + if err != nil { + log.Fatalf("Failed to create the Prometheus stats exporter: %v", err) + } + + // Register the Prometheus exporters as a stats exporter. + view.RegisterExporter(pe) + + // Now finally run the Prometheus exporter as a scrape endpoint. + // We'll run the server on port 8888. + go func() { + mux := http.NewServeMux() + mux.Handle("/metrics", pe) + if err := http.ListenAndServe(":8888", mux); err != nil { + log.Fatalf("Failed to run Prometheus scrape endpoint: %v", err) + } + }() } ``` ### Register the exporter ```go - // Register the Prometheus exporter. - // This step is needed so that metrics can be exported. - view.RegisterExporter(pe) +// Register the Prometheus exporter. +// This step is needed so that metrics can be exported. +view.RegisterExporter(pe) ``` ## End to end code Collectively the code will be -{{}} +```go package main import ( @@ -1253,15 +1284,14 @@ var ( // The latency in milliseconds MLatencyMs = stats.Float64("repl/latency", "The latency in milliseconds per REPL loop", "ms") - // Encounters the number of non EOF(end-of-file) errors. - MErrors = stats.Int64("repl/errors", "The number of errors encountered", "1") - // Counts/groups the lengths of lines read in. MLineLengths = stats.Int64("repl/line_lengths", "The distribution of line lengths", "By") ) var ( KeyMethod, _ = tag.NewKey("method") + KeyStatus, _ = tag.NewKey("status") + KeyError, _ = tag.NewKey("error") ) var ( @@ -1282,13 +1312,6 @@ var ( Aggregation: view.Count(), } - ErrorCountView = &view.View{ - Name: "demo/errors", - Measure: MErrors, - Description: "The number of errors encountered", - Aggregation: view.Count(), - } - LineLengthView = &view.View{ Name: "demo/line_lengths", Description: "Groups the lengths of keys in buckets", @@ -1301,7 +1324,7 @@ var ( func main() { // Register the views, it is imperative that this step exists // lest recorded metrics will be dropped and never exported. - if err := view.Register(LatencyView, LineCountView, ErrorCountView, LineLengthView); err != nil { + if err := view.Register(LatencyView, LineCountView, LineLengthView); err != nil { log.Fatalf("Failed to register the views: %v", err) } @@ -1332,7 +1355,7 @@ func main() { br := bufio.NewReader(os.Stdin) // Register the views - if err := view.Register(LatencyView, LineCountView, ErrorCountView, LineLengthView); err != nil { + if err := view.Register(LatencyView, LineCountView, LineLengthView); err != nil { log.Fatalf("Failed to register views: %v", err) } @@ -1349,24 +1372,32 @@ func main() { // readEvaluateProcess reads a line from the input reader and // then processes it. It returns an error if any was encountered. -func readEvaluateProcess(br *bufio.Reader) error { - ctx, err := tag.New(context.Background(), tag.Insert(KeyMethod, "repl")) +func readEvaluateProcess(br *bufio.Reader) (terr error) { + ctx, _ := tag.New(context.Background(), tag.Insert(KeyMethod, "repl"), tag.Insert(KeyStatus, "OK")) if err != nil { return err } + defer func() { + if terr != nil { + ctx, _ = tag.New(ctx, tag.Upsert(KeyStatus, "ERROR"), + tag.Upsert(KeyError, terr.Error())) + } + + stats.Record(ctx, MLatencyMs.M(sinceInMilliseconds(startTime))) + }() + fmt.Printf("> ") line, _, err := br.ReadLine() if err != nil { if err != io.EOF { - stats.Record(ctx, MErrors.M(1)) + return err } - return err + log.Fatal(err) } out, err := processLine(ctx, line) if err != nil { - stats.Record(ctx, MErrors.M(1)) return err } fmt.Printf("< %s\n\n", out) @@ -1378,13 +1409,17 @@ func readEvaluateProcess(br *bufio.Reader) error { func processLine(ctx context.Context, in []byte) (out []byte, err error) { startTime := time.Now() defer func() { - ms := float64(time.Since(startTime).Nanoseconds()) / 1e6 - stats.Record(ctx, MLatencyMs.M(ms), MLineLengths.M(int64(len(in)))) + stats.Record(ctx, MLatencyMs.M(sinceInMilliseconds(startTime)), + MLineLengths.M(int64(len(in)))) }() return bytes.ToUpper(in), nil } -{{}} + +func sinceInMilliseconds(startTime time.Time) float64 { + return float64(time.Since(startTime).Nanoseconds()) / 1e6 +} +``` ### Running the tutorial diff --git a/content/quickstart/java/metrics.md b/content/quickstart/java/metrics.md index 7225ea8b..3ffc9c52 100644 --- a/content/quickstart/java/metrics.md +++ b/content/quickstart/java/metrics.md @@ -328,9 +328,6 @@ First, we will create the variables needed to later record our metrics. Place th // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms"); -// Counts the number of non EOF(end-of-file) errors. -private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1"); - // Counts/groups the lengths of lines read in. private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By"); @@ -368,9 +365,6 @@ public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms"); - // Counts the number of non EOF(end-of-file) errors. - private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1"); - // Counts/groups the lengths of lines read in. private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By"); @@ -417,6 +411,8 @@ Insert the following snippet on the line before `private static final Tagger tag {{}} // The tag "method" private static final TagKey KEY_METHOD = TagKey.create("method"); +private static final TagKey KEY_STATUS = TagKey.create("status"); +private static final TagKey KEY_ERROR = TagKey.create("error"); {{}} {{}} @@ -445,14 +441,15 @@ public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms"); - // Counts the number of non EOF(end-of-file) errors. - private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1"); - // Counts/groups the lengths of lines read in. private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By"); // The tag "method" private static final TagKey KEY_METHOD = TagKey.create("method"); + // The tag "status" + private static final TagKey KEY_STATUS = TagKey.create("status"); + // The tag "error" + private static final TagKey KEY_ERROR = TagKey.create("error"); private static final Tagger tagger = Tags.getTagger(); private static final StatsRecorder statsRecorder = Stats.getStatsRecorder(); @@ -503,7 +500,7 @@ Later, if we used `OS_Key`, we will be given an opportunity to enter values such **Note**: `OS_Key` is not used in this quickstart. It is only used as an example in this text block. {{% /notice %}} -We will now create helper functions to assist us with recording Tagged Stats. One will record a `Long`, and the other will record a `Double`. +We will now create helper functions to assist us with recording Tagged Stats. One will record a `Long`, another a `Double`, and finally an array of `Doubles`. Insert the following snippet after `private static void recordStat`: @@ -522,6 +519,18 @@ private static void recordTaggedStat(TagKey key, String value, MeasureDouble md, statsRecorder.newMeasureMap().put(md, d).record(); } } + +private static void recordTaggedStat(TagKey[] keys, String[] values, MeasureDouble md, Double d) { + TagContextBuilder builder = tagger.emptyBuilder(); + for (int i = 0; i < keys.length; i++) { + builder.put(keys[i], TagValue.create(values[i])); + } + TagContext tctx = builder.build(); + + try (Scope ss = tagger.withTagContext(tctx)) { + statsRecorder.newMeasureMap().put(md, d).record(); + } +} {{}} {{}} @@ -550,14 +559,15 @@ public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms"); - // Counts the number of non EOF(end-of-file) errors. - private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1"); - // Counts/groups the lengths of lines read in. private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By"); // The tag "method" private static final TagKey KEY_METHOD = TagKey.create("method"); + // The tag "status" + private static final TagKey KEY_STATUS = TagKey.create("status"); + // The tag "error" + private static final TagKey KEY_ERROR = TagKey.create("error"); private static final Tagger tagger = Tags.getTagger(); private static final StatsRecorder statsRecorder = Stats.getStatsRecorder(); @@ -592,6 +602,18 @@ public class Repl { } } + private static void recordTaggedStat(TagKey[] keys, String[] values, MeasureDouble md, Double d) { + TagContextBuilder builder = tagger.emptyBuilder(); + for (int i = 0; i < keys.length; i++) { + builder.put(keys[i], TagValue.create(values[i])); + } + TagContext tctx = builder.build(); + + try (Scope ss = tagger.withTagContext(tctx)) { + statsRecorder.newMeasureMap().put(md, d).record(); + } + } + private static String processLine(String line) { return line.toUpperCase(); } @@ -612,18 +634,24 @@ Finally, we'll hook our stat recorders in to `main`, `processLine`, and `readEva {{}} {{}} -public static void main(String ...args) { - BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); +while (true) { + long startTimeNs = System.nanoTime(); - while (true) { - try { - readEvaluateProcessLine(stdin); - } catch (IOException e) { - System.err.println("EOF bye "+ e); - return; - } catch (Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); - } + try { + readEvaluateProcessLine(stdin); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); + } catch (IOException e) { + System.err.println("EOF bye "+ e); + return; + } catch (Exception e) { + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS, KEY_ERROR}; + String[] tagValues = {"repl", "ERROR", e.getMessage()}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); + return; } } @@ -633,23 +661,25 @@ private static String processLine(String line) { try { return line.toUpperCase(); } finally { - long totalTimeNs = System.nanoTime() - startTimeNs; - double timespentMs = (new Double(totalTimeNs))/1e6; - recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, sinceInMilliseconds(startTimeNs)); } } +private static double sinceInMilliseconds(long startTimeNs) { + return (new Double(System.nanoTime() - startTimeNs))/1e6; +} + private static void readEvaluateProcessLine(BufferedReader in) throws IOException { System.out.print("> "); System.out.flush(); - try { - String line = in.readLine(); - String processed = processLine(line); - System.out.println("< " + processed + "\n"); - recordStat(M_LINE_LENGTHS, new Long(line.length())); - } catch(Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); + String line = in.readLine(); + String processed = processLine(line); + System.out.println("< " + processed + "\n"); + if (line != null && line.length() > 0) { + recordStat(M_LINE_LENGTHS, new Long(line.length())); } } {{}} @@ -680,14 +710,15 @@ public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms"); - // Counts the number of non EOF(end-of-file) errors. - private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1"); - // Counts/groups the lengths of lines read in. private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By"); // The tag "method" private static final TagKey KEY_METHOD = TagKey.create("method"); + // The tag "status" + private static final TagKey KEY_STATUS = TagKey.create("status"); + // The tag "error" + private static final TagKey KEY_ERROR = TagKey.create("error"); private static final Tagger tagger = Tags.getTagger(); private static final StatsRecorder statsRecorder = Stats.getStatsRecorder(); @@ -696,13 +727,23 @@ public class Repl { BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); while (true) { + long startTimeNs = System.nanoTime(); + try { readEvaluateProcessLine(stdin); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); } catch (IOException e) { System.err.println("EOF bye "+ e); return; } catch (Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS, KEY_ERROR}; + String[] tagValues = {"repl", "ERROR", e.getMessage()}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); + return; } } } @@ -725,15 +766,27 @@ public class Repl { } } + private static void recordTaggedStat(TagKey[] keys, String[] values, MeasureDouble md, Double d) { + TagContextBuilder builder = tagger.emptyBuilder(); + for (int i = 0; i < keys.length; i++) { + builder.put(keys[i], TagValue.create(values[i])); + } + TagContext tctx = builder.build(); + + try (Scope ss = tagger.withTagContext(tctx)) { + statsRecorder.newMeasureMap().put(md, d).record(); + } + } + private static String processLine(String line) { long startTimeNs = System.nanoTime(); try { return line.toUpperCase(); } finally { - long totalTimeNs = System.nanoTime() - startTimeNs; - double timespentMs = (new Double(totalTimeNs))/1e6; - recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, sinceInMilliseconds(startTimeNs)); } } @@ -741,13 +794,11 @@ public class Repl { System.out.print("> "); System.out.flush(); - try { - String line = in.readLine(); - String processed = processLine(line); - System.out.println("< " + processed + "\n"); + String line = in.readLine(); + String processed = processLine(line); + System.out.println("< " + processed + "\n"); + if (line != null && line.length() > 0) { recordStat(M_LINE_LENGTHS, new Long(line.length())); - } catch(Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); } } } @@ -812,14 +863,15 @@ public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms"); - // Counts the number of non EOF(end-of-file) errors. - private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1"); - // Counts/groups the lengths of lines read in. private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By"); // The tag "method" private static final TagKey KEY_METHOD = TagKey.create("method"); + // The tag "status" + private static final TagKey KEY_STATUS = TagKey.create("status"); + // The tag "error" + private static final TagKey KEY_ERROR = TagKey.create("error"); private static final Tagger tagger = Tags.getTagger(); private static final StatsRecorder statsRecorder = Stats.getStatsRecorder(); @@ -854,15 +906,27 @@ public class Repl { } } + private static void recordTaggedStat(TagKey[] keys, String[] values, MeasureDouble md, Double d) { + TagContextBuilder builder = tagger.emptyBuilder(); + for (int i = 0; i < keys.length; i++) { + builder.put(keys[i], TagValue.create(values[i])); + } + TagContext tctx = builder.build(); + + try (Scope ss = tagger.withTagContext(tctx)) { + statsRecorder.newMeasureMap().put(md, d).record(); + } + } + private static String processLine(String line) { long startTimeNs = System.nanoTime(); try { return line.toUpperCase(); } finally { - long totalTimeNs = System.nanoTime() - startTimeNs; - double timespentMs = (new Double(totalTimeNs))/1e6; - recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, sinceInMilliseconds(startTimeNs)); } } @@ -870,13 +934,11 @@ public class Repl { System.out.print("> "); System.out.flush(); - try { - String line = in.readLine(); - String processed = processLine(line); - System.out.println("< " + processed + "\n"); + String line = in.readLine(); + String processed = processLine(line); + System.out.println("< " + processed + "\n"); + if (line != null && line.length() > 0) { recordStat(M_LINE_LENGTHS, new Long(line.length())); - } catch(Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); } } } @@ -910,10 +972,9 @@ private static void registerAllViews() { // Define the views View[] views = new View[]{ - View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.singletonList(KEY_METHOD)), - View.create(Name.create("ocjavametrics/lines_in"), "The number of lines read in from standard input", M_LINES_LENGTH, countAggregation, noKeys), - View.create(Name.create("ocjavametrics/errors"), "The number of errors encountered", M_ERRORS, countAggregation, noKeys), - View.create(Name.create("ocjavametrics/line_length"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys) + View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.unmodifiableList(Arrays.asList(KEY_METHOD, KEY_STATUS, KEY_ERROR))), + View.create(Name.create("ocjavametrics/lines_in"), "The number of lines read in from standard input", M_LINE_LENGTHS, countAggregation, noKeys), + View.create(Name.create("ocjavametrics/line_lengths"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys) }; // Create the view manager @@ -962,14 +1023,15 @@ public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms"); - // Counts the number of non EOF(end-of-file) errors. - private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1"); - // Counts/groups the lengths of lines read in. private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By"); // The tag "method" private static final TagKey KEY_METHOD = TagKey.create("method"); + // The tag "status" + private static final TagKey KEY_STATUS = TagKey.create("status"); + // The tag "error" + private static final TagKey KEY_ERROR = TagKey.create("error"); private static final Tagger tagger = Tags.getTagger(); private static final StatsRecorder statsRecorder = Stats.getStatsRecorder(); @@ -978,13 +1040,23 @@ public class Repl { BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); while (true) { + long startTimeNs = System.nanoTime(); + try { readEvaluateProcessLine(stdin); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); } catch (IOException e) { System.err.println("EOF bye "+ e); return; } catch (Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS, KEY_ERROR}; + String[] tagValues = {"repl", "ERROR", e.getMessage()}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); + return; } } } @@ -1007,15 +1079,27 @@ public class Repl { } } + private static void recordTaggedStat(TagKey[] keys, String[] values, MeasureDouble md, Double d) { + TagContextBuilder builder = tagger.emptyBuilder(); + for (int i = 0; i < keys.length; i++) { + builder.put(keys[i], TagValue.create(values[i])); + } + TagContext tctx = builder.build(); + + try (Scope ss = tagger.withTagContext(tctx)) { + statsRecorder.newMeasureMap().put(md, d).record(); + } + } + private static String processLine(String line) { long startTimeNs = System.nanoTime(); try { return line.toUpperCase(); } finally { - long totalTimeNs = System.nanoTime() - startTimeNs; - double timespentMs = (new Double(totalTimeNs))/1e6; - recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, sinceInMilliseconds(startTimeNs)); } } @@ -1023,13 +1107,11 @@ public class Repl { System.out.print("> "); System.out.flush(); - try { - String line = in.readLine(); - String processed = processLine(line); - System.out.println("< " + processed + "\n"); + String line = in.readLine(); + String processed = processLine(line); + System.out.println("< " + processed + "\n"); + if (line != null && line.length() > 0) { recordStat(M_LINE_LENGTHS, new Long(line.length())); - } catch(Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); } } @@ -1055,10 +1137,9 @@ public class Repl { // Define the views View[] views = new View[]{ - View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.singletonList(KEY_METHOD)), + View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.unmodifiableList(Arrays.asList(KEY_METHOD, KEY_STATUS, KEY_ERROR))), View.create(Name.create("ocjavametrics/lines_in"), "The number of lines read in from standard input", M_LINE_LENGTHS, countAggregation, noKeys), - View.create(Name.create("ocjavametrics/errors"), "The number of errors encountered", M_ERRORS, countAggregation, noKeys), - View.create(Name.create("ocjavametrics/line_length"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys) + View.create(Name.create("ocjavametrics/line_lengths"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys) }; // Create the view manager @@ -1089,13 +1170,23 @@ public static void main(String ...args) { BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); while (true) { + long startTimeNs = System.nanoTime(); + try { readEvaluateProcessLine(stdin); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); } catch (IOException e) { System.err.println("EOF bye "+ e); return; } catch (Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS, KEY_ERROR}; + String[] tagValues = {"repl", "ERROR", e.getMessage()}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); + return; } } } @@ -1142,14 +1233,15 @@ public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms"); - // Counts the number of non EOF(end-of-file) errors. - private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1"); - // Counts/groups the lengths of lines read in. private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By"); // The tag "method" private static final TagKey KEY_METHOD = TagKey.create("method"); + // The tag "status" + private static final TagKey KEY_STATUS = TagKey.create("status"); + // The tag "error" + private static final TagKey KEY_ERROR = TagKey.create("error"); private static final Tagger tagger = Tags.getTagger(); private static final StatsRecorder statsRecorder = Stats.getStatsRecorder(); @@ -1166,13 +1258,23 @@ public class Repl { BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); while (true) { + long startTimeNs = System.nanoTime(); + try { readEvaluateProcessLine(stdin); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); } catch (IOException e) { System.err.println("EOF bye "+ e); return; } catch (Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS, KEY_ERROR}; + String[] tagValues = {"repl", "ERROR", e.getMessage()}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); + return; } } } @@ -1195,15 +1297,27 @@ public class Repl { } } + private static void recordTaggedStat(TagKey[] keys, String[] values, MeasureDouble md, Double d) { + TagContextBuilder builder = tagger.emptyBuilder(); + for (int i = 0; i < keys.length; i++) { + builder.put(keys[i], TagValue.create(values[i])); + } + TagContext tctx = builder.build(); + + try (Scope ss = tagger.withTagContext(tctx)) { + statsRecorder.newMeasureMap().put(md, d).record(); + } + } + private static String processLine(String line) { long startTimeNs = System.nanoTime(); try { return line.toUpperCase(); } finally { - long totalTimeNs = System.nanoTime() - startTimeNs; - double timespentMs = (new Double(totalTimeNs))/1e6; - recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, sinceInMilliseconds(startTimeNs)); } } @@ -1211,13 +1325,11 @@ public class Repl { System.out.print("> "); System.out.flush(); - try { - String line = in.readLine(); - String processed = processLine(line); - System.out.println("< " + processed + "\n"); + String line = in.readLine(); + String processed = processLine(line); + System.out.println("< " + processed + "\n"); + if (line != null && line.length() > 0) { recordStat(M_LINE_LENGTHS, new Long(line.length())); - } catch(Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); } } @@ -1243,10 +1355,9 @@ public class Repl { // Define the views View[] views = new View[]{ - View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.singletonList(KEY_METHOD)), + View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.unmodifiableList(Arrays.asList(KEY_METHOD, KEY_STATUS, KEY_ERROR))), View.create(Name.create("ocjavametrics/lines_in"), "The number of lines read in from standard input", M_LINE_LENGTHS, countAggregation, noKeys), - View.create(Name.create("ocjavametrics/errors"), "The number of errors encountered", M_ERRORS, countAggregation, noKeys), - View.create(Name.create("ocjavametrics/line_length"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys) + View.create(Name.create("ocjavametrics/line_lengths"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys) }; // Create the view manager @@ -1423,14 +1534,15 @@ public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms"); - // Counts the number of non EOF(end-of-file) errors. - private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1"); - // Counts/groups the lengths of lines read in. private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By"); // The tag "method" private static final TagKey KEY_METHOD = TagKey.create("method"); + // The tag "status" + private static final TagKey KEY_STATUS = TagKey.create("status"); + // The tag "error" + private static final TagKey KEY_ERROR = TagKey.create("error"); private static final Tagger tagger = Tags.getTagger(); private static final StatsRecorder statsRecorder = Stats.getStatsRecorder(); @@ -1447,13 +1559,23 @@ public class Repl { BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); while (true) { + long startTimeNs = System.nanoTime(); + try { readEvaluateProcessLine(stdin); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); } catch (IOException e) { System.err.println("EOF bye "+ e); return; } catch (Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS, KEY_ERROR}; + String[] tagValues = {"repl", "ERROR", e.getMessage()}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); + return; } } } @@ -1476,15 +1598,27 @@ public class Repl { } } + private static void recordTaggedStat(TagKey[] keys, String[] values, MeasureDouble md, Double d) { + TagContextBuilder builder = tagger.emptyBuilder(); + for (int i = 0; i < keys.length; i++) { + builder.put(keys[i], TagValue.create(values[i])); + } + TagContext tctx = builder.build(); + + try (Scope ss = tagger.withTagContext(tctx)) { + statsRecorder.newMeasureMap().put(md, d).record(); + } + } + private static String processLine(String line) { long startTimeNs = System.nanoTime(); try { return line.toUpperCase(); } finally { - long totalTimeNs = System.nanoTime() - startTimeNs; - double timespentMs = (new Double(totalTimeNs))/1e6; - recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, sinceInMilliseconds(startTimeNs)); } } @@ -1492,13 +1626,11 @@ public class Repl { System.out.print("> "); System.out.flush(); - try { - String line = in.readLine(); - String processed = processLine(line); - System.out.println("< " + processed + "\n"); + String line = in.readLine(); + String processed = processLine(line); + System.out.println("< " + processed + "\n"); + if (line != null && line.length() > 0) { recordStat(M_LINE_LENGTHS, new Long(line.length())); - } catch(Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); } } @@ -1524,10 +1656,9 @@ public class Repl { // Define the views View[] views = new View[]{ - View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.singletonList(KEY_METHOD)), + View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.unmodifiableList(Arrays.asList(KEY_METHOD, KEY_STATUS, KEY_ERROR))), View.create(Name.create("ocjavametrics/lines_in"), "The number of lines read in from standard input", M_LINE_LENGTHS, countAggregation, noKeys), - View.create(Name.create("ocjavametrics/errors"), "The number of errors encountered", M_ERRORS, countAggregation, noKeys), - View.create(Name.create("ocjavametrics/line_length"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys) + View.create(Name.create("ocjavametrics/line_lengths"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys) }; // Create the view manager @@ -1604,14 +1735,15 @@ public class Repl { // The latency in milliseconds private static final MeasureDouble M_LATENCY_MS = MeasureDouble.create("repl/latency", "The latency in milliseconds per REPL loop", "ms"); - // Counts the number of non EOF(end-of-file) errors. - private static final MeasureLong M_ERRORS = MeasureLong.create("repl/errors", "The number of errors encountered", "1"); - // Counts/groups the lengths of lines read in. private static final MeasureLong M_LINE_LENGTHS = MeasureLong.create("repl/line_lengths", "The distribution of line lengths", "By"); // The tag "method" private static final TagKey KEY_METHOD = TagKey.create("method"); + // The tag "status" + private static final TagKey KEY_STATUS = TagKey.create("status"); + // The tag "error" + private static final TagKey KEY_ERROR = TagKey.create("error"); private static final Tagger tagger = Tags.getTagger(); private static final StatsRecorder statsRecorder = Stats.getStatsRecorder(); @@ -1628,13 +1760,22 @@ public class Repl { BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); while (true) { + long startTimeNs = System.nanoTime(); + try { readEvaluateProcessLine(stdin); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); } catch (IOException e) { System.err.println("EOF bye "+ e); return; } catch (Exception e) { - recordTaggedStat(KEY_METHOD, "repl", M_ERRORS, new Long(1)); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS, KEY_ERROR}; + String[] tagValues = {"repl", "ERROR", e.getMessage()}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, + sinceInMilliseconds(startTimeNs)); return; } } @@ -1661,21 +1802,34 @@ public class Repl { } } + private static void recordTaggedStat(TagKey[] keys, String[] values, MeasureDouble md, Double d) { + TagContextBuilder builder = tagger.emptyBuilder(); + for (int i = 0; i < keys.length; i++) { + builder.put(keys[i], TagValue.create(values[i])); + } + TagContext tctx = builder.build(); + + try (Scope ss = tagger.withTagContext(tctx)) { + statsRecorder.newMeasureMap().put(md, d).record(); + } + } + private static String processLine(String line) { long startTimeNs = System.nanoTime(); try { return line.toUpperCase(); - } catch (Exception e) { - recordTaggedStat(KEY_METHOD, "processLine", M_ERRORS, new Long(1)); - return ""; } finally { - long totalTimeNs = System.nanoTime() - startTimeNs; - double timespentMs = (new Double(totalTimeNs))/1e6; - recordTaggedStat(KEY_METHOD, "processLine", M_LATENCY_MS, timespentMs); + TagKey[] tagKeys = {KEY_METHOD, KEY_STATUS}; + String[] tagValues = {"repl", "OK"}; + recordTaggedStat(tagKeys, tagValues, M_LATENCY_MS, sinceInMilliseconds(startTimeNs)); } } + private static double sinceInMilliseconds(long startTimeNs) { + return (new Double(System.nanoTime() - startTimeNs))/1e6; + } + private static void readEvaluateProcessLine(BufferedReader in) throws IOException { System.out.print("> "); System.out.flush(); @@ -1710,9 +1864,8 @@ public class Repl { // Define the views View[] views = new View[]{ - View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.singletonList(KEY_METHOD)), + View.create(Name.create("ocjavametrics/latency"), "The distribution of latencies", M_LATENCY_MS, latencyDistribution, Collections.unmodifiableList(Arrays.asList(KEY_METHOD, KEY_STATUS, KEY_ERROR))), View.create(Name.create("ocjavametrics/lines_in"), "The number of lines read in from standard input", M_LINE_LENGTHS, countAggregation, noKeys), - View.create(Name.create("ocjavametrics/errors"), "The number of errors encountered", M_ERRORS, countAggregation, Collections.singletonList(KEY_METHOD)), View.create(Name.create("ocjavametrics/line_lengths"), "The distribution of line lengths", M_LINE_LENGTHS, lengthsDistribution, noKeys) };