From dbf960c8e1e302e7e4dfe9c835638d46358bfaa8 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Mon, 21 Nov 2022 07:45:47 -0800 Subject: [PATCH] Add view example tests (#3460) * Add the InstrumentKind type and vars to sdk/metric * Add the Instrument type to sdk/metric * Add the Stream type to sdk/metric * Add the View type to sdk/metric * Add NewView to create Views matching OTel spec * Add unit tests for NewView * Add changes to changelog * Apply suggestions from code review Co-authored-by: Anthony Mirabella * Update CHANGELOG.md * Update match and mask comments of Instrument * Explain wildcard logic in NewView with comment * Drop views that replace name for multi-inst match * Comment how users are expected to match zero-vals * Remove InstrumentKind and Scope from Stream * Fix redundant word in NewView comment * Add view example tests * Update comments to examples * Fix broken English Co-authored-by: Anthony Mirabella --- sdk/metric/view_test.go | 133 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/sdk/metric/view_test.go b/sdk/metric/view_test.go index 082b0106ebd..891de52dc6b 100644 --- a/sdk/metric/view_test.go +++ b/sdk/metric/view_test.go @@ -15,6 +15,8 @@ package metric // import "go.opentelemetry.io/otel/sdk/metric" import ( + "fmt" + "regexp" "testing" "github.com/go-logr/logr" @@ -469,3 +471,134 @@ func TestNewViewAggregationErrorLogged(t *testing.T) { assert.Nil(t, got.Aggregation, "erroring aggregation used") assert.Equal(t, 1, l.ErrorN()) } + +func ExampleNewView() { + // Create a view that renames the "latency" instrument from the v0.34.0 + // version of the "http" instrumentation library as "request.latency". + view := NewView(Instrument{ + Name: "latency", + Scope: instrumentation.Scope{ + Name: "http", + Version: "v0.34.0", + }, + }, Stream{Name: "request.latency"}) + + // The created view can then be registered with the OpenTelemetry metric + // SDK using the WithView option. Below is an example of how the view will + // function in the SDK for certain instruments. + + stream, _ := view(Instrument{ + Name: "latency", + Description: "request latency", + Unit: unit.Milliseconds, + Kind: InstrumentKindSyncCounter, + Scope: instrumentation.Scope{ + Name: "http", + Version: "v0.34.0", + SchemaURL: "https://opentelemetry.io/schemas/1.0.0", + }, + }) + fmt.Println("name:", stream.Name) + fmt.Println("description:", stream.Description) + fmt.Println("unit:", stream.Unit) + // Output: + // name: request.latency + // description: request latency + // unit: ms +} + +func ExampleNewView_drop() { + // Create a view that sets the drop aggregator for all instrumentation from + // the "db" library, effectively turning-off all instrumentation from that + // library. + view := NewView( + Instrument{Scope: instrumentation.Scope{Name: "db"}}, + Stream{Aggregation: aggregation.Drop{}}, + ) + + // The created view can then be registered with the OpenTelemetry metric + // SDK using the WithView option. Below is an example of how the view will + // function in the SDK for certain instruments. + + stream, _ := view(Instrument{ + Name: "queries", + Kind: InstrumentKindSyncCounter, + Scope: instrumentation.Scope{Name: "db", Version: "v0.4.0"}, + }) + fmt.Println("name:", stream.Name) + fmt.Printf("aggregation: %#v", stream.Aggregation) + // Output: + // name: queries + // aggregation: aggregation.Drop{} +} + +func ExampleNewView_wildcard() { + // Create a view that sets unit to milliseconds for any instrument with a + // name suffix of ".ms". + view := NewView( + Instrument{Name: "*.ms"}, + Stream{Unit: unit.Milliseconds}, + ) + + // The created view can then be registered with the OpenTelemetry metric + // SDK using the WithView option. Below is an example of how the view + // function in the SDK for certain instruments. + + stream, _ := view(Instrument{ + Name: "computation.time.ms", + Unit: unit.Dimensionless, + }) + fmt.Println("name:", stream.Name) + fmt.Println("unit:", stream.Unit) + // Output: + // name: computation.time.ms + // unit: ms +} + +func ExampleView() { + // The NewView function provides convenient creation of common Views + // construction. However, it is limited in what it can create. + // + // When NewView is not able to provide the functionally needed, a custom + // View can be constructed directly. Here a custom View is constructed that + // uses Go's regular expression matching to ensure all data stream names + // have a suffix of the units it uses. + + re := regexp.MustCompile(`[._](ms|byte)$`) + var view View = func(i Instrument) (Stream, bool) { + s := Stream{Name: i.Name, Description: i.Description, Unit: i.Unit} + // Any instrument that does not have a unit suffix defined, but has a + // dimensional unit defined, update the name with a unit suffix. + if re.MatchString(i.Name) { + return s, false + } + switch i.Unit { + case unit.Milliseconds: + s.Name += ".ms" + case unit.Bytes: + s.Name += ".byte" + default: + return s, false + } + return s, true + } + + // The created view can then be registered with the OpenTelemetry metric + // SDK using the WithView option. Below is an example of how the view will + // function in the SDK for certain instruments. + + stream, _ := view(Instrument{ + Name: "computation.time.ms", + Unit: unit.Milliseconds, + }) + fmt.Println("name:", stream.Name) + + stream, _ = view(Instrument{ + Name: "heap.size", + Unit: unit.Bytes, + }) + fmt.Println("name:", stream.Name) + // Output: + // name: computation.time.ms + // name: heap.size.byte +}