diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f130b8be10..c841901a7b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Removed + +- The deprecated `go.opentelemetry.io/otel/sdk/metric/view` package is removed. (#3520) + ## [1.11.2/0.34.0] 2022-12-05 ### Added diff --git a/sdk/metric/view/doc.go b/sdk/metric/view/doc.go deleted file mode 100644 index c757b75bd35..00000000000 --- a/sdk/metric/view/doc.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package view provides types and functionality that customize the metric -// telemetry an SDK will produce. The View type is used when a Reader is -// registered with a MeterProvider in the go.opentelemetry.io/otel/sdk/metric -// package. See the WithReader option in that package for more information on -// how this registration takes place. -// -// Deprecated: Use Instrument, InstrumentKind, View, and NewView in -// go.opentelemetry.io/otel/sdk/metric instead. -package view // import "go.opentelemetry.io/otel/sdk/metric/view" diff --git a/sdk/metric/view/example_test.go b/sdk/metric/view/example_test.go deleted file mode 100644 index 76d99df6d45..00000000000 --- a/sdk/metric/view/example_test.go +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package view // import "go.opentelemetry.io/otel/sdk/metric/view" - -import ( - "fmt" - - "go.opentelemetry.io/otel/sdk/instrumentation" - "go.opentelemetry.io/otel/sdk/metric/aggregation" -) - -func Example() { - // The "active-users" instrument created by the - // "github.com/super/noisy/instrumentation/package" your project includes - // has a bug, it records a measurment any time a user has any activity. - // This is causing a lot of strain on your program without providing any - // value to you. The next version of - // "github.com/super/noisy/instrumentation/package" corrects the - // instrumentation to only record a value when a user logs in, but it - // isn't out yet. - // - // Use a View to drop these measurments while you wait for the fix to come - // from upstream. - - v, err := New( - MatchInstrumentName("active-users"), - MatchInstrumentationScope(instrumentation.Scope{ - Name: "github.com/super/noisy/instrumentation/package", - Version: "v0.22.0", // Only match the problematic instrumentation version. - }), - WithSetAggregation(aggregation.Drop{}), - ) - if err != nil { - panic(err) - } - - // The SDK this view is registered with calls TransformInstrument when an - // instrument is created. Test that our fix will work as intended. - i, _ := v.TransformInstrument(Instrument{ - Name: "active-users", - Scope: instrumentation.Scope{ - Name: "github.com/super/noisy/instrumentation/package", - Version: "v0.22.0", - }, - Aggregation: aggregation.LastValue{}, - }) - fmt.Printf("Instrument{%q: %s}: %#v\n", i.Name, i.Scope.Version, i.Aggregation) - - // Also, ensure the next version will not be transformed. - _, ok := v.TransformInstrument(Instrument{ - Name: "active-users", - Scope: instrumentation.Scope{ - Name: "github.com/super/noisy/instrumentation/package", - Version: "v0.23.0", - }, - Aggregation: aggregation.LastValue{}, - }) - fmt.Printf("Instrument{\"active-users\": v0.23.0} matched: %t\n", ok) - // Output: - // - // Instrument{"active-users": v0.22.0}: aggregation.Drop{} - // Instrument{"active-users": v0.23.0} matched: false -} - -func ExampleMatchInstrumentName() { - v, err := New(MatchInstrumentName("request-*")) // Wildcard match. - if err != nil { - panic(err) - } - - for _, i := range []Instrument{ - {Name: "request-count"}, - {Name: "request-rate"}, - {Name: "latency"}, - } { - // The SDK calls TransformInstrument when an instrument is created. - _, ok := v.TransformInstrument(i) - fmt.Printf("Instrument{%q} matched: %t\n", i.Name, ok) - } - // Output: - // Instrument{"request-count"} matched: true - // Instrument{"request-rate"} matched: true - // Instrument{"latency"} matched: false -} - -func ExampleMatchInstrumentKind() { - v, err := New(MatchInstrumentKind(SyncCounter)) - if err != nil { - panic(err) - } - - for _, i := range []Instrument{ - {Name: "synchronous counter", Kind: SyncCounter}, - {Name: "synchronous histogram", Kind: SyncHistogram}, - {Name: "asynchronous counter", Kind: AsyncCounter}, - } { - // The SDK calls TransformInstrument when an instrument is created. - _, ok := v.TransformInstrument(i) - fmt.Printf("Instrument{%q} matched: %t\n", i.Name, ok) - } - // Output: - // Instrument{"synchronous counter"} matched: true - // Instrument{"synchronous histogram"} matched: false - // Instrument{"asynchronous counter"} matched: false -} - -func ExampleMatchInstrumentationScope() { - v, err := New(MatchInstrumentationScope(instrumentation.Scope{ - Name: "custom/instrumentation/package", - Version: "v0.22.0", // Only match this version of instrumentation. - })) - if err != nil { - panic(err) - } - - for _, i := range []Instrument{ - {Name: "v1.0.0 instrumentation", Scope: instrumentation.Scope{ - Name: "custom/instrumentation/package", - Version: "v1.0.0", - }}, - {Name: "v0.22.0 instrumentation", Scope: instrumentation.Scope{ - Name: "custom/instrumentation/package", - Version: "v0.22.0", - }}, - } { - // The SDK calls TransformInstrument when an instrument is created. - _, ok := v.TransformInstrument(i) - fmt.Printf("Instrument{%q} matched: %t\n", i.Name, ok) - } - // Output: - // Instrument{"v1.0.0 instrumentation"} matched: false - // Instrument{"v0.22.0 instrumentation"} matched: true -} - -func ExampleWithRename() { - v, err := New(MatchInstrumentName("bad-name"), WithRename("good-name")) - if err != nil { - panic(err) - } - - // The SDK calls TransformInstrument when an instrument is created. - i, _ := v.TransformInstrument(Instrument{Name: "bad-name"}) - fmt.Printf("Instrument{%q}\n", i.Name) - // Output: Instrument{"good-name"} -} - -func ExampleWithSetDescription() { - v, err := New( - MatchInstrumentName("requests"), - WithSetDescription("Number of requests received"), - ) - if err != nil { - panic(err) - } - - // The SDK calls TransformInstrument when an instrument is created. - i, _ := v.TransformInstrument(Instrument{ - Name: "requests", - Description: "incorrect description", - }) - fmt.Printf("Instrument{%q: %s}\n", i.Name, i.Description) - // Output: Instrument{"requests": Number of requests received} -} - -func ExampleWithSetAggregation() { - v, err := New(MatchInstrumentationScope(instrumentation.Scope{ - Name: "super/noisy/instrumentation/package", - }), WithSetAggregation(aggregation.Drop{})) - if err != nil { - panic(err) - } - - // The SDK calls TransformInstrument when an instrument is created. - i, _ := v.TransformInstrument(Instrument{ - Name: "active-users", - Scope: instrumentation.Scope{ - Name: "super/noisy/instrumentation/package", - Version: "v0.5.0", - }, - Aggregation: aggregation.LastValue{}, - }) - fmt.Printf("Instrument{%q}: %#v\n", i.Name, i.Aggregation) - // Output: Instrument{"active-users"}: aggregation.Drop{} -} diff --git a/sdk/metric/view/instrument.go b/sdk/metric/view/instrument.go deleted file mode 100644 index 77536de2114..00000000000 --- a/sdk/metric/view/instrument.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package view // import "go.opentelemetry.io/otel/sdk/metric/view" - -import ( - "go.opentelemetry.io/otel/sdk/instrumentation" - "go.opentelemetry.io/otel/sdk/metric/aggregation" -) - -// Instrument uniquely identifies an instrument within a meter. -// -// Deprecated: Use Instrument in go.opentelemetry.io/otel/sdk/metric instead. -type Instrument struct { - Scope instrumentation.Scope - - Name string - Description string - Kind InstrumentKind - Aggregation aggregation.Aggregation -} diff --git a/sdk/metric/view/instrumentkind.go b/sdk/metric/view/instrumentkind.go deleted file mode 100644 index 357117e334a..00000000000 --- a/sdk/metric/view/instrumentkind.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package view // import "go.opentelemetry.io/otel/sdk/metric/view" - -// InstrumentKind describes the kind of instrument a Meter can create. -// -// Deprecated: Use InstrumentKind in go.opentelemetry.io/otel/sdk/metric -// instead. -type InstrumentKind uint8 - -// These are all the instrument kinds supported by the SDK. -const ( - // undefinedInstrument is an uninitialized instrument kind, should not be used. - //nolint:deadcode,varcheck - undefinedInstrument InstrumentKind = iota - // SyncCounter is an instrument kind that records increasing values - // synchronously in application code. - // - // Deprecated: Use InstrumentKindSyncCounter in - // go.opentelemetry.io/otel/sdk/metric instead. - SyncCounter - // SyncUpDownCounter is an instrument kind that records increasing and - // decreasing values synchronously in application code. - // - // Deprecated: Use InstrumentKindSyncUpDownCounter in - // go.opentelemetry.io/otel/sdk/metric instead. - SyncUpDownCounter - // SyncHistogram is an instrument kind that records a distribution of - // values synchronously in application code. - // - // Deprecated: Use InstrumentKindSyncHistogram in - // go.opentelemetry.io/otel/sdk/metric instead. - SyncHistogram - // AsyncCounter is an instrument kind that records increasing values in an - // asynchronous callback. - // - // Deprecated: Use InstrumentKindAsyncCounter in - // go.opentelemetry.io/otel/sdk/metric instead. - AsyncCounter - // AsyncUpDownCounter is an instrument kind that records increasing and - // decreasing values in an asynchronous callback. - // - // Deprecated: Use InstrumentKindAsyncUpDownCounter in - // go.opentelemetry.io/otel/sdk/metric instead. - AsyncUpDownCounter - // AsyncGauge is an instrument kind that records current values in an - // asynchronous callback. - // - // Deprecated: Use InstrumentKindAsyncGauge in - // go.opentelemetry.io/otel/sdk/metric instead. - AsyncGauge -) diff --git a/sdk/metric/view/view.go b/sdk/metric/view/view.go deleted file mode 100644 index 3e432afb3f8..00000000000 --- a/sdk/metric/view/view.go +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package view // import "go.opentelemetry.io/otel/sdk/metric/view" - -import ( - "fmt" - "regexp" - "strings" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/internal/global" - "go.opentelemetry.io/otel/sdk/instrumentation" - "go.opentelemetry.io/otel/sdk/metric/aggregation" -) - -// View provides users with the flexibility to customize the metrics that are -// output by the SDK. A View can be used to ignore, change the name, -// description, and aggregation of, and customize which attribute(s) are to be -// reported by Instruments. -// -// An empty View will match all instruments, and do no transformations. -// -// Deprecated: Use View in go.opentelemetry.io/otel/sdk/metric instead. -type View struct { - instrumentName *regexp.Regexp - hasWildcard bool - scope instrumentation.Scope - instrumentKind InstrumentKind - - filter attribute.Filter - name string - description string - agg aggregation.Aggregation -} - -// New returns a new configured View. If there are any duplicate Options passed, -// the last one passed will take precedence. The unique, de-duplicated, -// Options are all applied to the View. An instrument needs to match all of -// the match Options passed for the View to be applied to it. Similarly, all -// transform operation Options are applied to matched Instruments. -// -// Deprecated: Use NewView in go.opentelemetry.io/otel/sdk/metric instead. -func New(opts ...Option) (View, error) { - v := View{} - - for _, opt := range opts { - v = opt.apply(v) - } - - emptyScope := instrumentation.Scope{} - if v.instrumentName == nil && - v.scope == emptyScope && - v.instrumentKind == undefinedInstrument { - return View{}, fmt.Errorf("must provide at least 1 match option") - } - - if v.hasWildcard && v.name != "" { - return View{}, fmt.Errorf("invalid view: view name specified for multiple instruments") - } - - return v, nil -} - -// TransformInstrument will check if an instrument matches this view -// and will convert it if it does. -func (v View) TransformInstrument(inst Instrument) (transformed Instrument, match bool) { - if !v.match(inst) { - return Instrument{}, false - } - if v.name != "" { - inst.Name = v.name - } - if v.description != "" { - inst.Description = v.description - } - if v.agg != nil { - inst.Aggregation = v.agg - } - return inst, true -} - -// AttributeFilter returns a function that returns only attributes specified by -// WithFilterAttributes. If no filter was provided nil is returned. -func (v View) AttributeFilter() func(attribute.Set) attribute.Set { - if v.filter == nil { - return nil - } - return func(input attribute.Set) attribute.Set { - out, _ := input.Filter(v.filter) - return out - } -} - -func (v View) matchName(name string) bool { - return v.instrumentName == nil || v.instrumentName.MatchString(name) -} - -func (v View) matchScopeName(name string) bool { - return v.scope.Name == "" || name == v.scope.Name -} - -func (v View) matchScopeVersion(version string) bool { - return v.scope.Version == "" || version == v.scope.Version -} - -func (v View) matchScopeSchemaURL(schemaURL string) bool { - return v.scope.SchemaURL == "" || schemaURL == v.scope.SchemaURL -} - -func (v View) matchInstrumentKind(kind InstrumentKind) bool { - return v.instrumentKind == undefinedInstrument || kind == v.instrumentKind -} - -func (v View) match(i Instrument) bool { - return v.matchName(i.Name) && - v.matchScopeName(i.Scope.Name) && - v.matchScopeSchemaURL(i.Scope.SchemaURL) && - v.matchScopeVersion(i.Scope.Version) && - v.matchInstrumentKind(i.Kind) -} - -// Option applies a configuration option value to a View. -type Option interface { - apply(View) View -} - -type optionFunc func(View) View - -func (f optionFunc) apply(v View) View { - return f(v) -} - -// MatchInstrumentName will match an instrument based on the its name. -// This will accept wildcards of * for zero or more characters, and ? for -// exactly one character. A name of "*" (default) will match all instruments. -func MatchInstrumentName(name string) Option { - return optionFunc(func(v View) View { - if strings.ContainsAny(name, "*?") { - v.hasWildcard = true - } - name = regexp.QuoteMeta(name) - name = "^" + name + "$" - name = strings.ReplaceAll(name, "\\?", ".") - name = strings.ReplaceAll(name, "\\*", ".*") - v.instrumentName = regexp.MustCompile(name) - return v - }) -} - -// MatchInstrumentKind with match an instrument based on the instrument's kind. -// The default is to match all instrument kinds. -func MatchInstrumentKind(kind InstrumentKind) Option { - return optionFunc(func(v View) View { - v.instrumentKind = kind - return v - }) -} - -// MatchInstrumentationScope will do an exact match on any -// instrumentation.Scope field that is non-empty (""). The default is to match all -// instrumentation scopes. -func MatchInstrumentationScope(scope instrumentation.Scope) Option { - return optionFunc(func(v View) View { - v.scope = scope - return v - }) -} - -// WithRename will rename the instrument the view matches. If not used or empty the -// instrument name will not be changed. Must be used with a non-wildcard -// instrument name match. The default does not change the instrument name. -func WithRename(name string) Option { - return optionFunc(func(v View) View { - v.name = name - return v - }) -} - -// WithSetDescription will change the description of the instruments the view -// matches to desc. If not used or empty the description will not be changed. -func WithSetDescription(desc string) Option { - return optionFunc(func(v View) View { - v.description = desc - return v - }) -} - -// WithFilterAttributes will select attributes that have a matching key. If not used -// or empty no filter will be applied. -func WithFilterAttributes(keys ...attribute.Key) Option { - return optionFunc(func(v View) View { - if len(keys) == 0 { - return v - } - filterKeys := map[attribute.Key]struct{}{} - for _, key := range keys { - filterKeys[key] = struct{}{} - } - - v.filter = attribute.Filter(func(kv attribute.KeyValue) bool { - _, ok := filterKeys[kv.Key] - return ok - }) - return v - }) -} - -// WithSetAggregation will use the aggregation a for matching instruments. If -// this option is not provided, the reader defined aggregation for the -// instrument will be used. -// -// If a is misconfigured, it will not be used and an error will be logged. -func WithSetAggregation(a aggregation.Aggregation) Option { - cpA := a.Copy() - if err := cpA.Err(); err != nil { - global.Error(err, "not using aggregation with view", "aggregation", a) - return optionFunc(func(v View) View { return v }) - } - - return optionFunc(func(v View) View { - v.agg = cpA - return v - }) -} diff --git a/sdk/metric/view/view_test.go b/sdk/metric/view/view_test.go deleted file mode 100644 index 92034345926..00000000000 --- a/sdk/metric/view/view_test.go +++ /dev/null @@ -1,444 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package view // import "go.opentelemetry.io/otel/sdk/metric/view" - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/sdk/instrumentation" -) - -var matchInstrument = Instrument{ - Scope: instrumentation.Scope{ - Name: "bar", - Version: "v1.0.0", - SchemaURL: "stuff.test/", - }, - Name: "foo", - Kind: SyncCounter, - Description: "", -} - -var noMatchInstrument = Instrument{ - Scope: instrumentation.Scope{ - Name: "notfoo", - Version: "v0.x.0", - SchemaURL: "notstuff.test/", - }, - Name: "notstuff", - Description: "", - Kind: undefinedInstrument, -} - -var emptyDescription = Instrument{} - -func TestViewTransformInstrument(t *testing.T) { - tests := []struct { - name string - options []Option - match Instrument - notMatch Instrument - }{ - { - name: "instrument name", - options: []Option{ - MatchInstrumentName("foo"), - }, - match: matchInstrument, - notMatch: emptyDescription, - }, - { - name: "Scope name", - options: []Option{ - MatchInstrumentationScope(instrumentation.Scope{ - Name: "bar", - }), - }, - match: matchInstrument, - notMatch: emptyDescription, - }, - { - name: "Scope version", - options: []Option{ - MatchInstrumentationScope(instrumentation.Scope{ - Version: "v1.0.0", - }), - }, - - match: matchInstrument, - notMatch: emptyDescription, - }, - { - name: "Scope SchemaURL", - options: []Option{ - MatchInstrumentationScope(instrumentation.Scope{ - SchemaURL: "stuff.test/", - }), - }, - match: matchInstrument, - notMatch: emptyDescription, - }, { - name: "instrument kind", - options: []Option{ - MatchInstrumentKind(SyncCounter), - }, - match: matchInstrument, - notMatch: emptyDescription, - }, - { - name: "Expands *", - options: []Option{ - MatchInstrumentName("f*"), - }, - match: matchInstrument, - notMatch: emptyDescription, - }, - { - name: "composite literal name", - options: []Option{ - MatchInstrumentName("foo"), - MatchInstrumentationScope(instrumentation.Scope{ - Name: "bar", - Version: "v1.0.0", - SchemaURL: "stuff.test/", - }), - }, - match: matchInstrument, - notMatch: emptyDescription, - }, - { - name: "rename", - options: []Option{ - MatchInstrumentName("foo"), - WithRename("baz"), - }, - match: Instrument{ - Scope: instrumentation.Scope{ - Name: "bar", - Version: "v1.0.0", - SchemaURL: "stuff.test/", - }, - Name: "baz", - Description: "", - Kind: SyncCounter, - }, - notMatch: emptyDescription, - }, - { - name: "change description", - options: []Option{ - MatchInstrumentName("foo"), - WithSetDescription("descriptive stuff"), - }, - match: Instrument{ - Scope: instrumentation.Scope{ - Name: "bar", - Version: "v1.0.0", - SchemaURL: "stuff.test/", - }, - Name: "foo", - Description: "descriptive stuff", - Kind: SyncCounter, - }, - notMatch: emptyDescription, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - v, err := New(tt.options...) - require.NoError(t, err) - - t.Run("match", func(t *testing.T) { - got, match := v.TransformInstrument(matchInstrument) - assert.Equal(t, tt.match, got) - assert.True(t, match) - }) - - t.Run("does not match", func(t *testing.T) { - got, match := v.TransformInstrument(noMatchInstrument) - assert.Equal(t, tt.notMatch, got) - assert.False(t, match) - }) - }) - } -} - -func TestViewMatchName(t *testing.T) { - tests := []struct { - name string - matchName string - matches []string - notMatches []string - hasWildcard bool - }{ - { - name: "exact", - matchName: "foo", - matches: []string{"foo"}, - notMatches: []string{"foobar", "barfoo", "barfoobaz"}, - hasWildcard: false, - }, - { - name: "*", - matchName: "*", - matches: []string{"foo", "foobar", "barfoo", "barfoobaz", ""}, - notMatches: []string{}, - hasWildcard: true, - }, - { - name: "front ?", - matchName: "?foo", - matches: []string{"1foo", "afoo"}, - notMatches: []string{"foo", "foobar", "barfoo", "barfoobaz"}, - hasWildcard: true, - }, - { - name: "back ?", - matchName: "foo?", - matches: []string{"foo1", "fooz"}, - notMatches: []string{"foo", "foobar", "barfoo", "barfoobaz"}, - hasWildcard: true, - }, - { - name: "front *", - matchName: "*foo", - matches: []string{"foo", "barfoo"}, - notMatches: []string{"foobar", "barfoobaz"}, - hasWildcard: true, - }, - { - name: "back *", - matchName: "foo*", - matches: []string{"foo", "foobar"}, - notMatches: []string{"barfoo", "barfoobaz"}, - hasWildcard: true, - }, - { - name: "both *", - matchName: "*foo*", - matches: []string{"foo", "foobar", "barfoo", "barfoobaz"}, - notMatches: []string{"baz"}, - hasWildcard: true, - }, - { - name: "front **", - matchName: "**foo", - matches: []string{"foo", "barfoo", "1foo", "afoo"}, - notMatches: []string{"foobar", "barfoobaz", "baz", "foo1", "fooz"}, - hasWildcard: true, - }, - { - name: "back **", - matchName: "foo**", - matches: []string{"foo", "foobar", "foo1", "fooz"}, - notMatches: []string{"barfoo", "barfoobaz", "baz", "1foo", "afoo"}, - hasWildcard: true, - }, - { - name: "front *?", - matchName: "*?foo", - matches: []string{"barfoo", "1foo", "afoo"}, - notMatches: []string{"foo", "foobar", "barfoobaz", "baz", "foo1", "fooz"}, - hasWildcard: true, - }, - { - name: "front ?*", - matchName: "?*foo", - matches: []string{"barfoo", "1foo", "afoo"}, - notMatches: []string{"foo", "foobar", "barfoobaz", "baz", "foo1", "fooz"}, - hasWildcard: true, - }, - { - name: "back *?", - matchName: "foo*?", - matches: []string{"foobar", "foo1", "fooz"}, - notMatches: []string{"foo", "barfoo", "barfoobaz", "baz", "1foo", "afoo"}, - hasWildcard: true, - }, - { - name: "back ?*", - matchName: "foo?*", - matches: []string{"foobar", "foo1", "fooz"}, - notMatches: []string{"foo", "barfoo", "barfoobaz", "baz", "1foo", "afoo"}, - hasWildcard: true, - }, - { - name: "middle *", - matchName: "foo*bar", - matches: []string{"foobar", "foo1bar", "foomanybar"}, - notMatches: []string{"foo", "barfoo", "barfoobaz", "baz", "1foo", "afoo", "foo1", "fooz"}, - hasWildcard: true, - }, - { - name: "middle ?", - matchName: "foo?bar", - matches: []string{"foo1bar", "fooabar"}, - notMatches: []string{"foobar", "foo", "barfoo", "barfoobaz", "baz", "1foo", "afoo", "foo1", "fooz", "foomanybar"}, - hasWildcard: true, - }, - { - name: "meta chars", - matchName: ".+()|[]{}^$-_", - matches: []string{".+()|[]{}^$-_"}, // Note this is not a valid name. - notMatches: []string{"foobar", "foo", "barfoo", "barfoobaz", "baz", "1foo", "afoo", "foo1", "fooz", "foomanybar", "foo1bar", "fooabar"}, - hasWildcard: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - v, err := New(MatchInstrumentName(tt.matchName)) - require.NoError(t, err) - - t.Log(v.instrumentName.String()) - assert.Equal(t, tt.hasWildcard, v.hasWildcard) - for _, name := range tt.matches { - assert.Truef(t, v.matchName(name), "name: %s", name) - } - for _, name := range tt.notMatches { - assert.Falsef(t, v.matchName(name), "name: %s", name) - } - }) - } -} - -func TestViewAttributeFilterNoFilter(t *testing.T) { - v, err := New( - MatchInstrumentName("*"), - ) - require.NoError(t, err) - filter := v.AttributeFilter() - assert.Nil(t, filter) - - v, err = New( - MatchInstrumentName("*"), - WithFilterAttributes(), - ) - require.NoError(t, err) - filter = v.AttributeFilter() - assert.Nil(t, filter) - - v, err = New( - MatchInstrumentName("*"), - WithFilterAttributes([]attribute.Key{}...), - ) - require.NoError(t, err) - filter = v.AttributeFilter() - assert.Nil(t, filter) -} - -func TestViewAttributeFilter(t *testing.T) { - inputSet := attribute.NewSet( - attribute.String("foo", "bar"), - attribute.Int("power-level", 9001), - attribute.Float64("lifeUniverseEverything", 42.0), - ) - - tests := []struct { - name string - filter []attribute.Key - want attribute.Set - }{ - { - name: "Match 1", - filter: []attribute.Key{ - attribute.Key("power-level"), - }, - want: attribute.NewSet( - attribute.Int("power-level", 9001), - ), - }, - { - name: "Match 2", - filter: []attribute.Key{ - attribute.Key("foo"), - attribute.Key("lifeUniverseEverything"), - }, - want: attribute.NewSet( - attribute.Float64("lifeUniverseEverything", 42.0), - attribute.String("foo", "bar"), - ), - }, - { - name: "Don't match", - filter: []attribute.Key{ - attribute.Key("nothing"), - }, - want: attribute.NewSet(), - }, - { - name: "Match some", - filter: []attribute.Key{ - attribute.Key("power-level"), - attribute.Key("nothing"), - }, - want: attribute.NewSet( - attribute.Int("power-level", 9001), - ), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - v, err := New( - MatchInstrumentName("*"), - WithFilterAttributes(tt.filter...), - ) - require.NoError(t, err) - filter := v.AttributeFilter() - require.NotNil(t, filter) - - got := filter(inputSet) - assert.Equal(t, got.Equivalent(), tt.want.Equivalent()) - }) - } -} - -func TestNewErrors(t *testing.T) { - tests := []struct { - name string - options []Option - }{ - { - name: "No Match Option", - options: []Option{}, - }, - { - name: "Match * with view name", - options: []Option{ - MatchInstrumentName("*"), - WithRename("newName"), - }, - }, - { - name: "Match expand * with view name", - options: []Option{ - MatchInstrumentName("old*"), - WithRename("newName"), - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := New(tt.options...) - - assert.Equal(t, View{}, got) - assert.Error(t, err) - }) - } -}