diff --git a/CODEOWNERS b/CODEOWNERS index c7e2ac013..868eb2405 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -12,6 +12,6 @@ # https://help.github.com/en/articles/about-code-owners # -* @tedsuo @jmacd @paivagustavo @krnowak @lizthegrey @MrAlias @Aneurysm9 +* @jmacd @paivagustavo @lizthegrey @MrAlias @Aneurysm9 @evantorrie CODEOWNERS @MrAlias @jmacd diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c4ee829d8..67a2e08bf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -139,11 +139,10 @@ https://github.com/open-telemetry/opentelemetry-specification/issues/165 Approvers: -- [Krzesimir Nowak](https://github.com/krnowak), Kinvolk - [Liz Fong-Jones](https://github.com/lizthegrey), Honeycomb - [Gustavo Silva Paiva](https://github.com/paivagustavo), Stilingue -- [Ted Young](https://github.com/tedsuo), LightStep - [Anthony Mirabella](https://github.com/Aneurysm9), Centene +- [Evan Torrie](https://github.com/evantorrie), Comcast Maintainers: diff --git a/Makefile b/Makefile index 507bdaa5b..9fd96fc9c 100644 --- a/Makefile +++ b/Makefile @@ -135,7 +135,11 @@ lint: $(TOOLS_DIR)/golangci-lint $(TOOLS_DIR)/misspell done generate: $(TOOLS_DIR)/stringer - PATH="$(TOOLS_DIR):$${PATH}" go generate ./... + set -e; for dir in $(ALL_GO_MOD_DIRS); do \ + echo "running generators in $${dir}"; \ + (cd "$${dir}" && \ + PATH="$(TOOLS_DIR):$${PATH}" go generate ./...); \ + done .PHONY: license-check license-check: diff --git a/api/core/key.go b/api/core/key.go deleted file mode 100644 index 45fec60ed..000000000 --- a/api/core/key.go +++ /dev/null @@ -1,389 +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 core - -//go:generate stringer -type=ValueType - -import ( - "encoding/json" - "fmt" - "strconv" - "unsafe" -) - -// Key represents the key part in key-value pairs. It's a string. The -// allowed character set in the key depends on the use of the key. -type Key string - -// KeyValue holds a key and value pair. -type KeyValue struct { - Key Key - Value Value -} - -// ValueType describes the type of the data Value holds. -type ValueType int - -// Value represents the value part in key-value pairs. -type Value struct { - vtype ValueType - numeric uint64 - stringly string - // TODO Lazy value type? -} - -const ( - INVALID ValueType = iota // No value. - BOOL // Boolean value, use AsBool() to get it. - INT32 // 32 bit signed integral value, use AsInt32() to get it. - INT64 // 64 bit signed integral value, use AsInt64() to get it. - UINT32 // 32 bit unsigned integral value, use AsUint32() to get it. - UINT64 // 64 bit unsigned integral value, use AsUint64() to get it. - FLOAT32 // 32 bit floating point value, use AsFloat32() to get it. - FLOAT64 // 64 bit floating point value, use AsFloat64() to get it. - STRING // String value, use AsString() to get it. -) - -// Bool creates a BOOL Value. -func Bool(v bool) Value { - return Value{ - vtype: BOOL, - numeric: boolToRaw(v), - } -} - -// Int64 creates an INT64 Value. -func Int64(v int64) Value { - return Value{ - vtype: INT64, - numeric: int64ToRaw(v), - } -} - -// Uint64 creates a UINT64 Value. -func Uint64(v uint64) Value { - return Value{ - vtype: UINT64, - numeric: uint64ToRaw(v), - } -} - -// Float64 creates a FLOAT64 Value. -func Float64(v float64) Value { - return Value{ - vtype: FLOAT64, - numeric: float64ToRaw(v), - } -} - -// Int32 creates an INT32 Value. -func Int32(v int32) Value { - return Value{ - vtype: INT32, - numeric: int32ToRaw(v), - } -} - -// Uint32 creates a UINT32 Value. -func Uint32(v uint32) Value { - return Value{ - vtype: UINT32, - numeric: uint32ToRaw(v), - } -} - -// Float32 creates a FLOAT32 Value. -func Float32(v float32) Value { - return Value{ - vtype: FLOAT32, - numeric: float32ToRaw(v), - } -} - -// String creates a STRING Value. -func String(v string) Value { - return Value{ - vtype: STRING, - stringly: v, - } -} - -// Int creates either an INT32 or an INT64 Value, depending on whether -// the int type is 32 or 64 bits wide. -func Int(v int) Value { - if unsafe.Sizeof(v) == 4 { - return Int32(int32(v)) - } - return Int64(int64(v)) -} - -// Uint creates either a UINT32 or a UINT64 Value, depending on -// whether the uint type is 32 or 64 bits wide. -func Uint(v uint) Value { - if unsafe.Sizeof(v) == 4 { - return Uint32(uint32(v)) - } - return Uint64(uint64(v)) -} - -// Bool creates a KeyValue instance with a BOOL Value. -// -// If creating both key and a bool value at the same time, then -// instead of calling core.Key(name).Bool(value) consider using a -// convenience function provided by the api/key package - -// key.Bool(name, value). -func (k Key) Bool(v bool) KeyValue { - return KeyValue{ - Key: k, - Value: Bool(v), - } -} - -// Int64 creates a KeyValue instance with an INT64 Value. -// -// If creating both key and an int64 value at the same time, then -// instead of calling core.Key(name).Int64(value) consider using a -// convenience function provided by the api/key package - -// key.Int64(name, value). -func (k Key) Int64(v int64) KeyValue { - return KeyValue{ - Key: k, - Value: Int64(v), - } -} - -// Uint64 creates a KeyValue instance with a UINT64 Value. -// -// If creating both key and a uint64 value at the same time, then -// instead of calling core.Key(name).Uint64(value) consider using a -// convenience function provided by the api/key package - -// key.Uint64(name, value). -func (k Key) Uint64(v uint64) KeyValue { - return KeyValue{ - Key: k, - Value: Uint64(v), - } -} - -// Float64 creates a KeyValue instance with a FLOAT64 Value. -// -// If creating both key and a float64 value at the same time, then -// instead of calling core.Key(name).Float64(value) consider using a -// convenience function provided by the api/key package - -// key.Float64(name, value). -func (k Key) Float64(v float64) KeyValue { - return KeyValue{ - Key: k, - Value: Float64(v), - } -} - -// Int32 creates a KeyValue instance with an INT32 Value. -// -// If creating both key and an int32 value at the same time, then -// instead of calling core.Key(name).Int32(value) consider using a -// convenience function provided by the api/key package - -// key.Int32(name, value). -func (k Key) Int32(v int32) KeyValue { - return KeyValue{ - Key: k, - Value: Int32(v), - } -} - -// Uint32 creates a KeyValue instance with a UINT32 Value. -// -// If creating both key and a uint32 value at the same time, then -// instead of calling core.Key(name).Uint32(value) consider using a -// convenience function provided by the api/key package - -// key.Uint32(name, value). -func (k Key) Uint32(v uint32) KeyValue { - return KeyValue{ - Key: k, - Value: Uint32(v), - } -} - -// Float32 creates a KeyValue instance with a FLOAT32 Value. -// -// If creating both key and a float32 value at the same time, then -// instead of calling core.Key(name).Float32(value) consider using a -// convenience function provided by the api/key package - -// key.Float32(name, value). -func (k Key) Float32(v float32) KeyValue { - return KeyValue{ - Key: k, - Value: Float32(v), - } -} - -// String creates a KeyValue instance with a STRING Value. -// -// If creating both key and a string value at the same time, then -// instead of calling core.Key(name).String(value) consider using a -// convenience function provided by the api/key package - -// key.String(name, value). -func (k Key) String(v string) KeyValue { - return KeyValue{ - Key: k, - Value: String(v), - } -} - -// Int creates a KeyValue instance with either an INT32 or an INT64 -// Value, depending on whether the int type is 32 or 64 bits wide. -// -// If creating both key and an int value at the same time, then -// instead of calling core.Key(name).Int(value) consider using a -// convenience function provided by the api/key package - -// key.Int(name, value). -func (k Key) Int(v int) KeyValue { - return KeyValue{ - Key: k, - Value: Int(v), - } -} - -// Uint creates a KeyValue instance with either a UINT32 or a UINT64 -// Value, depending on whether the uint type is 32 or 64 bits wide. -// -// If creating both key and a uint value at the same time, then -// instead of calling core.Key(name).Uint(value) consider using a -// convenience function provided by the api/key package - -// key.Uint(name, value). -func (k Key) Uint(v uint) KeyValue { - return KeyValue{ - Key: k, - Value: Uint(v), - } -} - -// Defined returns true for non-empty keys. -func (k Key) Defined() bool { - return len(k) != 0 -} - -// Type returns a type of the Value. -func (v Value) Type() ValueType { - return v.vtype -} - -// AsBool returns the bool value. Make sure that the Value's type is -// BOOL. -func (v Value) AsBool() bool { - return rawToBool(v.numeric) -} - -// AsInt32 returns the int32 value. Make sure that the Value's type is -// INT32. -func (v Value) AsInt32() int32 { - return rawToInt32(v.numeric) -} - -// AsInt64 returns the int64 value. Make sure that the Value's type is -// INT64. -func (v Value) AsInt64() int64 { - return rawToInt64(v.numeric) -} - -// AsUint32 returns the uint32 value. Make sure that the Value's type -// is UINT32. -func (v Value) AsUint32() uint32 { - return rawToUint32(v.numeric) -} - -// AsUint64 returns the uint64 value. Make sure that the Value's type is -// UINT64. -func (v Value) AsUint64() uint64 { - return rawToUint64(v.numeric) -} - -// AsFloat32 returns the float32 value. Make sure that the Value's -// type is FLOAT32. -func (v Value) AsFloat32() float32 { - return rawToFloat32(v.numeric) -} - -// AsFloat64 returns the float64 value. Make sure that the Value's -// type is FLOAT64. -func (v Value) AsFloat64() float64 { - return rawToFloat64(v.numeric) -} - -// AsString returns the string value. Make sure that the Value's type -// is STRING. -func (v Value) AsString() string { - return v.stringly -} - -type unknownValueType struct{} - -// AsInterface returns Value's data as interface{}. -func (v Value) AsInterface() interface{} { - switch v.Type() { - case BOOL: - return v.AsBool() - case INT32: - return v.AsInt32() - case INT64: - return v.AsInt64() - case UINT32: - return v.AsUint32() - case UINT64: - return v.AsUint64() - case FLOAT32: - return v.AsFloat32() - case FLOAT64: - return v.AsFloat64() - case STRING: - return v.stringly - } - return unknownValueType{} -} - -// Emit returns a string representation of Value's data. -func (v Value) Emit() string { - switch v.Type() { - case BOOL: - return strconv.FormatBool(v.AsBool()) - case INT32: - return strconv.FormatInt(int64(v.AsInt32()), 10) - case INT64: - return strconv.FormatInt(v.AsInt64(), 10) - case UINT32: - return strconv.FormatUint(uint64(v.AsUint32()), 10) - case UINT64: - return strconv.FormatUint(v.AsUint64(), 10) - case FLOAT32: - return fmt.Sprint(v.AsFloat32()) - case FLOAT64: - return fmt.Sprint(v.AsFloat64()) - case STRING: - return v.stringly - default: - return "unknown" - } -} - -// MarshalJSON returns the JSON encoding of the Value. -func (v Value) MarshalJSON() ([]byte, error) { - var jsonVal struct { - Type string - Value interface{} - } - jsonVal.Type = v.Type().String() - jsonVal.Value = v.AsInterface() - return json.Marshal(jsonVal) -} diff --git a/api/core/key_test.go b/api/core/key_test.go deleted file mode 100644 index 8c5f4b9ff..000000000 --- a/api/core/key_test.go +++ /dev/null @@ -1,275 +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 core_test - -import ( - "encoding/json" - "testing" - "unsafe" - - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/require" - - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" -) - -func TestValue(t *testing.T) { - k := core.Key("test") - bli := getBitlessInfo(42) - for _, testcase := range []struct { - name string - value core.Value - wantType core.ValueType - wantValue interface{} - }{ - { - name: "Key.Bool() correctly returns keys's internal bool value", - value: k.Bool(true).Value, - wantType: core.BOOL, - wantValue: true, - }, - { - name: "Key.Int64() correctly returns keys's internal int64 value", - value: k.Int64(42).Value, - wantType: core.INT64, - wantValue: int64(42), - }, - { - name: "Key.Uint64() correctly returns keys's internal uint64 value", - value: k.Uint64(42).Value, - wantType: core.UINT64, - wantValue: uint64(42), - }, - { - name: "Key.Float64() correctly returns keys's internal float64 value", - value: k.Float64(42.1).Value, - wantType: core.FLOAT64, - wantValue: 42.1, - }, - { - name: "Key.Int32() correctly returns keys's internal int32 value", - value: k.Int32(42).Value, - wantType: core.INT32, - wantValue: int32(42), - }, - { - name: "Key.Uint32() correctly returns keys's internal uint32 value", - value: k.Uint32(42).Value, - wantType: core.UINT32, - wantValue: uint32(42), - }, - { - name: "Key.Float32() correctly returns keys's internal float32 value", - value: k.Float32(42.1).Value, - wantType: core.FLOAT32, - wantValue: float32(42.1), - }, - { - name: "Key.String() correctly returns keys's internal string value", - value: k.String("foo").Value, - wantType: core.STRING, - wantValue: "foo", - }, - { - name: "Key.Int() correctly returns keys's internal signed integral value", - value: k.Int(bli.intValue).Value, - wantType: bli.signedType, - wantValue: bli.signedValue, - }, - { - name: "Key.Uint() correctly returns keys's internal unsigned integral value", - value: k.Uint(bli.uintValue).Value, - wantType: bli.unsignedType, - wantValue: bli.unsignedValue, - }, - } { - t.Logf("Running test case %s", testcase.name) - if testcase.value.Type() != testcase.wantType { - t.Errorf("wrong value type, got %#v, expected %#v", testcase.value.Type(), testcase.wantType) - } - got := testcase.value.AsInterface() - if diff := cmp.Diff(testcase.wantValue, got); diff != "" { - t.Errorf("+got, -want: %s", diff) - } - } -} - -type bitlessInfo struct { - intValue int - uintValue uint - signedType core.ValueType - unsignedType core.ValueType - signedValue interface{} - unsignedValue interface{} -} - -func getBitlessInfo(i int) bitlessInfo { - if unsafe.Sizeof(i) == 4 { - return bitlessInfo{ - intValue: i, - uintValue: uint(i), - signedType: core.INT32, - unsignedType: core.UINT32, - signedValue: int32(i), - unsignedValue: uint32(i), - } - } - return bitlessInfo{ - intValue: i, - uintValue: uint(i), - signedType: core.INT64, - unsignedType: core.UINT64, - signedValue: int64(i), - unsignedValue: uint64(i), - } -} - -func TestDefined(t *testing.T) { - for _, testcase := range []struct { - name string - k core.Key - want bool - }{ - { - name: "Key.Defined() returns true when len(v.Name) != 0", - k: core.Key("foo"), - want: true, - }, - { - name: "Key.Defined() returns false when len(v.Name) == 0", - k: core.Key(""), - want: false, - }, - } { - t.Run(testcase.name, func(t *testing.T) { - //func (k core.Key) Defined() bool { - have := testcase.k.Defined() - if have != testcase.want { - t.Errorf("Want: %v, but have: %v", testcase.want, have) - } - }) - } -} - -func TestJSONValue(t *testing.T) { - var kvs interface{} = [2]core.KeyValue{ - key.String("A", "B"), - key.Int64("C", 1), - } - - data, err := json.Marshal(kvs) - require.NoError(t, err) - require.Equal(t, - `[{"Key":"A","Value":{"Type":"STRING","Value":"B"}},{"Key":"C","Value":{"Type":"INT64","Value":1}}]`, - string(data)) -} - -func TestEmit(t *testing.T) { - for _, testcase := range []struct { - name string - v core.Value - want string - }{ - { - name: `test Key.Emit() can emit a string representing self.BOOL`, - v: core.Bool(true), - want: "true", - }, - { - name: `test Key.Emit() can emit a string representing self.INT32`, - v: core.Int32(42), - want: "42", - }, - { - name: `test Key.Emit() can emit a string representing self.INT64`, - v: core.Int64(42), - want: "42", - }, - { - name: `test Key.Emit() can emit a string representing self.UINT32`, - v: core.Uint32(42), - want: "42", - }, - { - name: `test Key.Emit() can emit a string representing self.UINT64`, - v: core.Uint64(42), - want: "42", - }, - { - name: `test Key.Emit() can emit a string representing self.FLOAT32`, - v: core.Float32(42.1), - want: "42.1", - }, - { - name: `test Key.Emit() can emit a string representing self.FLOAT64`, - v: core.Float64(42.1), - want: "42.1", - }, - { - name: `test Key.Emit() can emit a string representing self.STRING`, - v: core.String("foo"), - want: "foo", - }, - } { - t.Run(testcase.name, func(t *testing.T) { - //proto: func (v core.Value) Emit() string { - have := testcase.v.Emit() - if have != testcase.want { - t.Errorf("Want: %s, but have: %s", testcase.want, have) - } - }) - } -} - -func BenchmarkEmitBool(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - n := core.Bool(i%2 == 0) - _ = n.Emit() - } -} - -func BenchmarkEmitInt64(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - n := core.Int64(int64(i)) - _ = n.Emit() - } -} - -func BenchmarkEmitUInt64(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - n := core.Uint64(uint64(i)) - _ = n.Emit() - } -} - -func BenchmarkEmitFloat64(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - n := core.Float64(float64(i)) - _ = n.Emit() - } -} - -func BenchmarkEmitFloat32(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - n := core.Float32(float32(i)) - _ = n.Emit() - } -} diff --git a/api/core/valuetype_string.go b/api/core/valuetype_string.go deleted file mode 100644 index 35d2175cb..000000000 --- a/api/core/valuetype_string.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated by "stringer -type=ValueType"; DO NOT EDIT. - -package core - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[INVALID-0] - _ = x[BOOL-1] - _ = x[INT32-2] - _ = x[INT64-3] - _ = x[UINT32-4] - _ = x[UINT64-5] - _ = x[FLOAT32-6] - _ = x[FLOAT64-7] - _ = x[STRING-8] -} - -const _ValueType_name = "INVALIDBOOLINT32INT64UINT32UINT64FLOAT32FLOAT64STRING" - -var _ValueType_index = [...]uint8{0, 7, 11, 16, 21, 27, 33, 40, 47, 53} - -func (i ValueType) String() string { - if i < 0 || i >= ValueType(len(_ValueType_index)-1) { - return "ValueType(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _ValueType_name[_ValueType_index[i]:_ValueType_index[i+1]] -} diff --git a/api/correlation/context.go b/api/correlation/context.go index aa83ac4e2..155452063 100644 --- a/api/correlation/context.go +++ b/api/correlation/context.go @@ -17,7 +17,7 @@ package correlation import ( "context" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" ) type correlationsType struct{} @@ -150,7 +150,7 @@ func ContextWithMap(ctx context.Context, m Map) context.Context { // NewContext returns a context with the map from passed context // updated with the passed key-value pairs. -func NewContext(ctx context.Context, keyvalues ...core.KeyValue) context.Context { +func NewContext(ctx context.Context, keyvalues ...kv.KeyValue) context.Context { return ContextWithMap(ctx, MapFromContext(ctx).Apply(MapUpdate{ MultiKV: keyvalues, })) diff --git a/api/correlation/correlation_context_propagator.go b/api/correlation/correlation_context_propagator.go index 3ae2b931e..172a3b902 100644 --- a/api/correlation/correlation_context_propagator.go +++ b/api/correlation/correlation_context_propagator.go @@ -19,12 +19,13 @@ import ( "net/url" "strings" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/propagation" ) -const correlationContextHeader = "Correlation-Context" +// Temporary header name until W3C finalizes format. +// https://github.com/open-telemetry/opentelemetry-specification/blob/18b2752ebe6c7f0cdd8c7b2bcbdceb0ae3f5ad95/specification/correlationcontext/api.md#header-name +const correlationContextHeader = "otcorrelations" // CorrelationContext propagates Key:Values in W3C CorrelationContext // format. @@ -44,7 +45,7 @@ func (CorrelationContext) Inject(ctx context.Context, supplier propagation.HTTPS correlationCtx := MapFromContext(ctx) firstIter := true var headerValueBuilder strings.Builder - correlationCtx.Foreach(func(kv core.KeyValue) bool { + correlationCtx.Foreach(func(kv kv.KeyValue) bool { if !firstIter { headerValueBuilder.WriteRune(',') } @@ -68,7 +69,7 @@ func (CorrelationContext) Extract(ctx context.Context, supplier propagation.HTTP } contextValues := strings.Split(correlationContext, ",") - keyValues := make([]core.KeyValue, 0, len(contextValues)) + keyValues := make([]kv.KeyValue, 0, len(contextValues)) for _, contextValue := range contextValues { valueAndProps := strings.Split(contextValue, ";") if len(valueAndProps) < 1 { @@ -98,7 +99,7 @@ func (CorrelationContext) Extract(ctx context.Context, supplier propagation.HTTP trimmedValueWithProps.WriteString(prop) } - keyValues = append(keyValues, key.New(trimmedName).String(trimmedValueWithProps.String())) + keyValues = append(keyValues, kv.Key(trimmedName).String(trimmedValueWithProps.String())) } return ContextWithMap(ctx, NewMap(MapUpdate{ MultiKV: keyValues, diff --git a/api/correlation/correlation_context_propagator_test.go b/api/correlation/correlation_context_propagator_test.go index 5b4539a74..5a88133eb 100644 --- a/api/correlation/correlation_context_propagator_test.go +++ b/api/correlation/correlation_context_propagator_test.go @@ -20,11 +20,12 @@ import ( "strings" "testing" + "go.opentelemetry.io/otel/api/kv/value" + "github.com/google/go-cmp/cmp" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/correlation" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/propagation" ) @@ -33,54 +34,54 @@ func TestExtractValidDistributedContextFromHTTPReq(t *testing.T) { tests := []struct { name string header string - wantKVs []core.KeyValue + wantKVs []kv.KeyValue }{ { name: "valid w3cHeader", header: "key1=val1,key2=val2", - wantKVs: []core.KeyValue{ - key.New("key1").String("val1"), - key.New("key2").String("val2"), + wantKVs: []kv.KeyValue{ + kv.Key("key1").String("val1"), + kv.Key("key2").String("val2"), }, }, { name: "valid w3cHeader with spaces", header: "key1 = val1, key2 =val2 ", - wantKVs: []core.KeyValue{ - key.New("key1").String("val1"), - key.New("key2").String("val2"), + wantKVs: []kv.KeyValue{ + kv.Key("key1").String("val1"), + kv.Key("key2").String("val2"), }, }, { name: "valid w3cHeader with properties", header: "key1=val1,key2=val2;prop=1", - wantKVs: []core.KeyValue{ - key.New("key1").String("val1"), - key.New("key2").String("val2;prop=1"), + wantKVs: []kv.KeyValue{ + kv.Key("key1").String("val1"), + kv.Key("key2").String("val2;prop=1"), }, }, { name: "valid header with url-escaped comma", header: "key1=val1,key2=val2%2Cval3", - wantKVs: []core.KeyValue{ - key.New("key1").String("val1"), - key.New("key2").String("val2,val3"), + wantKVs: []kv.KeyValue{ + kv.Key("key1").String("val1"), + kv.Key("key2").String("val2,val3"), }, }, { name: "valid header with an invalid header", header: "key1=val1,key2=val2,a,val3", - wantKVs: []core.KeyValue{ - key.New("key1").String("val1"), - key.New("key2").String("val2"), + wantKVs: []kv.KeyValue{ + kv.Key("key1").String("val1"), + kv.Key("key2").String("val2"), }, }, { name: "valid header with no value", header: "key1=,key2=val2", - wantKVs: []core.KeyValue{ - key.New("key1").String(""), - key.New("key2").String("val2"), + wantKVs: []kv.KeyValue{ + kv.Key("key1").String(""), + kv.Key("key2").String("val2"), }, }, } @@ -88,7 +89,7 @@ func TestExtractValidDistributedContextFromHTTPReq(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req, _ := http.NewRequest("GET", "http://example.com", nil) - req.Header.Set("Correlation-Context", tt.header) + req.Header.Set("otcorrelations", tt.header) ctx := context.Background() ctx = propagation.ExtractHTTP(ctx, props, req.Header) @@ -102,9 +103,9 @@ func TestExtractValidDistributedContextFromHTTPReq(t *testing.T) { ) } totalDiff := "" - wantCorCtx.Foreach(func(kv core.KeyValue) bool { - val, _ := gotCorCtx.Value(kv.Key) - diff := cmp.Diff(kv, core.KeyValue{Key: kv.Key, Value: val}, cmp.AllowUnexported(core.Value{})) + wantCorCtx.Foreach(func(keyValue kv.KeyValue) bool { + val, _ := gotCorCtx.Value(keyValue.Key) + diff := cmp.Diff(keyValue, kv.KeyValue{Key: keyValue.Key, Value: val}, cmp.AllowUnexported(value.Value{})) if diff != "" { totalDiff += diff + "\n" } @@ -132,7 +133,7 @@ func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req, _ := http.NewRequest("GET", "http://example.com", nil) - req.Header.Set("Correlation-Context", tt.header) + req.Header.Set("otcorrelations", tt.header) ctx := context.Background() ctx = propagation.ExtractHTTP(ctx, props, req.Header) @@ -149,38 +150,38 @@ func TestInjectCorrelationContextToHTTPReq(t *testing.T) { props := propagation.New(propagation.WithInjectors(propagator)) tests := []struct { name string - kvs []core.KeyValue + kvs []kv.KeyValue wantInHeader []string wantedLen int }{ { name: "two simple values", - kvs: []core.KeyValue{ - key.New("key1").String("val1"), - key.New("key2").String("val2"), + kvs: []kv.KeyValue{ + kv.Key("key1").String("val1"), + kv.Key("key2").String("val2"), }, wantInHeader: []string{"key1=val1", "key2=val2"}, }, { name: "two values with escaped chars", - kvs: []core.KeyValue{ - key.New("key1").String("val1,val2"), - key.New("key2").String("val3=4"), + kvs: []kv.KeyValue{ + kv.Key("key1").String("val1,val2"), + kv.Key("key2").String("val3=4"), }, wantInHeader: []string{"key1=val1%2Cval2", "key2=val3%3D4"}, }, { name: "values of non-string types", - kvs: []core.KeyValue{ - key.New("key1").Bool(true), - key.New("key2").Int(123), - key.New("key3").Int64(123), - key.New("key4").Int32(123), - key.New("key5").Uint(123), - key.New("key6").Uint32(123), - key.New("key7").Uint64(123), - key.New("key8").Float64(123.567), - key.New("key9").Float32(123.567), + kvs: []kv.KeyValue{ + kv.Key("key1").Bool(true), + kv.Key("key2").Int(123), + kv.Key("key3").Int64(123), + kv.Key("key4").Int32(123), + kv.Key("key5").Uint(123), + kv.Key("key6").Uint32(123), + kv.Key("key7").Uint64(123), + kv.Key("key8").Float64(123.567), + kv.Key("key9").Float32(123.567), }, wantInHeader: []string{ "key1=true", @@ -201,17 +202,17 @@ func TestInjectCorrelationContextToHTTPReq(t *testing.T) { ctx := correlation.ContextWithMap(context.Background(), correlation.NewMap(correlation.MapUpdate{MultiKV: tt.kvs})) propagation.InjectHTTP(ctx, props, req.Header) - gotHeader := req.Header.Get("Correlation-Context") + gotHeader := req.Header.Get("otcorrelations") wantedLen := len(strings.Join(tt.wantInHeader, ",")) if wantedLen != len(gotHeader) { t.Errorf( - "%s: Inject Correlation-Context incorrect length %d != %d.", tt.name, tt.wantedLen, len(gotHeader), + "%s: Inject otcorrelations incorrect length %d != %d.", tt.name, tt.wantedLen, len(gotHeader), ) } for _, inHeader := range tt.wantInHeader { if !strings.Contains(gotHeader, inHeader) { t.Errorf( - "%s: Inject Correlation-Context missing part of header: %s in %s", tt.name, inHeader, gotHeader, + "%s: Inject otcorrelations missing part of header: %s in %s", tt.name, inHeader, gotHeader, ) } } @@ -221,7 +222,7 @@ func TestInjectCorrelationContextToHTTPReq(t *testing.T) { func TestTraceContextPropagator_GetAllKeys(t *testing.T) { var propagator correlation.CorrelationContext - want := []string{"Correlation-Context"} + want := []string{"otcorrelations"} got := propagator.GetAllKeys() if diff := cmp.Diff(got, want); diff != "" { t.Errorf("GetAllKeys: -got +want %s", diff) diff --git a/api/correlation/map.go b/api/correlation/map.go index 79a4f1868..93e92eedd 100644 --- a/api/correlation/map.go +++ b/api/correlation/map.go @@ -15,11 +15,12 @@ package correlation import ( - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" + "go.opentelemetry.io/otel/api/kv/value" ) -type rawMap map[core.Key]core.Value -type keySet map[core.Key]struct{} +type rawMap map[kv.Key]value.Value +type keySet map[kv.Key]struct{} // Map is an immutable storage for correlations. type Map struct { @@ -32,18 +33,18 @@ type MapUpdate struct { // DropSingleK contains a single key to be dropped from // correlations. Use this to avoid an overhead of a slice // allocation if there is only one key to drop. - DropSingleK core.Key + DropSingleK kv.Key // DropMultiK contains all the keys to be dropped from // correlations. - DropMultiK []core.Key + DropMultiK []kv.Key // SingleKV contains a single key-value pair to be added to // correlations. Use this to avoid an overhead of a slice // allocation if there is only one key-value pair to add. - SingleKV core.KeyValue + SingleKV kv.KeyValue // MultiKV contains all the key-value pairs to be added to // correlations. - MultiKV []core.KeyValue + MultiKV []kv.KeyValue } func newMap(raw rawMap) Map { @@ -101,7 +102,7 @@ func getModificationSets(update MapUpdate) (delSet, addSet keySet) { deletionsCount++ } if deletionsCount > 0 { - delSet = make(map[core.Key]struct{}, deletionsCount) + delSet = make(map[kv.Key]struct{}, deletionsCount) for _, k := range update.DropMultiK { delSet[k] = struct{}{} } @@ -115,7 +116,7 @@ func getModificationSets(update MapUpdate) (delSet, addSet keySet) { additionsCount++ } if additionsCount > 0 { - addSet = make(map[core.Key]struct{}, additionsCount) + addSet = make(map[kv.Key]struct{}, additionsCount) for _, k := range update.MultiKV { addSet[k.Key] = struct{}{} } @@ -146,14 +147,14 @@ func getNewMapSize(m rawMap, delSet, addSet keySet) int { // Value gets a value from correlations map and returns a boolean // value indicating whether the key exist in the map. -func (m Map) Value(k core.Key) (core.Value, bool) { +func (m Map) Value(k kv.Key) (value.Value, bool) { value, ok := m.m[k] return value, ok } // HasValue returns a boolean value indicating whether the key exist // in the map. -func (m Map) HasValue(k core.Key) bool { +func (m Map) HasValue(k kv.Key) bool { _, has := m.Value(k) return has } @@ -166,9 +167,9 @@ func (m Map) Len() int { // Foreach calls a passed callback once on each key-value pair until // all the key-value pairs of the map were iterated or the callback // returns false, whichever happens first. -func (m Map) Foreach(f func(kv core.KeyValue) bool) { +func (m Map) Foreach(f func(kv kv.KeyValue) bool) { for k, v := range m.m { - if !f(core.KeyValue{ + if !f(kv.KeyValue{ Key: k, Value: v, }) { diff --git a/api/correlation/map_test.go b/api/correlation/map_test.go index de0db6c6d..c886b842d 100644 --- a/api/correlation/map_test.go +++ b/api/correlation/map_test.go @@ -18,15 +18,16 @@ import ( "fmt" "testing" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv/value" + + "go.opentelemetry.io/otel/api/kv" ) type testCase struct { name string value MapUpdate init []int - wantKVs []core.KeyValue + wantKVs []kv.KeyValue } func TestMap(t *testing.T) { @@ -47,7 +48,7 @@ func TestMap(t *testing.T) { } } // test Foreach() - got.Foreach(func(kv core.KeyValue) bool { + got.Foreach(func(kv kv.KeyValue) bool { for _, want := range testcase.wantKVs { if kv == want { return false @@ -85,193 +86,193 @@ func TestSizeComputation(t *testing.T) { func getTestCases() []testCase { return []testCase{ { - name: "New map with MultiKV", - value: MapUpdate{MultiKV: []core.KeyValue{ - key.Int64("key1", 1), - key.String("key2", "val2")}, + name: "map with MultiKV", + value: MapUpdate{MultiKV: []kv.KeyValue{ + kv.Int64("key1", 1), + kv.String("key2", "val2")}, }, init: []int{}, - wantKVs: []core.KeyValue{ - key.Int64("key1", 1), - key.String("key2", "val2"), + wantKVs: []kv.KeyValue{ + kv.Int64("key1", 1), + kv.String("key2", "val2"), }, }, { - name: "New map with SingleKV", - value: MapUpdate{SingleKV: key.String("key1", "val1")}, + name: "map with SingleKV", + value: MapUpdate{SingleKV: kv.String("key1", "val1")}, init: []int{}, - wantKVs: []core.KeyValue{ - key.String("key1", "val1"), + wantKVs: []kv.KeyValue{ + kv.String("key1", "val1"), }, }, { - name: "New map with both add fields", - value: MapUpdate{SingleKV: key.Int64("key1", 3), - MultiKV: []core.KeyValue{ - key.String("key1", ""), - key.String("key2", "val2")}, + name: "map with both add fields", + value: MapUpdate{SingleKV: kv.Int64("key1", 3), + MultiKV: []kv.KeyValue{ + kv.String("key1", ""), + kv.String("key2", "val2")}, }, init: []int{}, - wantKVs: []core.KeyValue{ - key.String("key1", ""), - key.String("key2", "val2"), + wantKVs: []kv.KeyValue{ + kv.String("key1", ""), + kv.String("key2", "val2"), }, }, { - name: "New map with empty MapUpdate", + name: "map with empty MapUpdate", value: MapUpdate{}, init: []int{}, - wantKVs: []core.KeyValue{}, + wantKVs: []kv.KeyValue{}, }, { - name: "New map with DropSingleK", - value: MapUpdate{DropSingleK: core.Key("key1")}, + name: "map with DropSingleK", + value: MapUpdate{DropSingleK: kv.Key("key1")}, init: []int{}, - wantKVs: []core.KeyValue{}, + wantKVs: []kv.KeyValue{}, }, { - name: "New map with DropMultiK", - value: MapUpdate{DropMultiK: []core.Key{ - core.Key("key1"), core.Key("key2"), + name: "map with DropMultiK", + value: MapUpdate{DropMultiK: []kv.Key{ + kv.Key("key1"), kv.Key("key2"), }}, init: []int{}, - wantKVs: []core.KeyValue{}, + wantKVs: []kv.KeyValue{}, }, { - name: "New map with both drop fields", + name: "map with both drop fields", value: MapUpdate{ - DropSingleK: core.Key("key1"), - DropMultiK: []core.Key{ - core.Key("key1"), - core.Key("key2"), + DropSingleK: kv.Key("key1"), + DropMultiK: []kv.Key{ + kv.Key("key1"), + kv.Key("key2"), }, }, init: []int{}, - wantKVs: []core.KeyValue{}, + wantKVs: []kv.KeyValue{}, }, { - name: "New map with all fields", + name: "map with all fields", value: MapUpdate{ - DropSingleK: core.Key("key1"), - DropMultiK: []core.Key{ - core.Key("key1"), - core.Key("key2"), + DropSingleK: kv.Key("key1"), + DropMultiK: []kv.Key{ + kv.Key("key1"), + kv.Key("key2"), }, - SingleKV: key.String("key4", "val4"), - MultiKV: []core.KeyValue{ - key.String("key1", ""), - key.String("key2", "val2"), - key.String("key3", "val3"), + SingleKV: kv.String("key4", "val4"), + MultiKV: []kv.KeyValue{ + kv.String("key1", ""), + kv.String("key2", "val2"), + kv.String("key3", "val3"), }, }, init: []int{}, - wantKVs: []core.KeyValue{ - key.String("key1", ""), - key.String("key2", "val2"), - key.String("key3", "val3"), - key.String("key4", "val4"), + wantKVs: []kv.KeyValue{ + kv.String("key1", ""), + kv.String("key2", "val2"), + kv.String("key3", "val3"), + kv.String("key4", "val4"), }, }, { name: "Existing map with MultiKV", - value: MapUpdate{MultiKV: []core.KeyValue{ - key.Int64("key1", 1), - key.String("key2", "val2")}, + value: MapUpdate{MultiKV: []kv.KeyValue{ + kv.Int64("key1", 1), + kv.String("key2", "val2")}, }, init: []int{5}, - wantKVs: []core.KeyValue{ - key.Int64("key1", 1), - key.String("key2", "val2"), - key.Int("key5", 5), + wantKVs: []kv.KeyValue{ + kv.Int64("key1", 1), + kv.String("key2", "val2"), + kv.Int("key5", 5), }, }, { name: "Existing map with SingleKV", - value: MapUpdate{SingleKV: key.String("key1", "val1")}, + value: MapUpdate{SingleKV: kv.String("key1", "val1")}, init: []int{5}, - wantKVs: []core.KeyValue{ - key.String("key1", "val1"), - key.Int("key5", 5), + wantKVs: []kv.KeyValue{ + kv.String("key1", "val1"), + kv.Int("key5", 5), }, }, { name: "Existing map with both add fields", - value: MapUpdate{SingleKV: key.Int64("key1", 3), - MultiKV: []core.KeyValue{ - key.String("key1", ""), - key.String("key2", "val2")}, + value: MapUpdate{SingleKV: kv.Int64("key1", 3), + MultiKV: []kv.KeyValue{ + kv.String("key1", ""), + kv.String("key2", "val2")}, }, init: []int{5}, - wantKVs: []core.KeyValue{ - key.String("key1", ""), - key.String("key2", "val2"), - key.Int("key5", 5), + wantKVs: []kv.KeyValue{ + kv.String("key1", ""), + kv.String("key2", "val2"), + kv.Int("key5", 5), }, }, { name: "Existing map with empty MapUpdate", value: MapUpdate{}, init: []int{5}, - wantKVs: []core.KeyValue{ - key.Int("key5", 5), + wantKVs: []kv.KeyValue{ + kv.Int("key5", 5), }, }, { name: "Existing map with DropSingleK", - value: MapUpdate{DropSingleK: core.Key("key1")}, + value: MapUpdate{DropSingleK: kv.Key("key1")}, init: []int{1, 5}, - wantKVs: []core.KeyValue{ - key.Int("key5", 5), + wantKVs: []kv.KeyValue{ + kv.Int("key5", 5), }, }, { name: "Existing map with DropMultiK", - value: MapUpdate{DropMultiK: []core.Key{ - core.Key("key1"), core.Key("key2"), + value: MapUpdate{DropMultiK: []kv.Key{ + kv.Key("key1"), kv.Key("key2"), }}, init: []int{1, 5}, - wantKVs: []core.KeyValue{ - key.Int("key5", 5), + wantKVs: []kv.KeyValue{ + kv.Int("key5", 5), }, }, { name: "Existing map with both drop fields", value: MapUpdate{ - DropSingleK: core.Key("key1"), - DropMultiK: []core.Key{ - core.Key("key1"), - core.Key("key2"), + DropSingleK: kv.Key("key1"), + DropMultiK: []kv.Key{ + kv.Key("key1"), + kv.Key("key2"), }, }, init: []int{1, 2, 5}, - wantKVs: []core.KeyValue{ - key.Int("key5", 5), + wantKVs: []kv.KeyValue{ + kv.Int("key5", 5), }, }, { name: "Existing map with all the fields", value: MapUpdate{ - DropSingleK: core.Key("key1"), - DropMultiK: []core.Key{ - core.Key("key1"), - core.Key("key2"), - core.Key("key5"), - core.Key("key6"), + DropSingleK: kv.Key("key1"), + DropMultiK: []kv.Key{ + kv.Key("key1"), + kv.Key("key2"), + kv.Key("key5"), + kv.Key("key6"), }, - SingleKV: key.String("key4", "val4"), - MultiKV: []core.KeyValue{ - key.String("key1", ""), - key.String("key2", "val2"), - key.String("key3", "val3"), + SingleKV: kv.String("key4", "val4"), + MultiKV: []kv.KeyValue{ + kv.String("key1", ""), + kv.String("key2", "val2"), + kv.String("key3", "val3"), }, }, init: []int{5, 6, 7}, - wantKVs: []core.KeyValue{ - key.String("key1", ""), - key.String("key2", "val2"), - key.String("key3", "val3"), - key.String("key4", "val4"), - key.Int("key7", 7), + wantKVs: []kv.KeyValue{ + kv.String("key1", ""), + kv.String("key2", "val2"), + kv.String("key3", "val3"), + kv.String("key4", "val4"), + kv.Int("key7", 7), }, }, } @@ -280,7 +281,7 @@ func getTestCases() []testCase { func makeTestMap(ints []int) Map { r := make(rawMap, len(ints)) for _, v := range ints { - r[core.Key(fmt.Sprintf("key%d", v))] = core.Int(v) + r[kv.Key(fmt.Sprintf("key%d", v))] = value.Int(v) } return newMap(r) } diff --git a/api/global/global_test.go b/api/global/global_test.go index 3265c1d2b..974077aa6 100644 --- a/api/global/global_test.go +++ b/api/global/global_test.go @@ -37,7 +37,7 @@ func (*testTraceProvider) Tracer(_ string) trace.Tracer { } func (*testMeterProvider) Meter(_ string) metric.Meter { - return &metric.NoopMeter{} + return metric.Meter{} } func TestMultipleGlobalTracerProvider(t *testing.T) { diff --git a/api/global/internal/benchmark_test.go b/api/global/internal/benchmark_test.go index 92a431fac..66a3728d1 100644 --- a/api/global/internal/benchmark_test.go +++ b/api/global/internal/benchmark_test.go @@ -19,10 +19,9 @@ import ( "strings" "testing" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/global" "go.opentelemetry.io/otel/api/global/internal" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/api/trace" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -38,9 +37,9 @@ var Must = metric.Must // benchFixture is copied from sdk/metric/benchmark_test.go. // TODO refactor to share this code. type benchFixture struct { - sdk *sdk.SDK - meter metric.Meter - B *testing.B + accumulator *sdk.Accumulator + meter metric.Meter + B *testing.B } var _ metric.Provider = &benchFixture{} @@ -51,8 +50,8 @@ func newFixture(b *testing.B) *benchFixture { B: b, } - bf.sdk = sdk.New(bf) - bf.meter = metric.WrapMeterImpl(bf.sdk, "test") + bf.accumulator = sdk.NewAccumulator(bf) + bf.meter = metric.WrapMeterImpl(bf.accumulator, "test") return bf } @@ -91,7 +90,7 @@ func BenchmarkGlobalInt64CounterAddNoSDK(b *testing.B) { internal.ResetForTest() ctx := context.Background() sdk := global.Meter("test") - labs := []core.KeyValue{key.String("A", "B")} + labs := []kv.KeyValue{kv.String("A", "B")} cnt := Must(sdk).NewInt64Counter("int64.counter") b.ResetTimer() @@ -110,7 +109,7 @@ func BenchmarkGlobalInt64CounterAddWithSDK(b *testing.B) { global.SetMeterProvider(fix) - labs := []core.KeyValue{key.String("A", "B")} + labs := []kv.KeyValue{kv.String("A", "B")} cnt := Must(sdk).NewInt64Counter("int64.counter") b.ResetTimer() diff --git a/api/global/internal/meter.go b/api/global/internal/meter.go index d15e2b378..723def119 100644 --- a/api/global/internal/meter.go +++ b/api/global/internal/meter.go @@ -20,7 +20,7 @@ import ( "sync/atomic" "unsafe" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/api/metric/registry" ) @@ -49,22 +49,27 @@ import ( type meterProvider struct { delegate metric.Provider - lock sync.Mutex - meters map[string]*meter + // lock protects `delegate` and `meters`. + lock sync.Mutex + + // meters maintains a unique entry for every named Meter + // that has been registered through the global instance. + meters map[string]*meterEntry } -type meter struct { - delegate unsafe.Pointer // (*metric.Meter) - - provider *meterProvider - name string +type meterImpl struct { + delegate unsafe.Pointer // (*metric.MeterImpl) lock sync.Mutex - registry map[string]metric.InstrumentImpl syncInsts []*syncImpl asyncInsts []*asyncImpl } +type meterEntry struct { + unique metric.MeterImpl + impl meterImpl +} + type instrument struct { descriptor metric.Descriptor } @@ -73,8 +78,6 @@ type syncImpl struct { delegate unsafe.Pointer // (*metric.SyncImpl) instrument - - constructor func(metric.Meter) (metric.SyncImpl, error) } type asyncImpl struct { @@ -82,7 +85,7 @@ type asyncImpl struct { instrument - constructor func(metric.Meter) (metric.AsyncImpl, error) + runner metric.AsyncRunner } // SyncImpler is implemented by all of the sync metric @@ -101,13 +104,13 @@ type syncHandle struct { delegate unsafe.Pointer // (*metric.HandleImpl) inst *syncImpl - labels []core.KeyValue + labels []kv.KeyValue initialize sync.Once } var _ metric.Provider = &meterProvider{} -var _ metric.Meter = &meter{} +var _ metric.MeterImpl = &meterImpl{} var _ metric.InstrumentImpl = &syncImpl{} var _ metric.BoundSyncImpl = &syncHandle{} var _ metric.AsyncImpl = &asyncImpl{} @@ -120,7 +123,7 @@ func (inst *instrument) Descriptor() metric.Descriptor { func newMeterProvider() *meterProvider { return &meterProvider{ - meters: map[string]*meter{}, + meters: map[string]*meterEntry{}, } } @@ -129,8 +132,8 @@ func (p *meterProvider) setDelegate(provider metric.Provider) { defer p.lock.Unlock() p.delegate = provider - for _, m := range p.meters { - m.setDelegate(provider) + for name, entry := range p.meters { + entry.impl.setDelegate(name, provider) } p.meters = nil } @@ -143,29 +146,24 @@ func (p *meterProvider) Meter(name string) metric.Meter { return p.delegate.Meter(name) } - if exm, ok := p.meters[name]; ok { - return exm - } + entry, ok := p.meters[name] + if !ok { + entry = &meterEntry{} + entry.unique = registry.NewUniqueInstrumentMeterImpl(&entry.impl) + p.meters[name] = entry - m := &meter{ - provider: p, - name: name, - registry: map[string]metric.InstrumentImpl{}, - syncInsts: []*syncImpl{}, - asyncInsts: []*asyncImpl{}, } - p.meters[name] = m - return m + return metric.WrapMeterImpl(entry.unique, name) } // Meter interface and delegation -func (m *meter) setDelegate(provider metric.Provider) { +func (m *meterImpl) setDelegate(name string, provider metric.Provider) { m.lock.Lock() defer m.lock.Unlock() - d := new(metric.Meter) - *d = provider.Meter(m.name) + d := new(metric.MeterImpl) + *d = provider.Meter(name).MeterImpl() m.delegate = unsafe.Pointer(d) for _, inst := range m.syncInsts { @@ -178,49 +176,30 @@ func (m *meter) setDelegate(provider metric.Provider) { m.asyncInsts = nil } -func (m *meter) newSync(desc metric.Descriptor, constructor func(metric.Meter) (metric.SyncImpl, error)) (metric.SyncImpl, error) { +func (m *meterImpl) NewSyncInstrument(desc metric.Descriptor) (metric.SyncImpl, error) { m.lock.Lock() defer m.lock.Unlock() - if meterPtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { - return constructor(*meterPtr) - } - - if ex, ok := m.registry[desc.Name()]; ok { - if !registry.Compatible(desc, ex.Descriptor()) { - return nil, registry.NewMetricKindMismatchError(ex.Descriptor()) - } - return ex.(metric.SyncImpl), nil + if meterPtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { + return (*meterPtr).NewSyncInstrument(desc) } inst := &syncImpl{ instrument: instrument{ descriptor: desc, }, - constructor: constructor, } m.syncInsts = append(m.syncInsts, inst) - m.registry[desc.Name()] = inst return inst, nil } -func syncCheck(has SyncImpler, err error) (metric.SyncImpl, error) { - if has != nil { - return has.SyncImpl(), err - } - if err == nil { - err = metric.ErrSDKReturnedNilImpl - } - return nil, err -} - // Synchronous delegation -func (inst *syncImpl) setDelegate(d metric.Meter) { +func (inst *syncImpl) setDelegate(d metric.MeterImpl) { implPtr := new(metric.SyncImpl) var err error - *implPtr, err = inst.constructor(d) + *implPtr, err = d.NewSyncInstrument(inst.descriptor) if err != nil { // TODO: There is no standard way to deliver this error to the user. @@ -240,7 +219,7 @@ func (inst *syncImpl) Implementation() interface{} { return inst } -func (inst *syncImpl) Bind(labels []core.KeyValue) metric.BoundSyncImpl { +func (inst *syncImpl) Bind(labels []kv.KeyValue) metric.BoundSyncImpl { if implPtr := (*metric.SyncImpl)(atomic.LoadPointer(&inst.delegate)); implPtr != nil { return (*implPtr).Bind(labels) } @@ -264,29 +243,25 @@ func (bound *syncHandle) Unbind() { // Async delegation -func (m *meter) newAsync(desc metric.Descriptor, constructor func(metric.Meter) (metric.AsyncImpl, error)) (metric.AsyncImpl, error) { +func (m *meterImpl) NewAsyncInstrument( + desc metric.Descriptor, + runner metric.AsyncRunner, +) (metric.AsyncImpl, error) { + m.lock.Lock() defer m.lock.Unlock() - if meterPtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { - return constructor(*meterPtr) - } - - if ex, ok := m.registry[desc.Name()]; ok { - if !registry.Compatible(desc, ex.Descriptor()) { - return nil, registry.NewMetricKindMismatchError(ex.Descriptor()) - } - return ex.(metric.AsyncImpl), nil + if meterPtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { + return (*meterPtr).NewAsyncInstrument(desc, runner) } inst := &asyncImpl{ instrument: instrument{ descriptor: desc, }, - constructor: constructor, + runner: runner, } m.asyncInsts = append(m.asyncInsts, inst) - m.registry[desc.Name()] = inst return inst, nil } @@ -297,21 +272,11 @@ func (obs *asyncImpl) Implementation() interface{} { return obs } -func asyncCheck(has AsyncImpler, err error) (metric.AsyncImpl, error) { - if has != nil { - return has.AsyncImpl(), err - } - if err == nil { - err = metric.ErrSDKReturnedNilImpl - } - return nil, err -} - -func (obs *asyncImpl) setDelegate(d metric.Meter) { +func (obs *asyncImpl) setDelegate(d metric.MeterImpl) { implPtr := new(metric.AsyncImpl) var err error - *implPtr, err = obs.constructor(d) + *implPtr, err = d.NewAsyncInstrument(obs.descriptor, obs.runner) if err != nil { // TODO: There is no standard way to deliver this error to the user. @@ -326,13 +291,13 @@ func (obs *asyncImpl) setDelegate(d metric.Meter) { // Metric updates -func (m *meter) RecordBatch(ctx context.Context, labels []core.KeyValue, measurements ...metric.Measurement) { - if delegatePtr := (*metric.Meter)(atomic.LoadPointer(&m.delegate)); delegatePtr != nil { +func (m *meterImpl) RecordBatch(ctx context.Context, labels []kv.KeyValue, measurements ...metric.Measurement) { + if delegatePtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); delegatePtr != nil { (*delegatePtr).RecordBatch(ctx, labels, measurements...) } } -func (inst *syncImpl) RecordOne(ctx context.Context, number core.Number, labels []core.KeyValue) { +func (inst *syncImpl) RecordOne(ctx context.Context, number metric.Number, labels []kv.KeyValue) { if instPtr := (*metric.SyncImpl)(atomic.LoadPointer(&inst.delegate)); instPtr != nil { (*instPtr).RecordOne(ctx, number, labels) } @@ -340,7 +305,7 @@ func (inst *syncImpl) RecordOne(ctx context.Context, number core.Number, labels // Bound instrument initialization -func (bound *syncHandle) RecordOne(ctx context.Context, number core.Number) { +func (bound *syncHandle) RecordOne(ctx context.Context, number metric.Number) { instPtr := (*metric.SyncImpl)(atomic.LoadPointer(&bound.inst.delegate)) if instPtr == nil { return @@ -363,64 +328,10 @@ func (bound *syncHandle) RecordOne(ctx context.Context, number core.Number) { (*implPtr).RecordOne(ctx, number) } -// Constructors - -func (m *meter) withName(opts []metric.Option) []metric.Option { - return append(opts, metric.WithLibraryName(m.name)) -} - -func (m *meter) NewInt64Counter(name string, opts ...metric.Option) (metric.Int64Counter, error) { - return metric.WrapInt64CounterInstrument(m.newSync( - metric.NewDescriptor(name, metric.CounterKind, core.Int64NumberKind, m.withName(opts)...), - func(other metric.Meter) (metric.SyncImpl, error) { - return syncCheck(other.NewInt64Counter(name, opts...)) - })) -} - -func (m *meter) NewFloat64Counter(name string, opts ...metric.Option) (metric.Float64Counter, error) { - return metric.WrapFloat64CounterInstrument(m.newSync( - metric.NewDescriptor(name, metric.CounterKind, core.Float64NumberKind, m.withName(opts)...), - func(other metric.Meter) (metric.SyncImpl, error) { - return syncCheck(other.NewFloat64Counter(name, opts...)) - })) -} - -func (m *meter) NewInt64Measure(name string, opts ...metric.Option) (metric.Int64Measure, error) { - return metric.WrapInt64MeasureInstrument(m.newSync( - metric.NewDescriptor(name, metric.MeasureKind, core.Int64NumberKind, m.withName(opts)...), - func(other metric.Meter) (metric.SyncImpl, error) { - return syncCheck(other.NewInt64Measure(name, opts...)) - })) -} - -func (m *meter) NewFloat64Measure(name string, opts ...metric.Option) (metric.Float64Measure, error) { - return metric.WrapFloat64MeasureInstrument(m.newSync( - metric.NewDescriptor(name, metric.MeasureKind, core.Float64NumberKind, m.withName(opts)...), - func(other metric.Meter) (metric.SyncImpl, error) { - return syncCheck(other.NewFloat64Measure(name, opts...)) - })) -} - -func (m *meter) RegisterInt64Observer(name string, callback metric.Int64ObserverCallback, opts ...metric.Option) (metric.Int64Observer, error) { - return metric.WrapInt64ObserverInstrument(m.newAsync( - metric.NewDescriptor(name, metric.ObserverKind, core.Int64NumberKind, m.withName(opts)...), - func(other metric.Meter) (metric.AsyncImpl, error) { - return asyncCheck(other.RegisterInt64Observer(name, callback, opts...)) - })) -} - -func (m *meter) RegisterFloat64Observer(name string, callback metric.Float64ObserverCallback, opts ...metric.Option) (metric.Float64Observer, error) { - return metric.WrapFloat64ObserverInstrument(m.newAsync( - metric.NewDescriptor(name, metric.ObserverKind, core.Float64NumberKind, m.withName(opts)...), - func(other metric.Meter) (metric.AsyncImpl, error) { - return asyncCheck(other.RegisterFloat64Observer(name, callback, opts...)) - })) -} - func AtomicFieldOffsets() map[string]uintptr { return map[string]uintptr{ "meterProvider.delegate": unsafe.Offsetof(meterProvider{}.delegate), - "meter.delegate": unsafe.Offsetof(meter{}.delegate), + "meterImpl.delegate": unsafe.Offsetof(meterImpl{}.delegate), "syncImpl.delegate": unsafe.Offsetof(syncImpl{}.delegate), "asyncImpl.delegate": unsafe.Offsetof(asyncImpl{}.delegate), "syncHandle.delegate": unsafe.Offsetof(syncHandle{}.delegate), diff --git a/api/global/internal/meter_test.go b/api/global/internal/meter_test.go index 89691b686..070e65221 100644 --- a/api/global/internal/meter_test.go +++ b/api/global/internal/meter_test.go @@ -22,12 +22,13 @@ import ( "io/ioutil" "testing" + "go.opentelemetry.io/otel/api/kv/value" + "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/global" "go.opentelemetry.io/otel/api/global/internal" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/exporters/metric/stdout" metrictest "go.opentelemetry.io/otel/internal/metric" @@ -37,8 +38,8 @@ import ( type measured struct { Name string LibraryName string - Labels map[core.Key]core.Value - Number core.Number + Labels map[kv.Key]value.Value + Number metric.Number } func asStructs(batches []metrictest.Batch) []measured { @@ -56,16 +57,16 @@ func asStructs(batches []metrictest.Batch) []measured { return r } -func asMap(kvs ...core.KeyValue) map[core.Key]core.Value { - m := map[core.Key]core.Value{} +func asMap(kvs ...kv.KeyValue) map[kv.Key]value.Value { + m := map[kv.Key]value.Value{} for _, kv := range kvs { m[kv.Key] = kv.Value } return m } -var asInt = core.NewInt64Number -var asFloat = core.NewFloat64Number +var asInt = metric.NewInt64Number +var asFloat = metric.NewFloat64Number func TestDirect(t *testing.T) { internal.ResetForTest() @@ -73,9 +74,9 @@ func TestDirect(t *testing.T) { ctx := context.Background() meter1 := global.Meter("test1") meter2 := global.Meter("test2") - labels1 := []core.KeyValue{key.String("A", "B")} - labels2 := []core.KeyValue{key.String("C", "D")} - labels3 := []core.KeyValue{key.String("E", "F")} + labels1 := []kv.KeyValue{kv.String("A", "B")} + labels2 := []kv.KeyValue{kv.String("C", "D")} + labels3 := []kv.KeyValue{kv.String("E", "F")} counter := Must(meter1).NewInt64Counter("test.counter") counter.Add(ctx, 1, labels1...) @@ -166,7 +167,7 @@ func TestBound(t *testing.T) { // vs. the above, to cover all the instruments. ctx := context.Background() glob := global.Meter("test") - labels1 := []core.KeyValue{key.String("A", "B")} + labels1 := []kv.KeyValue{kv.String("A", "B")} counter := Must(glob).NewFloat64Counter("test.counter") boundC := counter.Bind(labels1...) @@ -210,7 +211,7 @@ func TestUnbind(t *testing.T) { internal.ResetForTest() glob := global.Meter("test") - labels1 := []core.KeyValue{key.String("A", "B")} + labels1 := []kv.KeyValue{kv.String("A", "B")} counter := Must(glob).NewFloat64Counter("test.counter") boundC := counter.Bind(labels1...) @@ -227,7 +228,7 @@ func TestDefaultSDK(t *testing.T) { ctx := context.Background() meter1 := global.Meter("builtin") - labels1 := []core.KeyValue{key.String("A", "B")} + labels1 := []kv.KeyValue{kv.String("A", "B")} counter := Must(meter1).NewInt64Counter("test.builtin") counter.Add(ctx, 1, labels1...) @@ -280,15 +281,15 @@ type meterProviderWithConstructorError struct { } type meterWithConstructorError struct { - metric.Meter + metric.MeterImpl } func (m *meterProviderWithConstructorError) Meter(name string) metric.Meter { - return &meterWithConstructorError{m.Provider.Meter(name)} + return metric.WrapMeterImpl(&meterWithConstructorError{m.Provider.Meter(name).MeterImpl()}, name) } -func (m *meterWithConstructorError) NewInt64Counter(name string, opts ...metric.Option) (metric.Int64Counter, error) { - return metric.Int64Counter{}, errors.New("constructor error") +func (m *meterWithConstructorError) NewSyncInstrument(_ metric.Descriptor) (metric.SyncImpl, error) { + return metric.NoopSync{}, errors.New("constructor error") } func TestErrorInDeferredConstructor(t *testing.T) { diff --git a/api/core/rawhelpers.go b/api/internal/rawhelpers.go similarity index 57% rename from api/core/rawhelpers.go rename to api/internal/rawhelpers.go index 1e8c7252f..dae825ed8 100644 --- a/api/core/rawhelpers.go +++ b/api/internal/rawhelpers.go @@ -12,80 +12,80 @@ // See the License for the specific language governing permissions and // limitations under the License. -package core +package internal import ( "math" "unsafe" ) -func boolToRaw(b bool) uint64 { +func BoolToRaw(b bool) uint64 { if b { return 1 } return 0 } -func rawToBool(r uint64) bool { +func RawToBool(r uint64) bool { return r != 0 } -func int64ToRaw(i int64) uint64 { +func Int64ToRaw(i int64) uint64 { return uint64(i) } -func rawToInt64(r uint64) int64 { +func RawToInt64(r uint64) int64 { return int64(r) } -func uint64ToRaw(u uint64) uint64 { +func Uint64ToRaw(u uint64) uint64 { return u } -func rawToUint64(r uint64) uint64 { +func RawToUint64(r uint64) uint64 { return r } -func float64ToRaw(f float64) uint64 { +func Float64ToRaw(f float64) uint64 { return math.Float64bits(f) } -func rawToFloat64(r uint64) float64 { +func RawToFloat64(r uint64) float64 { return math.Float64frombits(r) } -func int32ToRaw(i int32) uint64 { +func Int32ToRaw(i int32) uint64 { return uint64(i) } -func rawToInt32(r uint64) int32 { +func RawToInt32(r uint64) int32 { return int32(r) } -func uint32ToRaw(u uint32) uint64 { +func Uint32ToRaw(u uint32) uint64 { return uint64(u) } -func rawToUint32(r uint64) uint32 { +func RawToUint32(r uint64) uint32 { return uint32(r) } -func float32ToRaw(f float32) uint64 { - return uint32ToRaw(math.Float32bits(f)) +func Float32ToRaw(f float32) uint64 { + return Uint32ToRaw(math.Float32bits(f)) } -func rawToFloat32(r uint64) float32 { - return math.Float32frombits(rawToUint32(r)) +func RawToFloat32(r uint64) float32 { + return math.Float32frombits(RawToUint32(r)) } -func rawPtrToFloat64Ptr(r *uint64) *float64 { +func RawPtrToFloat64Ptr(r *uint64) *float64 { return (*float64)(unsafe.Pointer(r)) } -func rawPtrToInt64Ptr(r *uint64) *int64 { +func RawPtrToInt64Ptr(r *uint64) *int64 { return (*int64)(unsafe.Pointer(r)) } -func rawPtrToUint64Ptr(r *uint64) *uint64 { +func RawPtrToUint64Ptr(r *uint64) *uint64 { return r } diff --git a/api/key/benchmark_test.go b/api/kv/benchmark_test.go similarity index 90% rename from api/key/benchmark_test.go rename to api/kv/benchmark_test.go index d0e924018..a258e06ac 100644 --- a/api/key/benchmark_test.go +++ b/api/kv/benchmark_test.go @@ -12,14 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -package key_test +package kv_test import ( "context" "testing" + "go.opentelemetry.io/otel/api/kv" + "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/key" "go.opentelemetry.io/otel/api/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) @@ -35,7 +36,7 @@ func getSpan() trace.Span { func BenchmarkKeyInfer(b *testing.B) { for i := 0; i < b.N; i++ { - key.Infer("Attr", int(256)) + kv.Infer("Attr", int(256)) } } @@ -46,7 +47,7 @@ func BenchmarkMultiNoKeyInference(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - sp.SetAttributes(key.Int("Attr", 1)) + sp.SetAttributes(kv.Int("Attr", 1)) } } @@ -57,7 +58,7 @@ func BenchmarkMultiWithKeyInference(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - sp.SetAttributes(key.Infer("Attr", 1)) + sp.SetAttributes(kv.Infer("Attr", 1)) } } diff --git a/api/key/doc.go b/api/kv/doc.go similarity index 80% rename from api/key/doc.go rename to api/kv/doc.go index a4387b1ae..3e635cdc3 100644 --- a/api/key/doc.go +++ b/api/kv/doc.go @@ -12,6 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -// This package provides convenience functions for creating keys and -// key-value pairs. -package key // import "go.opentelemetry.io/otel/api/key" +// package kv provides basic key and value types. +package kv // import "go.opentelemetry.io/otel/api/kv" diff --git a/api/kv/key.go b/api/kv/key.go new file mode 100644 index 000000000..b1e04c447 --- /dev/null +++ b/api/kv/key.go @@ -0,0 +1,160 @@ +// 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 kv + +import ( + "go.opentelemetry.io/otel/api/kv/value" +) + +// Key represents the key part in key-value pairs. It's a string. The +// allowed character set in the key depends on the use of the key. +type Key string + +// Bool creates a KeyValue instance with a BOOL Value. +// +// If creating both key and a bool value at the same time, then +// instead of calling kv.Key(name).Bool(value) consider using a +// convenience function provided by the api/key package - +// key.Bool(name, value). +func (k Key) Bool(v bool) KeyValue { + return KeyValue{ + Key: k, + Value: value.Bool(v), + } +} + +// Int64 creates a KeyValue instance with an INT64 Value. +// +// If creating both key and an int64 value at the same time, then +// instead of calling kv.Key(name).Int64(value) consider using a +// convenience function provided by the api/key package - +// key.Int64(name, value). +func (k Key) Int64(v int64) KeyValue { + return KeyValue{ + Key: k, + Value: value.Int64(v), + } +} + +// Uint64 creates a KeyValue instance with a UINT64 Value. +// +// If creating both key and a uint64 value at the same time, then +// instead of calling kv.Key(name).Uint64(value) consider using a +// convenience function provided by the api/key package - +// key.Uint64(name, value). +func (k Key) Uint64(v uint64) KeyValue { + return KeyValue{ + Key: k, + Value: value.Uint64(v), + } +} + +// Float64 creates a KeyValue instance with a FLOAT64 Value. +// +// If creating both key and a float64 value at the same time, then +// instead of calling kv.Key(name).Float64(value) consider using a +// convenience function provided by the api/key package - +// key.Float64(name, value). +func (k Key) Float64(v float64) KeyValue { + return KeyValue{ + Key: k, + Value: value.Float64(v), + } +} + +// Int32 creates a KeyValue instance with an INT32 Value. +// +// If creating both key and an int32 value at the same time, then +// instead of calling kv.Key(name).Int32(value) consider using a +// convenience function provided by the api/key package - +// key.Int32(name, value). +func (k Key) Int32(v int32) KeyValue { + return KeyValue{ + Key: k, + Value: value.Int32(v), + } +} + +// Uint32 creates a KeyValue instance with a UINT32 Value. +// +// If creating both key and a uint32 value at the same time, then +// instead of calling kv.Key(name).Uint32(value) consider using a +// convenience function provided by the api/key package - +// key.Uint32(name, value). +func (k Key) Uint32(v uint32) KeyValue { + return KeyValue{ + Key: k, + Value: value.Uint32(v), + } +} + +// Float32 creates a KeyValue instance with a FLOAT32 Value. +// +// If creating both key and a float32 value at the same time, then +// instead of calling kv.Key(name).Float32(value) consider using a +// convenience function provided by the api/key package - +// key.Float32(name, value). +func (k Key) Float32(v float32) KeyValue { + return KeyValue{ + Key: k, + Value: value.Float32(v), + } +} + +// String creates a KeyValue instance with a STRING Value. +// +// If creating both key and a string value at the same time, then +// instead of calling kv.Key(name).String(value) consider using a +// convenience function provided by the api/key package - +// key.String(name, value). +func (k Key) String(v string) KeyValue { + return KeyValue{ + Key: k, + Value: value.String(v), + } +} + +// Int creates a KeyValue instance with either an INT32 or an INT64 +// Value, depending on whether the int type is 32 or 64 bits wide. +// +// If creating both key and an int value at the same time, then +// instead of calling kv.Key(name).Int(value) consider using a +// convenience function provided by the api/key package - +// key.Int(name, value). +func (k Key) Int(v int) KeyValue { + return KeyValue{ + Key: k, + Value: value.Int(v), + } +} + +// Uint creates a KeyValue instance with either a UINT32 or a UINT64 +// Value, depending on whether the uint type is 32 or 64 bits wide. +// +// If creating both key and a uint value at the same time, then +// instead of calling kv.Key(name).Uint(value) consider using a +// convenience function provided by the api/key package - +// key.Uint(name, value). +func (k Key) Uint(v uint) KeyValue { + return KeyValue{ + Key: k, + Value: value.Uint(v), + } +} + +// Defined returns true for non-empty keys. +func (k Key) Defined() bool { + return len(k) != 0 +} diff --git a/api/kv/key_test.go b/api/kv/key_test.go new file mode 100644 index 000000000..277750e02 --- /dev/null +++ b/api/kv/key_test.go @@ -0,0 +1,163 @@ +// 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 kv_test + +import ( + "encoding/json" + "testing" + + "go.opentelemetry.io/otel/api/kv" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/otel/api/kv/value" +) + +func TestDefined(t *testing.T) { + for _, testcase := range []struct { + name string + k kv.Key + want bool + }{ + { + name: "Key.Defined() returns true when len(v.Name) != 0", + k: kv.Key("foo"), + want: true, + }, + { + name: "Key.Defined() returns false when len(v.Name) == 0", + k: kv.Key(""), + want: false, + }, + } { + t.Run(testcase.name, func(t *testing.T) { + //func (k kv.Key) Defined() bool { + have := testcase.k.Defined() + if have != testcase.want { + t.Errorf("Want: %v, but have: %v", testcase.want, have) + } + }) + } +} + +func TestJSONValue(t *testing.T) { + var kvs interface{} = [2]kv.KeyValue{ + kv.String("A", "B"), + kv.Int64("C", 1), + } + + data, err := json.Marshal(kvs) + require.NoError(t, err) + require.Equal(t, + `[{"Key":"A","Value":{"Type":"STRING","Value":"B"}},{"Key":"C","Value":{"Type":"INT64","Value":1}}]`, + string(data)) +} + +func TestEmit(t *testing.T) { + for _, testcase := range []struct { + name string + v value.Value + want string + }{ + { + name: `test Key.Emit() can emit a string representing self.BOOL`, + v: value.Bool(true), + want: "true", + }, + { + name: `test Key.Emit() can emit a string representing self.INT32`, + v: value.Int32(42), + want: "42", + }, + { + name: `test Key.Emit() can emit a string representing self.INT64`, + v: value.Int64(42), + want: "42", + }, + { + name: `test Key.Emit() can emit a string representing self.UINT32`, + v: value.Uint32(42), + want: "42", + }, + { + name: `test Key.Emit() can emit a string representing self.UINT64`, + v: value.Uint64(42), + want: "42", + }, + { + name: `test Key.Emit() can emit a string representing self.FLOAT32`, + v: value.Float32(42.1), + want: "42.1", + }, + { + name: `test Key.Emit() can emit a string representing self.FLOAT64`, + v: value.Float64(42.1), + want: "42.1", + }, + { + name: `test Key.Emit() can emit a string representing self.STRING`, + v: value.String("foo"), + want: "foo", + }, + } { + t.Run(testcase.name, func(t *testing.T) { + //proto: func (v kv.Value) Emit() string { + have := testcase.v.Emit() + if have != testcase.want { + t.Errorf("Want: %s, but have: %s", testcase.want, have) + } + }) + } +} + +func BenchmarkEmitBool(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + n := value.Bool(i%2 == 0) + _ = n.Emit() + } +} + +func BenchmarkEmitInt64(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + n := value.Int64(int64(i)) + _ = n.Emit() + } +} + +func BenchmarkEmitUInt64(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + n := value.Uint64(uint64(i)) + _ = n.Emit() + } +} + +func BenchmarkEmitFloat64(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + n := value.Float64(float64(i)) + _ = n.Emit() + } +} + +func BenchmarkEmitFloat32(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + n := value.Float32(float32(i)) + _ = n.Emit() + } +} diff --git a/api/key/key.go b/api/kv/kv.go similarity index 73% rename from api/key/key.go rename to api/kv/kv.go index 2e0773944..e10b91349 100644 --- a/api/key/key.go +++ b/api/kv/kv.go @@ -12,91 +12,92 @@ // See the License for the specific language governing permissions and // limitations under the License. -package key +package kv import ( "fmt" "reflect" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv/value" ) -// New creates a new key with a passed name. -func New(name string) core.Key { - return core.Key(name) +// KeyValue holds a key and value pair. +type KeyValue struct { + Key Key + Value value.Value } // Bool creates a new key-value pair with a passed name and a bool // value. -func Bool(k string, v bool) core.KeyValue { - return New(k).Bool(v) +func Bool(k string, v bool) KeyValue { + return Key(k).Bool(v) } // Int64 creates a new key-value pair with a passed name and an int64 // value. -func Int64(k string, v int64) core.KeyValue { - return New(k).Int64(v) +func Int64(k string, v int64) KeyValue { + return Key(k).Int64(v) } // Uint64 creates a new key-value pair with a passed name and a uint64 // value. -func Uint64(k string, v uint64) core.KeyValue { - return New(k).Uint64(v) +func Uint64(k string, v uint64) KeyValue { + return Key(k).Uint64(v) } // Float64 creates a new key-value pair with a passed name and a float64 // value. -func Float64(k string, v float64) core.KeyValue { - return New(k).Float64(v) +func Float64(k string, v float64) KeyValue { + return Key(k).Float64(v) } // Int32 creates a new key-value pair with a passed name and an int32 // value. -func Int32(k string, v int32) core.KeyValue { - return New(k).Int32(v) +func Int32(k string, v int32) KeyValue { + return Key(k).Int32(v) } // Uint32 creates a new key-value pair with a passed name and a uint32 // value. -func Uint32(k string, v uint32) core.KeyValue { - return New(k).Uint32(v) +func Uint32(k string, v uint32) KeyValue { + return Key(k).Uint32(v) } // Float32 creates a new key-value pair with a passed name and a float32 // value. -func Float32(k string, v float32) core.KeyValue { - return New(k).Float32(v) +func Float32(k string, v float32) KeyValue { + return Key(k).Float32(v) } // String creates a new key-value pair with a passed name and a string // value. -func String(k, v string) core.KeyValue { - return New(k).String(v) +func String(k, v string) KeyValue { + return Key(k).String(v) } // Stringer creates a new key-value pair with a passed name and a string // value generated by the passed Stringer interface. -func Stringer(k string, v fmt.Stringer) core.KeyValue { - return New(k).String(v.String()) +func Stringer(k string, v fmt.Stringer) KeyValue { + return Key(k).String(v.String()) } // Int creates a new key-value pair instance with a passed name and // either an int32 or an int64 value, depending on whether the int // type is 32 or 64 bits wide. -func Int(k string, v int) core.KeyValue { - return New(k).Int(v) +func Int(k string, v int) KeyValue { + return Key(k).Int(v) } // Uint creates a new key-value pair instance with a passed name and // either an uint32 or an uint64 value, depending on whether the uint // type is 32 or 64 bits wide. -func Uint(k string, v uint) core.KeyValue { - return New(k).Uint(v) +func Uint(k string, v uint) KeyValue { + return Key(k).Uint(v) } // Infer creates a new key-value pair instance with a passed name and // automatic type inference. This is slower, and not type-safe. -func Infer(k string, value interface{}) core.KeyValue { +func Infer(k string, value interface{}) KeyValue { if value == nil { return String(k, "") } diff --git a/api/key/key_test.go b/api/kv/kv_test.go similarity index 63% rename from api/key/key_test.go rename to api/kv/kv_test.go index 6c76d5f41..9d2ccf476 100644 --- a/api/key/key_test.go +++ b/api/kv/kv_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package key_test +package kv_test import ( "strings" @@ -20,101 +20,101 @@ import ( "github.com/google/go-cmp/cmp" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" + "go.opentelemetry.io/otel/api/kv/value" ) func TestKeyValueConstructors(t *testing.T) { tt := []struct { name string - actual core.KeyValue - expected core.KeyValue + actual kv.KeyValue + expected kv.KeyValue }{ { name: "Bool", - actual: key.Bool("k1", true), - expected: core.KeyValue{ + actual: kv.Bool("k1", true), + expected: kv.KeyValue{ Key: "k1", - Value: core.Bool(true), + Value: value.Bool(true), }, }, { name: "Int64", - actual: key.Int64("k1", 123), - expected: core.KeyValue{ + actual: kv.Int64("k1", 123), + expected: kv.KeyValue{ Key: "k1", - Value: core.Int64(123), + Value: value.Int64(123), }, }, { name: "Uint64", - actual: key.Uint64("k1", 1), - expected: core.KeyValue{ + actual: kv.Uint64("k1", 1), + expected: kv.KeyValue{ Key: "k1", - Value: core.Uint64(1), + Value: value.Uint64(1), }, }, { name: "Float64", - actual: key.Float64("k1", 123.5), - expected: core.KeyValue{ + actual: kv.Float64("k1", 123.5), + expected: kv.KeyValue{ Key: "k1", - Value: core.Float64(123.5), + Value: value.Float64(123.5), }, }, { name: "Int32", - actual: key.Int32("k1", 123), - expected: core.KeyValue{ + actual: kv.Int32("k1", 123), + expected: kv.KeyValue{ Key: "k1", - Value: core.Int32(123), + Value: value.Int32(123), }, }, { name: "Uint32", - actual: key.Uint32("k1", 123), - expected: core.KeyValue{ + actual: kv.Uint32("k1", 123), + expected: kv.KeyValue{ Key: "k1", - Value: core.Uint32(123), + Value: value.Uint32(123), }, }, { name: "Float32", - actual: key.Float32("k1", 123.5), - expected: core.KeyValue{ + actual: kv.Float32("k1", 123.5), + expected: kv.KeyValue{ Key: "k1", - Value: core.Float32(123.5), + Value: value.Float32(123.5), }, }, { name: "String", - actual: key.String("k1", "123.5"), - expected: core.KeyValue{ + actual: kv.String("k1", "123.5"), + expected: kv.KeyValue{ Key: "k1", - Value: core.String("123.5"), + Value: value.String("123.5"), }, }, { name: "Int", - actual: key.Int("k1", 123), - expected: core.KeyValue{ + actual: kv.Int("k1", 123), + expected: kv.KeyValue{ Key: "k1", - Value: core.Int(123), + Value: value.Int(123), }, }, { name: "Uint", - actual: key.Uint("k1", 123), - expected: core.KeyValue{ + actual: kv.Uint("k1", 123), + expected: kv.KeyValue{ Key: "k1", - Value: core.Uint(123), + Value: value.Uint(123), }, }, } for _, test := range tt { t.Run(test.name, func(t *testing.T) { - if diff := cmp.Diff(test.actual, test.expected, cmp.AllowUnexported(core.Value{})); diff != "" { + if diff := cmp.Diff(test.actual, test.expected, cmp.AllowUnexported(value.Value{})); diff != "" { t.Fatal(diff) } }) @@ -127,76 +127,76 @@ func TestInfer(t *testing.T) { for _, testcase := range []struct { key string value interface{} - wantType core.ValueType + wantType value.Type wantValue interface{} }{ { key: "bool type inferred", value: true, - wantType: core.BOOL, + wantType: value.BOOL, wantValue: true, }, { key: "int64 type inferred", value: int64(42), - wantType: core.INT64, + wantType: value.INT64, wantValue: int64(42), }, { key: "uint64 type inferred", value: uint64(42), - wantType: core.UINT64, + wantType: value.UINT64, wantValue: uint64(42), }, { key: "float64 type inferred", value: float64(42.1), - wantType: core.FLOAT64, + wantType: value.FLOAT64, wantValue: 42.1, }, { key: "int32 type inferred", value: int32(42), - wantType: core.INT32, + wantType: value.INT32, wantValue: int32(42), }, { key: "uint32 type inferred", value: uint32(42), - wantType: core.UINT32, + wantType: value.UINT32, wantValue: uint32(42), }, { key: "float32 type inferred", value: float32(42.1), - wantType: core.FLOAT32, + wantType: value.FLOAT32, wantValue: float32(42.1), }, { key: "string type inferred", value: "foo", - wantType: core.STRING, + wantType: value.STRING, wantValue: "foo", }, { key: "stringer type inferred", value: builder, - wantType: core.STRING, + wantType: value.STRING, wantValue: "foo", }, { key: "unknown value serialized as %v", value: nil, - wantType: core.STRING, + wantType: value.STRING, wantValue: "", }, } { t.Logf("Running test case %s", testcase.key) - kv := key.Infer(testcase.key, testcase.value) - if kv.Value.Type() != testcase.wantType { - t.Errorf("wrong value type, got %#v, expected %#v", kv.Value.Type(), testcase.wantType) + keyValue := kv.Infer(testcase.key, testcase.value) + if keyValue.Value.Type() != testcase.wantType { + t.Errorf("wrong value type, got %#v, expected %#v", keyValue.Value.Type(), testcase.wantType) } - got := kv.Value.AsInterface() + got := keyValue.Value.AsInterface() if diff := cmp.Diff(testcase.wantValue, got); diff != "" { t.Errorf("+got, -want: %s", diff) } diff --git a/api/kv/value/type_string.go b/api/kv/value/type_string.go new file mode 100644 index 000000000..ae4b00324 --- /dev/null +++ b/api/kv/value/type_string.go @@ -0,0 +1,31 @@ +// Code generated by "stringer -type=Type"; DO NOT EDIT. + +package value + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[INVALID-0] + _ = x[BOOL-1] + _ = x[INT32-2] + _ = x[INT64-3] + _ = x[UINT32-4] + _ = x[UINT64-5] + _ = x[FLOAT32-6] + _ = x[FLOAT64-7] + _ = x[STRING-8] +} + +const _Type_name = "INVALIDBOOLINT32INT64UINT32UINT64FLOAT32FLOAT64STRING" + +var _Type_index = [...]uint8{0, 7, 11, 16, 21, 27, 33, 40, 47, 53} + +func (i Type) String() string { + if i < 0 || i >= Type(len(_Type_index)-1) { + return "Type(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Type_name[_Type_index[i]:_Type_index[i+1]] +} diff --git a/api/kv/value/value.go b/api/kv/value/value.go new file mode 100644 index 000000000..0e52da19b --- /dev/null +++ b/api/kv/value/value.go @@ -0,0 +1,244 @@ +// 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 value + +import ( + "encoding/json" + "fmt" + "strconv" + "unsafe" + + "go.opentelemetry.io/otel/api/internal" +) + +//go:generate stringer -type=Type + +// Type describes the type of the data Value holds. +type Type int + +// Value represents the value part in key-value pairs. +type Value struct { + vtype Type + numeric uint64 + stringly string + // TODO Lazy value type? +} + +const ( + INVALID Type = iota // No value. + BOOL // Boolean value, use AsBool() to get it. + INT32 // 32 bit signed integral value, use AsInt32() to get it. + INT64 // 64 bit signed integral value, use AsInt64() to get it. + UINT32 // 32 bit unsigned integral value, use AsUint32() to get it. + UINT64 // 64 bit unsigned integral value, use AsUint64() to get it. + FLOAT32 // 32 bit floating point value, use AsFloat32() to get it. + FLOAT64 // 64 bit floating point value, use AsFloat64() to get it. + STRING // String value, use AsString() to get it. +) + +// Bool creates a BOOL Value. +func Bool(v bool) Value { + return Value{ + vtype: BOOL, + numeric: internal.BoolToRaw(v), + } +} + +// Int64 creates an INT64 Value. +func Int64(v int64) Value { + return Value{ + vtype: INT64, + numeric: internal.Int64ToRaw(v), + } +} + +// Uint64 creates a UINT64 Value. +func Uint64(v uint64) Value { + return Value{ + vtype: UINT64, + numeric: internal.Uint64ToRaw(v), + } +} + +// Float64 creates a FLOAT64 Value. +func Float64(v float64) Value { + return Value{ + vtype: FLOAT64, + numeric: internal.Float64ToRaw(v), + } +} + +// Int32 creates an INT32 Value. +func Int32(v int32) Value { + return Value{ + vtype: INT32, + numeric: internal.Int32ToRaw(v), + } +} + +// Uint32 creates a UINT32 Value. +func Uint32(v uint32) Value { + return Value{ + vtype: UINT32, + numeric: internal.Uint32ToRaw(v), + } +} + +// Float32 creates a FLOAT32 Value. +func Float32(v float32) Value { + return Value{ + vtype: FLOAT32, + numeric: internal.Float32ToRaw(v), + } +} + +// String creates a STRING Value. +func String(v string) Value { + return Value{ + vtype: STRING, + stringly: v, + } +} + +// Int creates either an INT32 or an INT64 Value, depending on whether +// the int type is 32 or 64 bits wide. +func Int(v int) Value { + if unsafe.Sizeof(v) == 4 { + return Int32(int32(v)) + } + return Int64(int64(v)) +} + +// Uint creates either a UINT32 or a UINT64 Value, depending on +// whether the uint type is 32 or 64 bits wide. +func Uint(v uint) Value { + if unsafe.Sizeof(v) == 4 { + return Uint32(uint32(v)) + } + return Uint64(uint64(v)) +} + +// Type returns a type of the Value. +func (v Value) Type() Type { + return v.vtype +} + +// AsBool returns the bool value. Make sure that the Value's type is +// BOOL. +func (v Value) AsBool() bool { + return internal.RawToBool(v.numeric) +} + +// AsInt32 returns the int32 value. Make sure that the Value's type is +// INT32. +func (v Value) AsInt32() int32 { + return internal.RawToInt32(v.numeric) +} + +// AsInt64 returns the int64 value. Make sure that the Value's type is +// INT64. +func (v Value) AsInt64() int64 { + return internal.RawToInt64(v.numeric) +} + +// AsUint32 returns the uint32 value. Make sure that the Value's type +// is UINT32. +func (v Value) AsUint32() uint32 { + return internal.RawToUint32(v.numeric) +} + +// AsUint64 returns the uint64 value. Make sure that the Value's type is +// UINT64. +func (v Value) AsUint64() uint64 { + return internal.RawToUint64(v.numeric) +} + +// AsFloat32 returns the float32 value. Make sure that the Value's +// type is FLOAT32. +func (v Value) AsFloat32() float32 { + return internal.RawToFloat32(v.numeric) +} + +// AsFloat64 returns the float64 value. Make sure that the Value's +// type is FLOAT64. +func (v Value) AsFloat64() float64 { + return internal.RawToFloat64(v.numeric) +} + +// AsString returns the string value. Make sure that the Value's type +// is STRING. +func (v Value) AsString() string { + return v.stringly +} + +type unknownValueType struct{} + +// AsInterface returns Value's data as interface{}. +func (v Value) AsInterface() interface{} { + switch v.Type() { + case BOOL: + return v.AsBool() + case INT32: + return v.AsInt32() + case INT64: + return v.AsInt64() + case UINT32: + return v.AsUint32() + case UINT64: + return v.AsUint64() + case FLOAT32: + return v.AsFloat32() + case FLOAT64: + return v.AsFloat64() + case STRING: + return v.stringly + } + return unknownValueType{} +} + +// Emit returns a string representation of Value's data. +func (v Value) Emit() string { + switch v.Type() { + case BOOL: + return strconv.FormatBool(v.AsBool()) + case INT32: + return strconv.FormatInt(int64(v.AsInt32()), 10) + case INT64: + return strconv.FormatInt(v.AsInt64(), 10) + case UINT32: + return strconv.FormatUint(uint64(v.AsUint32()), 10) + case UINT64: + return strconv.FormatUint(v.AsUint64(), 10) + case FLOAT32: + return fmt.Sprint(v.AsFloat32()) + case FLOAT64: + return fmt.Sprint(v.AsFloat64()) + case STRING: + return v.stringly + default: + return "unknown" + } +} + +// MarshalJSON returns the JSON encoding of the Value. +func (v Value) MarshalJSON() ([]byte, error) { + var jsonVal struct { + Type string + Value interface{} + } + jsonVal.Type = v.Type().String() + jsonVal.Value = v.AsInterface() + return json.Marshal(jsonVal) +} diff --git a/api/kv/value/value_test.go b/api/kv/value/value_test.go new file mode 100644 index 000000000..9e225bdd2 --- /dev/null +++ b/api/kv/value/value_test.go @@ -0,0 +1,137 @@ +// 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 value_test + +import ( + "testing" + "unsafe" + + "go.opentelemetry.io/otel/api/kv" + + "github.com/google/go-cmp/cmp" + + "go.opentelemetry.io/otel/api/kv/value" +) + +func TestValue(t *testing.T) { + k := kv.Key("test") + bli := getBitlessInfo(42) + for _, testcase := range []struct { + name string + value value.Value + wantType value.Type + wantValue interface{} + }{ + { + name: "Key.Bool() correctly returns keys's internal bool value", + value: k.Bool(true).Value, + wantType: value.BOOL, + wantValue: true, + }, + { + name: "Key.Int64() correctly returns keys's internal int64 value", + value: k.Int64(42).Value, + wantType: value.INT64, + wantValue: int64(42), + }, + { + name: "Key.Uint64() correctly returns keys's internal uint64 value", + value: k.Uint64(42).Value, + wantType: value.UINT64, + wantValue: uint64(42), + }, + { + name: "Key.Float64() correctly returns keys's internal float64 value", + value: k.Float64(42.1).Value, + wantType: value.FLOAT64, + wantValue: 42.1, + }, + { + name: "Key.Int32() correctly returns keys's internal int32 value", + value: k.Int32(42).Value, + wantType: value.INT32, + wantValue: int32(42), + }, + { + name: "Key.Uint32() correctly returns keys's internal uint32 value", + value: k.Uint32(42).Value, + wantType: value.UINT32, + wantValue: uint32(42), + }, + { + name: "Key.Float32() correctly returns keys's internal float32 value", + value: k.Float32(42.1).Value, + wantType: value.FLOAT32, + wantValue: float32(42.1), + }, + { + name: "Key.String() correctly returns keys's internal string value", + value: k.String("foo").Value, + wantType: value.STRING, + wantValue: "foo", + }, + { + name: "Key.Int() correctly returns keys's internal signed integral value", + value: k.Int(bli.intValue).Value, + wantType: bli.signedType, + wantValue: bli.signedValue, + }, + { + name: "Key.Uint() correctly returns keys's internal unsigned integral value", + value: k.Uint(bli.uintValue).Value, + wantType: bli.unsignedType, + wantValue: bli.unsignedValue, + }, + } { + t.Logf("Running test case %s", testcase.name) + if testcase.value.Type() != testcase.wantType { + t.Errorf("wrong value type, got %#v, expected %#v", testcase.value.Type(), testcase.wantType) + } + got := testcase.value.AsInterface() + if diff := cmp.Diff(testcase.wantValue, got); diff != "" { + t.Errorf("+got, -want: %s", diff) + } + } +} + +type bitlessInfo struct { + intValue int + uintValue uint + signedType value.Type + unsignedType value.Type + signedValue interface{} + unsignedValue interface{} +} + +func getBitlessInfo(i int) bitlessInfo { + if unsafe.Sizeof(i) == 4 { + return bitlessInfo{ + intValue: i, + uintValue: uint(i), + signedType: value.INT32, + unsignedType: value.UINT32, + signedValue: int32(i), + unsignedValue: uint32(i), + } + } + return bitlessInfo{ + intValue: i, + uintValue: uint(i), + signedType: value.INT64, + unsignedType: value.UINT64, + signedValue: int64(i), + unsignedValue: uint64(i), + } +} diff --git a/api/label/encoder.go b/api/label/encoder.go index 949613a22..0c14ee520 100644 --- a/api/label/encoder.go +++ b/api/label/encoder.go @@ -19,7 +19,7 @@ import ( "sync" "sync/atomic" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv/value" ) type ( @@ -111,18 +111,18 @@ func (d *defaultLabelEncoder) Encode(iter Iterator) string { buf.Reset() for iter.Next() { - i, kv := iter.IndexedLabel() + i, keyValue := iter.IndexedLabel() if i > 0 { _, _ = buf.WriteRune(',') } - copyAndEscape(buf, string(kv.Key)) + copyAndEscape(buf, string(keyValue.Key)) _, _ = buf.WriteRune('=') - if kv.Value.Type() == core.STRING { - copyAndEscape(buf, kv.Value.AsString()) + if keyValue.Value.Type() == value.STRING { + copyAndEscape(buf, keyValue.Value.AsString()) } else { - _, _ = buf.WriteString(kv.Value.Emit()) + _, _ = buf.WriteString(keyValue.Value.Emit()) } } return buf.String() diff --git a/api/label/iterator.go b/api/label/iterator.go index ca25f29e9..6b345d092 100644 --- a/api/label/iterator.go +++ b/api/label/iterator.go @@ -15,7 +15,7 @@ package label import ( - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" ) // Iterator allows iterating over the set of labels in order, @@ -32,26 +32,26 @@ func (i *Iterator) Next() bool { return i.idx < i.Len() } -// Label returns current core.KeyValue. Must be called only after Next returns +// Label returns current kv.KeyValue. Must be called only after Next returns // true. -func (i *Iterator) Label() core.KeyValue { +func (i *Iterator) Label() kv.KeyValue { kv, _ := i.storage.Get(i.idx) return kv } // Attribute is a synonym for Label(). -func (i *Iterator) Attribute() core.KeyValue { +func (i *Iterator) Attribute() kv.KeyValue { return i.Label() } // IndexedLabel returns current index and label. Must be called only // after Next returns true. -func (i *Iterator) IndexedLabel() (int, core.KeyValue) { +func (i *Iterator) IndexedLabel() (int, kv.KeyValue) { return i.idx, i.Label() } // IndexedAttribute is a synonym for IndexedLabel(). -func (i *Iterator) IndexedAttribute() (int, core.KeyValue) { +func (i *Iterator) IndexedAttribute() (int, kv.KeyValue) { return i.IndexedLabel() } @@ -63,13 +63,13 @@ func (i *Iterator) Len() int { // ToSlice is a convenience function that creates a slice of labels // from the passed iterator. The iterator is set up to start from the // beginning before creating the slice. -func (i *Iterator) ToSlice() []core.KeyValue { +func (i *Iterator) ToSlice() []kv.KeyValue { l := i.Len() if l == 0 { return nil } i.idx = -1 - slice := make([]core.KeyValue, 0, l) + slice := make([]kv.KeyValue, 0, l) for i.Next() { slice = append(slice, i.Label()) } diff --git a/api/label/iterator_test.go b/api/label/iterator_test.go index 5120541e5..0548240f1 100644 --- a/api/label/iterator_test.go +++ b/api/label/iterator_test.go @@ -17,15 +17,16 @@ package label_test import ( "testing" + "go.opentelemetry.io/otel/api/kv" + "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/key" "go.opentelemetry.io/otel/api/label" ) func TestIterator(t *testing.T) { - one := key.String("one", "1") - two := key.Int("two", 2) + one := kv.String("one", "1") + two := kv.Int("two", 2) lbl := label.NewSet(one, two) iter := lbl.Iter() require.Equal(t, 2, iter.Len()) diff --git a/api/label/set.go b/api/label/set.go index 8533c5714..5b39287f5 100644 --- a/api/label/set.go +++ b/api/label/set.go @@ -20,7 +20,9 @@ import ( "sort" "sync" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv/value" + + "go.opentelemetry.io/otel/api/kv" ) type ( @@ -43,7 +45,7 @@ type ( encoded [maxConcurrentEncoders]string } - // Distinct wraps a variable-size array of `core.KeyValue`, + // Distinct wraps a variable-size array of `kv.KeyValue`, // constructed with keys in sorted order. This can be used as // a map key or for equality checking between Sets. Distinct struct { @@ -51,22 +53,22 @@ type ( } // Sortable implements `sort.Interface`, used for sorting - // `core.KeyValue`. This is an exported type to support a + // `kv.KeyValue`. This is an exported type to support a // memory optimization. A pointer to one of these is needed // for the call to `sort.Stable()`, which the caller may // provide in order to avoid an allocation. See // `NewSetWithSortable()`. - Sortable []core.KeyValue + Sortable []kv.KeyValue ) var ( // keyValueType is used in `computeDistinctReflect`. - keyValueType = reflect.TypeOf(core.KeyValue{}) + keyValueType = reflect.TypeOf(kv.KeyValue{}) // emptySet is returned for empty label sets. emptySet = &Set{ equivalent: Distinct{ - iface: [0]core.KeyValue{}, + iface: [0]kv.KeyValue{}, }, } ) @@ -96,44 +98,44 @@ func (l *Set) Len() int { } // Get returns the KeyValue at ordered position `idx` in this set. -func (l *Set) Get(idx int) (core.KeyValue, bool) { +func (l *Set) Get(idx int) (kv.KeyValue, bool) { if l == nil { - return core.KeyValue{}, false + return kv.KeyValue{}, false } value := l.equivalent.reflect() if idx >= 0 && idx < value.Len() { // Note: The Go compiler successfully avoids an allocation for // the interface{} conversion here: - return value.Index(idx).Interface().(core.KeyValue), true + return value.Index(idx).Interface().(kv.KeyValue), true } - return core.KeyValue{}, false + return kv.KeyValue{}, false } // Value returns the value of a specified key in this set. -func (l *Set) Value(k core.Key) (core.Value, bool) { +func (l *Set) Value(k kv.Key) (value.Value, bool) { if l == nil { - return core.Value{}, false + return value.Value{}, false } - value := l.equivalent.reflect() - vlen := value.Len() + rValue := l.equivalent.reflect() + vlen := rValue.Len() idx := sort.Search(vlen, func(idx int) bool { - return value.Index(idx).Interface().(core.KeyValue).Key >= k + return rValue.Index(idx).Interface().(kv.KeyValue).Key >= k }) if idx >= vlen { - return core.Value{}, false + return value.Value{}, false } - kv := value.Index(idx).Interface().(core.KeyValue) - if k == kv.Key { - return kv.Value, true + keyValue := rValue.Index(idx).Interface().(kv.KeyValue) + if k == keyValue.Key { + return keyValue.Value, true } - return core.Value{}, false + return value.Value{}, false } // HasValue tests whether a key is defined in this set. -func (l *Set) HasValue(k core.Key) bool { +func (l *Set) HasValue(k kv.Key) bool { if l == nil { return false } @@ -151,7 +153,7 @@ func (l *Set) Iter() Iterator { // ToSlice returns the set of labels belonging to this set, sorted, // where keys appear no more than once. -func (l *Set) ToSlice() []core.KeyValue { +func (l *Set) ToSlice() []kv.KeyValue { iter := l.Iter() return iter.ToSlice() } @@ -226,7 +228,7 @@ func (l *Set) Encoded(encoder Encoder) string { // // Except for empty sets, this method adds an additional allocation // compared with a call to `NewSetWithSortable`. -func NewSet(kvs ...core.KeyValue) Set { +func NewSet(kvs ...kv.KeyValue) Set { // Check for empty set. if len(kvs) == 0 { return Set{ @@ -258,7 +260,7 @@ func NewSet(kvs ...core.KeyValue) Set { // // The result maintains a cache of encoded labels, by label.EncoderID. // This value should not be copied after its first use. -func NewSetWithSortable(kvs []core.KeyValue, tmp *Sortable) Set { +func NewSetWithSortable(kvs []kv.KeyValue, tmp *Sortable) Set { // Check for empty set. if len(kvs) == 0 { return Set{ @@ -299,7 +301,7 @@ func NewSetWithSortable(kvs []core.KeyValue, tmp *Sortable) Set { // computeDistinct returns a `Distinct` using either the fixed- or // reflect-oriented code path, depending on the size of the input. // The input slice is assumed to already be sorted and de-duplicated. -func computeDistinct(kvs []core.KeyValue) Distinct { +func computeDistinct(kvs []kv.KeyValue) Distinct { iface := computeDistinctFixed(kvs) if iface == nil { iface = computeDistinctReflect(kvs) @@ -311,46 +313,46 @@ func computeDistinct(kvs []core.KeyValue) Distinct { // computeDistinctFixed computes a `Distinct` for small slices. It // returns nil if the input is too large for this code path. -func computeDistinctFixed(kvs []core.KeyValue) interface{} { +func computeDistinctFixed(kvs []kv.KeyValue) interface{} { switch len(kvs) { case 1: - ptr := new([1]core.KeyValue) + ptr := new([1]kv.KeyValue) copy((*ptr)[:], kvs) return *ptr case 2: - ptr := new([2]core.KeyValue) + ptr := new([2]kv.KeyValue) copy((*ptr)[:], kvs) return *ptr case 3: - ptr := new([3]core.KeyValue) + ptr := new([3]kv.KeyValue) copy((*ptr)[:], kvs) return *ptr case 4: - ptr := new([4]core.KeyValue) + ptr := new([4]kv.KeyValue) copy((*ptr)[:], kvs) return *ptr case 5: - ptr := new([5]core.KeyValue) + ptr := new([5]kv.KeyValue) copy((*ptr)[:], kvs) return *ptr case 6: - ptr := new([6]core.KeyValue) + ptr := new([6]kv.KeyValue) copy((*ptr)[:], kvs) return *ptr case 7: - ptr := new([7]core.KeyValue) + ptr := new([7]kv.KeyValue) copy((*ptr)[:], kvs) return *ptr case 8: - ptr := new([8]core.KeyValue) + ptr := new([8]kv.KeyValue) copy((*ptr)[:], kvs) return *ptr case 9: - ptr := new([9]core.KeyValue) + ptr := new([9]kv.KeyValue) copy((*ptr)[:], kvs) return *ptr case 10: - ptr := new([10]core.KeyValue) + ptr := new([10]kv.KeyValue) copy((*ptr)[:], kvs) return *ptr default: @@ -360,10 +362,10 @@ func computeDistinctFixed(kvs []core.KeyValue) interface{} { // computeDistinctReflect computes a `Distinct` using reflection, // works for any size input. -func computeDistinctReflect(kvs []core.KeyValue) interface{} { +func computeDistinctReflect(kvs []kv.KeyValue) interface{} { at := reflect.New(reflect.ArrayOf(len(kvs), keyValueType)).Elem() - for i, kv := range kvs { - *(at.Index(i).Addr().Interface().(*core.KeyValue)) = kv + for i, keyValue := range kvs { + *(at.Index(i).Addr().Interface().(*kv.KeyValue)) = keyValue } return at.Interface() } diff --git a/api/label/set_test.go b/api/label/set_test.go index f8255b6b0..84690b886 100644 --- a/api/label/set_test.go +++ b/api/label/set_test.go @@ -17,19 +17,18 @@ package label_test import ( "testing" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/label" "github.com/stretchr/testify/require" ) type testCase struct { - kvs []core.KeyValue + kvs []kv.KeyValue encoding string } -func expect(enc string, kvs ...core.KeyValue) testCase { +func expect(enc string, kvs ...kv.KeyValue) testCase { return testCase{ kvs: kvs, encoding: enc, @@ -38,16 +37,16 @@ func expect(enc string, kvs ...core.KeyValue) testCase { func TestSetDedup(t *testing.T) { cases := []testCase{ - expect("A=B", key.String("A", "2"), key.String("A", "B")), - expect("A=B", key.String("A", "2"), key.Int("A", 1), key.String("A", "B")), - expect("A=B", key.String("A", "B"), key.String("A", "C"), key.String("A", "D"), key.String("A", "B")), + expect("A=B", kv.String("A", "2"), kv.String("A", "B")), + expect("A=B", kv.String("A", "2"), kv.Int("A", 1), kv.String("A", "B")), + expect("A=B", kv.String("A", "B"), kv.String("A", "C"), kv.String("A", "D"), kv.String("A", "B")), - expect("A=B,C=D", key.String("A", "1"), key.String("C", "D"), key.String("A", "B")), - expect("A=B,C=D", key.String("A", "2"), key.String("A", "B"), key.String("C", "D")), - expect("A=B,C=D", key.Float64("C", 1.2), key.String("A", "2"), key.String("A", "B"), key.String("C", "D")), - expect("A=B,C=D", key.String("C", "D"), key.String("A", "B"), key.String("A", "C"), key.String("A", "D"), key.String("A", "B")), - expect("A=B,C=D", key.String("A", "B"), key.String("C", "D"), key.String("A", "C"), key.String("A", "D"), key.String("A", "B")), - expect("A=B,C=D", key.String("A", "B"), key.String("A", "C"), key.String("A", "D"), key.String("A", "B"), key.String("C", "D")), + expect("A=B,C=D", kv.String("A", "1"), kv.String("C", "D"), kv.String("A", "B")), + expect("A=B,C=D", kv.String("A", "2"), kv.String("A", "B"), kv.String("C", "D")), + expect("A=B,C=D", kv.Float64("C", 1.2), kv.String("A", "2"), kv.String("A", "B"), kv.String("C", "D")), + expect("A=B,C=D", kv.String("C", "D"), kv.String("A", "B"), kv.String("A", "C"), kv.String("A", "D"), kv.String("A", "B")), + expect("A=B,C=D", kv.String("A", "B"), kv.String("C", "D"), kv.String("A", "C"), kv.String("A", "D"), kv.String("A", "B")), + expect("A=B,C=D", kv.String("A", "B"), kv.String("A", "C"), kv.String("A", "D"), kv.String("A", "B"), kv.String("C", "D")), } enc := label.DefaultEncoder() @@ -55,7 +54,7 @@ func TestSetDedup(t *testing.T) { d2s := map[label.Distinct][]string{} for _, tc := range cases { - cpy := make([]core.KeyValue, len(tc.kvs)) + cpy := make([]kv.KeyValue, len(tc.kvs)) copy(cpy, tc.kvs) sl := label.NewSet(cpy...) diff --git a/api/metric/api.go b/api/metric/api.go deleted file mode 100644 index e64db32ef..000000000 --- a/api/metric/api.go +++ /dev/null @@ -1,210 +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. - -//go:generate stringer -type=Kind - -package metric - -import ( - "context" - - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/unit" -) - -// Provider supports named Meter instances. -type Provider interface { - // Meter gets a named Meter interface. If the name is an - // empty string, the provider uses a default name. - Meter(name string) Meter -} - -// Config contains some options for metrics of any kind. -type Config struct { - // Description is an optional field describing the metric - // instrument. - Description string - // Unit is an optional field describing the metric instrument. - Unit unit.Unit - // LibraryName is the name given to the Meter that created - // this instrument. See `Provider`. - LibraryName string -} - -// Option is an interface for applying metric options. -type Option interface { - // Apply is used to set the Option value of a Config. - Apply(*Config) -} - -// Measurement is used for reporting a batch of metric -// values. Instances of this type should be created by instruments -// (e.g., Int64Counter.Measurement()). -type Measurement struct { - // number needs to be aligned for 64-bit atomic operations. - number core.Number - instrument SyncImpl -} - -// SyncImpl returns the instrument that created this measurement. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (m Measurement) SyncImpl() SyncImpl { - return m.instrument -} - -// Number returns a number recorded in this measurement. -func (m Measurement) Number() core.Number { - return m.number -} - -// Kind describes the kind of instrument. -type Kind int8 - -const ( - // MeasureKind indicates a Measure instrument. - MeasureKind Kind = iota - // ObserverKind indicates an Observer instrument. - ObserverKind - // CounterKind indicates a Counter instrument. - CounterKind -) - -// Descriptor contains all the settings that describe an instrument, -// including its name, metric kind, number kind, and the configurable -// options. -type Descriptor struct { - name string - kind Kind - numberKind core.NumberKind - config Config -} - -// NewDescriptor returns a Descriptor with the given contents. -func NewDescriptor(name string, mkind Kind, nkind core.NumberKind, opts ...Option) Descriptor { - return Descriptor{ - name: name, - kind: mkind, - numberKind: nkind, - config: Configure(opts), - } -} - -// Name returns the metric instrument's name. -func (d Descriptor) Name() string { - return d.name -} - -// MetricKind returns the specific kind of instrument. -func (d Descriptor) MetricKind() Kind { - return d.kind -} - -// Description provides a human-readable description of the metric -// instrument. -func (d Descriptor) Description() string { - return d.config.Description -} - -// Unit describes the units of the metric instrument. Unitless -// metrics return the empty string. -func (d Descriptor) Unit() unit.Unit { - return d.config.Unit -} - -// NumberKind returns whether this instrument is declared over int64, -// float64, or uint64 values. -func (d Descriptor) NumberKind() core.NumberKind { - return d.numberKind -} - -// LibraryName returns the metric instrument's library name, typically -// given via a call to Provider.Meter(). -func (d Descriptor) LibraryName() string { - return d.config.LibraryName -} - -// Meter is an interface to the metrics portion of the OpenTelemetry SDK. -type Meter interface { - // RecordBatch atomically records a batch of measurements. - RecordBatch(context.Context, []core.KeyValue, ...Measurement) - - // All instrument constructors may return an error for - // conditions such as: - // `name` is an empty string - // `name` was previously registered as a different kind of instrument - // for a given named `Meter`. - - // NewInt64Counter creates a new integral counter with a given - // name and customized with passed options. - NewInt64Counter(name string, opts ...Option) (Int64Counter, error) - // NewFloat64Counter creates a new floating point counter with - // a given name and customized with passed options. - NewFloat64Counter(name string, opts ...Option) (Float64Counter, error) - // NewInt64Measure creates a new integral measure with a given - // name and customized with passed options. - NewInt64Measure(name string, opts ...Option) (Int64Measure, error) - // NewFloat64Measure creates a new floating point measure with - // a given name and customized with passed options. - NewFloat64Measure(name string, opts ...Option) (Float64Measure, error) - - // RegisterInt64Observer creates a new integral observer with a - // given name, running a given callback, and customized with passed - // options. Callback may be nil. - RegisterInt64Observer(name string, callback Int64ObserverCallback, opts ...Option) (Int64Observer, error) - // RegisterFloat64Observer creates a new floating point observer - // with a given name, running a given callback, and customized with - // passed options. Callback may be nil. - RegisterFloat64Observer(name string, callback Float64ObserverCallback, opts ...Option) (Float64Observer, error) -} - -// WithDescription applies provided description. -func WithDescription(desc string) Option { - return descriptionOption(desc) -} - -type descriptionOption string - -func (d descriptionOption) Apply(config *Config) { - config.Description = string(d) -} - -// WithUnit applies provided unit. -func WithUnit(unit unit.Unit) Option { - return unitOption(unit) -} - -type unitOption unit.Unit - -func (u unitOption) Apply(config *Config) { - config.Unit = unit.Unit(u) -} - -// WithLibraryName applies provided library name. This is meant for -// use in `Provider` implementations that have not used -// `WrapMeterImpl`. Implementations built using `WrapMeterImpl` have -// instrument descriptors taken care of through this package. -// -// This option will have no effect when supplied by the user. -// Provider implementations are expected to append this option after -// the user-supplied options when building instrument descriptors. -func WithLibraryName(name string) Option { - return libraryNameOption(name) -} - -type libraryNameOption string - -func (r libraryNameOption) Apply(config *Config) { - config.LibraryName = string(r) -} diff --git a/api/metric/api_test.go b/api/metric/api_test.go index 0c78466ef..1395b8687 100644 --- a/api/metric/api_test.go +++ b/api/metric/api_test.go @@ -20,8 +20,7 @@ import ( "fmt" "testing" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/api/unit" mockTest "go.opentelemetry.io/otel/internal/metric" @@ -98,25 +97,25 @@ func TestCounter(t *testing.T) { mockSDK, meter := mockTest.NewMeter() c := Must(meter).NewFloat64Counter("test.counter.float") ctx := context.Background() - labels := []core.KeyValue{key.String("A", "B")} + labels := []kv.KeyValue{kv.String("A", "B")} c.Add(ctx, 42, labels...) boundInstrument := c.Bind(labels...) boundInstrument.Add(ctx, 42) meter.RecordBatch(ctx, labels, c.Measurement(42)) t.Log("Testing float counter") - checkBatches(t, ctx, labels, mockSDK, core.Float64NumberKind, c.SyncImpl()) + checkBatches(t, ctx, labels, mockSDK, metric.Float64NumberKind, c.SyncImpl()) } { mockSDK, meter := mockTest.NewMeter() c := Must(meter).NewInt64Counter("test.counter.int") ctx := context.Background() - labels := []core.KeyValue{key.String("A", "B"), key.String("C", "D")} + labels := []kv.KeyValue{kv.String("A", "B"), kv.String("C", "D")} c.Add(ctx, 42, labels...) boundInstrument := c.Bind(labels...) boundInstrument.Add(ctx, 42) meter.RecordBatch(ctx, labels, c.Measurement(42)) t.Log("Testing int counter") - checkBatches(t, ctx, labels, mockSDK, core.Int64NumberKind, c.SyncImpl()) + checkBatches(t, ctx, labels, mockSDK, metric.Int64NumberKind, c.SyncImpl()) } } @@ -125,31 +124,31 @@ func TestMeasure(t *testing.T) { mockSDK, meter := mockTest.NewMeter() m := Must(meter).NewFloat64Measure("test.measure.float") ctx := context.Background() - labels := []core.KeyValue{} + labels := []kv.KeyValue{} m.Record(ctx, 42, labels...) boundInstrument := m.Bind(labels...) boundInstrument.Record(ctx, 42) meter.RecordBatch(ctx, labels, m.Measurement(42)) t.Log("Testing float measure") - checkBatches(t, ctx, labels, mockSDK, core.Float64NumberKind, m.SyncImpl()) + checkBatches(t, ctx, labels, mockSDK, metric.Float64NumberKind, m.SyncImpl()) } { mockSDK, meter := mockTest.NewMeter() m := Must(meter).NewInt64Measure("test.measure.int") ctx := context.Background() - labels := []core.KeyValue{key.Int("I", 1)} + labels := []kv.KeyValue{kv.Int("I", 1)} m.Record(ctx, 42, labels...) boundInstrument := m.Bind(labels...) boundInstrument.Record(ctx, 42) meter.RecordBatch(ctx, labels, m.Measurement(42)) t.Log("Testing int measure") - checkBatches(t, ctx, labels, mockSDK, core.Int64NumberKind, m.SyncImpl()) + checkBatches(t, ctx, labels, mockSDK, metric.Int64NumberKind, m.SyncImpl()) } } func TestObserver(t *testing.T) { { - labels := []core.KeyValue{key.String("O", "P")} + labels := []kv.KeyValue{kv.String("O", "P")} mockSDK, meter := mockTest.NewMeter() o := Must(meter).RegisterFloat64Observer("test.observer.float", func(result metric.Float64ObserverResult) { result.Observe(42, labels...) @@ -157,21 +156,21 @@ func TestObserver(t *testing.T) { t.Log("Testing float observer") mockSDK.RunAsyncInstruments() - checkObserverBatch(t, labels, mockSDK, core.Float64NumberKind, o.AsyncImpl()) + checkObserverBatch(t, labels, mockSDK, metric.Float64NumberKind, o.AsyncImpl()) } { - labels := []core.KeyValue{} + labels := []kv.KeyValue{} mockSDK, meter := mockTest.NewMeter() o := Must(meter).RegisterInt64Observer("test.observer.int", func(result metric.Int64ObserverResult) { result.Observe(42, labels...) }) t.Log("Testing int observer") mockSDK.RunAsyncInstruments() - checkObserverBatch(t, labels, mockSDK, core.Int64NumberKind, o.AsyncImpl()) + checkObserverBatch(t, labels, mockSDK, metric.Int64NumberKind, o.AsyncImpl()) } } -func checkBatches(t *testing.T, ctx context.Context, labels []core.KeyValue, mock *mockTest.MeterImpl, kind core.NumberKind, instrument metric.InstrumentImpl) { +func checkBatches(t *testing.T, ctx context.Context, labels []kv.KeyValue, mock *mockTest.MeterImpl, kind metric.NumberKind, instrument metric.InstrumentImpl) { t.Helper() if len(mock.MeasurementBatches) != 3 { t.Errorf("Expected 3 recorded measurement batches, got %d", len(mock.MeasurementBatches)) @@ -211,7 +210,52 @@ func checkBatches(t *testing.T, ctx context.Context, labels []core.KeyValue, moc } } -func checkObserverBatch(t *testing.T, labels []core.KeyValue, mock *mockTest.MeterImpl, kind core.NumberKind, observer metric.AsyncImpl) { +func TestBatchObserver(t *testing.T) { + mockSDK, meter := mockTest.NewMeter() + + var obs1 metric.Int64Observer + var obs2 metric.Float64Observer + + labels := []kv.KeyValue{ + kv.String("A", "B"), + kv.String("C", "D"), + } + + cb := Must(meter).NewBatchObserver( + func(result metric.BatchObserverResult) { + result.Observe(labels, + obs1.Observation(42), + obs2.Observation(42.0), + ) + }, + ) + obs1 = cb.RegisterInt64Observer("test.observer.int") + obs2 = cb.RegisterFloat64Observer("test.observer.float") + + mockSDK.RunAsyncInstruments() + + require.Len(t, mockSDK.MeasurementBatches, 1) + + impl1 := obs1.AsyncImpl().Implementation().(*mockTest.Async) + impl2 := obs2.AsyncImpl().Implementation().(*mockTest.Async) + + require.NotNil(t, impl1) + require.NotNil(t, impl2) + + got := mockSDK.MeasurementBatches[0] + require.Equal(t, labels, got.Labels) + require.Len(t, got.Measurements, 2) + + m1 := got.Measurements[0] + require.Equal(t, impl1, m1.Instrument.Implementation().(*mockTest.Async)) + require.Equal(t, 0, m1.Number.CompareNumber(metric.Int64NumberKind, fortyTwo(t, metric.Int64NumberKind))) + + m2 := got.Measurements[1] + require.Equal(t, impl2, m2.Instrument.Implementation().(*mockTest.Async)) + require.Equal(t, 0, m2.Number.CompareNumber(metric.Float64NumberKind, fortyTwo(t, metric.Float64NumberKind))) +} + +func checkObserverBatch(t *testing.T, labels []kv.KeyValue, mock *mockTest.MeterImpl, kind metric.NumberKind, observer metric.AsyncImpl) { t.Helper() assert.Len(t, mock.MeasurementBatches, 1) if len(mock.MeasurementBatches) < 1 { @@ -233,16 +277,16 @@ func checkObserverBatch(t *testing.T, labels []core.KeyValue, mock *mockTest.Met assert.Equal(t, 0, measurement.Number.CompareNumber(kind, ft)) } -func fortyTwo(t *testing.T, kind core.NumberKind) core.Number { +func fortyTwo(t *testing.T, kind metric.NumberKind) metric.Number { t.Helper() switch kind { - case core.Int64NumberKind: - return core.NewInt64Number(42) - case core.Float64NumberKind: - return core.NewFloat64Number(42) + case metric.Int64NumberKind: + return metric.NewInt64Number(42) + case metric.Float64NumberKind: + return metric.NewFloat64Number(42) } t.Errorf("Invalid value kind %q", kind) - return core.NewInt64Number(0) + return metric.NewInt64Number(0) } type testWrappedMeter struct { @@ -250,14 +294,14 @@ type testWrappedMeter struct { var _ metric.MeterImpl = testWrappedMeter{} -func (testWrappedMeter) RecordBatch(context.Context, []core.KeyValue, ...metric.Measurement) { +func (testWrappedMeter) RecordBatch(context.Context, []kv.KeyValue, ...metric.Measurement) { } func (testWrappedMeter) NewSyncInstrument(_ metric.Descriptor) (metric.SyncImpl, error) { return nil, nil } -func (testWrappedMeter) NewAsyncInstrument(_ metric.Descriptor, _ func(func(core.Number, []core.KeyValue))) (metric.AsyncImpl, error) { +func (testWrappedMeter) NewAsyncInstrument(_ metric.Descriptor, _ metric.AsyncRunner) (metric.AsyncImpl, error) { return nil, errors.New("Test wrap error") } diff --git a/api/metric/async.go b/api/metric/async.go new file mode 100644 index 000000000..bd22f714e --- /dev/null +++ b/api/metric/async.go @@ -0,0 +1,177 @@ +// 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 metric + +import "go.opentelemetry.io/otel/api/kv" + +// The file is organized as follows: +// +// - Observation type +// - Three kinds of Observer callback (int64, float64, batch) +// - Three kinds of Observer result (int64, float64, batch) +// - Three kinds of Observe() function (int64, float64, batch) +// - Three kinds of AsyncRunner interface (abstract, single, batch) +// - Two kinds of Observer constructor (int64, float64) +// - Two kinds of Observation() function (int64, float64) +// - Various internals + +// Observation is used for reporting an asynchronous batch of metric +// values. Instances of this type should be created by asynchronous +// instruments (e.g., Int64Observer.Observation()). +type Observation struct { + // number needs to be aligned for 64-bit atomic operations. + number Number + instrument AsyncImpl +} + +// Int64ObserverCallback is a type of callback that integral +// observers run. +type Int64ObserverCallback func(Int64ObserverResult) + +// Float64ObserverCallback is a type of callback that floating point +// observers run. +type Float64ObserverCallback func(Float64ObserverResult) + +// BatchObserverCallback is a callback argument for use with any +// Observer instrument that will be reported as a batch of +// observations. +type BatchObserverCallback func(BatchObserverResult) + +// Int64ObserverResult is passed to an observer callback to capture +// observations for one asynchronous integer metric instrument. +type Int64ObserverResult struct { + instrument AsyncImpl + function func([]kv.KeyValue, ...Observation) +} + +// Float64ObserverResult is passed to an observer callback to capture +// observations for one asynchronous floating point metric instrument. +type Float64ObserverResult struct { + instrument AsyncImpl + function func([]kv.KeyValue, ...Observation) +} + +// BatchObserverResult is passed to a batch observer callback to +// capture observations for multiple asynchronous instruments. +type BatchObserverResult struct { + function func([]kv.KeyValue, ...Observation) +} + +// Observe captures a single integer value from the associated +// instrument callback, with the given labels. +func (ir Int64ObserverResult) Observe(value int64, labels ...kv.KeyValue) { + ir.function(labels, Observation{ + instrument: ir.instrument, + number: NewInt64Number(value), + }) +} + +// Observe captures a single floating point value from the associated +// instrument callback, with the given labels. +func (fr Float64ObserverResult) Observe(value float64, labels ...kv.KeyValue) { + fr.function(labels, Observation{ + instrument: fr.instrument, + number: NewFloat64Number(value), + }) +} + +// Observe captures a multiple observations from the associated batch +// instrument callback, with the given labels. +func (br BatchObserverResult) Observe(labels []kv.KeyValue, obs ...Observation) { + br.function(labels, obs...) +} + +// AsyncRunner is expected to convert into an AsyncSingleRunner or an +// AsyncBatchRunner. SDKs will encounter an error if the AsyncRunner +// does not satisfy one of these interfaces. +type AsyncRunner interface { + // AnyRunner() is a non-exported method with no functional use + // other than to make this a non-empty interface. + AnyRunner() +} + +// AsyncSingleRunner is an interface implemented by single-observer +// callbacks. +type AsyncSingleRunner interface { + // Run accepts a single instrument and function for capturing + // observations of that instrument. Each call to the function + // receives one captured observation. (The function accepts + // multiple observations so the same implementation can be + // used for batch runners.) + Run(single AsyncImpl, capture func([]kv.KeyValue, ...Observation)) + + AsyncRunner +} + +// AsyncBatchRunner is an interface implemented by batch-observer +// callbacks. +type AsyncBatchRunner interface { + // Run accepts a function for capturing observations of + // multiple instruments. + Run(capture func([]kv.KeyValue, ...Observation)) + + AsyncRunner +} + +var _ AsyncSingleRunner = (*Int64ObserverCallback)(nil) +var _ AsyncSingleRunner = (*Float64ObserverCallback)(nil) +var _ AsyncBatchRunner = (*BatchObserverCallback)(nil) + +// newInt64AsyncRunner returns a single-observer callback for integer Observer instruments. +func newInt64AsyncRunner(c Int64ObserverCallback) AsyncSingleRunner { + return &c +} + +// newFloat64AsyncRunner returns a single-observer callback for floating point Observer instruments. +func newFloat64AsyncRunner(c Float64ObserverCallback) AsyncSingleRunner { + return &c +} + +// newBatchAsyncRunner returns a batch-observer callback use with multiple Observer instruments. +func newBatchAsyncRunner(c BatchObserverCallback) AsyncBatchRunner { + return &c +} + +// AnyRunner implements AsyncRunner. +func (*Int64ObserverCallback) AnyRunner() {} + +// AnyRunner implements AsyncRunner. +func (*Float64ObserverCallback) AnyRunner() {} + +// AnyRunner implements AsyncRunner. +func (*BatchObserverCallback) AnyRunner() {} + +// Run implements AsyncSingleRunner. +func (i *Int64ObserverCallback) Run(impl AsyncImpl, function func([]kv.KeyValue, ...Observation)) { + (*i)(Int64ObserverResult{ + instrument: impl, + function: function, + }) +} + +// Run implements AsyncSingleRunner. +func (f *Float64ObserverCallback) Run(impl AsyncImpl, function func([]kv.KeyValue, ...Observation)) { + (*f)(Float64ObserverResult{ + instrument: impl, + function: function, + }) +} + +// Run implements AsyncBatchRunner. +func (b *BatchObserverCallback) Run(function func([]kv.KeyValue, ...Observation)) { + (*b)(BatchObserverResult{ + function: function, + }) +} diff --git a/api/metric/common.go b/api/metric/common.go deleted file mode 100644 index 0c9c7368c..000000000 --- a/api/metric/common.go +++ /dev/null @@ -1,116 +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 metric - -import ( - "context" - "errors" - - "go.opentelemetry.io/otel/api/core" -) - -type syncInstrument struct { - instrument SyncImpl -} - -type syncBoundInstrument struct { - boundInstrument BoundSyncImpl -} - -type asyncInstrument struct { - instrument AsyncImpl -} - -var ErrSDKReturnedNilImpl = errors.New("SDK returned a nil implementation") - -func (s syncInstrument) bind(labels []core.KeyValue) syncBoundInstrument { - return newSyncBoundInstrument(s.instrument.Bind(labels)) -} - -func (s syncInstrument) float64Measurement(value float64) Measurement { - return newMeasurement(s.instrument, core.NewFloat64Number(value)) -} - -func (s syncInstrument) int64Measurement(value int64) Measurement { - return newMeasurement(s.instrument, core.NewInt64Number(value)) -} - -func (s syncInstrument) directRecord(ctx context.Context, number core.Number, labels []core.KeyValue) { - s.instrument.RecordOne(ctx, number, labels) -} - -func (s syncInstrument) SyncImpl() SyncImpl { - return s.instrument -} - -func (h syncBoundInstrument) directRecord(ctx context.Context, number core.Number) { - h.boundInstrument.RecordOne(ctx, number) -} - -func (h syncBoundInstrument) Unbind() { - h.boundInstrument.Unbind() -} - -func (a asyncInstrument) AsyncImpl() AsyncImpl { - return a.instrument -} - -// checkNewSync receives an SyncImpl and potential -// error, and returns the same types, checking for and ensuring that -// the returned interface is not nil. -func checkNewSync(instrument SyncImpl, err error) (syncInstrument, error) { - if instrument == nil { - if err == nil { - err = ErrSDKReturnedNilImpl - } - // Note: an alternate behavior would be to synthesize a new name - // or group all duplicately-named instruments of a certain type - // together and use a tag for the original name, e.g., - // name = 'invalid.counter.int64' - // label = 'original-name=duplicate-counter-name' - instrument = NoopSync{} - } - return syncInstrument{ - instrument: instrument, - }, err -} - -func newSyncBoundInstrument(boundInstrument BoundSyncImpl) syncBoundInstrument { - return syncBoundInstrument{ - boundInstrument: boundInstrument, - } -} - -func newMeasurement(instrument SyncImpl, number core.Number) Measurement { - return Measurement{ - instrument: instrument, - number: number, - } -} - -// checkNewAsync receives an AsyncImpl and potential -// error, and returns the same types, checking for and ensuring that -// the returned interface is not nil. -func checkNewAsync(instrument AsyncImpl, err error) (asyncInstrument, error) { - if instrument == nil { - if err == nil { - err = ErrSDKReturnedNilImpl - } - instrument = NoopAsync{} - } - return asyncInstrument{ - instrument: instrument, - }, err -} diff --git a/api/metric/config.go b/api/metric/config.go new file mode 100644 index 000000000..30a3f8a0b --- /dev/null +++ b/api/metric/config.go @@ -0,0 +1,84 @@ +// 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 metric + +import "go.opentelemetry.io/otel/api/unit" + +// Config contains some options for metrics of any kind. +type Config struct { + // Description is an optional field describing the metric + // instrument. + Description string + // Unit is an optional field describing the metric instrument. + Unit unit.Unit + // LibraryName is the name given to the Meter that created + // this instrument. See `Provider`. + LibraryName string +} + +// Option is an interface for applying metric options. +type Option interface { + // Apply is used to set the Option value of a Config. + Apply(*Config) +} + +// Configure is a helper that applies all the options to a Config. +func Configure(opts []Option) Config { + var config Config + for _, o := range opts { + o.Apply(&config) + } + return config +} + +// WithDescription applies provided description. +func WithDescription(desc string) Option { + return descriptionOption(desc) +} + +type descriptionOption string + +func (d descriptionOption) Apply(config *Config) { + config.Description = string(d) +} + +// WithUnit applies provided unit. +func WithUnit(unit unit.Unit) Option { + return unitOption(unit) +} + +type unitOption unit.Unit + +func (u unitOption) Apply(config *Config) { + config.Unit = unit.Unit(u) +} + +// WithLibraryName applies provided library name. This is meant for +// use in `Provider` implementations that have not used +// `WrapMeterImpl`. Implementations built using `WrapMeterImpl` have +// instrument descriptors taken care of through this package. +// +// This option will have no effect when supplied by the user. +// Provider implementations are expected to append this option after +// the user-supplied options when building instrument descriptors. +func WithLibraryName(name string) Option { + return libraryNameOption(name) +} + +type libraryNameOption string + +func (r libraryNameOption) Apply(config *Config) { + config.LibraryName = string(r) +} diff --git a/api/metric/counter.go b/api/metric/counter.go index b29881136..e9e73a358 100644 --- a/api/metric/counter.go +++ b/api/metric/counter.go @@ -17,7 +17,7 @@ package metric import ( "context" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" ) // Float64Counter is a metric that accumulates float64 values. @@ -46,14 +46,14 @@ type BoundInt64Counter struct { // Bind creates a bound instrument for this counter. The labels are // associated with values recorded via subsequent calls to Record. -func (c Float64Counter) Bind(labels ...core.KeyValue) (h BoundFloat64Counter) { +func (c Float64Counter) Bind(labels ...kv.KeyValue) (h BoundFloat64Counter) { h.syncBoundInstrument = c.bind(labels) return } // Bind creates a bound instrument for this counter. The labels are // associated with values recorded via subsequent calls to Record. -func (c Int64Counter) Bind(labels ...core.KeyValue) (h BoundInt64Counter) { +func (c Int64Counter) Bind(labels ...kv.KeyValue) (h BoundInt64Counter) { h.syncBoundInstrument = c.bind(labels) return } @@ -72,24 +72,24 @@ func (c Int64Counter) Measurement(value int64) Measurement { // Add adds the value to the counter's sum. The labels should contain // the keys and values to be associated with this value. -func (c Float64Counter) Add(ctx context.Context, value float64, labels ...core.KeyValue) { - c.directRecord(ctx, core.NewFloat64Number(value), labels) +func (c Float64Counter) Add(ctx context.Context, value float64, labels ...kv.KeyValue) { + c.directRecord(ctx, NewFloat64Number(value), labels) } // Add adds the value to the counter's sum. The labels should contain // the keys and values to be associated with this value. -func (c Int64Counter) Add(ctx context.Context, value int64, labels ...core.KeyValue) { - c.directRecord(ctx, core.NewInt64Number(value), labels) +func (c Int64Counter) Add(ctx context.Context, value int64, labels ...kv.KeyValue) { + c.directRecord(ctx, NewInt64Number(value), labels) } // Add adds the value to the counter's sum using the labels // previously bound to this counter via Bind() func (b BoundFloat64Counter) Add(ctx context.Context, value float64) { - b.directRecord(ctx, core.NewFloat64Number(value)) + b.directRecord(ctx, NewFloat64Number(value)) } // Add adds the value to the counter's sum using the labels // previously bound to this counter via Bind() func (b BoundInt64Counter) Add(ctx context.Context, value int64) { - b.directRecord(ctx, core.NewInt64Number(value)) + b.directRecord(ctx, NewInt64Number(value)) } diff --git a/api/metric/descriptor.go b/api/metric/descriptor.go new file mode 100644 index 000000000..a87cd6d75 --- /dev/null +++ b/api/metric/descriptor.go @@ -0,0 +1,71 @@ +// 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 metric + +import "go.opentelemetry.io/otel/api/unit" + +// Descriptor contains all the settings that describe an instrument, +// including its name, metric kind, number kind, and the configurable +// options. +type Descriptor struct { + name string + kind Kind + numberKind NumberKind + config Config +} + +// NewDescriptor returns a Descriptor with the given contents. +func NewDescriptor(name string, mkind Kind, nkind NumberKind, opts ...Option) Descriptor { + return Descriptor{ + name: name, + kind: mkind, + numberKind: nkind, + config: Configure(opts), + } +} + +// Name returns the metric instrument's name. +func (d Descriptor) Name() string { + return d.name +} + +// MetricKind returns the specific kind of instrument. +func (d Descriptor) MetricKind() Kind { + return d.kind +} + +// Description provides a human-readable description of the metric +// instrument. +func (d Descriptor) Description() string { + return d.config.Description +} + +// Unit describes the units of the metric instrument. Unitless +// metrics return the empty string. +func (d Descriptor) Unit() unit.Unit { + return d.config.Unit +} + +// NumberKind returns whether this instrument is declared over int64, +// float64, or uint64 values. +func (d Descriptor) NumberKind() NumberKind { + return d.numberKind +} + +// LibraryName returns the metric instrument's library name, typically +// given via a call to Provider.Meter(). +func (d Descriptor) LibraryName() string { + return d.config.LibraryName +} diff --git a/api/core/doc.go b/api/metric/kind.go similarity index 65% rename from api/core/doc.go rename to api/metric/kind.go index 34c4ecbad..63799ca96 100644 --- a/api/core/doc.go +++ b/api/metric/kind.go @@ -12,9 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -// This package provides basic types used in OpenTelemetry - keys, -// values, numbers and span contexts. -// -// See the api/key package for convenience functions for creating keys -// and key-value pairs. -package core // import "go.opentelemetry.io/otel/api/core" +//go:generate stringer -type=Kind + +package metric + +// Kind describes the kind of instrument. +type Kind int8 + +const ( + // MeasureKind indicates a Measure instrument. + MeasureKind Kind = iota + // ObserverKind indicates an Observer instrument. + ObserverKind + // CounterKind indicates a Counter instrument. + CounterKind +) diff --git a/api/metric/measure.go b/api/metric/measure.go index c0edbf230..11dd215ee 100644 --- a/api/metric/measure.go +++ b/api/metric/measure.go @@ -17,7 +17,7 @@ package metric import ( "context" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" ) // Float64Measure is a metric that records float64 values. @@ -46,14 +46,14 @@ type BoundInt64Measure struct { // Bind creates a bound instrument for this measure. The labels are // associated with values recorded via subsequent calls to Record. -func (c Float64Measure) Bind(labels ...core.KeyValue) (h BoundFloat64Measure) { +func (c Float64Measure) Bind(labels ...kv.KeyValue) (h BoundFloat64Measure) { h.syncBoundInstrument = c.bind(labels) return } // Bind creates a bound instrument for this measure. The labels are // associated with values recorded via subsequent calls to Record. -func (c Int64Measure) Bind(labels ...core.KeyValue) (h BoundInt64Measure) { +func (c Int64Measure) Bind(labels ...kv.KeyValue) (h BoundInt64Measure) { h.syncBoundInstrument = c.bind(labels) return } @@ -73,25 +73,25 @@ func (c Int64Measure) Measurement(value int64) Measurement { // Record adds a new value to the list of measure's records. The // labels should contain the keys and values to be associated with // this value. -func (c Float64Measure) Record(ctx context.Context, value float64, labels ...core.KeyValue) { - c.directRecord(ctx, core.NewFloat64Number(value), labels) +func (c Float64Measure) Record(ctx context.Context, value float64, labels ...kv.KeyValue) { + c.directRecord(ctx, NewFloat64Number(value), labels) } // Record adds a new value to the list of measure's records. The // labels should contain the keys and values to be associated with // this value. -func (c Int64Measure) Record(ctx context.Context, value int64, labels ...core.KeyValue) { - c.directRecord(ctx, core.NewInt64Number(value), labels) +func (c Int64Measure) Record(ctx context.Context, value int64, labels ...kv.KeyValue) { + c.directRecord(ctx, NewInt64Number(value), labels) } // Record adds a new value to the list of measure's records using the labels // previously bound to the measure via Bind() func (b BoundFloat64Measure) Record(ctx context.Context, value float64) { - b.directRecord(ctx, core.NewFloat64Number(value)) + b.directRecord(ctx, NewFloat64Number(value)) } // Record adds a new value to the list of measure's records using the labels // previously bound to the measure via Bind() func (b BoundInt64Measure) Record(ctx context.Context, value int64) { - b.directRecord(ctx, core.NewInt64Number(value)) + b.directRecord(ctx, NewInt64Number(value)) } diff --git a/api/metric/meter.go b/api/metric/meter.go new file mode 100644 index 000000000..e20b02b1e --- /dev/null +++ b/api/metric/meter.go @@ -0,0 +1,194 @@ +// 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 metric + +import ( + "context" + + "go.opentelemetry.io/otel/api/kv" +) + +// The file is organized as follows: +// +// - Provider interface +// - Meter struct +// - RecordBatch +// - BatchObserver +// - Synchronous instrument constructors (2 x int64,float64) +// - Asynchronous instrument constructors (1 x int64,float64) +// - Batch asynchronous constructors (1 x int64,float64) +// - Internals + +// Provider supports named Meter instances. +type Provider interface { + // Meter gets a named Meter interface. If the name is an + // empty string, the provider uses a default name. + Meter(name string) Meter +} + +// Meter is the OpenTelemetry metric API, based on a `MeterImpl` +// implementation and the `Meter` library name. +// +// An uninitialized Meter is a no-op implementation. +type Meter struct { + impl MeterImpl + libraryName string +} + +// RecordBatch atomically records a batch of measurements. +func (m Meter) RecordBatch(ctx context.Context, ls []kv.KeyValue, ms ...Measurement) { + if m.impl == nil { + return + } + m.impl.RecordBatch(ctx, ls, ms...) +} + +// NewBatchObserver creates a new BatchObserver that supports +// making batches of observations for multiple instruments. +func (m Meter) NewBatchObserver(callback BatchObserverCallback) BatchObserver { + return BatchObserver{ + meter: m, + runner: newBatchAsyncRunner(callback), + } +} + +// NewInt64Counter creates a new integer Counter instrument with the +// given name, customized with options. May return an error if the +// name is invalid (e.g., empty) or improperly registered (e.g., +// duplicate registration). +func (m Meter) NewInt64Counter(name string, options ...Option) (Int64Counter, error) { + return wrapInt64CounterInstrument( + m.newSync(name, CounterKind, Int64NumberKind, options)) +} + +// NewFloat64Counter creates a new floating point Counter with the +// given name, customized with options. May return an error if the +// name is invalid (e.g., empty) or improperly registered (e.g., +// duplicate registration). +func (m Meter) NewFloat64Counter(name string, options ...Option) (Float64Counter, error) { + return wrapFloat64CounterInstrument( + m.newSync(name, CounterKind, Float64NumberKind, options)) +} + +// NewInt64Measure creates a new integer Measure instrument with the +// given name, customized with options. May return an error if the +// name is invalid (e.g., empty) or improperly registered (e.g., +// duplicate registration). +func (m Meter) NewInt64Measure(name string, opts ...Option) (Int64Measure, error) { + return wrapInt64MeasureInstrument( + m.newSync(name, MeasureKind, Int64NumberKind, opts)) +} + +// NewFloat64Measure creates a new floating point Measure with the +// given name, customized with options. May return an error if the +// name is invalid (e.g., empty) or improperly registered (e.g., +// duplicate registration). +func (m Meter) NewFloat64Measure(name string, opts ...Option) (Float64Measure, error) { + return wrapFloat64MeasureInstrument( + m.newSync(name, MeasureKind, Float64NumberKind, opts)) +} + +// RegisterInt64Observer creates a new integer Observer instrument +// with the given name, running a given callback, and customized with +// options. May return an error if the name is invalid (e.g., empty) +// or improperly registered (e.g., duplicate registration). +func (m Meter) RegisterInt64Observer(name string, callback Int64ObserverCallback, opts ...Option) (Int64Observer, error) { + if callback == nil { + return wrapInt64ObserverInstrument(NoopAsync{}, nil) + } + return wrapInt64ObserverInstrument( + m.newAsync(name, ObserverKind, Int64NumberKind, opts, + newInt64AsyncRunner(callback))) +} + +// RegisterFloat64Observer creates a new floating point Observer with +// the given name, running a given callback, and customized with +// options. May return an error if the name is invalid (e.g., empty) +// or improperly registered (e.g., duplicate registration). +func (m Meter) RegisterFloat64Observer(name string, callback Float64ObserverCallback, opts ...Option) (Float64Observer, error) { + if callback == nil { + return wrapFloat64ObserverInstrument(NoopAsync{}, nil) + } + return wrapFloat64ObserverInstrument( + m.newAsync(name, ObserverKind, Float64NumberKind, opts, + newFloat64AsyncRunner(callback))) +} + +// RegisterInt64Observer creates a new integer Observer instrument +// with the given name, running in a batch callback, and customized with +// options. May return an error if the name is invalid (e.g., empty) +// or improperly registered (e.g., duplicate registration). +func (b BatchObserver) RegisterInt64Observer(name string, opts ...Option) (Int64Observer, error) { + if b.runner == nil { + return wrapInt64ObserverInstrument(NoopAsync{}, nil) + } + return wrapInt64ObserverInstrument( + b.meter.newAsync(name, ObserverKind, Int64NumberKind, opts, b.runner)) +} + +// RegisterFloat64Observer creates a new floating point Observer with +// the given name, running in a batch callback, and customized with +// options. May return an error if the name is invalid (e.g., empty) +// or improperly registered (e.g., duplicate registration). +func (b BatchObserver) RegisterFloat64Observer(name string, opts ...Option) (Float64Observer, error) { + if b.runner == nil { + return wrapFloat64ObserverInstrument(NoopAsync{}, nil) + } + return wrapFloat64ObserverInstrument( + b.meter.newAsync(name, ObserverKind, Float64NumberKind, opts, + b.runner)) +} + +// MeterImpl returns the underlying MeterImpl of this Meter. +func (m Meter) MeterImpl() MeterImpl { + return m.impl +} + +// newAsync constructs one new asynchronous instrument. +func (m Meter) newAsync( + name string, + mkind Kind, + nkind NumberKind, + opts []Option, + runner AsyncRunner, +) ( + AsyncImpl, + error, +) { + if m.impl == nil { + return NoopAsync{}, nil + } + desc := NewDescriptor(name, mkind, nkind, opts...) + desc.config.LibraryName = m.libraryName + return m.impl.NewAsyncInstrument(desc, runner) +} + +// newSync constructs one new synchronous instrument. +func (m Meter) newSync( + name string, + metricKind Kind, + numberKind NumberKind, + opts []Option, +) ( + SyncImpl, + error, +) { + if m.impl == nil { + return NoopSync{}, nil + } + desc := NewDescriptor(name, metricKind, numberKind, opts...) + desc.config.LibraryName = m.libraryName + return m.impl.NewSyncInstrument(desc) +} diff --git a/api/metric/must.go b/api/metric/must.go index 69697a822..ecd47b0e0 100644 --- a/api/metric/must.go +++ b/api/metric/must.go @@ -20,6 +20,12 @@ type MeterMust struct { meter Meter } +// BatchObserverMust is a wrapper for BatchObserver that panics when +// any instrument constructor encounters an error. +type BatchObserverMust struct { + batch BatchObserver +} + // Must constructs a MeterMust implementation from a Meter, allowing // the application to panic when any instrument constructor yields an // error. @@ -86,3 +92,31 @@ func (mm MeterMust) RegisterFloat64Observer(name string, callback Float64Observe return inst } } + +// NewBatchObserver returns a wrapper around BatchObserver that panics +// when any instrument constructor returns an error. +func (mm MeterMust) NewBatchObserver(callback BatchObserverCallback) BatchObserverMust { + return BatchObserverMust{ + batch: mm.meter.NewBatchObserver(callback), + } +} + +// RegisterInt64Observer calls `BatchObserver.RegisterInt64Observer` and +// returns the instrument, panicking if it encounters an error. +func (bm BatchObserverMust) RegisterInt64Observer(name string, oos ...Option) Int64Observer { + if inst, err := bm.batch.RegisterInt64Observer(name, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// RegisterFloat64Observer calls `BatchObserver.RegisterFloat64Observer` and +// returns the instrument, panicking if it encounters an error. +func (bm BatchObserverMust) RegisterFloat64Observer(name string, oos ...Option) Float64Observer { + if inst, err := bm.batch.RegisterFloat64Observer(name, oos...); err != nil { + panic(err) + } else { + return inst + } +} diff --git a/api/metric/noop.go b/api/metric/noop.go index c77e24a7e..54d659c54 100644 --- a/api/metric/noop.go +++ b/api/metric/noop.go @@ -17,11 +17,10 @@ package metric import ( "context" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" ) type NoopProvider struct{} -type NoopMeter struct{} type noopInstrument struct{} type noopBoundInstrument struct{} @@ -29,13 +28,12 @@ type NoopSync struct{ noopInstrument } type NoopAsync struct{ noopInstrument } var _ Provider = NoopProvider{} -var _ Meter = NoopMeter{} var _ SyncImpl = NoopSync{} var _ BoundSyncImpl = noopBoundInstrument{} var _ AsyncImpl = NoopAsync{} func (NoopProvider) Meter(name string) Meter { - return NoopMeter{} + return Meter{} } func (noopInstrument) Implementation() interface{} { @@ -46,42 +44,15 @@ func (noopInstrument) Descriptor() Descriptor { return Descriptor{} } -func (noopBoundInstrument) RecordOne(context.Context, core.Number) { +func (noopBoundInstrument) RecordOne(context.Context, Number) { } func (noopBoundInstrument) Unbind() { } -func (NoopSync) Bind([]core.KeyValue) BoundSyncImpl { +func (NoopSync) Bind([]kv.KeyValue) BoundSyncImpl { return noopBoundInstrument{} } -func (NoopSync) RecordOne(context.Context, core.Number, []core.KeyValue) { -} - -func (NoopMeter) RecordBatch(context.Context, []core.KeyValue, ...Measurement) { -} - -func (NoopMeter) NewInt64Counter(string, ...Option) (Int64Counter, error) { - return Int64Counter{syncInstrument{NoopSync{}}}, nil -} - -func (NoopMeter) NewFloat64Counter(string, ...Option) (Float64Counter, error) { - return Float64Counter{syncInstrument{NoopSync{}}}, nil -} - -func (NoopMeter) NewInt64Measure(string, ...Option) (Int64Measure, error) { - return Int64Measure{syncInstrument{NoopSync{}}}, nil -} - -func (NoopMeter) NewFloat64Measure(string, ...Option) (Float64Measure, error) { - return Float64Measure{syncInstrument{NoopSync{}}}, nil -} - -func (NoopMeter) RegisterInt64Observer(string, Int64ObserverCallback, ...Option) (Int64Observer, error) { - return Int64Observer{asyncInstrument{NoopAsync{}}}, nil -} - -func (NoopMeter) RegisterFloat64Observer(string, Float64ObserverCallback, ...Option) (Float64Observer, error) { - return Float64Observer{asyncInstrument{NoopAsync{}}}, nil +func (NoopSync) RecordOne(context.Context, Number, []kv.KeyValue) { } diff --git a/api/core/number.go b/api/metric/number.go similarity index 95% rename from api/core/number.go rename to api/metric/number.go index 6c67cdc56..9fcffa798 100644 --- a/api/core/number.go +++ b/api/metric/number.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package core +package metric //go:generate stringer -type=NumberKind @@ -20,6 +20,8 @@ import ( "fmt" "math" "sync/atomic" + + "go.opentelemetry.io/otel/api/internal" ) // NumberKind describes the data type of the Number. @@ -92,17 +94,17 @@ func NewNumberFromRaw(r uint64) Number { // NewInt64Number creates an integral Number. func NewInt64Number(i int64) Number { - return NewNumberFromRaw(int64ToRaw(i)) + return NewNumberFromRaw(internal.Int64ToRaw(i)) } // NewFloat64Number creates a floating point Number. func NewFloat64Number(f float64) Number { - return NewNumberFromRaw(float64ToRaw(f)) + return NewNumberFromRaw(internal.Float64ToRaw(f)) } // NewInt64Number creates an integral Number. func NewUint64Number(u uint64) Number { - return NewNumberFromRaw(uint64ToRaw(u)) + return NewNumberFromRaw(internal.Uint64ToRaw(u)) } // - as x @@ -121,19 +123,19 @@ func (n *Number) AsRaw() uint64 { // AsInt64 assumes that the value contains an int64 and returns it as // such. func (n *Number) AsInt64() int64 { - return rawToInt64(n.AsRaw()) + return internal.RawToInt64(n.AsRaw()) } // AsFloat64 assumes that the measurement value contains a float64 and // returns it as such. func (n *Number) AsFloat64() float64 { - return rawToFloat64(n.AsRaw()) + return internal.RawToFloat64(n.AsRaw()) } // AsUint64 assumes that the value contains an uint64 and returns it // as such. func (n *Number) AsUint64() uint64 { - return rawToUint64(n.AsRaw()) + return internal.RawToUint64(n.AsRaw()) } // - as x atomic @@ -158,7 +160,7 @@ func (n *Number) AsInt64Atomic() int64 { // AsFloat64Atomic assumes that the measurement value contains a // float64 and returns it as such atomically. func (n *Number) AsFloat64Atomic() float64 { - return rawToFloat64(n.AsRawAtomic()) + return internal.RawToFloat64(n.AsRawAtomic()) } // AsUint64Atomic assumes that the number contains a uint64 and @@ -178,19 +180,19 @@ func (n *Number) AsRawPtr() *uint64 { // AsInt64Ptr assumes that the number contains an int64 and returns a // pointer to it. func (n *Number) AsInt64Ptr() *int64 { - return rawPtrToInt64Ptr(n.AsRawPtr()) + return internal.RawPtrToInt64Ptr(n.AsRawPtr()) } // AsFloat64Ptr assumes that the number contains a float64 and returns a // pointer to it. func (n *Number) AsFloat64Ptr() *float64 { - return rawPtrToFloat64Ptr(n.AsRawPtr()) + return internal.RawPtrToFloat64Ptr(n.AsRawPtr()) } // AsUint64Ptr assumes that the number contains a uint64 and returns a // pointer to it. func (n *Number) AsUint64Ptr() *uint64 { - return rawPtrToUint64Ptr(n.AsRawPtr()) + return internal.RawPtrToUint64Ptr(n.AsRawPtr()) } // - coerce @@ -299,7 +301,7 @@ func (n *Number) SetInt64Atomic(i int64) { // SetFloat64Atomic assumes that the number contains a float64 and // sets it to the passed value atomically. func (n *Number) SetFloat64Atomic(f float64) { - atomic.StoreUint64(n.AsRawPtr(), float64ToRaw(f)) + atomic.StoreUint64(n.AsRawPtr(), internal.Float64ToRaw(f)) } // SetUint64Atomic assumes that the number contains a uint64 and sets @@ -378,7 +380,7 @@ func (n *Number) SwapInt64Atomic(i int64) int64 { // it to the passed value and returns the old float64 value // atomically. func (n *Number) SwapFloat64Atomic(f float64) float64 { - return rawToFloat64(atomic.SwapUint64(n.AsRawPtr(), float64ToRaw(f))) + return internal.RawToFloat64(atomic.SwapUint64(n.AsRawPtr(), internal.Float64ToRaw(f))) } // SwapUint64Atomic assumes that the number contains an uint64, sets @@ -496,7 +498,7 @@ func (n *Number) CompareAndSwapInt64(oi, ni int64) bool { // CompareAndSwapFloat64 assumes that this number contains a float64 and // does the atomic CAS operation on it. func (n *Number) CompareAndSwapFloat64(of, nf float64) bool { - return atomic.CompareAndSwapUint64(n.AsRawPtr(), float64ToRaw(of), float64ToRaw(nf)) + return atomic.CompareAndSwapUint64(n.AsRawPtr(), internal.Float64ToRaw(of), internal.Float64ToRaw(nf)) } // CompareAndSwapUint64 assumes that this number contains a uint64 and diff --git a/api/core/number_test.go b/api/metric/number_test.go similarity index 99% rename from api/core/number_test.go rename to api/metric/number_test.go index 609d806f8..5a91eb3f5 100644 --- a/api/core/number_test.go +++ b/api/metric/number_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package core +package metric import ( "testing" diff --git a/api/core/numberkind_string.go b/api/metric/numberkind_string.go similarity index 97% rename from api/core/numberkind_string.go rename to api/metric/numberkind_string.go index be3eea9be..213783785 100644 --- a/api/core/numberkind_string.go +++ b/api/metric/numberkind_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -type=NumberKind"; DO NOT EDIT. -package core +package metric import "strconv" diff --git a/api/metric/observer.go b/api/metric/observer.go index 0ad9421a4..c5b173ff1 100644 --- a/api/metric/observer.go +++ b/api/metric/observer.go @@ -14,28 +14,13 @@ package metric -import "go.opentelemetry.io/otel/api/core" - -// Int64ObserverResult is an interface for reporting integral -// observations. -type Int64ObserverResult interface { - Observe(value int64, labels ...core.KeyValue) +// BatchObserver represents an Observer callback that can report +// observations for multiple instruments. +type BatchObserver struct { + meter Meter + runner AsyncBatchRunner } -// Float64ObserverResult is an interface for reporting floating point -// observations. -type Float64ObserverResult interface { - Observe(value float64, labels ...core.KeyValue) -} - -// Int64ObserverCallback is a type of callback that integral -// observers run. -type Int64ObserverCallback func(result Int64ObserverResult) - -// Float64ObserverCallback is a type of callback that floating point -// observers run. -type Float64ObserverCallback func(result Float64ObserverResult) - // Int64Observer is a metric that captures a set of int64 values at a // point in time. type Int64Observer struct { @@ -47,3 +32,25 @@ type Int64Observer struct { type Float64Observer struct { asyncInstrument } + +// Observation returns an Observation, a BatchObserverCallback +// argument, for an asynchronous integer instrument. +// This returns an implementation-level object for use by the SDK, +// users should not refer to this. +func (i Int64Observer) Observation(v int64) Observation { + return Observation{ + number: NewInt64Number(v), + instrument: i.instrument, + } +} + +// Observation returns an Observation, a BatchObserverCallback +// argument, for an asynchronous integer instrument. +// This returns an implementation-level object for use by the SDK, +// users should not refer to this. +func (f Float64Observer) Observation(v float64) Observation { + return Observation{ + number: NewFloat64Number(v), + instrument: f.instrument, + } +} diff --git a/api/metric/registry/registry.go b/api/metric/registry/registry.go index cfc4d7ee9..3a66b6903 100644 --- a/api/metric/registry/registry.go +++ b/api/metric/registry/registry.go @@ -19,7 +19,7 @@ import ( "fmt" "sync" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" ) @@ -32,6 +32,8 @@ type uniqueInstrumentMeterImpl struct { state map[key]metric.InstrumentImpl } +var _ metric.MeterImpl = (*uniqueInstrumentMeterImpl)(nil) + type key struct { name string libraryName string @@ -42,8 +44,6 @@ type key struct { var ErrMetricKindMismatch = fmt.Errorf( "A metric was already registered by this name with another kind or number type") -var _ metric.MeterImpl = (*uniqueInstrumentMeterImpl)(nil) - // NewUniqueInstrumentMeterImpl returns a wrapped metric.MeterImpl with // the addition of uniqueness checking. func NewUniqueInstrumentMeterImpl(impl metric.MeterImpl) metric.MeterImpl { @@ -54,7 +54,7 @@ func NewUniqueInstrumentMeterImpl(impl metric.MeterImpl) metric.MeterImpl { } // RecordBatch implements metric.MeterImpl. -func (u *uniqueInstrumentMeterImpl) RecordBatch(ctx context.Context, labels []core.KeyValue, ms ...metric.Measurement) { +func (u *uniqueInstrumentMeterImpl) RecordBatch(ctx context.Context, labels []kv.KeyValue, ms ...metric.Measurement) { u.impl.RecordBatch(ctx, labels, ms...) } @@ -125,7 +125,7 @@ func (u *uniqueInstrumentMeterImpl) NewSyncInstrument(descriptor metric.Descript // NewAsyncInstrument implements metric.MeterImpl. func (u *uniqueInstrumentMeterImpl) NewAsyncInstrument( descriptor metric.Descriptor, - callback func(func(core.Number, []core.KeyValue)), + runner metric.AsyncRunner, ) (metric.AsyncImpl, error) { u.lock.Lock() defer u.lock.Unlock() @@ -138,7 +138,7 @@ func (u *uniqueInstrumentMeterImpl) NewAsyncInstrument( return impl.(metric.AsyncImpl), nil } - asyncInst, err := u.impl.NewAsyncInstrument(descriptor, callback) + asyncInst, err := u.impl.NewAsyncInstrument(descriptor, runner) if err != nil { return nil, err } diff --git a/api/metric/sdkapi.go b/api/metric/sdkapi.go new file mode 100644 index 000000000..c9b902dc8 --- /dev/null +++ b/api/metric/sdkapi.go @@ -0,0 +1,93 @@ +// 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 metric + +import ( + "context" + + "go.opentelemetry.io/otel/api/kv" +) + +// MeterImpl is the interface an SDK must implement to supply a Meter +// implementation. +type MeterImpl interface { + // RecordBatch atomically records a batch of measurements. + RecordBatch(context.Context, []kv.KeyValue, ...Measurement) + + // NewSyncInstrument returns a newly constructed + // synchronous instrument implementation or an error, should + // one occur. + NewSyncInstrument(descriptor Descriptor) (SyncImpl, error) + + // NewAsyncInstrument returns a newly constructed + // asynchronous instrument implementation or an error, should + // one occur. + NewAsyncInstrument( + descriptor Descriptor, + runner AsyncRunner, + ) (AsyncImpl, error) +} + +// InstrumentImpl is a common interface for synchronous and +// asynchronous instruments. +type InstrumentImpl interface { + // Implementation returns the underlying implementation of the + // instrument, which allows the implementation to gain access + // to its own representation especially from a `Measurement`. + Implementation() interface{} + + // Descriptor returns a copy of the instrument's Descriptor. + Descriptor() Descriptor +} + +// SyncImpl is the implementation-level interface to a generic +// synchronous instrument (e.g., Measure and Counter instruments). +type SyncImpl interface { + InstrumentImpl + + // Bind creates an implementation-level bound instrument, + // binding a label set with this instrument implementation. + Bind(labels []kv.KeyValue) BoundSyncImpl + + // RecordOne captures a single synchronous metric event. + RecordOne(ctx context.Context, number Number, labels []kv.KeyValue) +} + +// BoundSyncImpl is the implementation-level interface to a +// generic bound synchronous instrument +type BoundSyncImpl interface { + + // RecordOne captures a single synchronous metric event. + RecordOne(ctx context.Context, number Number) + + // Unbind frees the resources associated with this bound instrument. It + // does not affect the metric this bound instrument was created through. + Unbind() +} + +// AsyncImpl is an implementation-level interface to an +// asynchronous instrument (e.g., Observer instruments). +type AsyncImpl interface { + InstrumentImpl +} + +// WrapMeterImpl constructs a `Meter` implementation from a +// `MeterImpl` implementation. +func WrapMeterImpl(impl MeterImpl, libraryName string) Meter { + return Meter{ + impl: impl, + libraryName: libraryName, + } +} diff --git a/api/metric/sdkhelpers.go b/api/metric/sdkhelpers.go deleted file mode 100644 index 9c4dc705a..000000000 --- a/api/metric/sdkhelpers.go +++ /dev/null @@ -1,254 +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 metric - -import ( - "context" - - "go.opentelemetry.io/otel/api/core" -) - -// MeterImpl is a convenient interface for SDK and test -// implementations that would provide a `Meter` but do not wish to -// re-implement the API's type-safe interfaces. Helpers provided in -// this package will construct a `Meter` given a `MeterImpl`. -type MeterImpl interface { - // RecordBatch atomically records a batch of measurements. - RecordBatch(context.Context, []core.KeyValue, ...Measurement) - - // NewSyncInstrument returns a newly constructed - // synchronous instrument implementation or an error, should - // one occur. - NewSyncInstrument(descriptor Descriptor) (SyncImpl, error) - - // NewAsyncInstrument returns a newly constructed - // asynchronous instrument implementation or an error, should - // one occur. - NewAsyncInstrument( - descriptor Descriptor, - callback func(func(core.Number, []core.KeyValue)), - ) (AsyncImpl, error) -} - -// InstrumentImpl is a common interface for synchronous and -// asynchronous instruments. -type InstrumentImpl interface { - // Implementation returns the underlying implementation of the - // instrument, which allows the implementation to gain access - // to its own representation especially from a `Measurement`. - Implementation() interface{} - - // Descriptor returns a copy of the instrument's Descriptor. - Descriptor() Descriptor -} - -// SyncImpl is the implementation-level interface to a generic -// synchronous instrument (e.g., Measure and Counter instruments). -type SyncImpl interface { - InstrumentImpl - - // Bind creates an implementation-level bound instrument, - // binding a label set with this instrument implementation. - Bind(labels []core.KeyValue) BoundSyncImpl - - // RecordOne captures a single synchronous metric event. - RecordOne(ctx context.Context, number core.Number, labels []core.KeyValue) -} - -// BoundSyncImpl is the implementation-level interface to a -// generic bound synchronous instrument -type BoundSyncImpl interface { - - // RecordOne captures a single synchronous metric event. - RecordOne(ctx context.Context, number core.Number) - - // Unbind frees the resources associated with this bound instrument. It - // does not affect the metric this bound instrument was created through. - Unbind() -} - -// AsyncImpl is an implementation-level interface to an -// asynchronous instrument (e.g., Observer instruments). -type AsyncImpl interface { - InstrumentImpl - - // Note: An `Unregister()` API could be supported here. -} - -// wrappedMeterImpl implements the `Meter` interface given a -// `MeterImpl` implementation. -type wrappedMeterImpl struct { - impl MeterImpl - libraryName string -} - -// int64ObserverResult is an adapter for int64-valued asynchronous -// callbacks. -type int64ObserverResult struct { - observe func(core.Number, []core.KeyValue) -} - -// float64ObserverResult is an adapter for float64-valued asynchronous -// callbacks. -type float64ObserverResult struct { - observe func(core.Number, []core.KeyValue) -} - -var ( - _ Meter = (*wrappedMeterImpl)(nil) - _ Int64ObserverResult = int64ObserverResult{} - _ Float64ObserverResult = float64ObserverResult{} -) - -// Configure is a helper that applies all the options to a Config. -func Configure(opts []Option) Config { - var config Config - for _, o := range opts { - o.Apply(&config) - } - return config -} - -// WrapMeterImpl constructs a `Meter` implementation from a -// `MeterImpl` implementation. -func WrapMeterImpl(impl MeterImpl, libraryName string) Meter { - return &wrappedMeterImpl{ - impl: impl, - libraryName: libraryName, - } -} - -func (m *wrappedMeterImpl) RecordBatch(ctx context.Context, ls []core.KeyValue, ms ...Measurement) { - m.impl.RecordBatch(ctx, ls, ms...) -} - -func (m *wrappedMeterImpl) newSync(name string, metricKind Kind, numberKind core.NumberKind, opts []Option) (SyncImpl, error) { - desc := NewDescriptor(name, metricKind, numberKind, opts...) - desc.config.LibraryName = m.libraryName - return m.impl.NewSyncInstrument(desc) -} - -func (m *wrappedMeterImpl) NewInt64Counter(name string, opts ...Option) (Int64Counter, error) { - return WrapInt64CounterInstrument( - m.newSync(name, CounterKind, core.Int64NumberKind, opts)) -} - -// WrapInt64CounterInstrument returns an `Int64Counter` from a -// `SyncImpl`. An error will be generated if the -// `SyncImpl` is nil (in which case a No-op is substituted), -// otherwise the error passes through. -func WrapInt64CounterInstrument(syncInst SyncImpl, err error) (Int64Counter, error) { - common, err := checkNewSync(syncInst, err) - return Int64Counter{syncInstrument: common}, err -} - -func (m *wrappedMeterImpl) NewFloat64Counter(name string, opts ...Option) (Float64Counter, error) { - return WrapFloat64CounterInstrument( - m.newSync(name, CounterKind, core.Float64NumberKind, opts)) -} - -// WrapFloat64CounterInstrument returns an `Float64Counter` from a -// `SyncImpl`. An error will be generated if the -// `SyncImpl` is nil (in which case a No-op is substituted), -// otherwise the error passes through. -func WrapFloat64CounterInstrument(syncInst SyncImpl, err error) (Float64Counter, error) { - common, err := checkNewSync(syncInst, err) - return Float64Counter{syncInstrument: common}, err -} - -func (m *wrappedMeterImpl) NewInt64Measure(name string, opts ...Option) (Int64Measure, error) { - return WrapInt64MeasureInstrument( - m.newSync(name, MeasureKind, core.Int64NumberKind, opts)) -} - -// WrapInt64MeasureInstrument returns an `Int64Measure` from a -// `SyncImpl`. An error will be generated if the -// `SyncImpl` is nil (in which case a No-op is substituted), -// otherwise the error passes through. -func WrapInt64MeasureInstrument(syncInst SyncImpl, err error) (Int64Measure, error) { - common, err := checkNewSync(syncInst, err) - return Int64Measure{syncInstrument: common}, err -} - -func (m *wrappedMeterImpl) NewFloat64Measure(name string, opts ...Option) (Float64Measure, error) { - return WrapFloat64MeasureInstrument( - m.newSync(name, MeasureKind, core.Float64NumberKind, opts)) -} - -// WrapFloat64MeasureInstrument returns an `Float64Measure` from a -// `SyncImpl`. An error will be generated if the -// `SyncImpl` is nil (in which case a No-op is substituted), -// otherwise the error passes through. -func WrapFloat64MeasureInstrument(syncInst SyncImpl, err error) (Float64Measure, error) { - common, err := checkNewSync(syncInst, err) - return Float64Measure{syncInstrument: common}, err -} - -func (m *wrappedMeterImpl) newAsync(name string, mkind Kind, nkind core.NumberKind, opts []Option, callback func(func(core.Number, []core.KeyValue))) (AsyncImpl, error) { - desc := NewDescriptor(name, mkind, nkind, opts...) - desc.config.LibraryName = m.libraryName - return m.impl.NewAsyncInstrument(desc, callback) -} - -func (m *wrappedMeterImpl) RegisterInt64Observer(name string, callback Int64ObserverCallback, opts ...Option) (Int64Observer, error) { - if callback == nil { - return NoopMeter{}.RegisterInt64Observer("", nil) - } - return WrapInt64ObserverInstrument( - m.newAsync(name, ObserverKind, core.Int64NumberKind, opts, - func(observe func(core.Number, []core.KeyValue)) { - // Note: this memory allocation could be avoided by - // using a pointer to this object and mutating it - // on each collection interval. - callback(int64ObserverResult{observe}) - })) -} - -// WrapInt64ObserverInstrument returns an `Int64Observer` from a -// `AsyncImpl`. An error will be generated if the -// `AsyncImpl` is nil (in which case a No-op is substituted), -// otherwise the error passes through. -func WrapInt64ObserverInstrument(asyncInst AsyncImpl, err error) (Int64Observer, error) { - common, err := checkNewAsync(asyncInst, err) - return Int64Observer{asyncInstrument: common}, err -} - -func (m *wrappedMeterImpl) RegisterFloat64Observer(name string, callback Float64ObserverCallback, opts ...Option) (Float64Observer, error) { - if callback == nil { - return NoopMeter{}.RegisterFloat64Observer("", nil) - } - return WrapFloat64ObserverInstrument( - m.newAsync(name, ObserverKind, core.Float64NumberKind, opts, - func(observe func(core.Number, []core.KeyValue)) { - callback(float64ObserverResult{observe}) - })) -} - -// WrapFloat64ObserverInstrument returns an `Float64Observer` from a -// `AsyncImpl`. An error will be generated if the -// `AsyncImpl` is nil (in which case a No-op is substituted), -// otherwise the error passes through. -func WrapFloat64ObserverInstrument(asyncInst AsyncImpl, err error) (Float64Observer, error) { - common, err := checkNewAsync(asyncInst, err) - return Float64Observer{asyncInstrument: common}, err -} - -func (io int64ObserverResult) Observe(value int64, labels ...core.KeyValue) { - io.observe(core.NewInt64Number(value), labels) -} - -func (fo float64ObserverResult) Observe(value float64, labels ...core.KeyValue) { - fo.observe(core.NewFloat64Number(value), labels) -} diff --git a/api/metric/sync.go b/api/metric/sync.go new file mode 100644 index 000000000..6b8d3a2a3 --- /dev/null +++ b/api/metric/sync.go @@ -0,0 +1,211 @@ +// 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 metric + +import ( + "context" + "errors" + + "go.opentelemetry.io/otel/api/kv" +) + +// Measurement is used for reporting a synchronous batch of metric +// values. Instances of this type should be created by synchronous +// instruments (e.g., Int64Counter.Measurement()). +type Measurement struct { + // number needs to be aligned for 64-bit atomic operations. + number Number + instrument SyncImpl +} + +// syncInstrument contains a SyncImpl. +type syncInstrument struct { + instrument SyncImpl +} + +// syncBoundInstrument contains a BoundSyncImpl. +type syncBoundInstrument struct { + boundInstrument BoundSyncImpl +} + +// asyncInstrument contains a AsyncImpl. +type asyncInstrument struct { + instrument AsyncImpl +} + +// ErrSDKReturnedNilImpl is used when one of the `MeterImpl` New +// methods returns nil. +var ErrSDKReturnedNilImpl = errors.New("SDK returned a nil implementation") + +// SyncImpl returns the instrument that created this measurement. +// This returns an implementation-level object for use by the SDK, +// users should not refer to this. +func (m Measurement) SyncImpl() SyncImpl { + return m.instrument +} + +// Number returns a number recorded in this measurement. +func (m Measurement) Number() Number { + return m.number +} + +// AsyncImpl returns the instrument that created this observation. +// This returns an implementation-level object for use by the SDK, +// users should not refer to this. +func (m Observation) AsyncImpl() AsyncImpl { + return m.instrument +} + +// Number returns a number recorded in this observation. +func (m Observation) Number() Number { + return m.number +} + +// AsyncImpl implements AsyncImpl. +func (a asyncInstrument) AsyncImpl() AsyncImpl { + return a.instrument +} + +// SyncImpl returns the implementation object for synchronous instruments. +func (s syncInstrument) SyncImpl() SyncImpl { + return s.instrument +} + +func (s syncInstrument) bind(labels []kv.KeyValue) syncBoundInstrument { + return newSyncBoundInstrument(s.instrument.Bind(labels)) +} + +func (s syncInstrument) float64Measurement(value float64) Measurement { + return newMeasurement(s.instrument, NewFloat64Number(value)) +} + +func (s syncInstrument) int64Measurement(value int64) Measurement { + return newMeasurement(s.instrument, NewInt64Number(value)) +} + +func (s syncInstrument) directRecord(ctx context.Context, number Number, labels []kv.KeyValue) { + s.instrument.RecordOne(ctx, number, labels) +} + +func (h syncBoundInstrument) directRecord(ctx context.Context, number Number) { + h.boundInstrument.RecordOne(ctx, number) +} + +// Unbind calls SyncImpl.Unbind. +func (h syncBoundInstrument) Unbind() { + h.boundInstrument.Unbind() +} + +// checkNewAsync receives an AsyncImpl and potential +// error, and returns the same types, checking for and ensuring that +// the returned interface is not nil. +func checkNewAsync(instrument AsyncImpl, err error) (asyncInstrument, error) { + if instrument == nil { + if err == nil { + err = ErrSDKReturnedNilImpl + } + instrument = NoopAsync{} + } + return asyncInstrument{ + instrument: instrument, + }, err +} + +// checkNewSync receives an SyncImpl and potential +// error, and returns the same types, checking for and ensuring that +// the returned interface is not nil. +func checkNewSync(instrument SyncImpl, err error) (syncInstrument, error) { + if instrument == nil { + if err == nil { + err = ErrSDKReturnedNilImpl + } + // Note: an alternate behavior would be to synthesize a new name + // or group all duplicately-named instruments of a certain type + // together and use a tag for the original name, e.g., + // name = 'invalid.counter.int64' + // label = 'original-name=duplicate-counter-name' + instrument = NoopSync{} + } + return syncInstrument{ + instrument: instrument, + }, err +} + +func newSyncBoundInstrument(boundInstrument BoundSyncImpl) syncBoundInstrument { + return syncBoundInstrument{ + boundInstrument: boundInstrument, + } +} + +func newMeasurement(instrument SyncImpl, number Number) Measurement { + return Measurement{ + instrument: instrument, + number: number, + } +} + +// wrapInt64CounterInstrument returns an `Int64Counter` from a +// `SyncImpl`. An error will be generated if the +// `SyncImpl` is nil (in which case a No-op is substituted), +// otherwise the error passes through. +func wrapInt64CounterInstrument(syncInst SyncImpl, err error) (Int64Counter, error) { + common, err := checkNewSync(syncInst, err) + return Int64Counter{syncInstrument: common}, err +} + +// wrapFloat64CounterInstrument returns an `Float64Counter` from a +// `SyncImpl`. An error will be generated if the +// `SyncImpl` is nil (in which case a No-op is substituted), +// otherwise the error passes through. +func wrapFloat64CounterInstrument(syncInst SyncImpl, err error) (Float64Counter, error) { + common, err := checkNewSync(syncInst, err) + return Float64Counter{syncInstrument: common}, err +} + +// wrapInt64MeasureInstrument returns an `Int64Measure` from a +// `SyncImpl`. An error will be generated if the +// `SyncImpl` is nil (in which case a No-op is substituted), +// otherwise the error passes through. +func wrapInt64MeasureInstrument(syncInst SyncImpl, err error) (Int64Measure, error) { + common, err := checkNewSync(syncInst, err) + return Int64Measure{syncInstrument: common}, err +} + +// wrapFloat64MeasureInstrument returns an `Float64Measure` from a +// `SyncImpl`. An error will be generated if the +// `SyncImpl` is nil (in which case a No-op is substituted), +// otherwise the error passes through. +func wrapFloat64MeasureInstrument(syncInst SyncImpl, err error) (Float64Measure, error) { + common, err := checkNewSync(syncInst, err) + return Float64Measure{syncInstrument: common}, err +} + +// wrapInt64ObserverInstrument returns an `Int64Observer` from a +// `AsyncImpl`. An error will be generated if the +// `AsyncImpl` is nil (in which case a No-op is substituted), +// otherwise the error passes through. +func wrapInt64ObserverInstrument(asyncInst AsyncImpl, err error) (Int64Observer, error) { + common, err := checkNewAsync(asyncInst, err) + return Int64Observer{asyncInstrument: common}, err +} + +// wrapFloat64ObserverInstrument returns an `Float64Observer` from a +// `AsyncImpl`. An error will be generated if the +// `AsyncImpl` is nil (in which case a No-op is substituted), +// otherwise the error passes through. +func wrapFloat64ObserverInstrument(asyncInst AsyncImpl, err error) (Float64Observer, error) { + common, err := checkNewAsync(asyncInst, err) + return Float64Observer{asyncInstrument: common}, err +} diff --git a/api/testharness/harness.go b/api/testharness/harness.go index 834d94e45..f21921456 100644 --- a/api/testharness/harness.go +++ b/api/testharness/harness.go @@ -21,9 +21,10 @@ import ( "testing" "time" + "go.opentelemetry.io/otel/api/kv" + "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/key" "go.opentelemetry.io/otel/api/trace" "go.opentelemetry.io/otel/internal/matchers" ) @@ -329,7 +330,7 @@ func (h *Harness) testSpan(tracerFactory func() trace.Tracer) { span.SetName("new name") }, "#SetAttributes": func(span trace.Span) { - span.SetAttributes(key.String("key1", "value"), key.Int("key2", 123)) + span.SetAttributes(kv.String("key1", "value"), kv.Int("key2", 123)) }, } var mechanisms = map[string]func() trace.Span{ diff --git a/api/trace/always_off_sampler.go b/api/trace/always_off_sampler.go index 22116f299..f0679eb62 100644 --- a/api/trace/always_off_sampler.go +++ b/api/trace/always_off_sampler.go @@ -15,7 +15,7 @@ package trace import ( - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" ) const ( @@ -36,7 +36,7 @@ func (ns alwaysOffSampler) ShouldSample( _ SpanID, _ string, _ SpanKind, - _ []core.KeyValue, + _ []kv.KeyValue, _ []Link, ) Decision { return alwaysOffSamplerDecision diff --git a/api/trace/always_off_sampler_test.go b/api/trace/always_off_sampler_test.go index cc87af41f..3ead33435 100644 --- a/api/trace/always_off_sampler_test.go +++ b/api/trace/always_off_sampler_test.go @@ -19,12 +19,12 @@ import ( "github.com/google/go-cmp/cmp" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" ) func TestNeverSamperShouldSample(t *testing.T) { gotD := AlwaysOffSampler().ShouldSample( - SpanContext{}, false, ID{}, SpanID{}, "span", SpanKindClient, []core.KeyValue{}, []Link{}) + SpanContext{}, false, ID{}, SpanID{}, "span", SpanKindClient, []kv.KeyValue{}, []Link{}) wantD := Decision{Sampled: false} if diff := cmp.Diff(wantD, gotD); diff != "" { t.Errorf("Decision: +got, -want%v", diff) diff --git a/api/trace/always_on_sampler.go b/api/trace/always_on_sampler.go index 05e1d8050..da8d5c913 100644 --- a/api/trace/always_on_sampler.go +++ b/api/trace/always_on_sampler.go @@ -15,7 +15,7 @@ package trace import ( - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" ) const ( @@ -36,7 +36,7 @@ func (as alwaysOnSampler) ShouldSample( _ SpanID, _ string, _ SpanKind, - _ []core.KeyValue, + _ []kv.KeyValue, _ []Link, ) Decision { return alwaysOnSamplerDecision diff --git a/api/trace/always_on_sampler_test.go b/api/trace/always_on_sampler_test.go index 88f83f36a..033433194 100644 --- a/api/trace/always_on_sampler_test.go +++ b/api/trace/always_on_sampler_test.go @@ -19,12 +19,12 @@ import ( "github.com/google/go-cmp/cmp" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" ) func TestAlwaysOnSamplerShouldSample(t *testing.T) { gotD := AlwaysOnSampler().ShouldSample( - SpanContext{}, false, ID{}, SpanID{}, "span", SpanKindClient, []core.KeyValue{}, []Link{}) + SpanContext{}, false, ID{}, SpanID{}, "span", SpanKindClient, []kv.KeyValue{}, []Link{}) wantD := Decision{Sampled: true} if diff := cmp.Diff(wantD, gotD); diff != "" { t.Errorf("Decision: +got, -want%v", diff) diff --git a/api/trace/api.go b/api/trace/api.go index c8414d47c..620e0bd28 100644 --- a/api/trace/api.go +++ b/api/trace/api.go @@ -20,7 +20,7 @@ import ( "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" ) type Provider interface { @@ -92,10 +92,10 @@ type Span interface { End(options ...EndOption) // AddEvent adds an event to the span. - AddEvent(ctx context.Context, name string, attrs ...core.KeyValue) + AddEvent(ctx context.Context, name string, attrs ...kv.KeyValue) // AddEventWithTimestamp adds an event with a custom timestamp // to the span. - AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...core.KeyValue) + AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...kv.KeyValue) // IsRecording returns true if the span is active and recording events is enabled. IsRecording() bool @@ -120,7 +120,7 @@ type Span interface { SetName(name string) // Set span attributes - SetAttributes(...core.KeyValue) + SetAttributes(...kv.KeyValue) // Set singular span attribute, with type inference. SetAttribute(string, interface{}) @@ -132,7 +132,7 @@ type StartOption func(*StartConfig) // StartConfig provides options to set properties of span at the time of starting // a new span. type StartConfig struct { - Attributes []core.KeyValue + Attributes []kv.KeyValue StartTime time.Time Links []Link Record bool @@ -153,7 +153,7 @@ type StartConfig struct { // be correlated. type Link struct { SpanContext - Attributes []core.KeyValue + Attributes []kv.KeyValue } // SpanKind represents the role of a Span inside a Trace. Often, this defines how a Span @@ -221,7 +221,7 @@ func WithStartTime(t time.Time) StartOption { // WithAttributes sets attributes to span. These attributes provides additional // data about the span. // Multiple `WithAttributes` options appends the attributes preserving the order. -func WithAttributes(attrs ...core.KeyValue) StartOption { +func WithAttributes(attrs ...kv.KeyValue) StartOption { return func(c *StartConfig) { c.Attributes = append(c.Attributes, attrs...) } @@ -248,7 +248,7 @@ func WithNewRoot() StartOption { } // LinkedTo allows instantiating a Span with initial Links. -func LinkedTo(sc SpanContext, attrs ...core.KeyValue) StartOption { +func LinkedTo(sc SpanContext, attrs ...kv.KeyValue) StartOption { return func(c *StartConfig) { c.Links = append(c.Links, Link{sc, attrs}) } diff --git a/api/trace/context_test.go b/api/trace/context_test.go index 1c014eebc..fd03d146a 100644 --- a/api/trace/context_test.go +++ b/api/trace/context_test.go @@ -21,7 +21,7 @@ import ( "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/trace" ) @@ -94,7 +94,7 @@ func (mockSpan) SetError(v bool) { } // SetAttributes does nothing. -func (mockSpan) SetAttributes(attributes ...core.KeyValue) { +func (mockSpan) SetAttributes(attributes ...kv.KeyValue) { } // SetAttribute does nothing. @@ -115,9 +115,9 @@ func (mockSpan) Tracer() trace.Tracer { } // Event does nothing. -func (mockSpan) AddEvent(ctx context.Context, name string, attrs ...core.KeyValue) { +func (mockSpan) AddEvent(ctx context.Context, name string, attrs ...kv.KeyValue) { } // AddEventWithTimestamp does nothing. -func (mockSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...core.KeyValue) { +func (mockSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...kv.KeyValue) { } diff --git a/api/trace/noop_span.go b/api/trace/noop_span.go index 5d8a51347..e222ad7f5 100644 --- a/api/trace/noop_span.go +++ b/api/trace/noop_span.go @@ -20,7 +20,7 @@ import ( "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" ) type NoopSpan struct { @@ -47,7 +47,7 @@ func (NoopSpan) SetError(v bool) { } // SetAttributes does nothing. -func (NoopSpan) SetAttributes(attributes ...core.KeyValue) { +func (NoopSpan) SetAttributes(attributes ...kv.KeyValue) { } // SetAttribute does nothing. @@ -68,11 +68,11 @@ func (NoopSpan) Tracer() Tracer { } // AddEvent does nothing. -func (NoopSpan) AddEvent(ctx context.Context, name string, attrs ...core.KeyValue) { +func (NoopSpan) AddEvent(ctx context.Context, name string, attrs ...kv.KeyValue) { } // AddEventWithTimestamp does nothing. -func (NoopSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...core.KeyValue) { +func (NoopSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...kv.KeyValue) { } // SetName does nothing. diff --git a/api/trace/sampler.go b/api/trace/sampler.go index 91df24ed6..b90613c7a 100644 --- a/api/trace/sampler.go +++ b/api/trace/sampler.go @@ -14,7 +14,7 @@ package trace -import "go.opentelemetry.io/otel/api/core" +import "go.opentelemetry.io/otel/api/kv" type Sampler interface { // ShouldSample returns a Decision that contains a decision whether to sample @@ -27,7 +27,7 @@ type Sampler interface { spanID SpanID, spanName string, spanKind SpanKind, - attributes []core.KeyValue, + attributes []kv.KeyValue, links []Link, ) Decision @@ -43,5 +43,5 @@ type Decision struct { // Attributes provides insight into Sample r's decision process. // It could be empty slice or nil if no attributes are recorded by the sampler. - Attributes []core.KeyValue + Attributes []kv.KeyValue } diff --git a/api/trace/testtrace/event.go b/api/trace/testtrace/event.go index 60d1e8c02..69e0e1dba 100644 --- a/api/trace/testtrace/event.go +++ b/api/trace/testtrace/event.go @@ -17,12 +17,14 @@ package testtrace import ( "time" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" + + "go.opentelemetry.io/otel/api/kv/value" ) // Event encapsulates the properties of calls to AddEvent or AddEventWithTimestamp. type Event struct { Timestamp time.Time Name string - Attributes map[core.Key]core.Value + Attributes map[kv.Key]value.Value } diff --git a/api/trace/testtrace/span.go b/api/trace/testtrace/span.go index a97805aed..9053bfff7 100644 --- a/api/trace/testtrace/span.go +++ b/api/trace/testtrace/span.go @@ -21,16 +21,17 @@ import ( "sync" "time" + "go.opentelemetry.io/otel/api/kv/value" + "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/trace" ) const ( - errorTypeKey = core.Key("error.type") - errorMessageKey = core.Key("error.message") + errorTypeKey = kv.Key("error.type") + errorMessageKey = kv.Key("error.message") errorEventName = "error" ) @@ -47,9 +48,9 @@ type Span struct { endTime time.Time statusCode codes.Code statusMessage string - attributes map[core.Key]core.Value + attributes map[kv.Key]value.Value events []Event - links map[trace.SpanContext][]core.KeyValue + links map[trace.SpanContext][]kv.KeyValue } func (s *Span) Tracer() trace.Tracer { @@ -109,11 +110,11 @@ func (s *Span) RecordError(ctx context.Context, err error, opts ...trace.ErrorOp ) } -func (s *Span) AddEvent(ctx context.Context, name string, attrs ...core.KeyValue) { +func (s *Span) AddEvent(ctx context.Context, name string, attrs ...kv.KeyValue) { s.AddEventWithTimestamp(ctx, time.Now(), name, attrs...) } -func (s *Span) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...core.KeyValue) { +func (s *Span) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...kv.KeyValue) { s.lock.Lock() defer s.lock.Unlock() @@ -121,7 +122,7 @@ func (s *Span) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, n return } - attributes := make(map[core.Key]core.Value) + attributes := make(map[kv.Key]value.Value) for _, attr := range attrs { attributes[attr.Key] = attr.Value @@ -165,7 +166,7 @@ func (s *Span) SetName(name string) { s.name = name } -func (s *Span) SetAttributes(attrs ...core.KeyValue) { +func (s *Span) SetAttributes(attrs ...kv.KeyValue) { s.lock.Lock() defer s.lock.Unlock() @@ -179,7 +180,7 @@ func (s *Span) SetAttributes(attrs ...core.KeyValue) { } func (s *Span) SetAttribute(k string, v interface{}) { - s.SetAttributes(key.Infer(k, v)) + s.SetAttributes(kv.Infer(k, v)) } // Name returns the name most recently set on the Span, either at or after creation time. @@ -198,11 +199,11 @@ func (s *Span) ParentSpanID() trace.SpanID { // Attributes returns the attributes set on the Span, either at or after creation time. // If the same attribute key was set multiple times, the last call will be used. // Attributes cannot be changed after End has been called on the Span. -func (s *Span) Attributes() map[core.Key]core.Value { +func (s *Span) Attributes() map[kv.Key]value.Value { s.lock.RLock() defer s.lock.RUnlock() - attributes := make(map[core.Key]core.Value) + attributes := make(map[kv.Key]value.Value) for k, v := range s.attributes { attributes[k] = v @@ -219,11 +220,11 @@ func (s *Span) Events() []Event { // Links returns the links set on the Span at creation time. // If multiple links for the same SpanContext were set, the last link will be used. -func (s *Span) Links() map[trace.SpanContext][]core.KeyValue { - links := make(map[trace.SpanContext][]core.KeyValue) +func (s *Span) Links() map[trace.SpanContext][]kv.KeyValue { + links := make(map[trace.SpanContext][]kv.KeyValue) for sc, attributes := range s.links { - links[sc] = append([]core.KeyValue{}, attributes...) + links[sc] = append([]kv.KeyValue{}, attributes...) } return links diff --git a/api/trace/testtrace/span_test.go b/api/trace/testtrace/span_test.go index 455e4e4de..9b46bd6e0 100644 --- a/api/trace/testtrace/span_test.go +++ b/api/trace/testtrace/span_test.go @@ -22,10 +22,11 @@ import ( "testing" "time" + "go.opentelemetry.io/otel/api/kv/value" + "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/trace" "go.opentelemetry.io/otel/api/trace/testtrace" "go.opentelemetry.io/otel/internal/matchers" @@ -160,9 +161,9 @@ func TestSpan(t *testing.T) { expectedEvents := []testtrace.Event{{ Timestamp: testTime, Name: "error", - Attributes: map[core.Key]core.Value{ - core.Key("error.type"): core.String(s.typ), - core.Key("error.message"): core.String(s.msg), + Attributes: map[kv.Key]value.Value{ + kv.Key("error.type"): value.String(s.typ), + kv.Key("error.message"): value.String(s.msg), }, }} e.Expect(subject.Events()).ToEqual(expectedEvents) @@ -191,9 +192,9 @@ func TestSpan(t *testing.T) { expectedEvents := []testtrace.Event{{ Timestamp: testTime, Name: "error", - Attributes: map[core.Key]core.Value{ - core.Key("error.type"): core.String("go.opentelemetry.io/otel/internal/testing.TestError"), - core.Key("error.message"): core.String(errMsg), + Attributes: map[kv.Key]value.Value{ + kv.Key("error.type"): value.String("go.opentelemetry.io/otel/internal/testing.TestError"), + kv.Key("error.message"): value.String(errMsg), }, }} e.Expect(subject.Events()).ToEqual(expectedEvents) @@ -326,7 +327,7 @@ func TestSpan(t *testing.T) { subject, ok := span.(*testtrace.Span) e.Expect(ok).ToBeTrue() - e.Expect(subject.Attributes()).ToEqual(map[core.Key]core.Value{}) + e.Expect(subject.Attributes()).ToEqual(map[kv.Key]value.Value{}) }) t.Run("returns the most recently set attributes", func(t *testing.T) { @@ -340,9 +341,9 @@ func TestSpan(t *testing.T) { subject, ok := span.(*testtrace.Span) e.Expect(ok).ToBeTrue() - attr1 := key.String("key1", "value1") - attr2 := key.String("key2", "value2") - attr3 := key.String("key3", "value3") + attr1 := kv.String("key1", "value1") + attr2 := kv.String("key2", "value2") + attr3 := kv.String("key3", "value3") unexpectedAttr := attr2.Key.String("unexpected") subject.SetAttributes(attr1, unexpectedAttr, attr3) @@ -366,7 +367,7 @@ func TestSpan(t *testing.T) { subject, ok := span.(*testtrace.Span) e.Expect(ok).ToBeTrue() - expectedAttr := key.String("key", "value") + expectedAttr := kv.String("key", "value") subject.SetAttributes(expectedAttr) subject.End() @@ -396,7 +397,7 @@ func TestSpan(t *testing.T) { go func() { defer wg.Done() - subject.SetAttributes(key.String("key", "value")) + subject.SetAttributes(kv.String("key", "value")) }() go func() { @@ -452,9 +453,9 @@ func TestSpan(t *testing.T) { e.Expect(ok).ToBeTrue() event1Name := "event1" - event1Attributes := []core.KeyValue{ - key.String("event1Attr1", "foo"), - key.String("event1Attr2", "bar"), + event1Attributes := []kv.KeyValue{ + kv.String("event1Attr1", "foo"), + kv.String("event1Attr2", "bar"), } event1Start := time.Now() @@ -463,8 +464,8 @@ func TestSpan(t *testing.T) { event2Timestamp := time.Now().AddDate(5, 0, 0) event2Name := "event1" - event2Attributes := []core.KeyValue{ - key.String("event2Attr", "abc"), + event2Attributes := []kv.KeyValue{ + kv.String("event2Attr", "abc"), } subject.AddEventWithTimestamp(context.Background(), event2Timestamp, event2Name, event2Attributes...) diff --git a/api/trace/testtrace/tracer.go b/api/trace/testtrace/tracer.go index 49dfdd453..cbb1c8838 100644 --- a/api/trace/testtrace/tracer.go +++ b/api/trace/testtrace/tracer.go @@ -19,7 +19,9 @@ import ( "sync" "time" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv/value" + + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/trace" "go.opentelemetry.io/otel/internal/trace/parent" @@ -80,8 +82,8 @@ func (t *Tracer) Start(ctx context.Context, name string, opts ...trace.StartOpti SpanID: spanID, }, parentSpanID: parentSpanID, - attributes: make(map[core.Key]core.Value), - links: make(map[trace.SpanContext][]core.KeyValue), + attributes: make(map[kv.Key]value.Value), + links: make(map[trace.SpanContext][]kv.KeyValue), } span.SetName(name) diff --git a/api/trace/testtrace/tracer_test.go b/api/trace/testtrace/tracer_test.go index 8bf0a7535..fff385e1d 100644 --- a/api/trace/testtrace/tracer_test.go +++ b/api/trace/testtrace/tracer_test.go @@ -20,8 +20,7 @@ import ( "testing" "time" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/testharness" "go.opentelemetry.io/otel/api/trace" "go.opentelemetry.io/otel/api/trace/testtrace" @@ -61,8 +60,8 @@ func TestTracer(t *testing.T) { e := matchers.NewExpecter(t) - attr1 := key.String("a", "1") - attr2 := key.String("b", "2") + attr1 := kv.String("a", "1") + attr2 := kv.String("b", "2") subject := testtrace.NewTracer() _, span := subject.Start(context.Background(), "test", trace.WithAttributes(attr1, attr2)) @@ -194,14 +193,14 @@ func TestTracer(t *testing.T) { expectedLinks := []trace.Link{ { SpanContext: parentSpanContext, - Attributes: []core.KeyValue{ - key.String("ignored-on-demand", "current"), + Attributes: []kv.KeyValue{ + kv.String("ignored-on-demand", "current"), }, }, { SpanContext: remoteParentSpanContext, - Attributes: []core.KeyValue{ - key.String("ignored-on-demand", "remote"), + Attributes: []kv.KeyValue{ + kv.String("ignored-on-demand", "remote"), }, }, } @@ -226,16 +225,16 @@ func TestTracer(t *testing.T) { _, span := subject.Start(context.Background(), "link1") link1 := trace.Link{ SpanContext: span.SpanContext(), - Attributes: []core.KeyValue{ - key.String("a", "1"), + Attributes: []kv.KeyValue{ + kv.String("a", "1"), }, } _, span = subject.Start(context.Background(), "link2") link2 := trace.Link{ SpanContext: span.SpanContext(), - Attributes: []core.KeyValue{ - key.String("b", "2"), + Attributes: []kv.KeyValue{ + kv.String("b", "2"), }, } @@ -268,8 +267,8 @@ func TestTracer(t *testing.T) { e := matchers.NewExpecter(t) - attr1 := key.String("a", "1") - attr2 := key.String("b", "2") + attr1 := kv.String("a", "1") + attr2 := kv.String("b", "2") subject := testtrace.NewTracer() var span trace.Span diff --git a/bridge/opentracing/bridge.go b/bridge/opentracing/bridge.go index 848d88f62..dd8ee6190 100644 --- a/bridge/opentracing/bridge.go +++ b/bridge/opentracing/bridge.go @@ -27,10 +27,9 @@ import ( otext "github.com/opentracing/opentracing-go/ext" otlog "github.com/opentracing/opentracing-go/log" - otelcore "go.opentelemetry.io/otel/api/core" otelcorrelation "go.opentelemetry.io/otel/api/correlation" otelglobal "go.opentelemetry.io/otel/api/global" - otelkey "go.opentelemetry.io/otel/api/key" + otelcore "go.opentelemetry.io/otel/api/kv" otelpropagation "go.opentelemetry.io/otel/api/propagation" oteltrace "go.opentelemetry.io/otel/api/trace" otelparent "go.opentelemetry.io/otel/internal/trace/parent" @@ -67,12 +66,12 @@ func (c *bridgeSpanContext) ForeachBaggageItem(handler func(k, v string) bool) { func (c *bridgeSpanContext) setBaggageItem(restrictedKey, value string) { crk := http.CanonicalHeaderKey(restrictedKey) - c.baggageItems = c.baggageItems.Apply(otelcorrelation.MapUpdate{SingleKV: otelkey.New(crk).String(value)}) + c.baggageItems = c.baggageItems.Apply(otelcorrelation.MapUpdate{SingleKV: otelcore.Key(crk).String(value)}) } func (c *bridgeSpanContext) baggageItem(restrictedKey string) string { crk := http.CanonicalHeaderKey(restrictedKey) - val, _ := c.baggageItems.Value(otelkey.New(crk)) + val, _ := c.baggageItems.Value(otelcore.Key(crk)) return val.Emit() } @@ -373,7 +372,7 @@ func (t *BridgeTracer) correlationGetHook(ctx context.Context, m otelcorrelation } kv := make([]otelcore.KeyValue, 0, len(items)) for k, v := range items { - kv = append(kv, otelkey.String(k, v)) + kv = append(kv, otelcore.String(k, v)) } return m.Apply(otelcorrelation.MapUpdate{MultiKV: kv}) } @@ -559,7 +558,7 @@ func otSpanReferenceToOtelLink(bridgeSC *bridgeSpanContext, refType ot.SpanRefer func otSpanReferenceTypeToOtelLinkAttributes(refType ot.SpanReferenceType) []otelcore.KeyValue { return []otelcore.KeyValue{ - otelkey.String("ot-span-reference-type", otSpanReferenceTypeToString(refType)), + otelcore.String("ot-span-reference-type", otSpanReferenceTypeToString(refType)), } } diff --git a/bridge/opentracing/internal/mock.go b/bridge/opentracing/internal/mock.go index e3f8bd27b..718a1f044 100644 --- a/bridge/opentracing/internal/mock.go +++ b/bridge/opentracing/internal/mock.go @@ -23,9 +23,8 @@ import ( "google.golang.org/grpc/codes" - otelcore "go.opentelemetry.io/otel/api/core" otelcorrelation "go.opentelemetry.io/otel/api/correlation" - otelkey "go.opentelemetry.io/otel/api/key" + otelcore "go.opentelemetry.io/otel/api/kv" oteltrace "go.opentelemetry.io/otel/api/trace" otelparent "go.opentelemetry.io/otel/internal/trace/parent" @@ -33,12 +32,12 @@ import ( ) var ( - ComponentKey = otelkey.New("component") - ServiceKey = otelkey.New("service") - StatusCodeKey = otelkey.New("status.code") - StatusMessageKey = otelkey.New("status.message") - ErrorKey = otelkey.New("error") - NameKey = otelkey.New("name") + ComponentKey = otelcore.Key("component") + ServiceKey = otelcore.Key("service") + StatusCodeKey = otelcore.Key("status.code") + StatusMessageKey = otelcore.Key("status.message") + ErrorKey = otelcore.Key("error") + NameKey = otelcore.Key("name") ) type MockContextKeyValue struct { @@ -240,7 +239,7 @@ func (s *MockSpan) SetAttributes(attributes ...otelcore.KeyValue) { } func (s *MockSpan) SetAttribute(k string, v interface{}) { - s.SetAttributes(otelkey.Infer(k, v)) + s.SetAttributes(otelcore.Infer(k, v)) } func (s *MockSpan) applyUpdate(update otelcorrelation.MapUpdate) { @@ -289,8 +288,8 @@ func (s *MockSpan) RecordError(ctx context.Context, err error, opts ...oteltrace } s.AddEventWithTimestamp(ctx, cfg.Timestamp, "error", - otelkey.String("error.type", reflect.TypeOf(err).String()), - otelkey.String("error.message", err.Error()), + otelcore.String("error.type", reflect.TypeOf(err).String()), + otelcore.String("error.message", err.Error()), ) } diff --git a/bridge/opentracing/mix_test.go b/bridge/opentracing/mix_test.go index f1f4dd44e..4fb67e43c 100644 --- a/bridge/opentracing/mix_test.go +++ b/bridge/opentracing/mix_test.go @@ -21,10 +21,9 @@ import ( ot "github.com/opentracing/opentracing-go" - otelcore "go.opentelemetry.io/otel/api/core" otelcorrelation "go.opentelemetry.io/otel/api/correlation" otelglobal "go.opentelemetry.io/otel/api/global" - otelkey "go.opentelemetry.io/otel/api/key" + otelcore "go.opentelemetry.io/otel/api/kv" oteltrace "go.opentelemetry.io/otel/api/trace" "go.opentelemetry.io/otel/bridge/opentracing/internal" @@ -590,7 +589,7 @@ func (bio *baggageInteroperationTest) addAndRecordBaggage(t *testing.T, ctx cont value := bio.baggageItems[idx].value otSpan.SetBaggageItem(otKey, value) - ctx = otelcorrelation.NewContext(ctx, otelkey.String(otelKey, value)) + ctx = otelcorrelation.NewContext(ctx, otelcore.String(otelKey, value)) otRecording := make(map[string]string) otSpan.Context().ForeachBaggageItem(func(key, value string) bool { diff --git a/example/basic/go.mod b/example/basic/go.mod index 3e3618320..6e4fde14e 100644 --- a/example/basic/go.mod +++ b/example/basic/go.mod @@ -4,4 +4,4 @@ go 1.13 replace go.opentelemetry.io/otel => ../.. -require go.opentelemetry.io/otel v0.4.3 +require go.opentelemetry.io/otel v0.5.0 diff --git a/example/basic/main.go b/example/basic/main.go index 625f678f7..9a5b05983 100644 --- a/example/basic/main.go +++ b/example/basic/main.go @@ -18,10 +18,9 @@ import ( "context" "log" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/correlation" "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/api/trace" metricstdout "go.opentelemetry.io/otel/exporters/metric/stdout" @@ -31,10 +30,10 @@ import ( ) var ( - fooKey = key.New("ex.com/foo") - barKey = key.New("ex.com/bar") - lemonsKey = key.New("ex.com/lemons") - anotherKey = key.New("ex.com/another") + fooKey = kv.Key("ex.com/foo") + barKey = kv.Key("ex.com/bar") + lemonsKey = kv.Key("ex.com/lemons") + anotherKey = kv.Key("ex.com/another") ) // initTracer creates and registers trace provider instance. @@ -47,7 +46,7 @@ func initTracer() { } tp, err := sdktrace.NewProvider(sdktrace.WithSyncer(exp), sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}), - sdktrace.WithResourceAttributes(key.String("rk1", "rv11"), key.Int64("rk2", 5))) + sdktrace.WithResourceAttributes(kv.String("rk1", "rv11"), kv.Int64("rk2", 5))) if err != nil { log.Panicf("failed to initialize trace provider %v", err) } @@ -72,7 +71,7 @@ func main() { tracer := global.Tracer("ex.com/basic") meter := global.Meter("ex.com/basic") - commonLabels := []core.KeyValue{lemonsKey.Int(10), key.String("A", "1"), key.String("B", "2"), key.String("C", "3")} + commonLabels := []kv.KeyValue{lemonsKey.Int(10), kv.String("A", "1"), kv.String("B", "2"), kv.String("C", "3")} oneMetricCB := func(result metric.Float64ObserverResult) { result.Observe(1, commonLabels...) @@ -95,7 +94,7 @@ func main() { err := tracer.WithSpan(ctx, "operation", func(ctx context.Context) error { - trace.SpanFromContext(ctx).AddEvent(ctx, "Nice operation!", key.New("bogons").Int(100)) + trace.SpanFromContext(ctx).AddEvent(ctx, "Nice operation!", kv.Key("bogons").Int(100)) trace.SpanFromContext(ctx).SetAttributes(anotherKey.String("yes")) diff --git a/example/grpc/go.mod b/example/grpc/go.mod index 59f87fa50..7381880ea 100644 --- a/example/grpc/go.mod +++ b/example/grpc/go.mod @@ -6,7 +6,7 @@ replace go.opentelemetry.io/otel => ../.. require ( github.com/golang/protobuf v1.3.2 - go.opentelemetry.io/otel v0.4.3 + go.opentelemetry.io/otel v0.5.0 golang.org/x/net v0.0.0-20190311183353-d8887717615a google.golang.org/grpc v1.27.1 ) diff --git a/example/http/client/client.go b/example/http/client/client.go index 9fc1d4851..9ba7b31be 100644 --- a/example/http/client/client.go +++ b/example/http/client/client.go @@ -21,12 +21,13 @@ import ( "io/ioutil" "log" + "go.opentelemetry.io/otel/api/kv" + "net/http" "time" "go.opentelemetry.io/otel/api/correlation" "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/key" "go.opentelemetry.io/otel/exporters/trace/stdout" "go.opentelemetry.io/otel/plugin/httptrace" sdktrace "go.opentelemetry.io/otel/sdk/trace" @@ -57,7 +58,7 @@ func main() { client := http.DefaultClient ctx := correlation.NewContext(context.Background(), - key.String("username", "donuts"), + kv.String("username", "donuts"), ) var body []byte diff --git a/example/http/go.mod b/example/http/go.mod index 00f9d7280..fc1b92d5c 100644 --- a/example/http/go.mod +++ b/example/http/go.mod @@ -4,4 +4,4 @@ go 1.13 replace go.opentelemetry.io/otel => ../.. -require go.opentelemetry.io/otel v0.4.3 +require go.opentelemetry.io/otel v0.5.0 diff --git a/example/jaeger/go.mod b/example/jaeger/go.mod index a36ff34e3..ed023b8ae 100644 --- a/example/jaeger/go.mod +++ b/example/jaeger/go.mod @@ -8,6 +8,6 @@ replace ( ) require ( - go.opentelemetry.io/otel v0.4.3 - go.opentelemetry.io/otel/exporters/trace/jaeger v0.4.3 + go.opentelemetry.io/otel v0.5.0 + go.opentelemetry.io/otel/exporters/trace/jaeger v0.5.0 ) diff --git a/example/jaeger/main.go b/example/jaeger/main.go index 24a8383c4..7ef9e2389 100644 --- a/example/jaeger/main.go +++ b/example/jaeger/main.go @@ -20,9 +20,8 @@ import ( "context" "log" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/exporters/trace/jaeger" sdktrace "go.opentelemetry.io/otel/sdk/trace" @@ -35,9 +34,9 @@ func initTracer() func() { jaeger.WithCollectorEndpoint("http://localhost:14268/api/traces"), jaeger.WithProcess(jaeger.Process{ ServiceName: "trace-demo", - Tags: []core.KeyValue{ - key.String("exporter", "jaeger"), - key.Float64("float", 312.23), + Tags: []kv.KeyValue{ + kv.String("exporter", "jaeger"), + kv.Float64("float", 312.23), }, }), jaeger.RegisterAsGlobal(), diff --git a/example/namedtracer/foo/foo.go b/example/namedtracer/foo/foo.go index c6ec6af2c..160aa2740 100644 --- a/example/namedtracer/foo/foo.go +++ b/example/namedtracer/foo/foo.go @@ -18,12 +18,12 @@ import ( "context" "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/trace" ) var ( - lemonsKey = key.New("ex.com/lemons") + lemonsKey = kv.Key("ex.com/lemons") ) // SubOperation is an example to demonstrate the use of named tracer. diff --git a/example/namedtracer/go.mod b/example/namedtracer/go.mod index 426b52a83..6003fcfa8 100644 --- a/example/namedtracer/go.mod +++ b/example/namedtracer/go.mod @@ -4,4 +4,4 @@ go 1.13 replace go.opentelemetry.io/otel => ../.. -require go.opentelemetry.io/otel v0.4.3 +require go.opentelemetry.io/otel v0.5.0 diff --git a/example/namedtracer/main.go b/example/namedtracer/main.go index 98fdabef3..f0aae45ad 100644 --- a/example/namedtracer/main.go +++ b/example/namedtracer/main.go @@ -18,9 +18,10 @@ import ( "context" "log" + "go.opentelemetry.io/otel/api/kv" + "go.opentelemetry.io/otel/api/correlation" "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/key" "go.opentelemetry.io/otel/api/trace" "go.opentelemetry.io/otel/example/namedtracer/foo" "go.opentelemetry.io/otel/exporters/trace/stdout" @@ -28,9 +29,9 @@ import ( ) var ( - fooKey = key.New("ex.com/foo") - barKey = key.New("ex.com/bar") - anotherKey = key.New("ex.com/another") + fooKey = kv.Key("ex.com/foo") + barKey = kv.Key("ex.com/bar") + anotherKey = kv.Key("ex.com/another") ) var tp *sdktrace.Provider @@ -66,7 +67,7 @@ func main() { err := tracer.WithSpan(ctx, "operation", func(ctx context.Context) error { - trace.SpanFromContext(ctx).AddEvent(ctx, "Nice operation!", key.New("bogons").Int(100)) + trace.SpanFromContext(ctx).AddEvent(ctx, "Nice operation!", kv.Key("bogons").Int(100)) trace.SpanFromContext(ctx).SetAttributes(anotherKey.String("yes")) diff --git a/example/prometheus/go.mod b/example/prometheus/go.mod index 1c33c5dc3..1f540ce87 100644 --- a/example/prometheus/go.mod +++ b/example/prometheus/go.mod @@ -8,6 +8,6 @@ replace ( ) require ( - go.opentelemetry.io/otel v0.4.3 - go.opentelemetry.io/otel/exporters/metric/prometheus v0.4.3 + go.opentelemetry.io/otel v0.5.0 + go.opentelemetry.io/otel/exporters/metric/prometheus v0.5.0 ) diff --git a/example/prometheus/main.go b/example/prometheus/main.go index 28cd42e90..6c0282801 100644 --- a/example/prometheus/main.go +++ b/example/prometheus/main.go @@ -21,16 +21,15 @@ import ( "sync" "time" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/exporters/metric/prometheus" "go.opentelemetry.io/otel/sdk/metric/controller/push" ) var ( - lemonsKey = key.New("ex.com/lemons") + lemonsKey = kv.Key("ex.com/lemons") ) func initMeter() *push.Controller { @@ -52,7 +51,7 @@ func main() { meter := global.Meter("ex.com/basic") observerLock := new(sync.RWMutex) observerValueToReport := new(float64) - observerLabelsToReport := new([]core.KeyValue) + observerLabelsToReport := new([]kv.KeyValue) cb := func(result metric.Float64ObserverResult) { (*observerLock).RLock() value := *observerValueToReport @@ -67,8 +66,8 @@ func main() { measureTwo := metric.Must(meter).NewFloat64Measure("ex.com.two") measureThree := metric.Must(meter).NewFloat64Counter("ex.com.three") - commonLabels := []core.KeyValue{lemonsKey.Int(10), key.String("A", "1"), key.String("B", "2"), key.String("C", "3")} - notSoCommonLabels := []core.KeyValue{lemonsKey.Int(13)} + commonLabels := []kv.KeyValue{lemonsKey.Int(10), kv.String("A", "1"), kv.String("B", "2"), kv.String("C", "3")} + notSoCommonLabels := []kv.KeyValue{lemonsKey.Int(13)} ctx := context.Background() diff --git a/example/zipkin/go.mod b/example/zipkin/go.mod index f5246b908..9999bca0f 100644 --- a/example/zipkin/go.mod +++ b/example/zipkin/go.mod @@ -8,6 +8,6 @@ replace ( ) require ( - go.opentelemetry.io/otel v0.4.3 - go.opentelemetry.io/otel/exporters/trace/zipkin v0.4.3 + go.opentelemetry.io/otel v0.5.0 + go.opentelemetry.io/otel/exporters/trace/zipkin v0.5.0 ) diff --git a/exporters/metric/prometheus/go.mod b/exporters/metric/prometheus/go.mod index 75230ec20..c9c42f002 100644 --- a/exporters/metric/prometheus/go.mod +++ b/exporters/metric/prometheus/go.mod @@ -9,6 +9,6 @@ require ( github.com/prometheus/client_golang v1.5.0 github.com/prometheus/procfs v0.0.10 // indirect github.com/stretchr/testify v1.4.0 - go.opentelemetry.io/otel v0.4.3 + go.opentelemetry.io/otel v0.5.0 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect ) diff --git a/exporters/metric/prometheus/prometheus.go b/exporters/metric/prometheus/prometheus.go index d79e22e3b..2d8ec76de 100644 --- a/exporters/metric/prometheus/prometheus.go +++ b/exporters/metric/prometheus/prometheus.go @@ -20,16 +20,17 @@ import ( "net/http" "time" + "go.opentelemetry.io/otel/api/metric" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/global" "go.opentelemetry.io/otel/api/label" export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregator" - "go.opentelemetry.io/otel/sdk/metric/batcher/ungrouped" "go.opentelemetry.io/otel/sdk/metric/controller/push" + integrator "go.opentelemetry.io/otel/sdk/metric/integrator/simple" "go.opentelemetry.io/otel/sdk/metric/selector/simple" "go.opentelemetry.io/otel/sdk/resource" ) @@ -46,7 +47,7 @@ type Exporter struct { onError func(error) defaultSummaryQuantiles []float64 - defaultHistogramBoundaries []core.Number + defaultHistogramBoundaries []metric.Number } var _ export.Exporter = &Exporter{} @@ -78,7 +79,7 @@ type Config struct { // DefaultHistogramBoundaries defines the default histogram bucket // boundaries. - DefaultHistogramBoundaries []core.Number + DefaultHistogramBoundaries []metric.Number // OnError is a function that handle errors that may occur while exporting metrics. // TODO: This should be refactored or even removed once we have a better error handling mechanism. @@ -144,7 +145,7 @@ func InstallNewPipeline(config Config) (*push.Controller, http.HandlerFunc, erro } // NewExportPipeline sets up a complete export pipeline with the recommended setup, -// chaining a NewRawExporter into the recommended selectors and batchers. +// chaining a NewRawExporter into the recommended selectors and integrators. func NewExportPipeline(config Config, period time.Duration) (*push.Controller, http.HandlerFunc, error) { selector := simple.NewWithHistogramMeasure(config.DefaultHistogramBoundaries) exporter, err := NewRawExporter(config) @@ -152,7 +153,7 @@ func NewExportPipeline(config Config, period time.Duration) (*push.Controller, h return nil, nil, err } - // Prometheus needs to use a stateful batcher since counters (and histogram since they are a collection of Counters) + // Prometheus needs to use a stateful integrator since counters (and histogram since they are a collection of Counters) // are cumulative (i.e., monotonically increasing values) and should not be resetted after each export. // // Prometheus uses this approach to be resilient to scrape failures. @@ -160,8 +161,8 @@ func NewExportPipeline(config Config, period time.Duration) (*push.Controller, h // it could try again on the next scrape and no data would be lost, only resolution. // // Gauges (or LastValues) and Summaries are an exception to this and have different behaviors. - batcher := ungrouped.New(selector, true) - pusher := push.New(batcher, exporter, period) + integrator := integrator.New(selector, true) + pusher := push.New(integrator, exporter, period) pusher.Start() return pusher, exporter.ServeHTTP, nil @@ -245,7 +246,7 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) { } } -func (c *collector) exportLastValue(ch chan<- prometheus.Metric, lvagg aggregator.LastValue, kind core.NumberKind, desc *prometheus.Desc, labels []string) error { +func (c *collector) exportLastValue(ch chan<- prometheus.Metric, lvagg aggregator.LastValue, kind metric.NumberKind, desc *prometheus.Desc, labels []string) error { lv, _, err := lvagg.LastValue() if err != nil { return fmt.Errorf("error retrieving last value: %w", err) @@ -260,7 +261,7 @@ func (c *collector) exportLastValue(ch chan<- prometheus.Metric, lvagg aggregato return nil } -func (c *collector) exportCounter(ch chan<- prometheus.Metric, sum aggregator.Sum, kind core.NumberKind, desc *prometheus.Desc, labels []string) error { +func (c *collector) exportCounter(ch chan<- prometheus.Metric, sum aggregator.Sum, kind metric.NumberKind, desc *prometheus.Desc, labels []string) error { v, err := sum.Sum() if err != nil { return fmt.Errorf("error retrieving counter: %w", err) @@ -275,13 +276,13 @@ func (c *collector) exportCounter(ch chan<- prometheus.Metric, sum aggregator.Su return nil } -func (c *collector) exportSummary(ch chan<- prometheus.Metric, dist aggregator.Distribution, kind core.NumberKind, desc *prometheus.Desc, labels []string) error { +func (c *collector) exportSummary(ch chan<- prometheus.Metric, dist aggregator.Distribution, kind metric.NumberKind, desc *prometheus.Desc, labels []string) error { count, err := dist.Count() if err != nil { return fmt.Errorf("error retrieving count: %w", err) } - var sum core.Number + var sum metric.Number sum, err = dist.Sum() if err != nil { return fmt.Errorf("error retrieving distribution sum: %w", err) @@ -302,7 +303,7 @@ func (c *collector) exportSummary(ch chan<- prometheus.Metric, dist aggregator.D return nil } -func (c *collector) exportHistogram(ch chan<- prometheus.Metric, hist aggregator.Histogram, kind core.NumberKind, desc *prometheus.Desc, labels []string) error { +func (c *collector) exportHistogram(ch chan<- prometheus.Metric, hist aggregator.Histogram, kind metric.NumberKind, desc *prometheus.Desc, labels []string) error { buckets, err := hist.Histogram() if err != nil { return fmt.Errorf("error retrieving histogram: %w", err) diff --git a/exporters/metric/prometheus/prometheus_test.go b/exporters/metric/prometheus/prometheus_test.go index 1572b0b5d..362df65a6 100644 --- a/exporters/metric/prometheus/prometheus_test.go +++ b/exporters/metric/prometheus/prometheus_test.go @@ -24,8 +24,7 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/exporters/metric/prometheus" "go.opentelemetry.io/otel/exporters/metric/test" @@ -43,17 +42,17 @@ func TestPrometheusExporter(t *testing.T) { checkpointSet := test.NewCheckpointSet() counter := metric.NewDescriptor( - "counter", metric.CounterKind, core.Float64NumberKind) + "counter", metric.CounterKind, metric.Float64NumberKind) lastValue := metric.NewDescriptor( - "lastvalue", metric.ObserverKind, core.Float64NumberKind) + "lastvalue", metric.ObserverKind, metric.Float64NumberKind) measure := metric.NewDescriptor( - "measure", metric.MeasureKind, core.Float64NumberKind) + "measure", metric.MeasureKind, metric.Float64NumberKind) histogramMeasure := metric.NewDescriptor( - "histogram_measure", metric.MeasureKind, core.Float64NumberKind) + "histogram_measure", metric.MeasureKind, metric.Float64NumberKind) - labels := []core.KeyValue{ - key.New("A").String("B"), - key.New("C").String("D"), + labels := []kv.KeyValue{ + kv.Key("A").String("B"), + kv.Key("C").String("D"), } checkpointSet.AddCounter(&counter, 15.3, labels...) @@ -71,7 +70,7 @@ func TestPrometheusExporter(t *testing.T) { expected = append(expected, `measure_sum{A="B",C="D"} 45`) expected = append(expected, `measure_count{A="B",C="D"} 3`) - boundaries := []core.Number{core.NewFloat64Number(-0.5), core.NewFloat64Number(1)} + boundaries := []metric.Number{metric.NewFloat64Number(-0.5), metric.NewFloat64Number(1)} checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, -0.6, labels...) checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, -0.4, labels...) checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, 0.6, labels...) @@ -83,9 +82,9 @@ func TestPrometheusExporter(t *testing.T) { expected = append(expected, `histogram_measure_count{A="B",C="D"} 4`) expected = append(expected, `histogram_measure_sum{A="B",C="D"} 19.6`) - missingLabels := []core.KeyValue{ - key.New("A").String("E"), - key.New("C").String(""), + missingLabels := []kv.KeyValue{ + kv.Key("A").String("E"), + kv.Key("C").String(""), } checkpointSet.AddCounter(&counter, 12, missingLabels...) @@ -101,7 +100,7 @@ func TestPrometheusExporter(t *testing.T) { expected = append(expected, `measure_count{A="E",C=""} 1`) expected = append(expected, `measure_sum{A="E",C=""} 19`) - boundaries = []core.Number{core.NewFloat64Number(0), core.NewFloat64Number(1)} + boundaries = []metric.Number{metric.NewFloat64Number(0), metric.NewFloat64Number(1)} checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, -0.6, missingLabels...) checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, -0.4, missingLabels...) checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, -0.1, missingLabels...) diff --git a/exporters/metric/stdout/example_test.go b/exporters/metric/stdout/example_test.go index 06e45790c..9cb3b45ad 100644 --- a/exporters/metric/stdout/example_test.go +++ b/exporters/metric/stdout/example_test.go @@ -19,8 +19,7 @@ import ( "log" "time" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/exporters/metric/stdout" ) @@ -38,12 +37,12 @@ func ExampleNewExportPipeline() { ctx := context.Background() - key := key.New("key") + key := kv.Key("key") meter := pusher.Meter("example") // Create and update a single counter: counter := metric.Must(meter).NewInt64Counter("a.counter") - labels := []core.KeyValue{key.String("value")} + labels := []kv.KeyValue{key.String("value")} counter.Add(ctx, 100, labels...) diff --git a/exporters/metric/stdout/stdout.go b/exporters/metric/stdout/stdout.go index 373651906..04e39e6b1 100644 --- a/exporters/metric/stdout/stdout.go +++ b/exporters/metric/stdout/stdout.go @@ -29,8 +29,8 @@ import ( export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregator" - "go.opentelemetry.io/otel/sdk/metric/batcher/ungrouped" "go.opentelemetry.io/otel/sdk/metric/controller/push" + integrator "go.opentelemetry.io/otel/sdk/metric/integrator/simple" "go.opentelemetry.io/otel/sdk/metric/selector/simple" ) @@ -131,15 +131,15 @@ func InstallNewPipeline(config Config, opts ...push.Option) (*push.Controller, e } // NewExportPipeline sets up a complete export pipeline with the recommended setup, -// chaining a NewRawExporter into the recommended selectors and batchers. +// chaining a NewRawExporter into the recommended selectors and integrators. func NewExportPipeline(config Config, period time.Duration, opts ...push.Option) (*push.Controller, error) { selector := simple.NewWithExactMeasure() exporter, err := NewRawExporter(config) if err != nil { return nil, err } - batcher := ungrouped.New(selector, true) - pusher := push.New(batcher, exporter, period, opts...) + integrator := integrator.New(selector, true) + pusher := push.New(integrator, exporter, period, opts...) pusher.Start() return pusher, nil diff --git a/exporters/metric/stdout/stdout_test.go b/exporters/metric/stdout/stdout_test.go index abb9ff265..a5f94df6c 100644 --- a/exporters/metric/stdout/stdout_test.go +++ b/exporters/metric/stdout/stdout_test.go @@ -24,8 +24,7 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/exporters/metric/stdout" "go.opentelemetry.io/otel/exporters/metric/test" @@ -99,9 +98,9 @@ func TestStdoutTimestamp(t *testing.T) { checkpointSet := test.NewCheckpointSet() ctx := context.Background() - desc := metric.NewDescriptor("test.name", metric.ObserverKind, core.Int64NumberKind) + desc := metric.NewDescriptor("test.name", metric.ObserverKind, metric.Int64NumberKind) lvagg := lastvalue.New() - aggtest.CheckedUpdate(t, lvagg, core.NewInt64Number(321), &desc) + aggtest.CheckedUpdate(t, lvagg, metric.NewInt64Number(321), &desc) lvagg.Checkpoint(ctx, &desc) checkpointSet.Add(&desc, lvagg) @@ -144,12 +143,12 @@ func TestStdoutCounterFormat(t *testing.T) { checkpointSet := test.NewCheckpointSet() - desc := metric.NewDescriptor("test.name", metric.CounterKind, core.Int64NumberKind) + desc := metric.NewDescriptor("test.name", metric.CounterKind, metric.Int64NumberKind) cagg := sum.New() - aggtest.CheckedUpdate(fix.t, cagg, core.NewInt64Number(123), &desc) + aggtest.CheckedUpdate(fix.t, cagg, metric.NewInt64Number(123), &desc) cagg.Checkpoint(fix.ctx, &desc) - checkpointSet.Add(&desc, cagg, key.String("A", "B"), key.String("C", "D")) + checkpointSet.Add(&desc, cagg, kv.String("A", "B"), kv.String("C", "D")) fix.Export(checkpointSet) @@ -161,12 +160,12 @@ func TestStdoutLastValueFormat(t *testing.T) { checkpointSet := test.NewCheckpointSet() - desc := metric.NewDescriptor("test.name", metric.ObserverKind, core.Float64NumberKind) + desc := metric.NewDescriptor("test.name", metric.ObserverKind, metric.Float64NumberKind) lvagg := lastvalue.New() - aggtest.CheckedUpdate(fix.t, lvagg, core.NewFloat64Number(123.456), &desc) + aggtest.CheckedUpdate(fix.t, lvagg, metric.NewFloat64Number(123.456), &desc) lvagg.Checkpoint(fix.ctx, &desc) - checkpointSet.Add(&desc, lvagg, key.String("A", "B"), key.String("C", "D")) + checkpointSet.Add(&desc, lvagg, kv.String("A", "B"), kv.String("C", "D")) fix.Export(checkpointSet) @@ -178,13 +177,13 @@ func TestStdoutMinMaxSumCount(t *testing.T) { checkpointSet := test.NewCheckpointSet() - desc := metric.NewDescriptor("test.name", metric.MeasureKind, core.Float64NumberKind) + desc := metric.NewDescriptor("test.name", metric.MeasureKind, metric.Float64NumberKind) magg := minmaxsumcount.New(&desc) - aggtest.CheckedUpdate(fix.t, magg, core.NewFloat64Number(123.456), &desc) - aggtest.CheckedUpdate(fix.t, magg, core.NewFloat64Number(876.543), &desc) + aggtest.CheckedUpdate(fix.t, magg, metric.NewFloat64Number(123.456), &desc) + aggtest.CheckedUpdate(fix.t, magg, metric.NewFloat64Number(876.543), &desc) magg.Checkpoint(fix.ctx, &desc) - checkpointSet.Add(&desc, magg, key.String("A", "B"), key.String("C", "D")) + checkpointSet.Add(&desc, magg, kv.String("A", "B"), kv.String("C", "D")) fix.Export(checkpointSet) @@ -198,16 +197,16 @@ func TestStdoutMeasureFormat(t *testing.T) { checkpointSet := test.NewCheckpointSet() - desc := metric.NewDescriptor("test.name", metric.MeasureKind, core.Float64NumberKind) + desc := metric.NewDescriptor("test.name", metric.MeasureKind, metric.Float64NumberKind) magg := array.New() for i := 0; i < 1000; i++ { - aggtest.CheckedUpdate(fix.t, magg, core.NewFloat64Number(float64(i)+0.5), &desc) + aggtest.CheckedUpdate(fix.t, magg, metric.NewFloat64Number(float64(i)+0.5), &desc) } magg.Checkpoint(fix.ctx, &desc) - checkpointSet.Add(&desc, magg, key.String("A", "B"), key.String("C", "D")) + checkpointSet.Add(&desc, magg, kv.String("A", "B"), kv.String("C", "D")) fix.Export(checkpointSet) @@ -239,7 +238,7 @@ func TestStdoutMeasureFormat(t *testing.T) { } func TestStdoutNoData(t *testing.T) { - desc := metric.NewDescriptor("test.name", metric.MeasureKind, core.Float64NumberKind) + desc := metric.NewDescriptor("test.name", metric.MeasureKind, metric.Float64NumberKind) for name, tc := range map[string]export.Aggregator{ "ddsketch": ddsketch.New(ddsketch.NewDefaultConfig(), &desc), "minmaxsumcount": minmaxsumcount.New(&desc), @@ -269,11 +268,11 @@ func TestStdoutLastValueNotSet(t *testing.T) { checkpointSet := test.NewCheckpointSet() - desc := metric.NewDescriptor("test.name", metric.ObserverKind, core.Float64NumberKind) + desc := metric.NewDescriptor("test.name", metric.ObserverKind, metric.Float64NumberKind) lvagg := lastvalue.New() lvagg.Checkpoint(fix.ctx, &desc) - checkpointSet.Add(&desc, lvagg, key.String("A", "B"), key.String("C", "D")) + checkpointSet.Add(&desc, lvagg, kv.String("A", "B"), kv.String("C", "D")) fix.Export(checkpointSet) @@ -284,9 +283,9 @@ func TestStdoutResource(t *testing.T) { type testCase struct { expect string res *resource.Resource - attrs []core.KeyValue + attrs []kv.KeyValue } - newCase := func(expect string, res *resource.Resource, attrs ...core.KeyValue) testCase { + newCase := func(expect string, res *resource.Resource, attrs ...kv.KeyValue) testCase { return testCase{ expect: expect, res: res, @@ -295,23 +294,23 @@ func TestStdoutResource(t *testing.T) { } testCases := []testCase{ newCase("R1=V1,R2=V2,A=B,C=D", - resource.New(key.String("R1", "V1"), key.String("R2", "V2")), - key.String("A", "B"), - key.String("C", "D")), + resource.New(kv.String("R1", "V1"), kv.String("R2", "V2")), + kv.String("A", "B"), + kv.String("C", "D")), newCase("R1=V1,R2=V2", - resource.New(key.String("R1", "V1"), key.String("R2", "V2")), + resource.New(kv.String("R1", "V1"), kv.String("R2", "V2")), ), newCase("A=B,C=D", nil, - key.String("A", "B"), - key.String("C", "D"), + kv.String("A", "B"), + kv.String("C", "D"), ), // We explicitly do not de-duplicate between resources // and metric labels in this exporter. newCase("R1=V1,R2=V2,R1=V3,R2=V4", - resource.New(key.String("R1", "V1"), key.String("R2", "V2")), - key.String("R1", "V3"), - key.String("R2", "V4")), + resource.New(kv.String("R1", "V1"), kv.String("R2", "V2")), + kv.String("R1", "V3"), + kv.String("R2", "V4")), } for _, tc := range testCases { @@ -319,9 +318,9 @@ func TestStdoutResource(t *testing.T) { checkpointSet := test.NewCheckpointSet() - desc := metric.NewDescriptor("test.name", metric.ObserverKind, core.Float64NumberKind) + desc := metric.NewDescriptor("test.name", metric.ObserverKind, metric.Float64NumberKind) lvagg := lastvalue.New() - aggtest.CheckedUpdate(fix.t, lvagg, core.NewFloat64Number(123.456), &desc) + aggtest.CheckedUpdate(fix.t, lvagg, metric.NewFloat64Number(123.456), &desc) lvagg.Checkpoint(fix.ctx, &desc) checkpointSet.Add(&desc, lvagg, tc.attrs...) diff --git a/exporters/metric/test/test.go b/exporters/metric/test/test.go index f6842fda3..a7dca90d1 100644 --- a/exporters/metric/test/test.go +++ b/exporters/metric/test/test.go @@ -18,7 +18,7 @@ import ( "context" "errors" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/label" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -56,7 +56,7 @@ func (p *CheckpointSet) Reset() { // // If there is an existing record with the same descriptor and labels, // the stored aggregator will be returned and should be merged. -func (p *CheckpointSet) Add(desc *metric.Descriptor, newAgg export.Aggregator, labels ...core.KeyValue) (agg export.Aggregator, added bool) { +func (p *CheckpointSet) Add(desc *metric.Descriptor, newAgg export.Aggregator, labels ...kv.KeyValue) (agg export.Aggregator, added bool) { elabels := label.NewSet(labels...) key := mapkey{ @@ -73,30 +73,30 @@ func (p *CheckpointSet) Add(desc *metric.Descriptor, newAgg export.Aggregator, l return newAgg, true } -func createNumber(desc *metric.Descriptor, v float64) core.Number { - if desc.NumberKind() == core.Float64NumberKind { - return core.NewFloat64Number(v) +func createNumber(desc *metric.Descriptor, v float64) metric.Number { + if desc.NumberKind() == metric.Float64NumberKind { + return metric.NewFloat64Number(v) } - return core.NewInt64Number(int64(v)) + return metric.NewInt64Number(int64(v)) } -func (p *CheckpointSet) AddLastValue(desc *metric.Descriptor, v float64, labels ...core.KeyValue) { +func (p *CheckpointSet) AddLastValue(desc *metric.Descriptor, v float64, labels ...kv.KeyValue) { p.updateAggregator(desc, lastvalue.New(), v, labels...) } -func (p *CheckpointSet) AddCounter(desc *metric.Descriptor, v float64, labels ...core.KeyValue) { +func (p *CheckpointSet) AddCounter(desc *metric.Descriptor, v float64, labels ...kv.KeyValue) { p.updateAggregator(desc, sum.New(), v, labels...) } -func (p *CheckpointSet) AddMeasure(desc *metric.Descriptor, v float64, labels ...core.KeyValue) { +func (p *CheckpointSet) AddMeasure(desc *metric.Descriptor, v float64, labels ...kv.KeyValue) { p.updateAggregator(desc, array.New(), v, labels...) } -func (p *CheckpointSet) AddHistogramMeasure(desc *metric.Descriptor, boundaries []core.Number, v float64, labels ...core.KeyValue) { +func (p *CheckpointSet) AddHistogramMeasure(desc *metric.Descriptor, boundaries []metric.Number, v float64, labels ...kv.KeyValue) { p.updateAggregator(desc, histogram.New(desc, boundaries), v, labels...) } -func (p *CheckpointSet) updateAggregator(desc *metric.Descriptor, newAgg export.Aggregator, v float64, labels ...core.KeyValue) { +func (p *CheckpointSet) updateAggregator(desc *metric.Descriptor, newAgg export.Aggregator, v float64, labels ...kv.KeyValue) { ctx := context.Background() // Updates and checkpoint the new aggregator _ = newAgg.Update(ctx, createNumber(desc, v), desc) diff --git a/exporters/otlp/go.mod b/exporters/otlp/go.mod index b53125774..f16ea562d 100644 --- a/exporters/otlp/go.mod +++ b/exporters/otlp/go.mod @@ -9,7 +9,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.14.3 // indirect github.com/open-telemetry/opentelemetry-proto v0.3.0 github.com/stretchr/testify v1.4.0 - go.opentelemetry.io/otel v0.4.3 + go.opentelemetry.io/otel v0.5.0 golang.org/x/text v0.3.2 // indirect google.golang.org/grpc v1.27.1 ) diff --git a/exporters/otlp/internal/transform/attribute.go b/exporters/otlp/internal/transform/attribute.go index 9b8fe9960..b3ca6087a 100644 --- a/exporters/otlp/internal/transform/attribute.go +++ b/exporters/otlp/internal/transform/attribute.go @@ -17,12 +17,14 @@ package transform import ( commonpb "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv/value" + + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/sdk/resource" ) // Attributes transforms a slice of KeyValues into a slice of OTLP attribute key-values. -func Attributes(attrs []core.KeyValue) []*commonpb.AttributeKeyValue { +func Attributes(attrs []kv.KeyValue) []*commonpb.AttributeKeyValue { if len(attrs) == 0 { return nil } @@ -48,33 +50,33 @@ func ResourceAttributes(resource *resource.Resource) []*commonpb.AttributeKeyVal return out } -func toAttribute(v core.KeyValue) *commonpb.AttributeKeyValue { +func toAttribute(v kv.KeyValue) *commonpb.AttributeKeyValue { switch v.Value.Type() { - case core.BOOL: + case value.BOOL: return &commonpb.AttributeKeyValue{ Key: string(v.Key), Type: commonpb.AttributeKeyValue_BOOL, BoolValue: v.Value.AsBool(), } - case core.INT64, core.INT32, core.UINT32, core.UINT64: + case value.INT64, value.INT32, value.UINT32, value.UINT64: return &commonpb.AttributeKeyValue{ Key: string(v.Key), Type: commonpb.AttributeKeyValue_INT, IntValue: v.Value.AsInt64(), } - case core.FLOAT32: + case value.FLOAT32: return &commonpb.AttributeKeyValue{ Key: string(v.Key), Type: commonpb.AttributeKeyValue_DOUBLE, DoubleValue: float64(v.Value.AsFloat32()), } - case core.FLOAT64: + case value.FLOAT64: return &commonpb.AttributeKeyValue{ Key: string(v.Key), Type: commonpb.AttributeKeyValue_DOUBLE, DoubleValue: v.Value.AsFloat64(), } - case core.STRING: + case value.STRING: return &commonpb.AttributeKeyValue{ Key: string(v.Key), Type: commonpb.AttributeKeyValue_STRING, diff --git a/exporters/otlp/internal/transform/attribute_test.go b/exporters/otlp/internal/transform/attribute_test.go index 825cbf3c9..e6dea24d5 100644 --- a/exporters/otlp/internal/transform/attribute_test.go +++ b/exporters/otlp/internal/transform/attribute_test.go @@ -20,28 +20,27 @@ import ( commonpb "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1" "github.com/stretchr/testify/assert" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" ) func TestAttributes(t *testing.T) { for _, test := range []struct { - attrs []core.KeyValue + attrs []kv.KeyValue expected []*commonpb.AttributeKeyValue }{ {nil, nil}, { - []core.KeyValue{ - key.Int("int to int", 123), - key.Uint("uint to int", 1234), - key.Int32("int32 to int", 12345), - key.Uint32("uint32 to int", 123456), - key.Int64("int64 to int64", 1234567), - key.Uint64("uint64 to int64", 12345678), - key.Float32("float32 to double", 3.14), - key.Float32("float64 to double", 1.61), - key.String("string to string", "string"), - key.Bool("bool to bool", true), + []kv.KeyValue{ + kv.Int("int to int", 123), + kv.Uint("uint to int", 1234), + kv.Int32("int32 to int", 12345), + kv.Uint32("uint32 to int", 123456), + kv.Int64("int64 to int64", 1234567), + kv.Uint64("uint64 to int64", 12345678), + kv.Float32("float32 to double", 3.14), + kv.Float32("float64 to double", 1.61), + kv.String("string to string", "string"), + kv.Bool("bool to bool", true), }, []*commonpb.AttributeKeyValue{ { diff --git a/exporters/otlp/internal/transform/metric.go b/exporters/otlp/internal/transform/metric.go index 1ed6436ac..f9dd696bd 100644 --- a/exporters/otlp/internal/transform/metric.go +++ b/exporters/otlp/internal/transform/metric.go @@ -27,7 +27,6 @@ import ( metricpb "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1" resourcepb "github.com/open-telemetry/opentelemetry-proto/gen/go/resource/v1" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/label" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -257,12 +256,12 @@ func sum(desc *metric.Descriptor, labels *label.Set, a aggregator.Sum) (*metricp } switch n := desc.NumberKind(); n { - case core.Int64NumberKind, core.Uint64NumberKind: + case metric.Int64NumberKind, metric.Uint64NumberKind: m.MetricDescriptor.Type = metricpb.MetricDescriptor_COUNTER_INT64 m.Int64DataPoints = []*metricpb.Int64DataPoint{ {Value: sum.CoerceToInt64(n)}, } - case core.Float64NumberKind: + case metric.Float64NumberKind: m.MetricDescriptor.Type = metricpb.MetricDescriptor_COUNTER_DOUBLE m.DoubleDataPoints = []*metricpb.DoubleDataPoint{ {Value: sum.CoerceToFloat64(n)}, @@ -276,7 +275,7 @@ func sum(desc *metric.Descriptor, labels *label.Set, a aggregator.Sum) (*metricp // minMaxSumCountValue returns the values of the MinMaxSumCount Aggregator // as discret values. -func minMaxSumCountValues(a aggregator.MinMaxSumCount) (min, max, sum core.Number, count int64, err error) { +func minMaxSumCountValues(a aggregator.MinMaxSumCount) (min, max, sum metric.Number, count int64, err error) { if min, err = a.Min(); err != nil { return } diff --git a/exporters/otlp/internal/transform/metric_test.go b/exporters/otlp/internal/transform/metric_test.go index a7da3b9e6..57e0388a9 100644 --- a/exporters/otlp/internal/transform/metric_test.go +++ b/exporters/otlp/internal/transform/metric_test.go @@ -23,8 +23,7 @@ import ( metricpb "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1" "github.com/stretchr/testify/assert" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/label" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/api/unit" @@ -35,7 +34,7 @@ import ( func TestStringKeyValues(t *testing.T) { tests := []struct { - kvs []core.KeyValue + kvs []kv.KeyValue expected []*commonpb.StringKeyValue }{ { @@ -43,21 +42,21 @@ func TestStringKeyValues(t *testing.T) { nil, }, { - []core.KeyValue{}, + []kv.KeyValue{}, nil, }, { - []core.KeyValue{ - key.Bool("true", true), - key.Int64("one", 1), - key.Uint64("two", 2), - key.Float64("three", 3), - key.Int32("four", 4), - key.Uint32("five", 5), - key.Float32("six", 6), - key.Int("seven", 7), - key.Uint("eight", 8), - key.String("the", "final word"), + []kv.KeyValue{ + kv.Bool("true", true), + kv.Int64("one", 1), + kv.Uint64("two", 2), + kv.Float64("three", 3), + kv.Int32("four", 4), + kv.Uint32("five", 5), + kv.Float32("six", 6), + kv.Int("seven", 7), + kv.Uint("eight", 8), + kv.String("the", "final word"), }, []*commonpb.StringKeyValue{ {Key: "eight", Value: "8"}, @@ -93,9 +92,9 @@ func TestMinMaxSumCountValue(t *testing.T) { mmsc.Checkpoint(context.Background(), &metric.Descriptor{}) min, max, sum, count, err := minMaxSumCountValues(mmsc) if assert.NoError(t, err) { - assert.Equal(t, min, core.NewInt64Number(1)) - assert.Equal(t, max, core.NewInt64Number(10)) - assert.Equal(t, sum, core.NewInt64Number(11)) + assert.Equal(t, min, metric.NewInt64Number(1)) + assert.Equal(t, max, metric.NewInt64Number(10)) + assert.Equal(t, sum, metric.NewInt64Number(11)) assert.Equal(t, count, int64(2)) } } @@ -106,8 +105,8 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) { metricKind metric.Kind description string unit unit.Unit - numberKind core.NumberKind - labels []core.KeyValue + numberKind metric.NumberKind + labels []kv.KeyValue expected *metricpb.MetricDescriptor }{ { @@ -115,8 +114,8 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) { metric.MeasureKind, "test-a-description", unit.Dimensionless, - core.Int64NumberKind, - []core.KeyValue{}, + metric.Int64NumberKind, + []kv.KeyValue{}, &metricpb.MetricDescriptor{ Name: "mmsc-test-a", Description: "test-a-description", @@ -130,8 +129,8 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) { metric.CounterKind, // This shouldn't change anything. "test-b-description", unit.Bytes, - core.Float64NumberKind, // This shouldn't change anything. - []core.KeyValue{key.String("A", "1")}, + metric.Float64NumberKind, // This shouldn't change anything. + []kv.KeyValue{kv.String("A", "1")}, &metricpb.MetricDescriptor{ Name: "mmsc-test-b", Description: "test-b-description", @@ -161,7 +160,7 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) { } func TestMinMaxSumCountDatapoints(t *testing.T) { - desc := metric.NewDescriptor("", metric.MeasureKind, core.Int64NumberKind) + desc := metric.NewDescriptor("", metric.MeasureKind, metric.Int64NumberKind) labels := label.NewSet() mmsc := minmaxsumcount.New(&desc) assert.NoError(t, mmsc.Update(context.Background(), 1, &desc)) @@ -208,8 +207,8 @@ func TestSumMetricDescriptor(t *testing.T) { metricKind metric.Kind description string unit unit.Unit - numberKind core.NumberKind - labels []core.KeyValue + numberKind metric.NumberKind + labels []kv.KeyValue expected *metricpb.MetricDescriptor }{ { @@ -217,8 +216,8 @@ func TestSumMetricDescriptor(t *testing.T) { metric.CounterKind, "test-a-description", unit.Dimensionless, - core.Int64NumberKind, - []core.KeyValue{}, + metric.Int64NumberKind, + []kv.KeyValue{}, &metricpb.MetricDescriptor{ Name: "sum-test-a", Description: "test-a-description", @@ -232,8 +231,8 @@ func TestSumMetricDescriptor(t *testing.T) { metric.MeasureKind, // This shouldn't change anything. "test-b-description", unit.Milliseconds, - core.Float64NumberKind, - []core.KeyValue{key.String("A", "1")}, + metric.Float64NumberKind, + []kv.KeyValue{kv.String("A", "1")}, &metricpb.MetricDescriptor{ Name: "sum-test-b", Description: "test-b-description", @@ -258,10 +257,10 @@ func TestSumMetricDescriptor(t *testing.T) { } func TestSumInt64DataPoints(t *testing.T) { - desc := metric.NewDescriptor("", metric.MeasureKind, core.Int64NumberKind) + desc := metric.NewDescriptor("", metric.MeasureKind, metric.Int64NumberKind) labels := label.NewSet() s := sumAgg.New() - assert.NoError(t, s.Update(context.Background(), core.Number(1), &desc)) + assert.NoError(t, s.Update(context.Background(), metric.Number(1), &desc)) s.Checkpoint(context.Background(), &desc) if m, err := sum(&desc, &labels, s); assert.NoError(t, err) { assert.Equal(t, []*metricpb.Int64DataPoint{{Value: 1}}, m.Int64DataPoints) @@ -272,10 +271,10 @@ func TestSumInt64DataPoints(t *testing.T) { } func TestSumFloat64DataPoints(t *testing.T) { - desc := metric.NewDescriptor("", metric.MeasureKind, core.Float64NumberKind) + desc := metric.NewDescriptor("", metric.MeasureKind, metric.Float64NumberKind) labels := label.NewSet() s := sumAgg.New() - assert.NoError(t, s.Update(context.Background(), core.NewFloat64Number(1), &desc)) + assert.NoError(t, s.Update(context.Background(), metric.NewFloat64Number(1), &desc)) s.Checkpoint(context.Background(), &desc) if m, err := sum(&desc, &labels, s); assert.NoError(t, err) { assert.Equal(t, []*metricpb.Int64DataPoint(nil), m.Int64DataPoints) @@ -286,7 +285,7 @@ func TestSumFloat64DataPoints(t *testing.T) { } func TestSumErrUnknownValueType(t *testing.T) { - desc := metric.NewDescriptor("", metric.MeasureKind, core.NumberKind(-1)) + desc := metric.NewDescriptor("", metric.MeasureKind, metric.NumberKind(-1)) labels := label.NewSet() s := sumAgg.New() _, err := sum(&desc, &labels, s) diff --git a/exporters/otlp/internal/transform/resource_test.go b/exporters/otlp/internal/transform/resource_test.go index 7dcf13519..34c1d52c9 100644 --- a/exporters/otlp/internal/transform/resource_test.go +++ b/exporters/otlp/internal/transform/resource_test.go @@ -19,8 +19,7 @@ import ( "github.com/stretchr/testify/assert" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/sdk/resource" ) @@ -39,7 +38,7 @@ func TestEmptyResource(t *testing.T) { */ func TestResourceAttributes(t *testing.T) { - attrs := []core.KeyValue{key.Int("one", 1), key.Int("two", 2)} + attrs := []kv.KeyValue{kv.Int("one", 1), kv.Int("two", 2)} got := Resource(resource.New(attrs...)).GetAttributes() if !assert.Len(t, attrs, 2) { diff --git a/exporters/otlp/internal/transform/span_test.go b/exporters/otlp/internal/transform/span_test.go index 90ed5d2fb..1fb6a9877 100644 --- a/exporters/otlp/internal/transform/span_test.go +++ b/exporters/otlp/internal/transform/span_test.go @@ -25,8 +25,7 @@ import ( "github.com/stretchr/testify/assert" "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" apitrace "go.opentelemetry.io/otel/api/trace" export "go.opentelemetry.io/otel/sdk/export/trace" "go.opentelemetry.io/otel/sdk/resource" @@ -75,12 +74,12 @@ func TestEmptySpanEvent(t *testing.T) { } func TestSpanEvent(t *testing.T) { - attrs := []core.KeyValue{key.Int("one", 1), key.Int("two", 2)} + attrs := []kv.KeyValue{kv.Int("one", 1), kv.Int("two", 2)} now := time.Now() got := spanEvents([]export.Event{ { Name: "test 1", - Attributes: []core.KeyValue{}, + Attributes: []kv.KeyValue{}, Time: now, }, { @@ -119,7 +118,7 @@ func TestEmptyLinks(t *testing.T) { } func TestLinks(t *testing.T) { - attrs := []core.KeyValue{key.Int("one", 1), key.Int("two", 2)} + attrs := []kv.KeyValue{kv.Int("one", 1), kv.Int("two", 2)} l := []apitrace.Link{ {}, { @@ -281,13 +280,13 @@ func TestSpanData(t *testing.T) { EndTime: endTime, MessageEvents: []export.Event{ {Time: startTime, - Attributes: []core.KeyValue{ - key.Uint64("CompressedByteSize", 512), + Attributes: []kv.KeyValue{ + kv.Uint64("CompressedByteSize", 512), }, }, {Time: endTime, - Attributes: []core.KeyValue{ - key.String("MessageEventType", "Recv"), + Attributes: []kv.KeyValue{ + kv.String("MessageEventType", "Recv"), }, }, }, @@ -298,8 +297,8 @@ func TestSpanData(t *testing.T) { SpanID: apitrace.SpanID{0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7}, TraceFlags: 0, }, - Attributes: []core.KeyValue{ - key.String("LinkType", "Parent"), + Attributes: []kv.KeyValue{ + kv.String("LinkType", "Parent"), }, }, { @@ -308,21 +307,21 @@ func TestSpanData(t *testing.T) { SpanID: apitrace.SpanID{0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7}, TraceFlags: 0, }, - Attributes: []core.KeyValue{ - key.String("LinkType", "Child"), + Attributes: []kv.KeyValue{ + kv.String("LinkType", "Child"), }, }, }, StatusCode: codes.Internal, StatusMessage: "utterly unrecognized", HasRemoteParent: true, - Attributes: []core.KeyValue{ - key.Int64("timeout_ns", 12e9), + Attributes: []kv.KeyValue{ + kv.Int64("timeout_ns", 12e9), }, DroppedAttributeCount: 1, DroppedMessageEventCount: 2, DroppedLinkCount: 3, - Resource: resource.New(key.String("rk1", "rv1"), key.Int64("rk2", 5)), + Resource: resource.New(kv.String("rk1", "rv1"), kv.Int64("rk2", 5)), } // Not checking resource as the underlying map of our Resource makes diff --git a/exporters/otlp/otlp_integration_test.go b/exporters/otlp/otlp_integration_test.go index cb1dc826f..79121a292 100644 --- a/exporters/otlp/otlp_integration_test.go +++ b/exporters/otlp/otlp_integration_test.go @@ -26,14 +26,13 @@ import ( metricpb "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" metricapi "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/exporters/otlp" exporttrace "go.opentelemetry.io/otel/sdk/export/trace" - "go.opentelemetry.io/otel/sdk/metric/batcher/ungrouped" "go.opentelemetry.io/otel/sdk/metric/controller/push" + integrator "go.opentelemetry.io/otel/sdk/metric/integrator/simple" "go.opentelemetry.io/otel/sdk/metric/selector/simple" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) @@ -87,13 +86,13 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) ), } tp1, err := sdktrace.NewProvider(append(pOpts, - sdktrace.WithResourceAttributes(key.String("rk1", "rv11)"), - key.Int64("rk2", 5)))...) + sdktrace.WithResourceAttributes(kv.String("rk1", "rv11)"), + kv.Int64("rk2", 5)))...) assert.NoError(t, err) tp2, err := sdktrace.NewProvider(append(pOpts, - sdktrace.WithResourceAttributes(key.String("rk1", "rv12)"), - key.Float32("rk3", 6.5)))...) + sdktrace.WithResourceAttributes(kv.String("rk1", "rv12)"), + kv.Float32("rk3", 6.5)))...) assert.NoError(t, err) tr1 := tp1.Tracer("test-tracer1") @@ -102,64 +101,64 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) m := 4 for i := 0; i < m; i++ { _, span := tr1.Start(context.Background(), "AlwaysSample") - span.SetAttributes(key.Int64("i", int64(i))) + span.SetAttributes(kv.Int64("i", int64(i))) span.End() _, span = tr2.Start(context.Background(), "AlwaysSample") - span.SetAttributes(key.Int64("i", int64(i))) + span.SetAttributes(kv.Int64("i", int64(i))) span.End() } selector := simple.NewWithExactMeasure() - batcher := ungrouped.New(selector, true) - pusher := push.New(batcher, exp, 60*time.Second) + integrator := integrator.New(selector, true) + pusher := push.New(integrator, exp, 60*time.Second) pusher.Start() ctx := context.Background() meter := pusher.Meter("test-meter") - labels := []core.KeyValue{key.Bool("test", true)} + labels := []kv.KeyValue{kv.Bool("test", true)} type data struct { iKind metric.Kind - nKind core.NumberKind + nKind metricapi.NumberKind val int64 } instruments := map[string]data{ - "test-int64-counter": {metric.CounterKind, core.Int64NumberKind, 1}, - "test-float64-counter": {metric.CounterKind, core.Float64NumberKind, 1}, - "test-int64-measure": {metric.MeasureKind, core.Int64NumberKind, 2}, - "test-float64-measure": {metric.MeasureKind, core.Float64NumberKind, 2}, - "test-int64-observer": {metric.ObserverKind, core.Int64NumberKind, 3}, - "test-float64-observer": {metric.ObserverKind, core.Float64NumberKind, 3}, + "test-int64-counter": {metric.CounterKind, metricapi.Int64NumberKind, 1}, + "test-float64-counter": {metric.CounterKind, metricapi.Float64NumberKind, 1}, + "test-int64-measure": {metric.MeasureKind, metricapi.Int64NumberKind, 2}, + "test-float64-measure": {metric.MeasureKind, metricapi.Float64NumberKind, 2}, + "test-int64-observer": {metric.ObserverKind, metricapi.Int64NumberKind, 3}, + "test-float64-observer": {metric.ObserverKind, metricapi.Float64NumberKind, 3}, } for name, data := range instruments { switch data.iKind { case metric.CounterKind: switch data.nKind { - case core.Int64NumberKind: + case metricapi.Int64NumberKind: metricapi.Must(meter).NewInt64Counter(name).Add(ctx, data.val, labels...) - case core.Float64NumberKind: + case metricapi.Float64NumberKind: metricapi.Must(meter).NewFloat64Counter(name).Add(ctx, float64(data.val), labels...) default: assert.Failf(t, "unsupported number testing kind", data.nKind.String()) } case metric.MeasureKind: switch data.nKind { - case core.Int64NumberKind: + case metricapi.Int64NumberKind: metricapi.Must(meter).NewInt64Measure(name).Record(ctx, data.val, labels...) - case core.Float64NumberKind: + case metricapi.Float64NumberKind: metricapi.Must(meter).NewFloat64Measure(name).Record(ctx, float64(data.val), labels...) default: assert.Failf(t, "unsupported number testing kind", data.nKind.String()) } case metric.ObserverKind: switch data.nKind { - case core.Int64NumberKind: + case metricapi.Int64NumberKind: callback := func(v int64) metricapi.Int64ObserverCallback { return metricapi.Int64ObserverCallback(func(result metricapi.Int64ObserverResult) { result.Observe(v, labels...) }) }(data.val) metricapi.Must(meter).RegisterInt64Observer(name, callback) - case core.Float64NumberKind: + case metricapi.Float64NumberKind: callback := func(v float64) metricapi.Float64ObserverCallback { return metricapi.Float64ObserverCallback(func(result metricapi.Float64ObserverResult) { result.Observe(v, labels...) }) }(float64(data.val)) @@ -234,12 +233,12 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) switch data.iKind { case metric.CounterKind: switch data.nKind { - case core.Int64NumberKind: + case metricapi.Int64NumberKind: assert.Equal(t, metricpb.MetricDescriptor_COUNTER_INT64.String(), desc.GetType().String()) if dp := m.GetInt64DataPoints(); assert.Len(t, dp, 1) { assert.Equal(t, data.val, dp[0].Value, "invalid value for %q", desc.Name) } - case core.Float64NumberKind: + case metricapi.Float64NumberKind: assert.Equal(t, metricpb.MetricDescriptor_COUNTER_DOUBLE.String(), desc.GetType().String()) if dp := m.GetDoubleDataPoints(); assert.Len(t, dp, 1) { assert.Equal(t, float64(data.val), dp[0].Value, "invalid value for %q", desc.Name) diff --git a/exporters/otlp/otlp_metric_test.go b/exporters/otlp/otlp_metric_test.go index db25667f4..0471d0add 100644 --- a/exporters/otlp/otlp_metric_test.go +++ b/exporters/otlp/otlp_metric_test.go @@ -25,8 +25,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/label" "go.opentelemetry.io/otel/api/metric" metricsdk "go.opentelemetry.io/otel/sdk/export/metric" @@ -76,18 +75,18 @@ func (m checkpointSet) ForEach(fn func(metricsdk.Record) error) error { type record struct { name string mKind metric.Kind - nKind core.NumberKind + nKind metric.NumberKind resource *resource.Resource opts []metric.Option - labels []core.KeyValue + labels []kv.KeyValue } var ( - baseKeyValues = []core.KeyValue{key.String("host", "test.com")} - cpuKey = core.Key("CPU") + baseKeyValues = []kv.KeyValue{kv.String("host", "test.com")} + cpuKey = kv.Key("CPU") - testInstA = resource.New(key.String("instance", "tester-a")) - testInstB = resource.New(key.String("instance", "tester-b")) + testInstA = resource.New(kv.String("instance", "tester-a")) + testInstB = resource.New(kv.String("instance", "tester-b")) cpu1MD = &metricpb.MetricDescriptor{ Name: "int64-count", @@ -145,7 +144,7 @@ func TestNoGroupingExport(t *testing.T) { { "int64-count", metric.CounterKind, - core.Int64NumberKind, + metric.Int64NumberKind, nil, nil, append(baseKeyValues, cpuKey.Int(1)), @@ -153,7 +152,7 @@ func TestNoGroupingExport(t *testing.T) { { "int64-count", metric.CounterKind, - core.Int64NumberKind, + metric.Int64NumberKind, nil, nil, append(baseKeyValues, cpuKey.Int(2)), @@ -193,7 +192,7 @@ func TestMeasureMetricGroupingExport(t *testing.T) { r := record{ "measure", metric.MeasureKind, - core.Int64NumberKind, + metric.Int64NumberKind, nil, nil, append(baseKeyValues, cpuKey.Int(1)), @@ -257,9 +256,9 @@ func TestMeasureMetricGroupingExport(t *testing.T) { } runMetricExportTests(t, []record{r, r}, expected) //changing the number kind should make no difference. - r.nKind = core.Uint64NumberKind + r.nKind = metric.Uint64NumberKind runMetricExportTests(t, []record{r, r}, expected) - r.nKind = core.Float64NumberKind + r.nKind = metric.Float64NumberKind runMetricExportTests(t, []record{r, r}, expected) } @@ -267,7 +266,7 @@ func TestCountInt64MetricGroupingExport(t *testing.T) { r := record{ "int64-count", metric.CounterKind, - core.Int64NumberKind, + metric.Int64NumberKind, nil, nil, append(baseKeyValues, cpuKey.Int(1)), @@ -304,7 +303,7 @@ func TestCountUint64MetricGroupingExport(t *testing.T) { r := record{ "uint64-count", metric.CounterKind, - core.Uint64NumberKind, + metric.Uint64NumberKind, nil, nil, append(baseKeyValues, cpuKey.Int(1)), @@ -354,7 +353,7 @@ func TestCountFloat64MetricGroupingExport(t *testing.T) { r := record{ "float64-count", metric.CounterKind, - core.Float64NumberKind, + metric.Float64NumberKind, nil, nil, append(baseKeyValues, cpuKey.Int(1)), @@ -407,7 +406,7 @@ func TestResourceMetricGroupingExport(t *testing.T) { { "int64-count", metric.CounterKind, - core.Int64NumberKind, + metric.Int64NumberKind, testInstA, nil, append(baseKeyValues, cpuKey.Int(1)), @@ -415,7 +414,7 @@ func TestResourceMetricGroupingExport(t *testing.T) { { "int64-count", metric.CounterKind, - core.Int64NumberKind, + metric.Int64NumberKind, testInstA, nil, append(baseKeyValues, cpuKey.Int(1)), @@ -423,7 +422,7 @@ func TestResourceMetricGroupingExport(t *testing.T) { { "int64-count", metric.CounterKind, - core.Int64NumberKind, + metric.Int64NumberKind, testInstA, nil, append(baseKeyValues, cpuKey.Int(2)), @@ -431,7 +430,7 @@ func TestResourceMetricGroupingExport(t *testing.T) { { "int64-count", metric.CounterKind, - core.Int64NumberKind, + metric.Int64NumberKind, testInstB, nil, append(baseKeyValues, cpuKey.Int(1)), @@ -494,7 +493,7 @@ func TestResourceInstLibMetricGroupingExport(t *testing.T) { { "int64-count", metric.CounterKind, - core.Int64NumberKind, + metric.Int64NumberKind, testInstA, []metric.Option{ metric.WithLibraryName("couting-lib"), @@ -504,7 +503,7 @@ func TestResourceInstLibMetricGroupingExport(t *testing.T) { { "int64-count", metric.CounterKind, - core.Int64NumberKind, + metric.Int64NumberKind, testInstA, []metric.Option{ metric.WithLibraryName("couting-lib"), @@ -514,7 +513,7 @@ func TestResourceInstLibMetricGroupingExport(t *testing.T) { { "int64-count", metric.CounterKind, - core.Int64NumberKind, + metric.Int64NumberKind, testInstA, []metric.Option{ metric.WithLibraryName("couting-lib"), @@ -524,7 +523,7 @@ func TestResourceInstLibMetricGroupingExport(t *testing.T) { { "int64-count", metric.CounterKind, - core.Int64NumberKind, + metric.Int64NumberKind, testInstA, []metric.Option{ metric.WithLibraryName("summing-lib"), @@ -534,7 +533,7 @@ func TestResourceInstLibMetricGroupingExport(t *testing.T) { { "int64-count", metric.CounterKind, - core.Int64NumberKind, + metric.Int64NumberKind, testInstB, []metric.Option{ metric.WithLibraryName("couting-lib"), @@ -644,15 +643,15 @@ func runMetricExportTest(t *testing.T, exp *Exporter, rs []record, expected []me ctx := context.Background() switch r.nKind { - case core.Uint64NumberKind: - require.NoError(t, agg.Update(ctx, core.NewUint64Number(1), &desc)) - require.NoError(t, agg.Update(ctx, core.NewUint64Number(10), &desc)) - case core.Int64NumberKind: - require.NoError(t, agg.Update(ctx, core.NewInt64Number(1), &desc)) - require.NoError(t, agg.Update(ctx, core.NewInt64Number(10), &desc)) - case core.Float64NumberKind: - require.NoError(t, agg.Update(ctx, core.NewFloat64Number(1), &desc)) - require.NoError(t, agg.Update(ctx, core.NewFloat64Number(10), &desc)) + case metric.Uint64NumberKind: + require.NoError(t, agg.Update(ctx, metric.NewUint64Number(1), &desc)) + require.NoError(t, agg.Update(ctx, metric.NewUint64Number(10), &desc)) + case metric.Int64NumberKind: + require.NoError(t, agg.Update(ctx, metric.NewInt64Number(1), &desc)) + require.NoError(t, agg.Update(ctx, metric.NewInt64Number(10), &desc)) + case metric.Float64NumberKind: + require.NoError(t, agg.Update(ctx, metric.NewFloat64Number(1), &desc)) + require.NoError(t, agg.Update(ctx, metric.NewFloat64Number(10), &desc)) default: t.Fatalf("invalid number kind: %v", r.nKind) } @@ -714,7 +713,7 @@ func TestEmptyMetricExport(t *testing.T) { exp.metricExporter = msc exp.started = true - resource := resource.New(key.String("R", "S")) + resource := resource.New(kv.String("R", "S")) for _, test := range []struct { records []metricsdk.Record diff --git a/exporters/otlp/otlp_span_test.go b/exporters/otlp/otlp_span_test.go index 22e1ba71d..1e63d21de 100644 --- a/exporters/otlp/otlp_span_test.go +++ b/exporters/otlp/otlp_span_test.go @@ -27,8 +27,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" apitrace "go.opentelemetry.io/otel/api/trace" tracesdk "go.opentelemetry.io/otel/sdk/export/trace" "go.opentelemetry.io/otel/sdk/resource" @@ -90,13 +89,13 @@ func TestExportSpans(t *testing.T) { Name: "parent process", StartTime: startTime, EndTime: endTime, - Attributes: []core.KeyValue{ - key.String("user", "alice"), - key.Bool("authenticated", true), + Attributes: []kv.KeyValue{ + kv.String("user", "alice"), + kv.Bool("authenticated", true), }, StatusCode: codes.OK, StatusMessage: "Ok", - Resource: resource.New(key.String("instance", "tester-a")), + Resource: resource.New(kv.String("instance", "tester-a")), }, { SpanContext: apitrace.SpanContext{ @@ -109,13 +108,13 @@ func TestExportSpans(t *testing.T) { Name: "internal process", StartTime: startTime, EndTime: endTime, - Attributes: []core.KeyValue{ - key.String("user", "alice"), - key.Bool("authenticated", true), + Attributes: []kv.KeyValue{ + kv.String("user", "alice"), + kv.Bool("authenticated", true), }, StatusCode: codes.OK, StatusMessage: "Ok", - Resource: resource.New(key.String("instance", "tester-a")), + Resource: resource.New(kv.String("instance", "tester-a")), }, { SpanContext: apitrace.SpanContext{ @@ -127,13 +126,13 @@ func TestExportSpans(t *testing.T) { Name: "parent process", StartTime: startTime, EndTime: endTime, - Attributes: []core.KeyValue{ - key.String("user", "bob"), - key.Bool("authenticated", false), + Attributes: []kv.KeyValue{ + kv.String("user", "bob"), + kv.Bool("authenticated", false), }, StatusCode: codes.Unauthenticated, StatusMessage: "Unauthenticated", - Resource: resource.New(key.String("instance", "tester-b")), + Resource: resource.New(kv.String("instance", "tester-b")), }, }, []tracepb.ResourceSpans{ diff --git a/exporters/trace/jaeger/go.mod b/exporters/trace/jaeger/go.mod index e849c6238..dcbf19246 100644 --- a/exporters/trace/jaeger/go.mod +++ b/exporters/trace/jaeger/go.mod @@ -8,7 +8,7 @@ require ( github.com/apache/thrift v0.13.0 github.com/google/go-cmp v0.4.0 github.com/stretchr/testify v1.4.0 - go.opentelemetry.io/otel v0.4.3 + go.opentelemetry.io/otel v0.5.0 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect google.golang.org/api v0.20.0 google.golang.org/grpc v1.27.1 diff --git a/exporters/trace/jaeger/jaeger.go b/exporters/trace/jaeger/jaeger.go index 1e8092520..1ebcaf708 100644 --- a/exporters/trace/jaeger/jaeger.go +++ b/exporters/trace/jaeger/jaeger.go @@ -19,11 +19,13 @@ import ( "encoding/binary" "log" + "go.opentelemetry.io/otel/api/kv/value" + "google.golang.org/api/support/bundler" "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/global" + "go.opentelemetry.io/otel/api/kv" gen "go.opentelemetry.io/otel/exporters/trace/jaeger/internal/gen-go/jaeger" export "go.opentelemetry.io/otel/sdk/export/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace" @@ -176,7 +178,7 @@ type Process struct { ServiceName string // Tags are added to Jaeger Process exports - Tags []core.KeyValue + Tags []kv.KeyValue } // Exporter is an implementation of trace.SpanSyncer that uploads spans to Jaeger. @@ -271,48 +273,48 @@ func spanDataToThrift(data *export.SpanData) *gen.Span { } } -func keyValueToTag(kv core.KeyValue) *gen.Tag { +func keyValueToTag(keyValue kv.KeyValue) *gen.Tag { var tag *gen.Tag - switch kv.Value.Type() { - case core.STRING: - s := kv.Value.AsString() + switch keyValue.Value.Type() { + case value.STRING: + s := keyValue.Value.AsString() tag = &gen.Tag{ - Key: string(kv.Key), + Key: string(keyValue.Key), VStr: &s, VType: gen.TagType_STRING, } - case core.BOOL: - b := kv.Value.AsBool() + case value.BOOL: + b := keyValue.Value.AsBool() tag = &gen.Tag{ - Key: string(kv.Key), + Key: string(keyValue.Key), VBool: &b, VType: gen.TagType_BOOL, } - case core.INT32: - i := int64(kv.Value.AsInt32()) + case value.INT32: + i := int64(keyValue.Value.AsInt32()) tag = &gen.Tag{ - Key: string(kv.Key), + Key: string(keyValue.Key), VLong: &i, VType: gen.TagType_LONG, } - case core.INT64: - i := kv.Value.AsInt64() + case value.INT64: + i := keyValue.Value.AsInt64() tag = &gen.Tag{ - Key: string(kv.Key), + Key: string(keyValue.Key), VLong: &i, VType: gen.TagType_LONG, } - case core.FLOAT32: - f := float64(kv.Value.AsFloat32()) + case value.FLOAT32: + f := float64(keyValue.Value.AsFloat32()) tag = &gen.Tag{ - Key: string(kv.Key), + Key: string(keyValue.Key), VDouble: &f, VType: gen.TagType_DOUBLE, } - case core.FLOAT64: - f := kv.Value.AsFloat64() + case value.FLOAT64: + f := keyValue.Value.AsFloat64() tag = &gen.Tag{ - Key: string(kv.Key), + Key: string(keyValue.Key), VDouble: &f, VType: gen.TagType_DOUBLE, } diff --git a/exporters/trace/jaeger/jaeger_test.go b/exporters/trace/jaeger/jaeger_test.go index bb234d8e8..eca524083 100644 --- a/exporters/trace/jaeger/jaeger_test.go +++ b/exporters/trace/jaeger/jaeger_test.go @@ -25,9 +25,8 @@ import ( "github.com/stretchr/testify/assert" "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" apitrace "go.opentelemetry.io/otel/api/trace" gen "go.opentelemetry.io/otel/exporters/trace/jaeger/internal/gen-go/jaeger" export "go.opentelemetry.io/otel/sdk/export/trace" @@ -94,8 +93,8 @@ func TestNewRawExporter(t *testing.T) { WithCollectorEndpoint(collectorEndpoint), WithProcess(Process{ ServiceName: serviceName, - Tags: []core.KeyValue{ - key.String(tagKey, tagVal), + Tags: []kv.KeyValue{ + kv.String(tagKey, tagVal), }, }), ) @@ -141,8 +140,8 @@ func TestExporter_ExportSpan(t *testing.T) { withTestCollectorEndpoint(), WithProcess(Process{ ServiceName: serviceName, - Tags: []core.KeyValue{ - key.String(tagKey, tagVal), + Tags: []kv.KeyValue{ + kv.String(tagKey, tagVal), }, }), ) @@ -230,19 +229,19 @@ func Test_spanDataToThrift(t *testing.T) { }, }, }, - Attributes: []core.KeyValue{ - key.String("key", keyValue), - key.Float64("double", doubleValue), + Attributes: []kv.KeyValue{ + kv.String("key", keyValue), + kv.Float64("double", doubleValue), // Jaeger doesn't handle Uint tags, this should be ignored. - key.Uint64("ignored", 123), + kv.Uint64("ignored", 123), }, MessageEvents: []export.Event{ - {Name: eventNameValue, Attributes: []core.KeyValue{key.String("k1", keyValue)}, Time: now}, + {Name: eventNameValue, Attributes: []kv.KeyValue{kv.String("k1", keyValue)}, Time: now}, }, StatusCode: codes.Unknown, StatusMessage: statusMessage, SpanKind: apitrace.SpanKindClient, - Resource: resource.New(key.String("rk1", rv1), key.Int64("rk2", rv2)), + Resource: resource.New(kv.String("rk1", rv1), kv.Int64("rk2", rv2)), }, want: &gen.Span{ TraceIdLow: 651345242494996240, diff --git a/exporters/trace/stdout/stdout_test.go b/exporters/trace/stdout/stdout_test.go index f95edf014..91d5c74df 100644 --- a/exporters/trace/stdout/stdout_test.go +++ b/exporters/trace/stdout/stdout_test.go @@ -23,8 +23,7 @@ import ( "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/trace" export "go.opentelemetry.io/otel/sdk/export/trace" "go.opentelemetry.io/otel/sdk/resource" @@ -44,7 +43,7 @@ func TestExporter_ExportSpan(t *testing.T) { spanID, _ := trace.SpanIDFromHex("0102030405060708") keyValue := "value" doubleValue := 123.456 - resource := resource.New(key.String("rk1", "rv11")) + resource := resource.New(kv.String("rk1", "rv11")) testSpan := &export.SpanData{ SpanContext: trace.SpanContext{ @@ -54,13 +53,13 @@ func TestExporter_ExportSpan(t *testing.T) { Name: "/foo", StartTime: now, EndTime: now, - Attributes: []core.KeyValue{ - key.String("key", keyValue), - key.Float64("double", doubleValue), + Attributes: []kv.KeyValue{ + kv.String("key", keyValue), + kv.Float64("double", doubleValue), }, MessageEvents: []export.Event{ - {Name: "foo", Attributes: []core.KeyValue{key.String("key", keyValue)}, Time: now}, - {Name: "bar", Attributes: []core.KeyValue{key.Float64("double", doubleValue)}, Time: now}, + {Name: "foo", Attributes: []kv.KeyValue{kv.String("key", keyValue)}, Time: now}, + {Name: "bar", Attributes: []kv.KeyValue{kv.Float64("double", doubleValue)}, Time: now}, }, SpanKind: trace.SpanKindInternal, StatusCode: codes.Unknown, diff --git a/exporters/trace/zipkin/go.mod b/exporters/trace/zipkin/go.mod index aad3c458e..ba86783b3 100644 --- a/exporters/trace/zipkin/go.mod +++ b/exporters/trace/zipkin/go.mod @@ -7,6 +7,6 @@ replace go.opentelemetry.io/otel => ../../.. require ( github.com/openzipkin/zipkin-go v0.2.2 github.com/stretchr/testify v1.4.0 - go.opentelemetry.io/otel v0.4.3 + go.opentelemetry.io/otel v0.5.0 google.golang.org/grpc v1.27.1 ) diff --git a/exporters/trace/zipkin/model.go b/exporters/trace/zipkin/model.go index 4c2efb3c3..a320d33d8 100644 --- a/exporters/trace/zipkin/model.go +++ b/exporters/trace/zipkin/model.go @@ -21,7 +21,7 @@ import ( zkmodel "github.com/openzipkin/zipkin-go/model" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/trace" export "go.opentelemetry.io/otel/sdk/export/trace" ) @@ -122,7 +122,7 @@ func toZipkinAnnotations(events []export.Event) []zkmodel.Annotation { return annotations } -func attributesToJSONMapString(attributes []core.KeyValue) string { +func attributesToJSONMapString(attributes []kv.KeyValue) string { m := make(map[string]interface{}, len(attributes)) for _, attribute := range attributes { m[(string)(attribute.Key)] = attribute.Value.AsInterface() diff --git a/exporters/trace/zipkin/model_test.go b/exporters/trace/zipkin/model_test.go index 64f01fbe8..876130336 100644 --- a/exporters/trace/zipkin/model_test.go +++ b/exporters/trace/zipkin/model_test.go @@ -22,8 +22,7 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/trace" export "go.opentelemetry.io/otel/sdk/export/trace" ) @@ -41,16 +40,16 @@ func TestModelConversion(t *testing.T) { Name: "foo", StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC), EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC), - Attributes: []core.KeyValue{ - key.Uint64("attr1", 42), - key.String("attr2", "bar"), + Attributes: []kv.KeyValue{ + kv.Uint64("attr1", 42), + kv.String("attr2", "bar"), }, MessageEvents: []export.Event{ { Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC), Name: "ev1", - Attributes: []core.KeyValue{ - key.Uint64("eventattr1", 123), + Attributes: []kv.KeyValue{ + kv.Uint64("eventattr1", 123), }, }, { @@ -74,16 +73,16 @@ func TestModelConversion(t *testing.T) { Name: "foo", StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC), EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC), - Attributes: []core.KeyValue{ - key.Uint64("attr1", 42), - key.String("attr2", "bar"), + Attributes: []kv.KeyValue{ + kv.Uint64("attr1", 42), + kv.String("attr2", "bar"), }, MessageEvents: []export.Event{ { Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC), Name: "ev1", - Attributes: []core.KeyValue{ - key.Uint64("eventattr1", 123), + Attributes: []kv.KeyValue{ + kv.Uint64("eventattr1", 123), }, }, { @@ -106,16 +105,16 @@ func TestModelConversion(t *testing.T) { Name: "foo", StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC), EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC), - Attributes: []core.KeyValue{ - key.Uint64("attr1", 42), - key.String("attr2", "bar"), + Attributes: []kv.KeyValue{ + kv.Uint64("attr1", 42), + kv.String("attr2", "bar"), }, MessageEvents: []export.Event{ { Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC), Name: "ev1", - Attributes: []core.KeyValue{ - key.Uint64("eventattr1", 123), + Attributes: []kv.KeyValue{ + kv.Uint64("eventattr1", 123), }, }, { @@ -138,16 +137,16 @@ func TestModelConversion(t *testing.T) { Name: "foo", StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC), EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC), - Attributes: []core.KeyValue{ - key.Uint64("attr1", 42), - key.String("attr2", "bar"), + Attributes: []kv.KeyValue{ + kv.Uint64("attr1", 42), + kv.String("attr2", "bar"), }, MessageEvents: []export.Event{ { Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC), Name: "ev1", - Attributes: []core.KeyValue{ - key.Uint64("eventattr1", 123), + Attributes: []kv.KeyValue{ + kv.Uint64("eventattr1", 123), }, }, { @@ -170,16 +169,16 @@ func TestModelConversion(t *testing.T) { Name: "foo", StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC), EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC), - Attributes: []core.KeyValue{ - key.Uint64("attr1", 42), - key.String("attr2", "bar"), + Attributes: []kv.KeyValue{ + kv.Uint64("attr1", 42), + kv.String("attr2", "bar"), }, MessageEvents: []export.Event{ { Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC), Name: "ev1", - Attributes: []core.KeyValue{ - key.Uint64("eventattr1", 123), + Attributes: []kv.KeyValue{ + kv.Uint64("eventattr1", 123), }, }, { @@ -202,16 +201,16 @@ func TestModelConversion(t *testing.T) { Name: "foo", StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC), EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC), - Attributes: []core.KeyValue{ - key.Uint64("attr1", 42), - key.String("attr2", "bar"), + Attributes: []kv.KeyValue{ + kv.Uint64("attr1", 42), + kv.String("attr2", "bar"), }, MessageEvents: []export.Event{ { Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC), Name: "ev1", - Attributes: []core.KeyValue{ - key.Uint64("eventattr1", 123), + Attributes: []kv.KeyValue{ + kv.Uint64("eventattr1", 123), }, }, { @@ -234,16 +233,16 @@ func TestModelConversion(t *testing.T) { Name: "foo", StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC), EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC), - Attributes: []core.KeyValue{ - key.Uint64("attr1", 42), - key.String("attr2", "bar"), + Attributes: []kv.KeyValue{ + kv.Uint64("attr1", 42), + kv.String("attr2", "bar"), }, MessageEvents: []export.Event{ { Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC), Name: "ev1", - Attributes: []core.KeyValue{ - key.Uint64("eventattr1", 123), + Attributes: []kv.KeyValue{ + kv.Uint64("eventattr1", 123), }, }, { @@ -266,9 +265,9 @@ func TestModelConversion(t *testing.T) { Name: "foo", StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC), EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC), - Attributes: []core.KeyValue{ - key.Uint64("attr1", 42), - key.String("attr2", "bar"), + Attributes: []kv.KeyValue{ + kv.Uint64("attr1", 42), + kv.String("attr2", "bar"), }, MessageEvents: nil, StatusCode: codes.NotFound, @@ -285,15 +284,15 @@ func TestModelConversion(t *testing.T) { Name: "foo", StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC), EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC), - Attributes: []core.KeyValue{ - key.String("error", "false"), + Attributes: []kv.KeyValue{ + kv.String("error", "false"), }, MessageEvents: []export.Event{ { Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC), Name: "ev1", - Attributes: []core.KeyValue{ - key.Uint64("eventattr1", 123), + Attributes: []kv.KeyValue{ + kv.Uint64("eventattr1", 123), }, }, { diff --git a/internal/metric/async.go b/internal/metric/async.go new file mode 100644 index 000000000..07b7e01df --- /dev/null +++ b/internal/metric/async.go @@ -0,0 +1,160 @@ +// 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 metric + +import ( + "errors" + "fmt" + "os" + "sync" + + "go.opentelemetry.io/otel/api/kv" + "go.opentelemetry.io/otel/api/metric" +) + +var ErrInvalidAsyncRunner = errors.New("unknown async runner type") + +// AsyncCollector is an interface used between the MeterImpl and the +// AsyncInstrumentState helper below. This interface is implemented by +// the SDK to provide support for running observer callbacks. +type AsyncCollector interface { + // CollectAsync passes a batch of observations to the MeterImpl. + CollectAsync([]kv.KeyValue, ...metric.Observation) +} + +// AsyncInstrumentState manages an ordered set of asynchronous +// instruments and the distinct runners, taking into account batch +// observer callbacks. +type AsyncInstrumentState struct { + lock sync.Mutex + + // errorHandler will be called in case of an invalid + // metric.AsyncRunner, i.e., one that does not implement + // either the single-or batch-runner interfaces. + errorHandler func(error) + errorOnce sync.Once + + // runnerMap keeps the set of runners that will run each + // collection interval. Singletons are entered with a real + // instrument each, batch observers are entered with a nil + // instrument, ensuring that when a singleton callback is used + // repeatedly, it is excuted repeatedly in the interval, while + // when a batch callback is used repeatedly, it only executes + // once per interval. + runnerMap map[asyncRunnerPair]struct{} + + // runners maintains the set of runners in the order they were + // registered. + runners []asyncRunnerPair + + // instruments maintains the set of instruments in the order + // they were registered. + instruments []metric.AsyncImpl +} + +// asyncRunnerPair is a map entry for Observer callback runners. +type asyncRunnerPair struct { + // runner is used as a map key here. The API ensures + // that all callbacks are pointers for this reason. + runner metric.AsyncRunner + + // inst refers to a non-nil instrument when `runner` is a + // AsyncSingleRunner. + inst metric.AsyncImpl +} + +// NewAsyncInstrumentState returns a new *AsyncInstrumentState, for +// use by MeterImpl to manage running the set of observer callbacks in +// the correct order. +// +// errorHandler is used to print an error condition. If errorHandler +// nil, the default error handler will be used that prints to +// os.Stderr. Only the first error is passed to the handler, after +// which errors are skipped. +func NewAsyncInstrumentState(errorHandler func(error)) *AsyncInstrumentState { + if errorHandler == nil { + errorHandler = func(err error) { + fmt.Fprintln(os.Stderr, "Metrics Async state error:", err) + } + } + return &AsyncInstrumentState{ + errorHandler: errorHandler, + runnerMap: map[asyncRunnerPair]struct{}{}, + } +} + +// Instruments returns the asynchronous instruments managed by this +// object, the set that should be checkpointed after observers are +// run. +func (a *AsyncInstrumentState) Instruments() []metric.AsyncImpl { + a.lock.Lock() + defer a.lock.Unlock() + return a.instruments +} + +// Register adds a new asynchronous instrument to by managed by this +// object. This should be called during NewAsyncInstrument() and +// assumes that errors (e.g., duplicate registration) have already +// been checked. +func (a *AsyncInstrumentState) Register(inst metric.AsyncImpl, runner metric.AsyncRunner) { + a.lock.Lock() + defer a.lock.Unlock() + + a.instruments = append(a.instruments, inst) + + // asyncRunnerPair reflects this callback in the asyncRunners + // list. If this is a batch runner, the instrument is nil. + // If this is a single-Observer runner, the instrument is + // included. This ensures that batch callbacks are called + // once and single callbacks are called once per instrument. + rp := asyncRunnerPair{ + runner: runner, + } + if _, ok := runner.(metric.AsyncSingleRunner); ok { + rp.inst = inst + } + + if _, ok := a.runnerMap[rp]; !ok { + a.runnerMap[rp] = struct{}{} + a.runners = append(a.runners, rp) + } +} + +// Run executes the complete set of observer callbacks. +func (a *AsyncInstrumentState) Run(collector AsyncCollector) { + a.lock.Lock() + runners := a.runners + a.lock.Unlock() + + for _, rp := range runners { + // The runner must be a single or batch runner, no + // other implementations are possible because the + // interface has un-exported methods. + + if singleRunner, ok := rp.runner.(metric.AsyncSingleRunner); ok { + singleRunner.Run(rp.inst, collector.CollectAsync) + continue + } + + if multiRunner, ok := rp.runner.(metric.AsyncBatchRunner); ok { + multiRunner.Run(collector.CollectAsync) + continue + } + + a.errorOnce.Do(func() { + a.errorHandler(fmt.Errorf("%w: type %T (reported once)", ErrInvalidAsyncRunner, rp)) + }) + } +} diff --git a/internal/metric/mock.go b/internal/metric/mock.go index dcd3f0ab5..4ec328585 100644 --- a/internal/metric/mock.go +++ b/internal/metric/mock.go @@ -18,7 +18,7 @@ import ( "context" "sync" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" apimetric "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/api/metric/registry" @@ -27,14 +27,14 @@ import ( type ( Handle struct { Instrument *Sync - Labels []core.KeyValue + Labels []kv.KeyValue } Batch struct { // Measurement needs to be aligned for 64-bit atomic operations. Measurements []Measurement Ctx context.Context - Labels []core.KeyValue + Labels []kv.KeyValue LibraryName string } @@ -46,13 +46,16 @@ type ( } MeterImpl struct { + lock sync.Mutex + MeasurementBatches []Batch - AsyncInstruments []*Async + + asyncInstruments *AsyncInstrumentState } Measurement struct { // Number needs to be aligned for 64-bit atomic operations. - Number core.Number + Number apimetric.Number Instrument apimetric.InstrumentImpl } @@ -64,7 +67,7 @@ type ( Async struct { Instrument - callback func(func(core.Number, []core.KeyValue)) + runner apimetric.AsyncRunner } Sync struct { @@ -91,33 +94,35 @@ func (s *Sync) Implementation() interface{} { return s } -func (s *Sync) Bind(labels []core.KeyValue) apimetric.BoundSyncImpl { +func (s *Sync) Bind(labels []kv.KeyValue) apimetric.BoundSyncImpl { return &Handle{ Instrument: s, Labels: labels, } } -func (s *Sync) RecordOne(ctx context.Context, number core.Number, labels []core.KeyValue) { +func (s *Sync) RecordOne(ctx context.Context, number apimetric.Number, labels []kv.KeyValue) { s.meter.doRecordSingle(ctx, labels, s, number) } -func (h *Handle) RecordOne(ctx context.Context, number core.Number) { +func (h *Handle) RecordOne(ctx context.Context, number apimetric.Number) { h.Instrument.meter.doRecordSingle(ctx, h.Labels, h.Instrument, number) } func (h *Handle) Unbind() { } -func (m *MeterImpl) doRecordSingle(ctx context.Context, labels []core.KeyValue, instrument apimetric.InstrumentImpl, number core.Number) { - m.recordMockBatch(ctx, labels, Measurement{ +func (m *MeterImpl) doRecordSingle(ctx context.Context, labels []kv.KeyValue, instrument apimetric.InstrumentImpl, number apimetric.Number) { + m.collect(ctx, labels, []Measurement{{ Instrument: instrument, Number: number, - }) + }}) } func NewProvider() (*MeterImpl, apimetric.Provider) { - impl := &MeterImpl{} + impl := &MeterImpl{ + asyncInstruments: NewAsyncInstrumentState(nil), + } p := &MeterProvider{ impl: impl, unique: registry.NewUniqueInstrumentMeterImpl(impl), @@ -144,6 +149,9 @@ func NewMeter() (*MeterImpl, apimetric.Meter) { } func (m *MeterImpl) NewSyncInstrument(descriptor metric.Descriptor) (apimetric.SyncImpl, error) { + m.lock.Lock() + defer m.lock.Unlock() + return &Sync{ Instrument{ descriptor: descriptor, @@ -152,19 +160,22 @@ func (m *MeterImpl) NewSyncInstrument(descriptor metric.Descriptor) (apimetric.S }, nil } -func (m *MeterImpl) NewAsyncInstrument(descriptor metric.Descriptor, callback func(func(core.Number, []core.KeyValue))) (apimetric.AsyncImpl, error) { +func (m *MeterImpl) NewAsyncInstrument(descriptor metric.Descriptor, runner metric.AsyncRunner) (apimetric.AsyncImpl, error) { + m.lock.Lock() + defer m.lock.Unlock() + a := &Async{ Instrument: Instrument{ descriptor: descriptor, meter: m, }, - callback: callback, + runner: runner, } - m.AsyncInstruments = append(m.AsyncInstruments, a) + m.asyncInstruments.Register(a, runner) return a, nil } -func (m *MeterImpl) RecordBatch(ctx context.Context, labels []core.KeyValue, measurements ...apimetric.Measurement) { +func (m *MeterImpl) RecordBatch(ctx context.Context, labels []kv.KeyValue, measurements ...apimetric.Measurement) { mm := make([]Measurement, len(measurements)) for i := 0; i < len(measurements); i++ { m := measurements[i] @@ -173,10 +184,25 @@ func (m *MeterImpl) RecordBatch(ctx context.Context, labels []core.KeyValue, mea Number: m.Number(), } } - m.recordMockBatch(ctx, labels, mm...) + m.collect(ctx, labels, mm) } -func (m *MeterImpl) recordMockBatch(ctx context.Context, labels []core.KeyValue, measurements ...Measurement) { +func (m *MeterImpl) CollectAsync(labels []kv.KeyValue, obs ...metric.Observation) { + mm := make([]Measurement, len(obs)) + for i := 0; i < len(obs); i++ { + o := obs[i] + mm[i] = Measurement{ + Instrument: o.AsyncImpl(), + Number: o.Number(), + } + } + m.collect(context.Background(), labels, mm) +} + +func (m *MeterImpl) collect(ctx context.Context, labels []kv.KeyValue, measurements []Measurement) { + m.lock.Lock() + defer m.lock.Unlock() + m.MeasurementBatches = append(m.MeasurementBatches, Batch{ Ctx: ctx, Labels: labels, @@ -185,9 +211,5 @@ func (m *MeterImpl) recordMockBatch(ctx context.Context, labels []core.KeyValue, } func (m *MeterImpl) RunAsyncInstruments() { - for _, observer := range m.AsyncInstruments { - observer.callback(func(n core.Number, labels []core.KeyValue) { - m.doRecordSingle(context.Background(), labels, observer, n) - }) - } + m.asyncInstruments.Run(m) } diff --git a/internal/trace/mock_span.go b/internal/trace/mock_span.go index f8f59459a..a86653fea 100644 --- a/internal/trace/mock_span.go +++ b/internal/trace/mock_span.go @@ -20,7 +20,7 @@ import ( "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" apitrace "go.opentelemetry.io/otel/api/trace" ) @@ -33,8 +33,8 @@ type MockSpan struct { var _ apitrace.Span = (*MockSpan)(nil) -// SpanContext returns associated core.SpanContext. If the receiver is nil it returns -// an empty core.SpanContext +// SpanContext returns associated kv.SpanContext. If the receiver is nil it returns +// an empty kv.SpanContext func (ms *MockSpan) SpanContext() apitrace.SpanContext { if ms == nil { return apitrace.EmptySpanContext() @@ -56,7 +56,7 @@ func (ms *MockSpan) SetError(v bool) { } // SetAttributes does nothing. -func (ms *MockSpan) SetAttributes(attributes ...core.KeyValue) { +func (ms *MockSpan) SetAttributes(attributes ...kv.KeyValue) { } // SetAttribute does nothing. @@ -82,9 +82,9 @@ func (ms *MockSpan) Tracer() apitrace.Tracer { } // AddEvent does nothing. -func (ms *MockSpan) AddEvent(ctx context.Context, name string, attrs ...core.KeyValue) { +func (ms *MockSpan) AddEvent(ctx context.Context, name string, attrs ...kv.KeyValue) { } // AddEvent does nothing. -func (ms *MockSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...core.KeyValue) { +func (ms *MockSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...kv.KeyValue) { } diff --git a/internal/trace/parent/parent.go b/internal/trace/parent/parent.go index 7aac95088..5080aed91 100644 --- a/internal/trace/parent/parent.go +++ b/internal/trace/parent/parent.go @@ -17,8 +17,7 @@ package parent import ( "context" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/trace" ) @@ -47,8 +46,8 @@ func addLinkIfValid(links []trace.Link, sc trace.SpanContext, kind string) []tra } return append(links, trace.Link{ SpanContext: sc, - Attributes: []core.KeyValue{ - key.String("ignored-on-demand", kind), + Attributes: []kv.KeyValue{ + kv.String("ignored-on-demand", kind), }, }) } diff --git a/plugin/grpctrace/grpctrace.go b/plugin/grpctrace/grpctrace.go index 9e27b2a9e..294cc0db6 100644 --- a/plugin/grpctrace/grpctrace.go +++ b/plugin/grpctrace/grpctrace.go @@ -19,9 +19,9 @@ import ( "google.golang.org/grpc/metadata" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/correlation" "go.opentelemetry.io/otel/api/global" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/propagation" "go.opentelemetry.io/otel/api/trace" ) @@ -54,14 +54,14 @@ func Inject(ctx context.Context, metadata *metadata.MD) { // Extract returns the correlation context and span context that // another service encoded in the gRPC metadata object with Inject. // This function is meant to be used on incoming requests. -func Extract(ctx context.Context, metadata *metadata.MD) ([]core.KeyValue, trace.SpanContext) { +func Extract(ctx context.Context, metadata *metadata.MD) ([]kv.KeyValue, trace.SpanContext) { ctx = propagation.ExtractHTTP(ctx, global.Propagators(), &metadataSupplier{ metadata: metadata, }) spanContext := trace.RemoteSpanContextFromContext(ctx) - var correlationCtxKVs []core.KeyValue - correlation.MapFromContext(ctx).Foreach(func(kv core.KeyValue) bool { + var correlationCtxKVs []kv.KeyValue + correlation.MapFromContext(ctx).Foreach(func(kv kv.KeyValue) bool { correlationCtxKVs = append(correlationCtxKVs, kv) return true }) diff --git a/plugin/grpctrace/interceptor.go b/plugin/grpctrace/interceptor.go index f3f13963e..a84aec9e1 100644 --- a/plugin/grpctrace/interceptor.go +++ b/plugin/grpctrace/interceptor.go @@ -28,20 +28,19 @@ import ( "google.golang.org/grpc/peer" "google.golang.org/grpc/status" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/correlation" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/trace" ) var ( - rpcServiceKey = key.New("rpc.service") - netPeerIPKey = key.New("net.peer.ip") - netPeerPortKey = key.New("net.peer.port") + rpcServiceKey = kv.Key("rpc.service") + netPeerIPKey = kv.Key("net.peer.ip") + netPeerPortKey = kv.Key("net.peer.port") - messageTypeKey = key.New("message.type") - messageIDKey = key.New("message.id") - messageUncompressedSizeKey = key.New("message.uncompressed_size") + messageTypeKey = kv.Key("message.type") + messageIDKey = kv.Key("message.id") + messageUncompressedSizeKey = kv.Key("message.uncompressed_size") ) const ( @@ -399,28 +398,28 @@ func StreamServerInterceptor(tracer trace.Tracer) grpc.StreamServerInterceptor { } } -func peerInfoFromTarget(target string) []core.KeyValue { +func peerInfoFromTarget(target string) []kv.KeyValue { host, port, err := net.SplitHostPort(target) if err != nil { - return []core.KeyValue{} + return []kv.KeyValue{} } if host == "" { host = "127.0.0.1" } - return []core.KeyValue{ + return []kv.KeyValue{ netPeerIPKey.String(host), netPeerPortKey.String(port), } } -func peerInfoFromContext(ctx context.Context) []core.KeyValue { +func peerInfoFromContext(ctx context.Context) []kv.KeyValue { p, ok := peer.FromContext(ctx) if !ok { - return []core.KeyValue{} + return []kv.KeyValue{} } return peerInfoFromTarget(p.Addr.String()) diff --git a/plugin/httptrace/clienttrace.go b/plugin/httptrace/clienttrace.go index f7e86402c..66df26260 100644 --- a/plugin/httptrace/clienttrace.go +++ b/plugin/httptrace/clienttrace.go @@ -24,17 +24,16 @@ import ( "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/trace" ) var ( - HTTPStatus = key.New("http.status") - HTTPHeaderMIME = key.New("http.mime") - HTTPRemoteAddr = key.New("http.remote") - HTTPLocalAddr = key.New("http.local") + HTTPStatus = kv.Key("http.status") + HTTPHeaderMIME = kv.Key("http.mime") + HTTPRemoteAddr = kv.Key("http.remote") + HTTPLocalAddr = kv.Key("http.local") ) var ( @@ -90,7 +89,7 @@ func NewClientTrace(ctx context.Context) *httptrace.ClientTrace { } } -func (ct *clientTracer) start(hook, spanName string, attrs ...core.KeyValue) { +func (ct *clientTracer) start(hook, spanName string, attrs ...kv.KeyValue) { ct.mtx.Lock() defer ct.mtx.Unlock() @@ -110,7 +109,7 @@ func (ct *clientTracer) start(hook, spanName string, attrs ...core.KeyValue) { } } -func (ct *clientTracer) end(hook string, err error, attrs ...core.KeyValue) { +func (ct *clientTracer) end(hook string, err error, attrs ...kv.KeyValue) { ct.mtx.Lock() defer ct.mtx.Unlock() if ctx, ok := ct.activeHooks[hook]; ok { @@ -198,7 +197,7 @@ func (ct *clientTracer) wroteHeaderField(k string, v []string) { if ct.span("http.headers") == nil { ct.start("http.headers", "http.headers") } - ct.root.SetAttributes(key.String("http."+strings.ToLower(k), sliceToString(v))) + ct.root.SetAttributes(kv.String("http."+strings.ToLower(k), sliceToString(v))) } func (ct *clientTracer) wroteHeaders() { diff --git a/plugin/httptrace/clienttrace_test.go b/plugin/httptrace/clienttrace_test.go index b4508cfcb..072313be5 100644 --- a/plugin/httptrace/clienttrace_test.go +++ b/plugin/httptrace/clienttrace_test.go @@ -23,9 +23,8 @@ import ( "github.com/google/go-cmp/cmp" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/plugin/httptrace" export "go.opentelemetry.io/otel/sdk/export/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace" @@ -102,19 +101,19 @@ func TestHTTPRequestWithClientTrace(t *testing.T) { testLen := []struct { name string - attributes []core.KeyValue + attributes []kv.KeyValue parent string }{ { name: "http.connect", - attributes: []core.KeyValue{key.String("http.remote", address.String())}, + attributes: []kv.KeyValue{kv.String("http.remote", address.String())}, parent: "http.getconn", }, { name: "http.getconn", - attributes: []core.KeyValue{ - key.String("http.remote", address.String()), - key.String("http.host", address.String()), + attributes: []kv.KeyValue{ + kv.String("http.remote", address.String()), + kv.String("http.host", address.String()), }, parent: "test", }, @@ -141,18 +140,18 @@ func TestHTTPRequestWithClientTrace(t *testing.T) { } } - actualAttrs := make(map[core.Key]string) + actualAttrs := make(map[kv.Key]string) for _, attr := range span.Attributes { actualAttrs[attr.Key] = attr.Value.Emit() } - expectedAttrs := make(map[core.Key]string) + expectedAttrs := make(map[kv.Key]string) for _, attr := range tl.attributes { expectedAttrs[attr.Key] = attr.Value.Emit() } if tl.name == "http.getconn" { - local := key.New("http.local") + local := kv.Key("http.local") // http.local attribute is not deterministic, just make sure it exists for `getconn`. if _, ok := actualAttrs[local]; ok { delete(actualAttrs, local) diff --git a/plugin/httptrace/httptrace.go b/plugin/httptrace/httptrace.go index 70394027c..87746574d 100644 --- a/plugin/httptrace/httptrace.go +++ b/plugin/httptrace/httptrace.go @@ -18,30 +18,29 @@ import ( "context" "net/http" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/correlation" "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/propagation" "go.opentelemetry.io/otel/api/trace" ) var ( - HostKey = key.New("http.host") - URLKey = key.New("http.url") + HostKey = kv.Key("http.host") + URLKey = kv.Key("http.url") ) // Returns the Attributes, Context Entries, and SpanContext that were encoded by Inject. -func Extract(ctx context.Context, req *http.Request) ([]core.KeyValue, []core.KeyValue, trace.SpanContext) { +func Extract(ctx context.Context, req *http.Request) ([]kv.KeyValue, []kv.KeyValue, trace.SpanContext) { ctx = propagation.ExtractHTTP(ctx, global.Propagators(), req.Header) - attrs := []core.KeyValue{ + attrs := []kv.KeyValue{ URLKey.String(req.URL.String()), // Etc. } - var correlationCtxKVs []core.KeyValue - correlation.MapFromContext(ctx).Foreach(func(kv core.KeyValue) bool { + var correlationCtxKVs []kv.KeyValue + correlation.MapFromContext(ctx).Foreach(func(kv kv.KeyValue) bool { correlationCtxKVs = append(correlationCtxKVs, kv) return true }) diff --git a/plugin/othttp/common.go b/plugin/othttp/common.go index 2f08e51f7..ff48ac854 100644 --- a/plugin/othttp/common.go +++ b/plugin/othttp/common.go @@ -17,24 +17,25 @@ package othttp import ( "net/http" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" + "go.opentelemetry.io/otel/api/trace" ) // Attribute keys that can be added to a span. const ( - HostKey = core.Key("http.host") // the HTTP host (http.Request.Host) - MethodKey = core.Key("http.method") // the HTTP method (http.Request.Method) - PathKey = core.Key("http.path") // the HTTP path (http.Request.URL.Path) - URLKey = core.Key("http.url") // the HTTP URL (http.Request.URL.String()) - UserAgentKey = core.Key("http.user_agent") // the HTTP user agent (http.Request.UserAgent()) - RouteKey = core.Key("http.route") // the HTTP route (ex: /users/:id) - RemoteAddrKey = core.Key("http.remote_addr") // the network address of the client that sent the HTTP request (http.Request.RemoteAddr) - StatusCodeKey = core.Key("http.status_code") // if set, the HTTP status - ReadBytesKey = core.Key("http.read_bytes") // if anything was read from the request body, the total number of bytes read - ReadErrorKey = core.Key("http.read_error") // If an error occurred while reading a request, the string of the error (io.EOF is not recorded) - WroteBytesKey = core.Key("http.wrote_bytes") // if anything was written to the response writer, the total number of bytes written - WriteErrorKey = core.Key("http.write_error") // if an error occurred while writing a reply, the string of the error (io.EOF is not recorded) + HostKey = kv.Key("http.host") // the HTTP host (http.Request.Host) + MethodKey = kv.Key("http.method") // the HTTP method (http.Request.Method) + PathKey = kv.Key("http.path") // the HTTP path (http.Request.URL.Path) + URLKey = kv.Key("http.url") // the HTTP URL (http.Request.URL.String()) + UserAgentKey = kv.Key("http.user_agent") // the HTTP user agent (http.Request.UserAgent()) + RouteKey = kv.Key("http.route") // the HTTP route (ex: /users/:id) + RemoteAddrKey = kv.Key("http.remote_addr") // the network address of the client that sent the HTTP request (http.Request.RemoteAddr) + StatusCodeKey = kv.Key("http.status_code") // if set, the HTTP status + ReadBytesKey = kv.Key("http.read_bytes") // if anything was read from the request body, the total number of bytes read + ReadErrorKey = kv.Key("http.read_error") // If an error occurred while reading a request, the string of the error (io.EOF is not recorded) + WroteBytesKey = kv.Key("http.wrote_bytes") // if anything was written to the response writer, the total number of bytes written + WriteErrorKey = kv.Key("http.write_error") // if an error occurred while writing a reply, the string of the error (io.EOF is not recorded) ) // Filter is a predicate used to determine whether a given http.request should diff --git a/plugin/othttp/handler.go b/plugin/othttp/handler.go index d620dec18..c75c8d1fb 100644 --- a/plugin/othttp/handler.go +++ b/plugin/othttp/handler.go @@ -18,8 +18,8 @@ import ( "io" "net/http" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/global" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/propagation" "go.opentelemetry.io/otel/api/trace" ) @@ -29,7 +29,7 @@ var _ http.Handler = &Handler{} // Handler is http middleware that corresponds to the http.Handler interface and // is designed to wrap a http.Mux (or equivalent), while individual routes on // the mux are wrapped with WithRouteTag. A Handler will add various attributes -// to the span using the core.Keys defined in this package. +// to the span using the kv.Keys defined in this package. type Handler struct { operation string handler http.Handler @@ -121,7 +121,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } func setAfterServeAttributes(span trace.Span, read, wrote, statusCode int64, rerr, werr error) { - kv := make([]core.KeyValue, 0, 5) + kv := make([]kv.KeyValue, 0, 5) // TODO: Consider adding an event after each read and write, possibly as an // option (defaulting to off), so as to not create needlessly verbose spans. if read > 0 { diff --git a/plugin/othttp/handler_example_test.go b/plugin/othttp/handler_example_test.go index 63e610834..96f374dbb 100644 --- a/plugin/othttp/handler_example_test.go +++ b/plugin/othttp/handler_example_test.go @@ -22,8 +22,9 @@ import ( "net/http" "strings" + "go.opentelemetry.io/otel/api/kv" + "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/key" "go.opentelemetry.io/otel/api/trace" "go.opentelemetry.io/otel/exporters/trace/stdout" "go.opentelemetry.io/otel/plugin/othttp" @@ -65,7 +66,7 @@ func ExampleNewHandler() { case "": err = fmt.Errorf("expected /hello/:name in %q", s) default: - trace.SpanFromContext(ctx).SetAttributes(key.String("name", pp[1])) + trace.SpanFromContext(ctx).SetAttributes(kv.String("name", pp[1])) } return pp[1], err } diff --git a/sdk/export/metric/aggregator/aggregator.go b/sdk/export/metric/aggregator/aggregator.go index 3922aad8e..df1285108 100644 --- a/sdk/export/metric/aggregator/aggregator.go +++ b/sdk/export/metric/aggregator/aggregator.go @@ -19,7 +19,6 @@ import ( "math" "time" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" ) @@ -30,7 +29,7 @@ import ( type ( // Sum returns an aggregated sum. Sum interface { - Sum() (core.Number, error) + Sum() (metric.Number, error) } // Sum returns the number of values that were aggregated. @@ -40,28 +39,28 @@ type ( // Min returns the minimum value over the set of values that were aggregated. Min interface { - Min() (core.Number, error) + Min() (metric.Number, error) } // Max returns the maximum value over the set of values that were aggregated. Max interface { - Max() (core.Number, error) + Max() (metric.Number, error) } // Quantile returns an exact or estimated quantile over the // set of values that were aggregated. Quantile interface { - Quantile(float64) (core.Number, error) + Quantile(float64) (metric.Number, error) } // LastValue returns the latest value that was aggregated. LastValue interface { - LastValue() (core.Number, time.Time, error) + LastValue() (metric.Number, time.Time, error) } // Points returns the raw set of values that were aggregated. Points interface { - Points() ([]core.Number, error) + Points() ([]metric.Number, error) } // Buckets represents histogram buckets boundaries and counts. @@ -69,8 +68,8 @@ type ( // For a Histogram with N defined boundaries, e.g, [x, y, z]. // There are N+1 counts: [-inf, x), [x, y), [y, z), [z, +inf] Buckets struct { - Boundaries []core.Number - Counts []core.Number + Boundaries []metric.Number + Counts []metric.Number } // Histogram returns the count of events in pre-determined buckets. @@ -118,10 +117,10 @@ func NewInconsistentMergeError(a1, a2 export.Aggregator) error { // This rejects NaN values. This rejects negative values when the // metric instrument does not support negative values, including // monotonic counter metrics and absolute measure metrics. -func RangeTest(number core.Number, descriptor *metric.Descriptor) error { +func RangeTest(number metric.Number, descriptor *metric.Descriptor) error { numberKind := descriptor.NumberKind() - if numberKind == core.Float64NumberKind && math.IsNaN(number.AsFloat64()) { + if numberKind == metric.Float64NumberKind && math.IsNaN(number.AsFloat64()) { return ErrNaNInput } diff --git a/sdk/export/metric/aggregator/aggregator_test.go b/sdk/export/metric/aggregator/aggregator_test.go index 33db25954..1907b92b7 100644 --- a/sdk/export/metric/aggregator/aggregator_test.go +++ b/sdk/export/metric/aggregator/aggregator_test.go @@ -21,7 +21,6 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregator" "go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue" @@ -40,10 +39,10 @@ func TestInconsistentMergeErr(t *testing.T) { func testRangeNaN(t *testing.T, desc *metric.Descriptor) { // If the descriptor uses int64 numbers, this won't register as NaN - nan := core.NewFloat64Number(math.NaN()) + nan := metric.NewFloat64Number(math.NaN()) err := aggregator.RangeTest(nan, desc) - if desc.NumberKind() == core.Float64NumberKind { + if desc.NumberKind() == metric.Float64NumberKind { require.Equal(t, aggregator.ErrNaNInput, err) } else { require.Nil(t, err) @@ -51,14 +50,14 @@ func testRangeNaN(t *testing.T, desc *metric.Descriptor) { } func testRangeNegative(t *testing.T, desc *metric.Descriptor) { - var neg, pos core.Number + var neg, pos metric.Number - if desc.NumberKind() == core.Float64NumberKind { - pos = core.NewFloat64Number(+1) - neg = core.NewFloat64Number(-1) + if desc.NumberKind() == metric.Float64NumberKind { + pos = metric.NewFloat64Number(+1) + neg = metric.NewFloat64Number(-1) } else { - pos = core.NewInt64Number(+1) - neg = core.NewInt64Number(-1) + pos = metric.NewInt64Number(+1) + neg = metric.NewInt64Number(-1) } posErr := aggregator.RangeTest(pos, desc) @@ -70,7 +69,7 @@ func testRangeNegative(t *testing.T, desc *metric.Descriptor) { func TestRangeTest(t *testing.T) { // Only Counters implement a range test. - for _, nkind := range []core.NumberKind{core.Float64NumberKind, core.Int64NumberKind} { + for _, nkind := range []metric.NumberKind{metric.Float64NumberKind, metric.Int64NumberKind} { t.Run(nkind.String(), func(t *testing.T) { desc := metric.NewDescriptor( "name", @@ -83,7 +82,7 @@ func TestRangeTest(t *testing.T) { } func TestNaNTest(t *testing.T) { - for _, nkind := range []core.NumberKind{core.Float64NumberKind, core.Int64NumberKind} { + for _, nkind := range []metric.NumberKind{metric.Float64NumberKind, metric.Int64NumberKind} { t.Run(nkind.String(), func(t *testing.T) { for _, mkind := range []metric.Kind{ metric.CounterKind, diff --git a/sdk/export/metric/metric.go b/sdk/export/metric/metric.go index f278731a8..5b3a19a8f 100644 --- a/sdk/export/metric/metric.go +++ b/sdk/export/metric/metric.go @@ -17,13 +17,12 @@ package metric // import "go.opentelemetry.io/otel/sdk/export/metric" import ( "context" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/label" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/sdk/resource" ) -// Batcher is responsible for deciding which kind of aggregation to +// Integrator is responsible for deciding which kind of aggregation to // use (via AggregationSelector), gathering exported results from the // SDK during collection, and deciding over which dimensions to group // the exported data. @@ -38,13 +37,13 @@ import ( // // The `Process` method is called during collection in a // single-threaded context from the SDK, after the aggregator is -// checkpointed, allowing the batcher to build the set of metrics +// checkpointed, allowing the integrator to build the set of metrics // currently being exported. // // The `CheckpointSet` method is called during collection in a // single-threaded context from the Exporter, giving the exporter // access to a producer for iterating over the complete checkpoint. -type Batcher interface { +type Integrator interface { // AggregationSelector is responsible for selecting the // concrete type of Aggregator used for a metric in the SDK. // @@ -78,8 +77,8 @@ type Batcher interface { // The returned CheckpointSet is passed to the Exporter. CheckpointSet() CheckpointSet - // FinishedCollection informs the Batcher that a complete - // collection round was completed. Stateless batchers might + // FinishedCollection informs the Integrator that a complete + // collection round was completed. Stateless integrators might // reset state in this method, for example. FinishedCollection() } @@ -127,7 +126,7 @@ type Aggregator interface { // // The Context argument comes from user-level code and could be // inspected for distributed or span context. - Update(context.Context, core.Number, *metric.Descriptor) error + Update(context.Context, metric.Number, *metric.Descriptor) error // Checkpoint is called during collection to finish one period // of aggregation by atomically saving the current value. @@ -164,13 +163,13 @@ type Exporter interface { // The Resource contains common attributes that apply to all // metric events in the SDK. // - // The CheckpointSet interface refers to the Batcher that just + // The CheckpointSet interface refers to the Integrator that just // completed collection. Export(context.Context, *resource.Resource, CheckpointSet) error } // CheckpointSet allows a controller to access a complete checkpoint of -// aggregated metrics from the Batcher. This is passed to the +// aggregated metrics from the Integrator. This is passed to the // Exporter which may then use ForEach to iterate over the collection // of aggregated metrics. type CheckpointSet interface { @@ -193,7 +192,7 @@ type Record struct { aggregator Aggregator } -// NewRecord allows Batcher implementations to construct export +// NewRecord allows Integrator implementations to construct export // records. The Descriptor, Labels, and Aggregator represent // aggregate metric events received over a single collection period. func NewRecord(descriptor *metric.Descriptor, labels *label.Set, aggregator Aggregator) Record { diff --git a/sdk/export/metric/metric_test.go b/sdk/export/metric/metric_test.go index b172cf2e7..bfb575e35 100644 --- a/sdk/export/metric/metric_test.go +++ b/sdk/export/metric/metric_test.go @@ -17,19 +17,18 @@ package metric import ( "testing" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/label" "github.com/stretchr/testify/require" ) -var testSlice = []core.KeyValue{ - key.String("bar", "baz"), - key.Int("foo", 42), +var testSlice = []kv.KeyValue{ + kv.String("bar", "baz"), + kv.Int("foo", 42), } -func newIter(slice []core.KeyValue) label.Iterator { +func newIter(slice []kv.KeyValue) label.Iterator { labels := label.NewSet(slice...) return labels.Iter() } @@ -39,17 +38,17 @@ func TestLabelIterator(t *testing.T) { require.Equal(t, 2, iter.Len()) require.True(t, iter.Next()) - require.Equal(t, key.String("bar", "baz"), iter.Label()) + require.Equal(t, kv.String("bar", "baz"), iter.Label()) idx, label := iter.IndexedLabel() require.Equal(t, 0, idx) - require.Equal(t, key.String("bar", "baz"), label) + require.Equal(t, kv.String("bar", "baz"), label) require.Equal(t, 2, iter.Len()) require.True(t, iter.Next()) - require.Equal(t, key.Int("foo", 42), iter.Label()) + require.Equal(t, kv.Int("foo", 42), iter.Label()) idx, label = iter.IndexedLabel() require.Equal(t, 1, idx) - require.Equal(t, key.Int("foo", 42), label) + require.Equal(t, kv.Int("foo", 42), label) require.Equal(t, 2, iter.Len()) require.False(t, iter.Next()) diff --git a/sdk/export/trace/trace.go b/sdk/export/trace/trace.go index f76067cf7..b608c5323 100644 --- a/sdk/export/trace/trace.go +++ b/sdk/export/trace/trace.go @@ -20,7 +20,7 @@ import ( "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" apitrace "go.opentelemetry.io/otel/api/trace" "go.opentelemetry.io/otel/sdk/resource" ) @@ -56,7 +56,7 @@ type SpanData struct { // The wall clock time of EndTime will be adjusted to always be offset // from StartTime by the duration of the span. EndTime time.Time - Attributes []core.KeyValue + Attributes []kv.KeyValue MessageEvents []Event Links []apitrace.Link StatusCode codes.Code @@ -79,8 +79,8 @@ type Event struct { // Name is the name of this event Name string - // Attributes contains a list of keyvalue pairs. - Attributes []core.KeyValue + // Attributes contains a list of kv pairs. + Attributes []kv.KeyValue // Time is the time at which this event was recorded. Time time.Time diff --git a/sdk/metric/aggregator/array/array.go b/sdk/metric/aggregator/array/array.go index 050424209..38168bcc2 100644 --- a/sdk/metric/aggregator/array/array.go +++ b/sdk/metric/aggregator/array/array.go @@ -21,7 +21,6 @@ import ( "sync" "unsafe" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregator" @@ -30,13 +29,13 @@ import ( type ( Aggregator struct { // ckptSum needs to be aligned for 64-bit atomic operations. - ckptSum core.Number + ckptSum metric.Number lock sync.Mutex current points checkpoint points } - points []core.Number + points []metric.Number ) var _ export.Aggregator = &Aggregator{} @@ -52,7 +51,7 @@ func New() *Aggregator { } // Sum returns the sum of values in the checkpoint. -func (c *Aggregator) Sum() (core.Number, error) { +func (c *Aggregator) Sum() (metric.Number, error) { return c.ckptSum, nil } @@ -62,23 +61,23 @@ func (c *Aggregator) Count() (int64, error) { } // Max returns the maximum value in the checkpoint. -func (c *Aggregator) Max() (core.Number, error) { +func (c *Aggregator) Max() (metric.Number, error) { return c.checkpoint.Quantile(1) } // Min returns the mininum value in the checkpoint. -func (c *Aggregator) Min() (core.Number, error) { +func (c *Aggregator) Min() (metric.Number, error) { return c.checkpoint.Quantile(0) } // Quantile returns the estimated quantile of data in the checkpoint. // It is an error if `q` is less than 0 or greated than 1. -func (c *Aggregator) Quantile(q float64) (core.Number, error) { +func (c *Aggregator) Quantile(q float64) (metric.Number, error) { return c.checkpoint.Quantile(q) } // Points returns access to the raw data set. -func (c *Aggregator) Points() ([]core.Number, error) { +func (c *Aggregator) Points() ([]metric.Number, error) { return c.checkpoint, nil } @@ -97,7 +96,7 @@ func (c *Aggregator) Checkpoint(ctx context.Context, desc *metric.Descriptor) { // received as an alternative to requesting quantile information. c.sort(kind) - c.ckptSum = core.Number(0) + c.ckptSum = metric.Number(0) for _, v := range c.checkpoint { c.ckptSum.AddNumber(kind, v) @@ -107,7 +106,7 @@ func (c *Aggregator) Checkpoint(ctx context.Context, desc *metric.Descriptor) { // Update adds the recorded measurement to the current data set. // Update takes a lock to prevent concurrent Update() and Checkpoint() // calls. -func (c *Aggregator) Update(_ context.Context, number core.Number, desc *metric.Descriptor) error { +func (c *Aggregator) Update(_ context.Context, number metric.Number, desc *metric.Descriptor) error { c.lock.Lock() c.current = append(c.current, number) c.lock.Unlock() @@ -126,12 +125,12 @@ func (c *Aggregator) Merge(oa export.Aggregator, desc *metric.Descriptor) error return nil } -func (c *Aggregator) sort(kind core.NumberKind) { +func (c *Aggregator) sort(kind metric.NumberKind) { switch kind { - case core.Float64NumberKind: + case metric.Float64NumberKind: sort.Float64s(*(*[]float64)(unsafe.Pointer(&c.checkpoint))) - case core.Int64NumberKind: + case metric.Int64NumberKind: sort.Sort(&c.checkpoint) default: @@ -141,7 +140,7 @@ func (c *Aggregator) sort(kind core.NumberKind) { } } -func combine(a, b points, kind core.NumberKind) points { +func combine(a, b points, kind metric.NumberKind) points { result := make(points, 0, len(a)+len(b)) for len(a) != 0 && len(b) != 0 { @@ -176,13 +175,13 @@ func (p *points) Swap(i, j int) { // Quantile returns the least X such that Pr(x=q, where X is an // element of the data set. This uses the "Nearest-Rank" definition // of a quantile. -func (p *points) Quantile(q float64) (core.Number, error) { +func (p *points) Quantile(q float64) (metric.Number, error) { if len(*p) == 0 { - return core.Number(0), aggregator.ErrNoData + return metric.Number(0), aggregator.ErrNoData } if q < 0 || q > 1 { - return core.Number(0), aggregator.ErrInvalidQuantile + return metric.Number(0), aggregator.ErrInvalidQuantile } if q == 0 || len(*p) == 1 { diff --git a/sdk/metric/aggregator/array/array_test.go b/sdk/metric/aggregator/array/array_test.go index 6773ca682..87ea6d98f 100644 --- a/sdk/metric/aggregator/array/array_test.go +++ b/sdk/metric/aggregator/array/array_test.go @@ -24,7 +24,6 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" ottest "go.opentelemetry.io/otel/internal/testing" "go.opentelemetry.io/otel/sdk/export/metric/aggregator" @@ -218,10 +217,10 @@ func TestArrayErrors(t *testing.T) { descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) - test.CheckedUpdate(t, agg, core.Number(0), descriptor) + test.CheckedUpdate(t, agg, metric.Number(0), descriptor) - if profile.NumberKind == core.Float64NumberKind { - test.CheckedUpdate(t, agg, core.NewFloat64Number(math.NaN()), descriptor) + if profile.NumberKind == metric.Float64NumberKind { + test.CheckedUpdate(t, agg, metric.NewFloat64Number(math.NaN()), descriptor) } agg.Checkpoint(ctx, descriptor) @@ -231,7 +230,7 @@ func TestArrayErrors(t *testing.T) { num, err := agg.Quantile(0) require.Nil(t, err) - require.Equal(t, num, core.Number(0)) + require.Equal(t, num, metric.Number(0)) _, err = agg.Quantile(-0.0001) require.Error(t, err) @@ -244,7 +243,7 @@ func TestArrayErrors(t *testing.T) { } func TestArrayFloat64(t *testing.T) { - descriptor := test.NewAggregatorTest(metric.MeasureKind, core.Float64NumberKind) + descriptor := test.NewAggregatorTest(metric.MeasureKind, metric.Float64NumberKind) fpsf := func(sign int) []float64 { // Check behavior of a bunch of odd floating @@ -274,19 +273,19 @@ func TestArrayFloat64(t *testing.T) { } } - all := test.NewNumbers(core.Float64NumberKind) + all := test.NewNumbers(metric.Float64NumberKind) ctx := context.Background() agg := New() for _, f := range fpsf(1) { - all.Append(core.NewFloat64Number(f)) - test.CheckedUpdate(t, agg, core.NewFloat64Number(f), descriptor) + all.Append(metric.NewFloat64Number(f)) + test.CheckedUpdate(t, agg, metric.NewFloat64Number(f), descriptor) } for _, f := range fpsf(-1) { - all.Append(core.NewFloat64Number(f)) - test.CheckedUpdate(t, agg, core.NewFloat64Number(f), descriptor) + all.Append(metric.NewFloat64Number(f)) + test.CheckedUpdate(t, agg, metric.NewFloat64Number(f), descriptor) } agg.Checkpoint(ctx, descriptor) diff --git a/sdk/metric/aggregator/ddsketch/ddsketch.go b/sdk/metric/aggregator/ddsketch/ddsketch.go index b44e67c1f..a6b95da15 100644 --- a/sdk/metric/aggregator/ddsketch/ddsketch.go +++ b/sdk/metric/aggregator/ddsketch/ddsketch.go @@ -20,7 +20,6 @@ import ( sdk "github.com/DataDog/sketches-go/ddsketch" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -34,7 +33,7 @@ type Config = sdk.Config type Aggregator struct { lock sync.Mutex cfg *Config - kind core.NumberKind + kind metric.NumberKind current *sdk.DDSketch checkpoint *sdk.DDSketch } @@ -63,7 +62,7 @@ func NewDefaultConfig() *Config { } // Sum returns the sum of values in the checkpoint. -func (c *Aggregator) Sum() (core.Number, error) { +func (c *Aggregator) Sum() (metric.Number, error) { return c.toNumber(c.checkpoint.Sum()), nil } @@ -73,33 +72,33 @@ func (c *Aggregator) Count() (int64, error) { } // Max returns the maximum value in the checkpoint. -func (c *Aggregator) Max() (core.Number, error) { +func (c *Aggregator) Max() (metric.Number, error) { return c.Quantile(1) } // Min returns the minimum value in the checkpoint. -func (c *Aggregator) Min() (core.Number, error) { +func (c *Aggregator) Min() (metric.Number, error) { return c.Quantile(0) } // Quantile returns the estimated quantile of data in the checkpoint. // It is an error if `q` is less than 0 or greated than 1. -func (c *Aggregator) Quantile(q float64) (core.Number, error) { +func (c *Aggregator) Quantile(q float64) (metric.Number, error) { if c.checkpoint.Count() == 0 { - return core.Number(0), aggregator.ErrNoData + return metric.Number(0), aggregator.ErrNoData } f := c.checkpoint.Quantile(q) if math.IsNaN(f) { - return core.Number(0), aggregator.ErrInvalidQuantile + return metric.Number(0), aggregator.ErrInvalidQuantile } return c.toNumber(f), nil } -func (c *Aggregator) toNumber(f float64) core.Number { - if c.kind == core.Float64NumberKind { - return core.NewFloat64Number(f) +func (c *Aggregator) toNumber(f float64) metric.Number { + if c.kind == metric.Float64NumberKind { + return metric.NewFloat64Number(f) } - return core.NewInt64Number(int64(f)) + return metric.NewInt64Number(int64(f)) } // Checkpoint saves the current state and resets the current state to @@ -116,7 +115,7 @@ func (c *Aggregator) Checkpoint(ctx context.Context, _ *metric.Descriptor) { // Update adds the recorded measurement to the current data set. // Update takes a lock to prevent concurrent Update() and Checkpoint() // calls. -func (c *Aggregator) Update(_ context.Context, number core.Number, desc *metric.Descriptor) error { +func (c *Aggregator) Update(_ context.Context, number metric.Number, desc *metric.Descriptor) error { c.lock.Lock() defer c.lock.Unlock() c.current.Add(number.CoerceToFloat64(desc.NumberKind())) diff --git a/sdk/metric/aggregator/histogram/histogram.go b/sdk/metric/aggregator/histogram/histogram.go index 2e1055d34..f861d9651 100644 --- a/sdk/metric/aggregator/histogram/histogram.go +++ b/sdk/metric/aggregator/histogram/histogram.go @@ -19,7 +19,6 @@ import ( "sort" "sync" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregator" @@ -32,8 +31,8 @@ type ( lock sync.Mutex current state checkpoint state - boundaries []core.Number - kind core.NumberKind + boundaries []metric.Number + kind metric.NumberKind } // state represents the state of a histogram, consisting of @@ -42,8 +41,8 @@ type ( state struct { // all fields have to be aligned for 64-bit atomic operations. buckets aggregator.Buckets - count core.Number - sum core.Number + count metric.Number + sum metric.Number } ) @@ -60,11 +59,11 @@ var _ aggregator.Histogram = &Aggregator{} // Note that this aggregator maintains each value using independent // atomic operations, which introduces the possibility that // checkpoints are inconsistent. -func New(desc *metric.Descriptor, boundaries []core.Number) *Aggregator { +func New(desc *metric.Descriptor, boundaries []metric.Number) *Aggregator { // Boundaries MUST be ordered otherwise the histogram could not // be properly computed. sortedBoundaries := numbers{ - numbers: make([]core.Number, len(boundaries)), + numbers: make([]metric.Number, len(boundaries)), kind: desc.NumberKind(), } @@ -78,7 +77,7 @@ func New(desc *metric.Descriptor, boundaries []core.Number) *Aggregator { current: state{ buckets: aggregator.Buckets{ Boundaries: boundaries, - Counts: make([]core.Number, len(boundaries)+1), + Counts: make([]metric.Number, len(boundaries)+1), }, }, } @@ -86,7 +85,7 @@ func New(desc *metric.Descriptor, boundaries []core.Number) *Aggregator { } // Sum returns the sum of all values in the checkpoint. -func (c *Aggregator) Sum() (core.Number, error) { +func (c *Aggregator) Sum() (metric.Number, error) { c.lock.Lock() defer c.lock.Unlock() return c.checkpoint.sum, nil @@ -120,13 +119,13 @@ func (c *Aggregator) emptyState() state { return state{ buckets: aggregator.Buckets{ Boundaries: c.boundaries, - Counts: make([]core.Number, len(c.boundaries)+1), + Counts: make([]metric.Number, len(c.boundaries)+1), }, } } // Update adds the recorded measurement to the current data set. -func (c *Aggregator) Update(_ context.Context, number core.Number, desc *metric.Descriptor) error { +func (c *Aggregator) Update(_ context.Context, number metric.Number, desc *metric.Descriptor) error { kind := desc.NumberKind() bucketID := len(c.boundaries) @@ -155,18 +154,18 @@ func (c *Aggregator) Merge(oa export.Aggregator, desc *metric.Descriptor) error } c.checkpoint.sum.AddNumber(desc.NumberKind(), o.checkpoint.sum) - c.checkpoint.count.AddNumber(core.Uint64NumberKind, o.checkpoint.count) + c.checkpoint.count.AddNumber(metric.Uint64NumberKind, o.checkpoint.count) for i := 0; i < len(c.checkpoint.buckets.Counts); i++ { - c.checkpoint.buckets.Counts[i].AddNumber(core.Uint64NumberKind, o.checkpoint.buckets.Counts[i]) + c.checkpoint.buckets.Counts[i].AddNumber(metric.Uint64NumberKind, o.checkpoint.buckets.Counts[i]) } return nil } -// numbers is an auxiliary struct to order histogram bucket boundaries (slice of core.Number) +// numbers is an auxiliary struct to order histogram bucket boundaries (slice of kv.Number) type numbers struct { - numbers []core.Number - kind core.NumberKind + numbers []metric.Number + kind metric.NumberKind } var _ sort.Interface = (*numbers)(nil) diff --git a/sdk/metric/aggregator/histogram/histogram_test.go b/sdk/metric/aggregator/histogram/histogram_test.go index a9277f035..53aa1250b 100644 --- a/sdk/metric/aggregator/histogram/histogram_test.go +++ b/sdk/metric/aggregator/histogram/histogram_test.go @@ -23,7 +23,6 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/sdk/metric/aggregator/test" ) @@ -58,9 +57,9 @@ var ( }, } - boundaries = map[core.NumberKind][]core.Number{ - core.Float64NumberKind: {core.NewFloat64Number(500), core.NewFloat64Number(250), core.NewFloat64Number(750)}, - core.Int64NumberKind: {core.NewInt64Number(500), core.NewInt64Number(250), core.NewInt64Number(750)}, + boundaries = map[metric.NumberKind][]metric.Number{ + metric.Float64NumberKind: {metric.NewFloat64Number(500), metric.NewFloat64Number(250), metric.NewFloat64Number(750)}, + metric.Int64NumberKind: {metric.NewInt64Number(500), metric.NewInt64Number(250), metric.NewInt64Number(750)}, } ) @@ -185,7 +184,7 @@ func TestHistogramNotSet(t *testing.T) { agg.Checkpoint(ctx, descriptor) asum, err := agg.Sum() - require.Equal(t, core.Number(0), asum, "Empty checkpoint sum = 0") + require.Equal(t, metric.Number(0), asum, "Empty checkpoint sum = 0") require.Nil(t, err) count, err := agg.Count() @@ -199,9 +198,9 @@ func TestHistogramNotSet(t *testing.T) { }) } -func calcBuckets(points []core.Number, profile test.Profile) []uint64 { +func calcBuckets(points []metric.Number, profile test.Profile) []uint64 { sortedBoundaries := numbers{ - numbers: make([]core.Number, len(boundaries[profile.NumberKind])), + numbers: make([]metric.Number, len(boundaries[profile.NumberKind])), kind: profile.NumberKind, } diff --git a/sdk/metric/aggregator/lastvalue/lastvalue.go b/sdk/metric/aggregator/lastvalue/lastvalue.go index adeee9349..338a05cf1 100644 --- a/sdk/metric/aggregator/lastvalue/lastvalue.go +++ b/sdk/metric/aggregator/lastvalue/lastvalue.go @@ -20,7 +20,6 @@ import ( "time" "unsafe" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregator" @@ -43,7 +42,7 @@ type ( // value is the int64- or float64-encoded Set() data // // value needs to be aligned for 64-bit atomic operations. - value core.Number + value metric.Number // timestamp indicates when this record was submitted. // this can be used to pick a winner when multiple @@ -72,10 +71,10 @@ func New() *Aggregator { // corresponding timestamp. The error value aggregator.ErrNoData // will be returned if (due to a race condition) the checkpoint was // computed before the first value was set. -func (g *Aggregator) LastValue() (core.Number, time.Time, error) { +func (g *Aggregator) LastValue() (metric.Number, time.Time, error) { gd := (*lastValueData)(g.checkpoint) if gd == unsetLastValue { - return core.Number(0), time.Time{}, aggregator.ErrNoData + return metric.Number(0), time.Time{}, aggregator.ErrNoData } return gd.value.AsNumber(), gd.timestamp, nil } @@ -86,7 +85,7 @@ func (g *Aggregator) Checkpoint(ctx context.Context, _ *metric.Descriptor) { } // Update atomically sets the current "last" value. -func (g *Aggregator) Update(_ context.Context, number core.Number, desc *metric.Descriptor) error { +func (g *Aggregator) Update(_ context.Context, number metric.Number, desc *metric.Descriptor) error { ngd := &lastValueData{ value: number, timestamp: time.Now(), diff --git a/sdk/metric/aggregator/lastvalue/lastvalue_test.go b/sdk/metric/aggregator/lastvalue/lastvalue_test.go index 8580da7c2..49b9e6970 100644 --- a/sdk/metric/aggregator/lastvalue/lastvalue_test.go +++ b/sdk/metric/aggregator/lastvalue/lastvalue_test.go @@ -23,7 +23,6 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" ottest "go.opentelemetry.io/otel/internal/testing" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -58,7 +57,7 @@ func TestLastValueUpdate(t *testing.T) { record := test.NewAggregatorTest(metric.ObserverKind, profile.NumberKind) - var last core.Number + var last metric.Number for i := 0; i < count; i++ { x := profile.Random(rand.Intn(1)*2 - 1) last = x @@ -108,7 +107,7 @@ func TestLastValueMerge(t *testing.T) { } func TestLastValueNotSet(t *testing.T) { - descriptor := test.NewAggregatorTest(metric.ObserverKind, core.Int64NumberKind) + descriptor := test.NewAggregatorTest(metric.ObserverKind, metric.Int64NumberKind) g := New() g.Checkpoint(context.Background(), descriptor) @@ -116,5 +115,5 @@ func TestLastValueNotSet(t *testing.T) { value, timestamp, err := g.LastValue() require.Equal(t, aggregator.ErrNoData, err) require.True(t, timestamp.IsZero()) - require.Equal(t, core.Number(0), value) + require.Equal(t, metric.Number(0), value) } diff --git a/sdk/metric/aggregator/minmaxsumcount/mmsc.go b/sdk/metric/aggregator/minmaxsumcount/mmsc.go index d1f174fd5..1c840a158 100644 --- a/sdk/metric/aggregator/minmaxsumcount/mmsc.go +++ b/sdk/metric/aggregator/minmaxsumcount/mmsc.go @@ -18,7 +18,6 @@ import ( "context" "sync" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregator" @@ -31,14 +30,14 @@ type ( lock sync.Mutex current state checkpoint state - kind core.NumberKind + kind metric.NumberKind } state struct { - count core.Number - sum core.Number - min core.Number - max core.Number + count metric.Number + sum metric.Number + min metric.Number + max metric.Number } ) @@ -54,7 +53,7 @@ func New(desc *metric.Descriptor) *Aggregator { return &Aggregator{ kind: kind, current: state{ - count: core.NewUint64Number(0), + count: metric.NewUint64Number(0), sum: kind.Zero(), min: kind.Maximum(), max: kind.Minimum(), @@ -63,7 +62,7 @@ func New(desc *metric.Descriptor) *Aggregator { } // Sum returns the sum of values in the checkpoint. -func (c *Aggregator) Sum() (core.Number, error) { +func (c *Aggregator) Sum() (metric.Number, error) { c.lock.Lock() defer c.lock.Unlock() return c.checkpoint.sum, nil @@ -73,16 +72,16 @@ func (c *Aggregator) Sum() (core.Number, error) { func (c *Aggregator) Count() (int64, error) { c.lock.Lock() defer c.lock.Unlock() - return c.checkpoint.count.CoerceToInt64(core.Uint64NumberKind), nil + return c.checkpoint.count.CoerceToInt64(metric.Uint64NumberKind), nil } // Min returns the minimum value in the checkpoint. // The error value aggregator.ErrNoData will be returned // if there were no measurements recorded during the checkpoint. -func (c *Aggregator) Min() (core.Number, error) { +func (c *Aggregator) Min() (metric.Number, error) { c.lock.Lock() defer c.lock.Unlock() - if c.checkpoint.count.IsZero(core.Uint64NumberKind) { + if c.checkpoint.count.IsZero(metric.Uint64NumberKind) { return c.kind.Zero(), aggregator.ErrNoData } return c.checkpoint.min, nil @@ -91,10 +90,10 @@ func (c *Aggregator) Min() (core.Number, error) { // Max returns the maximum value in the checkpoint. // The error value aggregator.ErrNoData will be returned // if there were no measurements recorded during the checkpoint. -func (c *Aggregator) Max() (core.Number, error) { +func (c *Aggregator) Max() (metric.Number, error) { c.lock.Lock() defer c.lock.Unlock() - if c.checkpoint.count.IsZero(core.Uint64NumberKind) { + if c.checkpoint.count.IsZero(metric.Uint64NumberKind) { return c.kind.Zero(), aggregator.ErrNoData } return c.checkpoint.max, nil @@ -111,7 +110,7 @@ func (c *Aggregator) Checkpoint(ctx context.Context, desc *metric.Descriptor) { func (c *Aggregator) emptyState() state { kind := c.kind return state{ - count: core.NewUint64Number(0), + count: metric.NewUint64Number(0), sum: kind.Zero(), min: kind.Maximum(), max: kind.Minimum(), @@ -119,7 +118,7 @@ func (c *Aggregator) emptyState() state { } // Update adds the recorded measurement to the current data set. -func (c *Aggregator) Update(_ context.Context, number core.Number, desc *metric.Descriptor) error { +func (c *Aggregator) Update(_ context.Context, number metric.Number, desc *metric.Descriptor) error { kind := desc.NumberKind() c.lock.Lock() @@ -142,7 +141,7 @@ func (c *Aggregator) Merge(oa export.Aggregator, desc *metric.Descriptor) error return aggregator.NewInconsistentMergeError(c, oa) } - c.checkpoint.count.AddNumber(core.Uint64NumberKind, o.checkpoint.count) + c.checkpoint.count.AddNumber(metric.Uint64NumberKind, o.checkpoint.count) c.checkpoint.sum.AddNumber(desc.NumberKind(), o.checkpoint.sum) if c.checkpoint.min.CompareNumber(desc.NumberKind(), o.checkpoint.min) > 0 { diff --git a/sdk/metric/aggregator/minmaxsumcount/mmsc_test.go b/sdk/metric/aggregator/minmaxsumcount/mmsc_test.go index 58262d7ff..50c2fa5fc 100644 --- a/sdk/metric/aggregator/minmaxsumcount/mmsc_test.go +++ b/sdk/metric/aggregator/minmaxsumcount/mmsc_test.go @@ -22,7 +22,6 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregator" "go.opentelemetry.io/otel/sdk/metric/aggregator/test" @@ -192,7 +191,7 @@ func TestMaxSumCountNotSet(t *testing.T) { agg.Checkpoint(ctx, descriptor) asum, err := agg.Sum() - require.Equal(t, core.Number(0), asum, "Empty checkpoint sum = 0") + require.Equal(t, metric.Number(0), asum, "Empty checkpoint sum = 0") require.Nil(t, err) count, err := agg.Count() @@ -201,6 +200,6 @@ func TestMaxSumCountNotSet(t *testing.T) { max, err := agg.Max() require.Equal(t, aggregator.ErrNoData, err) - require.Equal(t, core.Number(0), max) + require.Equal(t, metric.Number(0), max) }) } diff --git a/sdk/metric/aggregator/sum/sum.go b/sdk/metric/aggregator/sum/sum.go index 86f99d522..1bf6505e1 100644 --- a/sdk/metric/aggregator/sum/sum.go +++ b/sdk/metric/aggregator/sum/sum.go @@ -17,7 +17,6 @@ package sum // import "go.opentelemetry.io/otel/sdk/metric/aggregator/sum" import ( "context" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregator" @@ -27,11 +26,11 @@ import ( type Aggregator struct { // current holds current increments to this counter record // current needs to be aligned for 64-bit atomic operations. - current core.Number + current metric.Number // checkpoint is a temporary used during Checkpoint() // checkpoint needs to be aligned for 64-bit atomic operations. - checkpoint core.Number + checkpoint metric.Number } var _ export.Aggregator = &Aggregator{} @@ -46,18 +45,18 @@ func New() *Aggregator { // Sum returns the last-checkpointed sum. This will never return an // error. -func (c *Aggregator) Sum() (core.Number, error) { +func (c *Aggregator) Sum() (metric.Number, error) { return c.checkpoint, nil } // Checkpoint atomically saves the current value and resets the // current sum to zero. func (c *Aggregator) Checkpoint(ctx context.Context, _ *metric.Descriptor) { - c.checkpoint = c.current.SwapNumberAtomic(core.Number(0)) + c.checkpoint = c.current.SwapNumberAtomic(metric.Number(0)) } // Update atomically adds to the current value. -func (c *Aggregator) Update(_ context.Context, number core.Number, desc *metric.Descriptor) error { +func (c *Aggregator) Update(_ context.Context, number metric.Number, desc *metric.Descriptor) error { c.current.AddNumberAtomic(desc.NumberKind(), number) return nil } diff --git a/sdk/metric/aggregator/sum/sum_test.go b/sdk/metric/aggregator/sum/sum_test.go index b8f1c512b..acd37e9ab 100644 --- a/sdk/metric/aggregator/sum/sum_test.go +++ b/sdk/metric/aggregator/sum/sum_test.go @@ -22,7 +22,6 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" ottest "go.opentelemetry.io/otel/internal/testing" "go.opentelemetry.io/otel/sdk/metric/aggregator/test" @@ -57,7 +56,7 @@ func TestCounterSum(t *testing.T) { descriptor := test.NewAggregatorTest(metric.CounterKind, profile.NumberKind) - sum := core.Number(0) + sum := metric.Number(0) for i := 0; i < count; i++ { x := profile.Random(+1) sum.AddNumber(profile.NumberKind, x) @@ -80,7 +79,7 @@ func TestMeasureSum(t *testing.T) { descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) - sum := core.Number(0) + sum := metric.Number(0) for i := 0; i < count; i++ { r1 := profile.Random(+1) @@ -108,7 +107,7 @@ func TestCounterMerge(t *testing.T) { descriptor := test.NewAggregatorTest(metric.CounterKind, profile.NumberKind) - sum := core.Number(0) + sum := metric.Number(0) for i := 0; i < count; i++ { x := profile.Random(+1) sum.AddNumber(profile.NumberKind, x) diff --git a/sdk/metric/aggregator/test/test.go b/sdk/metric/aggregator/test/test.go index 8fcd3dcfa..edb4a1d73 100644 --- a/sdk/metric/aggregator/test/test.go +++ b/sdk/metric/aggregator/test/test.go @@ -22,7 +22,6 @@ import ( "testing" "unsafe" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" ottest "go.opentelemetry.io/otel/internal/testing" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -32,29 +31,29 @@ import ( const Magnitude = 1000 type Profile struct { - NumberKind core.NumberKind - Random func(sign int) core.Number + NumberKind metric.NumberKind + Random func(sign int) metric.Number } func newProfiles() []Profile { rnd := rand.New(rand.NewSource(rand.Int63())) return []Profile{ { - NumberKind: core.Int64NumberKind, - Random: func(sign int) core.Number { - return core.NewInt64Number(int64(sign) * int64(rnd.Intn(Magnitude+1))) + NumberKind: metric.Int64NumberKind, + Random: func(sign int) metric.Number { + return metric.NewInt64Number(int64(sign) * int64(rnd.Intn(Magnitude+1))) }, }, { - NumberKind: core.Float64NumberKind, - Random: func(sign int) core.Number { - return core.NewFloat64Number(float64(sign) * rnd.Float64() * Magnitude) + NumberKind: metric.Float64NumberKind, + Random: func(sign int) metric.Number { + return metric.NewFloat64Number(float64(sign) * rnd.Float64() * Magnitude) }, }, } } -func NewAggregatorTest(mkind metric.Kind, nkind core.NumberKind) *metric.Descriptor { +func NewAggregatorTest(mkind metric.Kind, nkind metric.NumberKind) *metric.Descriptor { desc := metric.NewDescriptor("test.name", mkind, nkind) return &desc } @@ -84,17 +83,17 @@ func TestMain(m *testing.M) { type Numbers struct { // numbers has to be aligned for 64-bit atomic operations. - numbers []core.Number - kind core.NumberKind + numbers []metric.Number + kind metric.NumberKind } -func NewNumbers(kind core.NumberKind) Numbers { +func NewNumbers(kind metric.NumberKind) Numbers { return Numbers{ kind: kind, } } -func (n *Numbers) Append(v core.Number) { +func (n *Numbers) Append(v metric.Number) { n.numbers = append(n.numbers, v) } @@ -114,8 +113,8 @@ func (n *Numbers) Swap(i, j int) { n.numbers[i], n.numbers[j] = n.numbers[j], n.numbers[i] } -func (n *Numbers) Sum() core.Number { - var sum core.Number +func (n *Numbers) Sum() metric.Number { + var sum metric.Number for _, num := range n.numbers { sum.AddNumber(n.kind, num) } @@ -126,16 +125,16 @@ func (n *Numbers) Count() int64 { return int64(len(n.numbers)) } -func (n *Numbers) Min() core.Number { +func (n *Numbers) Min() metric.Number { return n.numbers[0] } -func (n *Numbers) Max() core.Number { +func (n *Numbers) Max() metric.Number { return n.numbers[len(n.numbers)-1] } // Median() is an alias for Quantile(0.5). -func (n *Numbers) Median() core.Number { +func (n *Numbers) Median() metric.Number { // Note that len(n.numbers) is 1 greater than the max element // index, so dividing by two rounds up. This gives the // intended definition for Quantile() in tests, which is to @@ -144,12 +143,12 @@ func (n *Numbers) Median() core.Number { return n.numbers[len(n.numbers)/2] } -func (n *Numbers) Points() []core.Number { +func (n *Numbers) Points() []metric.Number { return n.numbers } // Performs the same range test the SDK does on behalf of the aggregator. -func CheckedUpdate(t *testing.T, agg export.Aggregator, number core.Number, descriptor *metric.Descriptor) { +func CheckedUpdate(t *testing.T, agg export.Aggregator, number metric.Number, descriptor *metric.Descriptor) { ctx := context.Background() // Note: Aggregator tests are written assuming that the SDK diff --git a/sdk/metric/benchmark_test.go b/sdk/metric/benchmark_test.go index a707e47a3..9cbc1a578 100644 --- a/sdk/metric/benchmark_test.go +++ b/sdk/metric/benchmark_test.go @@ -21,8 +21,7 @@ import ( "strings" "testing" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/label" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -36,10 +35,10 @@ import ( type processFunc func(context.Context, export.Record) error type benchFixture struct { - meter metric.MeterMust - sdk *sdk.SDK - B *testing.B - pcb processFunc + meter metric.MeterMust + accumulator *sdk.Accumulator + B *testing.B + pcb processFunc } func newFixture(b *testing.B) *benchFixture { @@ -48,8 +47,8 @@ func newFixture(b *testing.B) *benchFixture { B: b, } - bf.sdk = sdk.New(bf) - bf.meter = metric.Must(metric.WrapMeterImpl(bf.sdk, "benchmarks")) + bf.accumulator = sdk.NewAccumulator(bf) + bf.meter = metric.Must(metric.WrapMeterImpl(bf.accumulator, "benchmarks")) return bf } @@ -90,8 +89,8 @@ func (*benchFixture) CheckpointSet() export.CheckpointSet { func (*benchFixture) FinishedCollection() { } -func makeManyLabels(n int) [][]core.KeyValue { - r := make([][]core.KeyValue, n) +func makeManyLabels(n int) [][]kv.KeyValue { + r := make([][]kv.KeyValue, n) for i := 0; i < n; i++ { r[i] = makeLabels(1) @@ -100,9 +99,9 @@ func makeManyLabels(n int) [][]core.KeyValue { return r } -func makeLabels(n int) []core.KeyValue { +func makeLabels(n int) []kv.KeyValue { used := map[string]bool{} - l := make([]core.KeyValue, n) + l := make([]kv.KeyValue, n) for i := 0; i < n; i++ { var k string for { @@ -112,7 +111,7 @@ func makeLabels(n int) []core.KeyValue { break } } - l[i] = key.New(k).String(fmt.Sprint("v", rand.Intn(1000000000))) + l[i] = kv.Key(k).String(fmt.Sprint("v", rand.Intn(1000000000))) } return l } @@ -199,12 +198,12 @@ func BenchmarkAcquireReleaseExistingHandle(b *testing.B) { // Iterators -var benchmarkIteratorVar core.KeyValue +var benchmarkIteratorVar kv.KeyValue func benchmarkIterator(b *testing.B, n int) { fix := newFixture(b) fix.setProcessCallback(func(ctx context.Context, rec export.Record) error { - var kv core.KeyValue + var kv kv.KeyValue li := rec.Labels().Iter() fix.B.StartTimer() for i := 0; i < fix.B.N; i++ { @@ -223,7 +222,7 @@ func benchmarkIterator(b *testing.B, n int) { cnt.Add(ctx, 1, makeLabels(n)...) b.ResetTimer() - fix.sdk.Collect(ctx) + fix.accumulator.Collect(ctx) } func BenchmarkIterator_0(b *testing.B) { @@ -447,7 +446,7 @@ func BenchmarkObserverObservationInt64(b *testing.B) { b.ResetTimer() - fix.sdk.Collect(ctx) + fix.accumulator.Collect(ctx) } func BenchmarkObserverObservationFloat64(b *testing.B) { @@ -462,7 +461,7 @@ func BenchmarkObserverObservationFloat64(b *testing.B) { b.ResetTimer() - fix.sdk.Collect(ctx) + fix.accumulator.Collect(ctx) } // MaxSumCount @@ -536,7 +535,7 @@ func benchmarkBatchRecord8Labels(b *testing.B, numInst int) { b.ResetTimer() for i := 0; i < b.N; i++ { - fix.sdk.RecordBatch(ctx, labs, meas...) + fix.accumulator.RecordBatch(ctx, labs, meas...) } } @@ -568,13 +567,13 @@ func BenchmarkRepeatedDirectCalls(b *testing.B) { } c := fix.meter.NewInt64Counter("int64.counter") - k := key.String("bench", "true") + k := kv.String("bench", "true") b.ResetTimer() for i := 0; i < b.N; i++ { c.Add(ctx, 1, k) - fix.sdk.Collect(ctx) + fix.accumulator.Collect(ctx) } } @@ -595,13 +594,13 @@ func BenchmarkLabelIterator(b *testing.B) { counter := fix.meter.NewInt64Counter("test.counter") counter.Add(ctx, 1, keyValues...) - fix.sdk.Collect(ctx) + fix.accumulator.Collect(ctx) b.ResetTimer() labels := rec.Labels() iter := labels.Iter() - var val core.KeyValue + var val kv.KeyValue for i := 0; i < b.N; i++ { if !iter.Next() { iter = labels.Iter() diff --git a/sdk/metric/controller/push/config_test.go b/sdk/metric/controller/push/config_test.go index e0d5986d7..f96b4a28c 100644 --- a/sdk/metric/controller/push/config_test.go +++ b/sdk/metric/controller/push/config_test.go @@ -18,9 +18,10 @@ import ( "fmt" "testing" + "go.opentelemetry.io/otel/api/kv" + "github.com/stretchr/testify/assert" - "go.opentelemetry.io/otel/api/key" sdk "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/resource" ) @@ -49,7 +50,7 @@ func TestWithErrorHandler(t *testing.T) { } func TestWithResource(t *testing.T) { - r := resource.New(key.String("A", "a")) + r := resource.New(kv.String("A", "a")) c := &Config{} WithResource(r).Apply(c) diff --git a/sdk/metric/controller/push/push.go b/sdk/metric/controller/push/push.go index 152c5f115..d93d032de 100644 --- a/sdk/metric/controller/push/push.go +++ b/sdk/metric/controller/push/push.go @@ -30,12 +30,12 @@ import ( type Controller struct { lock sync.Mutex collectLock sync.Mutex - sdk *sdk.SDK + accumulator *sdk.Accumulator resource *resource.Resource uniq metric.MeterImpl named map[string]metric.Meter errorHandler sdk.ErrorHandler - batcher export.Batcher + integrator export.Integrator exporter export.Exporter wg sync.WaitGroup ch chan struct{} @@ -70,23 +70,23 @@ var _ Clock = realClock{} var _ Ticker = realTicker{} // New constructs a Controller, an implementation of metric.Provider, -// using the provided batcher, exporter, collection period, and SDK +// using the provided integrator, exporter, collection period, and SDK // configuration options to configure an SDK with periodic collection. -// The batcher itself is configured with the aggregation selector policy. -func New(batcher export.Batcher, exporter export.Exporter, period time.Duration, opts ...Option) *Controller { +// The integrator itself is configured with the aggregation selector policy. +func New(integrator export.Integrator, exporter export.Exporter, period time.Duration, opts ...Option) *Controller { c := &Config{ErrorHandler: sdk.DefaultErrorHandler} for _, opt := range opts { opt.Apply(c) } - impl := sdk.New(batcher, sdk.WithErrorHandler(c.ErrorHandler)) + impl := sdk.NewAccumulator(integrator, sdk.WithErrorHandler(c.ErrorHandler)) return &Controller{ - sdk: impl, + accumulator: impl, resource: c.Resource, uniq: registry.NewUniqueInstrumentMeterImpl(impl), named: map[string]metric.Meter{}, errorHandler: c.ErrorHandler, - batcher: batcher, + integrator: integrator, exporter: exporter, ch: make(chan struct{}), period: period, @@ -106,7 +106,7 @@ func (c *Controller) SetErrorHandler(errorHandler sdk.ErrorHandler) { c.lock.Lock() defer c.lock.Unlock() c.errorHandler = errorHandler - c.sdk.SetErrorHandler(errorHandler) + c.accumulator.SetErrorHandler(errorHandler) } // Meter returns a named Meter, satisifying the metric.Provider @@ -176,10 +176,10 @@ func (c *Controller) tick() { c.collect(ctx) checkpointSet := syncCheckpointSet{ mtx: &c.collectLock, - delegate: c.batcher.CheckpointSet(), + delegate: c.integrator.CheckpointSet(), } err := c.exporter.Export(ctx, c.resource, checkpointSet) - c.batcher.FinishedCollection() + c.integrator.FinishedCollection() if err != nil { c.errorHandler(err) @@ -190,7 +190,7 @@ func (c *Controller) collect(ctx context.Context) { c.collectLock.Lock() defer c.collectLock.Unlock() - c.sdk.Collect(ctx) + c.accumulator.Collect(ctx) } // syncCheckpointSet is a wrapper for a CheckpointSet to synchronize diff --git a/sdk/metric/controller/push/push_test.go b/sdk/metric/controller/push/push_test.go index 24d6f62b5..11dbf4a52 100644 --- a/sdk/metric/controller/push/push_test.go +++ b/sdk/metric/controller/push/push_test.go @@ -34,7 +34,7 @@ import ( "go.opentelemetry.io/otel/sdk/resource" ) -type testBatcher struct { +type testIntegrator struct { t *testing.T lock sync.Mutex checkpointSet *test.CheckpointSet @@ -52,7 +52,7 @@ type testExporter struct { type testFixture struct { checkpointSet *test.CheckpointSet - batcher *testBatcher + integrator *testIntegrator exporter *testExporter } @@ -70,7 +70,7 @@ var _ push.Ticker = mockTicker{} func newFixture(t *testing.T) testFixture { checkpointSet := test.NewCheckpointSet() - batcher := &testBatcher{ + integrator := &testIntegrator{ t: t, checkpointSet: checkpointSet, } @@ -79,29 +79,29 @@ func newFixture(t *testing.T) testFixture { } return testFixture{ checkpointSet: checkpointSet, - batcher: batcher, + integrator: integrator, exporter: exporter, } } -func (b *testBatcher) AggregatorFor(*metric.Descriptor) export.Aggregator { +func (b *testIntegrator) AggregatorFor(*metric.Descriptor) export.Aggregator { return sum.New() } -func (b *testBatcher) CheckpointSet() export.CheckpointSet { +func (b *testIntegrator) CheckpointSet() export.CheckpointSet { b.lock.Lock() defer b.lock.Unlock() b.checkpoints++ return b.checkpointSet } -func (b *testBatcher) FinishedCollection() { +func (b *testIntegrator) FinishedCollection() { b.lock.Lock() defer b.lock.Unlock() b.finishes++ } -func (b *testBatcher) Process(_ context.Context, record export.Record) error { +func (b *testIntegrator) Process(_ context.Context, record export.Record) error { b.lock.Lock() defer b.lock.Unlock() labels := record.Labels().ToSlice() @@ -109,7 +109,7 @@ func (b *testBatcher) Process(_ context.Context, record export.Record) error { return nil } -func (b *testBatcher) getCounts() (checkpoints, finishes int) { +func (b *testIntegrator) getCounts() (checkpoints, finishes int) { b.lock.Lock() defer b.lock.Unlock() return b.checkpoints, b.finishes @@ -165,7 +165,7 @@ func (t mockTicker) C() <-chan time.Time { func TestPushDoubleStop(t *testing.T) { fix := newFixture(t) - p := push.New(fix.batcher, fix.exporter, time.Second) + p := push.New(fix.integrator, fix.exporter, time.Second) p.Start() p.Stop() p.Stop() @@ -173,7 +173,7 @@ func TestPushDoubleStop(t *testing.T) { func TestPushDoubleStart(t *testing.T) { fix := newFixture(t) - p := push.New(fix.batcher, fix.exporter, time.Second) + p := push.New(fix.integrator, fix.exporter, time.Second) p.Start() p.Start() p.Stop() @@ -182,7 +182,7 @@ func TestPushDoubleStart(t *testing.T) { func TestPushTicker(t *testing.T) { fix := newFixture(t) - p := push.New(fix.batcher, fix.exporter, time.Second) + p := push.New(fix.integrator, fix.exporter, time.Second) meter := p.Meter("name") mock := mockClock{clock.NewMock()} @@ -197,7 +197,7 @@ func TestPushTicker(t *testing.T) { counter.Add(ctx, 3) records, exports := fix.exporter.resetRecords() - checkpoints, finishes := fix.batcher.getCounts() + checkpoints, finishes := fix.integrator.getCounts() require.Equal(t, 0, checkpoints) require.Equal(t, 0, finishes) require.Equal(t, 0, exports) @@ -207,7 +207,7 @@ func TestPushTicker(t *testing.T) { runtime.Gosched() records, exports = fix.exporter.resetRecords() - checkpoints, finishes = fix.batcher.getCounts() + checkpoints, finishes = fix.integrator.getCounts() require.Equal(t, 1, checkpoints) require.Equal(t, 1, finishes) require.Equal(t, 1, exports) @@ -226,7 +226,7 @@ func TestPushTicker(t *testing.T) { runtime.Gosched() records, exports = fix.exporter.resetRecords() - checkpoints, finishes = fix.batcher.getCounts() + checkpoints, finishes = fix.integrator.getCounts() require.Equal(t, 2, checkpoints) require.Equal(t, 2, finishes) require.Equal(t, 2, exports) @@ -265,7 +265,7 @@ func TestPushExportError(t *testing.T) { fix := newFixture(t) fix.exporter.injectErr = injector("counter1", tt.injectedError) - p := push.New(fix.batcher, fix.exporter, time.Second) + p := push.New(fix.integrator, fix.exporter, time.Second) var err error var lock sync.Mutex @@ -297,7 +297,7 @@ func TestPushExportError(t *testing.T) { runtime.Gosched() records, exports := fix.exporter.resetRecords() - checkpoints, finishes := fix.batcher.getCounts() + checkpoints, finishes := fix.integrator.getCounts() require.Equal(t, 1, exports) require.Equal(t, 1, checkpoints) require.Equal(t, 1, finishes) diff --git a/sdk/metric/correct_test.go b/sdk/metric/correct_test.go index bcc0f53a5..02174b877 100644 --- a/sdk/metric/correct_test.go +++ b/sdk/metric/correct_test.go @@ -24,8 +24,7 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/label" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -33,12 +32,12 @@ import ( metricsdk "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/aggregator/array" "go.opentelemetry.io/otel/sdk/metric/aggregator/sum" - batchTest "go.opentelemetry.io/otel/sdk/metric/batcher/test" + batchTest "go.opentelemetry.io/otel/sdk/metric/integrator/test" ) var Must = metric.Must -type correctnessBatcher struct { +type correctnessIntegrator struct { newAggCount int64 t *testing.T @@ -46,7 +45,7 @@ type correctnessBatcher struct { records []export.Record } -func (cb *correctnessBatcher) AggregatorFor(descriptor *metric.Descriptor) (agg export.Aggregator) { +func (cb *correctnessIntegrator) AggregatorFor(descriptor *metric.Descriptor) (agg export.Aggregator) { name := descriptor.Name() switch { @@ -63,25 +62,25 @@ func (cb *correctnessBatcher) AggregatorFor(descriptor *metric.Descriptor) (agg return } -func (cb *correctnessBatcher) CheckpointSet() export.CheckpointSet { +func (cb *correctnessIntegrator) CheckpointSet() export.CheckpointSet { cb.t.Fatal("Should not be called") return nil } -func (*correctnessBatcher) FinishedCollection() { +func (*correctnessIntegrator) FinishedCollection() { } -func (cb *correctnessBatcher) Process(_ context.Context, record export.Record) error { +func (cb *correctnessIntegrator) Process(_ context.Context, record export.Record) error { cb.records = append(cb.records, record) return nil } func TestInputRangeTestCounter(t *testing.T) { ctx := context.Background() - batcher := &correctnessBatcher{ + integrator := &correctnessIntegrator{ t: t, } - sdk := metricsdk.New(batcher) + sdk := metricsdk.NewAccumulator(integrator) meter := metric.WrapMeterImpl(sdk, "test") var sdkErr error @@ -98,10 +97,10 @@ func TestInputRangeTestCounter(t *testing.T) { checkpointed := sdk.Collect(ctx) require.Equal(t, 0, checkpointed) - batcher.records = nil + integrator.records = nil counter.Add(ctx, 1) checkpointed = sdk.Collect(ctx) - sum, err := batcher.records[0].Aggregator().(aggregator.Sum).Sum() + sum, err := integrator.records[0].Aggregator().(aggregator.Sum).Sum() require.Equal(t, int64(1), sum.AsInt64()) require.Equal(t, 1, checkpointed) require.Nil(t, err) @@ -110,10 +109,10 @@ func TestInputRangeTestCounter(t *testing.T) { func TestInputRangeTestMeasure(t *testing.T) { ctx := context.Background() - batcher := &correctnessBatcher{ + integrator := &correctnessIntegrator{ t: t, } - sdk := metricsdk.New(batcher) + sdk := metricsdk.NewAccumulator(integrator) meter := metric.WrapMeterImpl(sdk, "test") var sdkErr error @@ -133,10 +132,10 @@ func TestInputRangeTestMeasure(t *testing.T) { measure.Record(ctx, 1) measure.Record(ctx, 2) - batcher.records = nil + integrator.records = nil checkpointed = sdk.Collect(ctx) - count, err := batcher.records[0].Aggregator().(aggregator.Distribution).Count() + count, err := integrator.records[0].Aggregator().(aggregator.Distribution).Count() require.Equal(t, int64(2), count) require.Equal(t, 1, checkpointed) require.Nil(t, sdkErr) @@ -145,10 +144,10 @@ func TestInputRangeTestMeasure(t *testing.T) { func TestDisabledInstrument(t *testing.T) { ctx := context.Background() - batcher := &correctnessBatcher{ + integrator := &correctnessIntegrator{ t: t, } - sdk := metricsdk.New(batcher) + sdk := metricsdk.NewAccumulator(integrator) meter := metric.WrapMeterImpl(sdk, "test") measure := Must(meter).NewFloat64Measure("name.disabled") @@ -157,16 +156,16 @@ func TestDisabledInstrument(t *testing.T) { checkpointed := sdk.Collect(ctx) require.Equal(t, 0, checkpointed) - require.Equal(t, 0, len(batcher.records)) + require.Equal(t, 0, len(integrator.records)) } func TestRecordNaN(t *testing.T) { ctx := context.Background() - batcher := &correctnessBatcher{ + integrator := &correctnessIntegrator{ t: t, } - sdk := metricsdk.New(batcher) + sdk := metricsdk.NewAccumulator(integrator) meter := metric.WrapMeterImpl(sdk, "test") var sdkErr error @@ -182,10 +181,10 @@ func TestRecordNaN(t *testing.T) { func TestSDKLabelsDeduplication(t *testing.T) { ctx := context.Background() - batcher := &correctnessBatcher{ + integrator := &correctnessIntegrator{ t: t, } - sdk := metricsdk.New(batcher) + sdk := metricsdk.NewAccumulator(integrator) meter := metric.WrapMeterImpl(sdk, "test") counter := Must(meter).NewInt64Counter("counter") @@ -195,19 +194,19 @@ func TestSDKLabelsDeduplication(t *testing.T) { keySets = 2 repeats = 3 ) - var keysA []core.Key - var keysB []core.Key + var keysA []kv.Key + var keysB []kv.Key for i := 0; i < maxKeys; i++ { - keysA = append(keysA, core.Key(fmt.Sprintf("A%03d", i))) - keysB = append(keysB, core.Key(fmt.Sprintf("B%03d", i))) + keysA = append(keysA, kv.Key(fmt.Sprintf("A%03d", i))) + keysB = append(keysB, kv.Key(fmt.Sprintf("B%03d", i))) } - var allExpect [][]core.KeyValue + var allExpect [][]kv.KeyValue for numKeys := 0; numKeys < maxKeys; numKeys++ { - var kvsA []core.KeyValue - var kvsB []core.KeyValue + var kvsA []kv.KeyValue + var kvsB []kv.KeyValue for r := 0; r < repeats; r++ { for i := 0; i < numKeys; i++ { kvsA = append(kvsA, keysA[i].Int(r)) @@ -215,8 +214,8 @@ func TestSDKLabelsDeduplication(t *testing.T) { } } - var expectA []core.KeyValue - var expectB []core.KeyValue + var expectA []kv.KeyValue + var expectB []kv.KeyValue for i := 0; i < numKeys; i++ { expectA = append(expectA, keysA[i].Int(repeats-1)) expectB = append(expectB, keysB[i].Int(repeats-1)) @@ -237,10 +236,10 @@ func TestSDKLabelsDeduplication(t *testing.T) { sdk.Collect(ctx) - var actual [][]core.KeyValue - for _, rec := range batcher.records { + var actual [][]kv.KeyValue + for _, rec := range integrator.records { sum, _ := rec.Aggregator().(aggregator.Sum).Sum() - require.Equal(t, sum, core.NewInt64Number(2)) + require.Equal(t, sum, metric.NewInt64Number(2)) kvs := rec.Labels().ToSlice() actual = append(actual, kvs) @@ -249,7 +248,7 @@ func TestSDKLabelsDeduplication(t *testing.T) { require.ElementsMatch(t, allExpect, actual) } -func newSetIter(kvs ...core.KeyValue) label.Iterator { +func newSetIter(kvs ...kv.KeyValue) label.Iterator { labels := label.NewSet(kvs...) return labels.Iter() } @@ -257,52 +256,52 @@ func newSetIter(kvs ...core.KeyValue) label.Iterator { func TestDefaultLabelEncoder(t *testing.T) { encoder := label.DefaultEncoder() - encoded := encoder.Encode(newSetIter(key.String("A", "B"), key.String("C", "D"))) + encoded := encoder.Encode(newSetIter(kv.String("A", "B"), kv.String("C", "D"))) require.Equal(t, `A=B,C=D`, encoded) - encoded = encoder.Encode(newSetIter(key.String("A", "B,c=d"), key.String(`C\`, "D"))) + encoded = encoder.Encode(newSetIter(kv.String("A", "B,c=d"), kv.String(`C\`, "D"))) require.Equal(t, `A=B\,c\=d,C\\=D`, encoded) - encoded = encoder.Encode(newSetIter(key.String(`\`, `=`), key.String(`,`, `\`))) + encoded = encoder.Encode(newSetIter(kv.String(`\`, `=`), kv.String(`,`, `\`))) require.Equal(t, `\,=\\,\\=\=`, encoded) // Note: the label encoder does not sort or de-dup values, // that is done in Labels(...). encoded = encoder.Encode(newSetIter( - key.Int("I", 1), - key.Uint("U", 1), - key.Int32("I32", 1), - key.Uint32("U32", 1), - key.Int64("I64", 1), - key.Uint64("U64", 1), - key.Float64("F64", 1), - key.Float64("F64", 1), - key.String("S", "1"), - key.Bool("B", true), + kv.Int("I", 1), + kv.Uint("U", 1), + kv.Int32("I32", 1), + kv.Uint32("U32", 1), + kv.Int64("I64", 1), + kv.Uint64("U64", 1), + kv.Float64("F64", 1), + kv.Float64("F64", 1), + kv.String("S", "1"), + kv.Bool("B", true), )) require.Equal(t, "B=true,F64=1,I=1,I32=1,I64=1,S=1,U=1,U32=1,U64=1", encoded) } func TestObserverCollection(t *testing.T) { ctx := context.Background() - batcher := &correctnessBatcher{ + integrator := &correctnessIntegrator{ t: t, } - sdk := metricsdk.New(batcher) + sdk := metricsdk.NewAccumulator(integrator) meter := metric.WrapMeterImpl(sdk, "test") _ = Must(meter).RegisterFloat64Observer("float.observer", func(result metric.Float64ObserverResult) { - result.Observe(1, key.String("A", "B")) + result.Observe(1, kv.String("A", "B")) // last value wins - result.Observe(-1, key.String("A", "B")) - result.Observe(-1, key.String("C", "D")) + result.Observe(-1, kv.String("A", "B")) + result.Observe(-1, kv.String("C", "D")) }) _ = Must(meter).RegisterInt64Observer("int.observer", func(result metric.Int64ObserverResult) { - result.Observe(-1, key.String("A", "B")) + result.Observe(-1, kv.String("A", "B")) result.Observe(1) // last value wins - result.Observe(1, key.String("A", "B")) + result.Observe(1, kv.String("A", "B")) result.Observe(1) }) _ = Must(meter).RegisterInt64Observer("empty.observer", func(result metric.Int64ObserverResult) { @@ -311,10 +310,64 @@ func TestObserverCollection(t *testing.T) { collected := sdk.Collect(ctx) require.Equal(t, 4, collected) - require.Equal(t, 4, len(batcher.records)) + require.Equal(t, 4, len(integrator.records)) out := batchTest.NewOutput(label.DefaultEncoder()) - for _, rec := range batcher.records { + for _, rec := range integrator.records { + _ = out.AddTo(rec) + } + require.EqualValues(t, map[string]float64{ + "float.observer/A=B": -1, + "float.observer/C=D": -1, + "int.observer/": 1, + "int.observer/A=B": 1, + }, out.Map) +} + +func TestObserverBatch(t *testing.T) { + ctx := context.Background() + integrator := &correctnessIntegrator{ + t: t, + } + + sdk := metricsdk.NewAccumulator(integrator) + meter := metric.WrapMeterImpl(sdk, "test") + + var floatObs metric.Float64Observer + var intObs metric.Int64Observer + var batch = Must(meter).NewBatchObserver( + func(result metric.BatchObserverResult) { + result.Observe( + []kv.KeyValue{ + kv.String("A", "B"), + }, + floatObs.Observation(1), + floatObs.Observation(-1), + intObs.Observation(-1), + intObs.Observation(1), + ) + result.Observe( + []kv.KeyValue{ + kv.String("C", "D"), + }, + floatObs.Observation(-1), + ) + result.Observe( + nil, + intObs.Observation(1), + intObs.Observation(1), + ) + }) + floatObs = batch.RegisterFloat64Observer("float.observer") + intObs = batch.RegisterInt64Observer("int.observer") + + collected := sdk.Collect(ctx) + + require.Equal(t, 4, collected) + require.Equal(t, 4, len(integrator.records)) + + out := batchTest.NewOutput(label.DefaultEncoder()) + for _, rec := range integrator.records { _ = out.AddTo(rec) } require.EqualValues(t, map[string]float64{ @@ -327,11 +380,11 @@ func TestObserverCollection(t *testing.T) { func TestRecordBatch(t *testing.T) { ctx := context.Background() - batcher := &correctnessBatcher{ + integrator := &correctnessIntegrator{ t: t, } - sdk := metricsdk.New(batcher) + sdk := metricsdk.NewAccumulator(integrator) meter := metric.WrapMeterImpl(sdk, "test") counter1 := Must(meter).NewInt64Counter("int64.counter") @@ -341,9 +394,9 @@ func TestRecordBatch(t *testing.T) { sdk.RecordBatch( ctx, - []core.KeyValue{ - key.String("A", "B"), - key.String("C", "D"), + []kv.KeyValue{ + kv.String("A", "B"), + kv.String("C", "D"), }, counter1.Measurement(1), counter2.Measurement(2), @@ -354,7 +407,7 @@ func TestRecordBatch(t *testing.T) { sdk.Collect(ctx) out := batchTest.NewOutput(label.DefaultEncoder()) - for _, rec := range batcher.records { + for _, rec := range integrator.records { _ = out.AddTo(rec) } require.EqualValues(t, map[string]float64{ @@ -370,16 +423,16 @@ func TestRecordBatch(t *testing.T) { // that its encoded labels will be cached across collection intervals. func TestRecordPersistence(t *testing.T) { ctx := context.Background() - batcher := &correctnessBatcher{ + integrator := &correctnessIntegrator{ t: t, } - sdk := metricsdk.New(batcher) + sdk := metricsdk.NewAccumulator(integrator) meter := metric.WrapMeterImpl(sdk, "test") c := Must(meter).NewFloat64Counter("sum.name") - b := c.Bind(key.String("bound", "true")) - uk := key.String("bound", "false") + b := c.Bind(kv.String("bound", "true")) + uk := kv.String("bound", "false") for i := 0; i < 100; i++ { c.Add(ctx, 1, uk) @@ -387,5 +440,5 @@ func TestRecordPersistence(t *testing.T) { sdk.Collect(ctx) } - require.Equal(t, int64(2), batcher.newAggCount) + require.Equal(t, int64(2), integrator.newAggCount) } diff --git a/sdk/metric/doc.go b/sdk/metric/doc.go index 40bdeae37..cee67d00b 100644 --- a/sdk/metric/doc.go +++ b/sdk/metric/doc.go @@ -28,7 +28,7 @@ boilerplate. The API and SDK are separated such that an event reaching the SDK has a uniform structure: an instrument, a label set, and a numerical value. -To this end, the API uses a core.Number type to represent either an int64 +To this end, the API uses a kv.Number type to represent either an int64 or a float64, depending on the instrument's definition. A single implementation interface is used for counter and measure instruments, metric.InstrumentImpl, and a single implementation interface is used for @@ -124,22 +124,22 @@ Aggregators implement a Merge method, also called in collection context, that combines state from two aggregators into one. Each SDK record has an associated aggregator. -Batcher is an interface which sits between the SDK and an exporter. -The Batcher embeds an AggregationSelector, used by the SDK to assign -new Aggregators. The Batcher supports a Process() API for submitting -checkpointed aggregators to the batcher, and a CheckpointSet() API +Integrator is an interface which sits between the SDK and an exporter. +The Integrator embeds an AggregationSelector, used by the SDK to assign +new Aggregators. The Integrator supports a Process() API for submitting +checkpointed aggregators to the integrator, and a CheckpointSet() API for producing a complete checkpoint for the exporter. Two default -Batcher implementations are provided, the "defaultkeys" Batcher groups +Integrator implementations are provided, the "defaultkeys" Integrator groups aggregate metrics by their recommended Descriptor.Keys(), the -"ungrouped" Batcher aggregates metrics at full dimensionality. +"simple" Integrator aggregates metrics at full dimensionality. LabelEncoder is an optional optimization that allows an exporter to provide the serialization logic for labels. This allows avoiding duplicate serialization of labels, once as a unique key in the SDK (or -Batcher) and once in the exporter. +Integrator) and once in the exporter. -CheckpointSet is an interface between the Batcher and the Exporter. -After completing a collection pass, the Batcher.CheckpointSet() method +CheckpointSet is an interface between the Integrator and the Exporter. +After completing a collection pass, the Integrator.CheckpointSet() method returns a CheckpointSet, which the Exporter uses to iterate over all the updated metrics. diff --git a/sdk/metric/example_test.go b/sdk/metric/example_test.go index 7c84ca7f2..4f39441b5 100644 --- a/sdk/metric/example_test.go +++ b/sdk/metric/example_test.go @@ -19,7 +19,8 @@ import ( "fmt" "time" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" + "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/exporters/metric/stdout" ) @@ -36,7 +37,7 @@ func ExampleNew() { ctx := context.Background() - key := key.New("key") + key := kv.Key("key") meter := pusher.Meter("example") counter := metric.Must(meter).NewInt64Counter("a.counter") diff --git a/sdk/metric/histogram_stress_test.go b/sdk/metric/histogram_stress_test.go index f2473abf2..4a40823ef 100644 --- a/sdk/metric/histogram_stress_test.go +++ b/sdk/metric/histogram_stress_test.go @@ -20,14 +20,13 @@ import ( "testing" "time" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/sdk/metric/aggregator/histogram" ) func TestStressInt64Histogram(t *testing.T) { - desc := metric.NewDescriptor("some_metric", metric.MeasureKind, core.Int64NumberKind) - h := histogram.New(&desc, []core.Number{core.NewInt64Number(25), core.NewInt64Number(50), core.NewInt64Number(75)}) + desc := metric.NewDescriptor("some_metric", metric.MeasureKind, metric.Int64NumberKind) + h := histogram.New(&desc, []metric.Number{metric.NewInt64Number(25), metric.NewInt64Number(50), metric.NewInt64Number(75)}) ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() @@ -38,7 +37,7 @@ func TestStressInt64Histogram(t *testing.T) { case <-ctx.Done(): return default: - _ = h.Update(ctx, core.NewInt64Number(rnd.Int63()%100), &desc) + _ = h.Update(ctx, metric.NewInt64Number(rnd.Int63()%100), &desc) } } }() diff --git a/sdk/metric/batcher/ungrouped/ungrouped.go b/sdk/metric/integrator/simple/simple.go similarity index 80% rename from sdk/metric/batcher/ungrouped/ungrouped.go rename to sdk/metric/integrator/simple/simple.go index 5f6e836dd..9a379c9fc 100644 --- a/sdk/metric/batcher/ungrouped/ungrouped.go +++ b/sdk/metric/integrator/simple/simple.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ungrouped // import "go.opentelemetry.io/otel/sdk/metric/batcher/ungrouped" +package simple // import "go.opentelemetry.io/otel/sdk/metric/integrator/simple" import ( "context" @@ -25,7 +25,7 @@ import ( ) type ( - Batcher struct { + Integrator struct { selector export.AggregationSelector batchMap batchMap stateful bool @@ -44,22 +44,22 @@ type ( batchMap map[batchKey]batchValue ) -var _ export.Batcher = &Batcher{} +var _ export.Integrator = &Integrator{} var _ export.CheckpointSet = batchMap{} -func New(selector export.AggregationSelector, stateful bool) *Batcher { - return &Batcher{ +func New(selector export.AggregationSelector, stateful bool) *Integrator { + return &Integrator{ selector: selector, batchMap: batchMap{}, stateful: stateful, } } -func (b *Batcher) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { +func (b *Integrator) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { return b.selector.AggregatorFor(descriptor) } -func (b *Batcher) Process(_ context.Context, record export.Record) error { +func (b *Integrator) Process(_ context.Context, record export.Record) error { desc := record.Descriptor() key := batchKey{ descriptor: desc, @@ -70,12 +70,12 @@ func (b *Batcher) Process(_ context.Context, record export.Record) error { if ok { // Note: The call to Merge here combines only // identical records. It is required even for a - // stateless Batcher because such identical records + // stateless Integrator because such identical records // may arise in the Meter implementation due to race // conditions. return value.aggregator.Merge(agg, desc) } - // If this Batcher is stateful, create a copy of the + // If this integrator is stateful, create a copy of the // Aggregator for long-term storage. Otherwise the // Meter implementation will checkpoint the aggregator // again, overwriting the long-lived state. @@ -95,11 +95,11 @@ func (b *Batcher) Process(_ context.Context, record export.Record) error { return nil } -func (b *Batcher) CheckpointSet() export.CheckpointSet { +func (b *Integrator) CheckpointSet() export.CheckpointSet { return b.batchMap } -func (b *Batcher) FinishedCollection() { +func (b *Integrator) FinishedCollection() { if !b.stateful { b.batchMap = batchMap{} } diff --git a/sdk/metric/batcher/ungrouped/ungrouped_test.go b/sdk/metric/integrator/simple/simple_test.go similarity index 91% rename from sdk/metric/batcher/ungrouped/ungrouped_test.go rename to sdk/metric/integrator/simple/simple_test.go index 49756c0e3..75a9b7a42 100644 --- a/sdk/metric/batcher/ungrouped/ungrouped_test.go +++ b/sdk/metric/integrator/simple/simple_test.go @@ -12,25 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ungrouped_test +package simple_test import ( "context" "testing" + "go.opentelemetry.io/otel/api/metric" + "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" export "go.opentelemetry.io/otel/sdk/export/metric" - "go.opentelemetry.io/otel/sdk/metric/batcher/test" - "go.opentelemetry.io/otel/sdk/metric/batcher/ungrouped" + "go.opentelemetry.io/otel/sdk/metric/integrator/simple" + "go.opentelemetry.io/otel/sdk/metric/integrator/test" ) // These tests use the ../test label encoding. func TestUngroupedStateless(t *testing.T) { ctx := context.Background() - b := ungrouped.New(test.NewAggregationSelector(), false) + b := simple.New(test.NewAggregationSelector(), false) // Set initial lastValue values _ = b.Process(ctx, test.NewLastValueRecord(&test.LastValueADesc, test.Labels1, 10)) @@ -92,7 +93,7 @@ func TestUngroupedStateless(t *testing.T) { func TestUngroupedStateful(t *testing.T) { ctx := context.Background() - b := ungrouped.New(test.NewAggregationSelector(), true) + b := simple.New(test.NewAggregationSelector(), true) counterA := test.NewCounterRecord(&test.CounterADesc, test.Labels1, 10) caggA := counterA.Aggregator() @@ -123,12 +124,12 @@ func TestUngroupedStateful(t *testing.T) { require.EqualValues(t, records1.Map, records2.Map) // Update and re-checkpoint the original record. - _ = caggA.Update(ctx, core.NewInt64Number(20), &test.CounterADesc) - _ = caggB.Update(ctx, core.NewInt64Number(20), &test.CounterBDesc) + _ = caggA.Update(ctx, metric.NewInt64Number(20), &test.CounterADesc) + _ = caggB.Update(ctx, metric.NewInt64Number(20), &test.CounterBDesc) caggA.Checkpoint(ctx, &test.CounterADesc) caggB.Checkpoint(ctx, &test.CounterBDesc) - // As yet cagg has not been passed to Batcher.Process. Should + // As yet cagg has not been passed to Integrator.Process. Should // not see an update. checkpointSet = b.CheckpointSet() b.FinishedCollection() diff --git a/sdk/metric/batcher/test/test.go b/sdk/metric/integrator/test/test.go similarity index 87% rename from sdk/metric/batcher/test/test.go rename to sdk/metric/integrator/test/test.go index d64d50126..383c77645 100644 --- a/sdk/metric/batcher/test/test.go +++ b/sdk/metric/integrator/test/test.go @@ -19,8 +19,7 @@ import ( "fmt" "strings" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/label" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -41,21 +40,21 @@ type ( // testAggregationSelector returns aggregators consistent with // the test variables below, needed for testing stateful - // batchers, which clone Aggregators using AggregatorFor(desc). + // integrators, which clone Aggregators using AggregatorFor(desc). testAggregationSelector struct{} ) var ( // LastValueADesc and LastValueBDesc group by "G" LastValueADesc = metric.NewDescriptor( - "lastvalue.a", metric.ObserverKind, core.Int64NumberKind) + "lastvalue.a", metric.ObserverKind, metric.Int64NumberKind) LastValueBDesc = metric.NewDescriptor( - "lastvalue.b", metric.ObserverKind, core.Int64NumberKind) + "lastvalue.b", metric.ObserverKind, metric.Int64NumberKind) // CounterADesc and CounterBDesc group by "C" CounterADesc = metric.NewDescriptor( - "sum.a", metric.CounterKind, core.Int64NumberKind) + "sum.a", metric.CounterKind, metric.Int64NumberKind) CounterBDesc = metric.NewDescriptor( - "sum.b", metric.CounterKind, core.Int64NumberKind) + "sum.b", metric.CounterKind, metric.Int64NumberKind) // SdkEncoder uses a non-standard encoder like K1~V1&K2~V2 SdkEncoder = &Encoder{} @@ -66,9 +65,9 @@ var ( // Counter groups are (labels1+labels2), (labels3) // Labels1 has G=H and C=D - Labels1 = makeLabels(key.String("G", "H"), key.String("C", "D")) + Labels1 = makeLabels(kv.String("G", "H"), kv.String("C", "D")) // Labels2 has C=D and E=F - Labels2 = makeLabels(key.String("C", "D"), key.String("E", "F")) + Labels2 = makeLabels(kv.String("C", "D"), kv.String("E", "F")) // Labels3 is the empty set Labels3 = makeLabels() @@ -84,7 +83,7 @@ func NewOutput(labelEncoder label.Encoder) Output { // NewAggregationSelector returns a policy that is consistent with the // test descriptors above. I.e., it returns sum.New() for counter -// instruments and lastvalue.New for lastValue instruments. +// instruments and lastvalue.New() for lastValue instruments. func NewAggregationSelector() export.AggregationSelector { return &testAggregationSelector{} } @@ -100,7 +99,7 @@ func (*testAggregationSelector) AggregatorFor(desc *metric.Descriptor) export.Ag } } -func makeLabels(labels ...core.KeyValue) *label.Set { +func makeLabels(labels ...kv.KeyValue) *label.Set { s := label.NewSet(labels...) return &s } @@ -127,7 +126,7 @@ func (Encoder) ID() label.EncoderID { func LastValueAgg(desc *metric.Descriptor, v int64) export.Aggregator { ctx := context.Background() gagg := lastvalue.New() - _ = gagg.Update(ctx, core.NewInt64Number(v), desc) + _ = gagg.Update(ctx, metric.NewInt64Number(v), desc) gagg.Checkpoint(ctx, desc) return gagg } @@ -146,7 +145,7 @@ func NewCounterRecord(desc *metric.Descriptor, labels *label.Set, value int64) e func CounterAgg(desc *metric.Descriptor, v int64) export.Aggregator { ctx := context.Background() cagg := sum.New() - _ = cagg.Update(ctx, core.NewInt64Number(v), desc) + _ = cagg.Update(ctx, metric.NewInt64Number(v), desc) cagg.Checkpoint(ctx, desc) return cagg } diff --git a/sdk/metric/minmaxsumcount_stress_test.go b/sdk/metric/minmaxsumcount_stress_test.go index 10611f24f..ecec40564 100644 --- a/sdk/metric/minmaxsumcount_stress_test.go +++ b/sdk/metric/minmaxsumcount_stress_test.go @@ -20,13 +20,12 @@ import ( "testing" "time" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/sdk/metric/aggregator/minmaxsumcount" ) func TestStressInt64MinMaxSumCount(t *testing.T) { - desc := metric.NewDescriptor("some_metric", metric.MeasureKind, core.Int64NumberKind) + desc := metric.NewDescriptor("some_metric", metric.MeasureKind, metric.Int64NumberKind) mmsc := minmaxsumcount.New(&desc) ctx, cancel := context.WithCancel(context.Background()) @@ -39,7 +38,7 @@ func TestStressInt64MinMaxSumCount(t *testing.T) { case <-ctx.Done(): return default: - _ = mmsc.Update(ctx, core.NewInt64Number(v), &desc) + _ = mmsc.Update(ctx, metric.NewInt64Number(v), &desc) } v++ } diff --git a/sdk/metric/sdk.go b/sdk/metric/sdk.go index 536a6ca87..9be8b17ca 100644 --- a/sdk/metric/sdk.go +++ b/sdk/metric/sdk.go @@ -22,37 +22,41 @@ import ( "sync" "sync/atomic" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/label" "go.opentelemetry.io/otel/api/metric" api "go.opentelemetry.io/otel/api/metric" + internal "go.opentelemetry.io/otel/internal/metric" export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregator" ) type ( - // SDK implements the OpenTelemetry Meter API. The SDK is - // bound to a single export.Batcher in `New()`. + // Accumulator implements the OpenTelemetry Meter API. The + // Accumulator is bound to a single export.Integrator in + // `NewAccumulator()`. // - // The SDK supports a Collect() API to gather and export + // The Accumulator supports a Collect() API to gather and export // current data. Collect() should be arranged according to - // the batcher model. Push-based batchers will setup a - // timer to call Collect() periodically. Pull-based batchers + // the integrator model. Push-based integrators will setup a + // timer to call Collect() periodically. Pull-based integrators // will call Collect() when a pull request arrives. - SDK struct { + Accumulator struct { // current maps `mapkey` to *record. current sync.Map // asyncInstruments is a set of // `*asyncInstrument` instances - asyncInstruments sync.Map + asyncLock sync.Mutex + asyncInstruments *internal.AsyncInstrumentState + asyncContext context.Context // currentEpoch is the current epoch number. It is // incremented in `Collect()`. currentEpoch int64 - // batcher is the configured batcher+configuration. - batcher export.Batcher + // integrator is the configured integrator+configuration. + integrator export.Integrator // collectLock prevents simultaneous calls to Collect(). collectLock sync.Mutex @@ -80,10 +84,10 @@ type ( // record maintains the state of one metric instrument. Due // the use of lock-free algorithms, there may be more than one // `record` in existence at a time, although at most one can - // be referenced from the `SDK.current` map. + // be referenced from the `Accumulator.current` map. record struct { // refMapped keeps track of refcounts and the mapping state to the - // SDK.current map. + // Accumulator.current map. refMapped refcountMapped // updateCount is incremented on every Update. @@ -119,7 +123,7 @@ type ( } instrument struct { - meter *SDK + meter *Accumulator descriptor metric.Descriptor } @@ -128,8 +132,6 @@ type ( // recorders maps ordered labels to the pair of // labelset and recorder recorders map[label.Distinct]*labeledRecorder - - callback func(func(core.Number, []core.KeyValue)) } labeledRecorder struct { @@ -142,7 +144,7 @@ type ( ) var ( - _ api.MeterImpl = &SDK{} + _ api.MeterImpl = &Accumulator{} _ api.AsyncImpl = &asyncInstrument{} _ api.SyncImpl = &syncInstrument{} _ api.BoundSyncImpl = &record{} @@ -160,7 +162,7 @@ func (s *syncInstrument) Implementation() interface{} { return s } -func (a *asyncInstrument) observe(number core.Number, labels []core.KeyValue) { +func (a *asyncInstrument) observe(number api.Number, labels *label.Set) { if err := aggregator.RangeTest(number, &a.descriptor); err != nil { a.meter.errorHandler(err) return @@ -177,25 +179,20 @@ func (a *asyncInstrument) observe(number core.Number, labels []core.KeyValue) { } } -func (a *asyncInstrument) getRecorder(kvs []core.KeyValue) export.Aggregator { - // We are in a single-threaded context. Note: this assumption - // could be violated if the user added concurrency within - // their callback. - labels := label.NewSetWithSortable(kvs, &a.meter.asyncSortSlice) - +func (a *asyncInstrument) getRecorder(labels *label.Set) export.Aggregator { lrec, ok := a.recorders[labels.Equivalent()] if ok { if lrec.observedEpoch == a.meter.currentEpoch { // last value wins for Observers, so if we see the same labels // in the current epoch, we replace the old recorder - lrec.recorder = a.meter.batcher.AggregatorFor(&a.descriptor) + lrec.recorder = a.meter.integrator.AggregatorFor(&a.descriptor) } else { lrec.observedEpoch = a.meter.currentEpoch } a.recorders[labels.Equivalent()] = lrec return lrec.recorder } - rec := a.meter.batcher.AggregatorFor(&a.descriptor) + rec := a.meter.integrator.AggregatorFor(&a.descriptor) if a.recorders == nil { a.recorders = make(map[label.Distinct]*labeledRecorder) } @@ -204,13 +201,13 @@ func (a *asyncInstrument) getRecorder(kvs []core.KeyValue) export.Aggregator { // but will be revisited later. a.recorders[labels.Equivalent()] = &labeledRecorder{ recorder: rec, - labels: &labels, + labels: labels, observedEpoch: a.meter.currentEpoch, } return rec } -func (m *SDK) SetErrorHandler(f ErrorHandler) { +func (m *Accumulator) SetErrorHandler(f ErrorHandler) { m.errorHandler = f } @@ -219,7 +216,7 @@ func (m *SDK) SetErrorHandler(f ErrorHandler) { // support re-use of the orderedLabels computed by a previous // measurement in the same batch. This performs two allocations // in the common case. -func (s *syncInstrument) acquireHandle(kvs []core.KeyValue, labelPtr *label.Set) *record { +func (s *syncInstrument) acquireHandle(kvs []kv.KeyValue, labelPtr *label.Set) *record { var rec *record var equiv label.Distinct @@ -259,7 +256,7 @@ func (s *syncInstrument) acquireHandle(kvs []core.KeyValue, labelPtr *label.Set) } rec.refMapped = refcountMapped{value: 2} rec.inst = s - rec.recorder = s.meter.batcher.AggregatorFor(&s.descriptor) + rec.recorder = s.meter.integrator.AggregatorFor(&s.descriptor) for { // Load/Store: there's a memory allocation to place `mk` into @@ -291,42 +288,46 @@ func (s *syncInstrument) acquireHandle(kvs []core.KeyValue, labelPtr *label.Set) } } -func (s *syncInstrument) Bind(kvs []core.KeyValue) api.BoundSyncImpl { +func (s *syncInstrument) Bind(kvs []kv.KeyValue) api.BoundSyncImpl { return s.acquireHandle(kvs, nil) } -func (s *syncInstrument) RecordOne(ctx context.Context, number core.Number, kvs []core.KeyValue) { +func (s *syncInstrument) RecordOne(ctx context.Context, number api.Number, kvs []kv.KeyValue) { h := s.acquireHandle(kvs, nil) defer h.Unbind() h.RecordOne(ctx, number) } -// New constructs a new SDK for the given batcher. This SDK supports -// only a single batcher. +// NewAccumulator constructs a new Accumulator for the given +// integrator. This Accumulator supports only a single integrator. // -// The SDK does not start any background process to collect itself -// periodically, this responsbility lies with the batcher, typically, +// The Accumulator does not start any background process to collect itself +// periodically, this responsbility lies with the integrator, typically, // depending on the type of export. For example, a pull-based -// batcher will call Collect() when it receives a request to scrape -// current metric values. A push-based batcher should configure its +// integrator will call Collect() when it receives a request to scrape +// current metric values. A push-based integrator should configure its // own periodic collection. -func New(batcher export.Batcher, opts ...Option) *SDK { +func NewAccumulator(integrator export.Integrator, opts ...Option) *Accumulator { c := &Config{ErrorHandler: DefaultErrorHandler} for _, opt := range opts { opt.Apply(c) } - return &SDK{ - batcher: batcher, - errorHandler: c.ErrorHandler, + return &Accumulator{ + integrator: integrator, + errorHandler: c.ErrorHandler, + asyncInstruments: internal.NewAsyncInstrumentState(c.ErrorHandler), } } +// DefaultErrorHandler is used when the user does not configure an +// error handler. Prints messages to os.Stderr. func DefaultErrorHandler(err error) { - fmt.Fprintln(os.Stderr, "Metrics SDK error:", err) + fmt.Fprintln(os.Stderr, "Metrics Accumulator error:", err) } -func (m *SDK) NewSyncInstrument(descriptor api.Descriptor) (api.SyncImpl, error) { +// NewSyncInstrument implements api.MetricImpl. +func (m *Accumulator) NewSyncInstrument(descriptor api.Descriptor) (api.SyncImpl, error) { return &syncInstrument{ instrument: instrument{ descriptor: descriptor, @@ -335,15 +336,17 @@ func (m *SDK) NewSyncInstrument(descriptor api.Descriptor) (api.SyncImpl, error) }, nil } -func (m *SDK) NewAsyncInstrument(descriptor api.Descriptor, callback func(func(core.Number, []core.KeyValue))) (api.AsyncImpl, error) { +// NewAsyncInstrument implements api.MetricImpl. +func (m *Accumulator) NewAsyncInstrument(descriptor api.Descriptor, runner metric.AsyncRunner) (api.AsyncImpl, error) { a := &asyncInstrument{ instrument: instrument{ descriptor: descriptor, meter: m, }, - callback: callback, } - m.asyncInstruments.Store(a, nil) + m.asyncLock.Lock() + defer m.asyncLock.Unlock() + m.asyncInstruments.Register(a, runner) return a, nil } @@ -351,21 +354,21 @@ func (m *SDK) NewAsyncInstrument(descriptor api.Descriptor, callback func(func(c // exports data for each active instrument. Collect() may not be // called concurrently. // -// During the collection pass, the export.Batcher will receive +// During the collection pass, the export.Integrator will receive // one Export() call per current aggregation. // // Returns the number of records that were checkpointed. -func (m *SDK) Collect(ctx context.Context) int { +func (m *Accumulator) Collect(ctx context.Context) int { m.collectLock.Lock() defer m.collectLock.Unlock() - checkpointed := m.collectRecords(ctx) - checkpointed += m.collectAsync(ctx) + checkpointed := m.collectSyncInstruments(ctx) + checkpointed += m.observeAsyncInstruments(ctx) m.currentEpoch++ return checkpointed } -func (m *SDK) collectRecords(ctx context.Context) int { +func (m *Accumulator) collectSyncInstruments(ctx context.Context) int { checkpointed := 0 m.current.Range(func(key interface{}, value interface{}) bool { @@ -408,24 +411,39 @@ func (m *SDK) collectRecords(ctx context.Context) int { return checkpointed } -func (m *SDK) collectAsync(ctx context.Context) int { - checkpointed := 0 +// CollectAsync implements internal.AsyncCollector. +func (m *Accumulator) CollectAsync(kv []kv.KeyValue, obs ...metric.Observation) { + labels := label.NewSetWithSortable(kv, &m.asyncSortSlice) - m.asyncInstruments.Range(func(key, value interface{}) bool { - a := key.(*asyncInstrument) - a.callback(a.observe) - checkpointed += m.checkpointAsync(ctx, a) - return true - }) - - return checkpointed + for _, ob := range obs { + a := ob.AsyncImpl().Implementation().(*asyncInstrument) + a.observe(ob.Number(), &labels) + } } -func (m *SDK) checkpointRecord(ctx context.Context, r *record) int { +func (m *Accumulator) observeAsyncInstruments(ctx context.Context) int { + m.asyncLock.Lock() + defer m.asyncLock.Unlock() + + asyncCollected := 0 + m.asyncContext = ctx + + m.asyncInstruments.Run(m) + m.asyncContext = nil + + for _, inst := range m.asyncInstruments.Instruments() { + a := inst.Implementation().(*asyncInstrument) + asyncCollected += m.checkpointAsync(a) + } + + return asyncCollected +} + +func (m *Accumulator) checkpointRecord(ctx context.Context, r *record) int { return m.checkpoint(ctx, &r.inst.descriptor, r.recorder, r.labels) } -func (m *SDK) checkpointAsync(ctx context.Context, a *asyncInstrument) int { +func (m *Accumulator) checkpointAsync(a *asyncInstrument) int { if len(a.recorders) == 0 { return 0 } @@ -434,7 +452,7 @@ func (m *SDK) checkpointAsync(ctx context.Context, a *asyncInstrument) int { lrec := lrec epochDiff := m.currentEpoch - lrec.observedEpoch if epochDiff == 0 { - checkpointed += m.checkpoint(ctx, &a.descriptor, lrec.recorder, lrec.labels) + checkpointed += m.checkpoint(m.asyncContext, &a.descriptor, lrec.recorder, lrec.labels) } else if epochDiff > 1 { // This is second collection cycle with no // observations for this labelset. Remove the @@ -448,14 +466,14 @@ func (m *SDK) checkpointAsync(ctx context.Context, a *asyncInstrument) int { return checkpointed } -func (m *SDK) checkpoint(ctx context.Context, descriptor *metric.Descriptor, recorder export.Aggregator, labels *label.Set) int { +func (m *Accumulator) checkpoint(ctx context.Context, descriptor *metric.Descriptor, recorder export.Aggregator, labels *label.Set) int { if recorder == nil { return 0 } recorder.Checkpoint(ctx, descriptor) exportRecord := export.NewRecord(descriptor, labels, recorder) - err := m.batcher.Process(ctx, exportRecord) + err := m.integrator.Process(ctx, exportRecord) if err != nil { m.errorHandler(err) } @@ -463,7 +481,7 @@ func (m *SDK) checkpoint(ctx context.Context, descriptor *metric.Descriptor, rec } // RecordBatch enters a batch of metric events. -func (m *SDK) RecordBatch(ctx context.Context, kvs []core.KeyValue, measurements ...api.Measurement) { +func (m *Accumulator) RecordBatch(ctx context.Context, kvs []kv.KeyValue, measurements ...api.Measurement) { // Labels will be computed the first time acquireHandle is // called. Subsequent calls to acquireHandle will re-use the // previously computed value instead of recomputing the @@ -484,7 +502,8 @@ func (m *SDK) RecordBatch(ctx context.Context, kvs []core.KeyValue, measurements } } -func (r *record) RecordOne(ctx context.Context, number core.Number) { +// RecordOne implements api.SyncImpl. +func (r *record) RecordOne(ctx context.Context, number api.Number) { if r.recorder == nil { // The instrument is disabled according to the AggregationSelector. return @@ -502,6 +521,7 @@ func (r *record) RecordOne(ctx context.Context, number core.Number) { atomic.AddInt64(&r.updateCount, 1) } +// Unbind implements api.SyncImpl. func (r *record) Unbind() { r.refMapped.unref() } diff --git a/sdk/metric/selector/simple/simple.go b/sdk/metric/selector/simple/simple.go index efd259267..e8929f093 100644 --- a/sdk/metric/selector/simple/simple.go +++ b/sdk/metric/selector/simple/simple.go @@ -15,7 +15,6 @@ package simple // import "go.opentelemetry.io/otel/sdk/metric/selector/simple" import ( - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/metric/aggregator/array" @@ -32,7 +31,7 @@ type ( config *ddsketch.Config } selectorHistogram struct { - boundaries []core.Number + boundaries []metric.Number } ) @@ -76,7 +75,7 @@ func NewWithExactMeasure() export.AggregationSelector { // histogram, and histogram aggregators for the three kinds of metric. This // selector uses more memory than the NewWithInexpensiveMeasure because it // uses a counter per bucket. -func NewWithHistogramMeasure(boundaries []core.Number) export.AggregationSelector { +func NewWithHistogramMeasure(boundaries []metric.Number) export.AggregationSelector { return selectorHistogram{boundaries: boundaries} } diff --git a/sdk/metric/selector/simple/simple_test.go b/sdk/metric/selector/simple/simple_test.go index 0815e5ecc..0f79df535 100644 --- a/sdk/metric/selector/simple/simple_test.go +++ b/sdk/metric/selector/simple/simple_test.go @@ -19,7 +19,6 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/metric" "go.opentelemetry.io/otel/sdk/metric/aggregator/array" "go.opentelemetry.io/otel/sdk/metric/aggregator/ddsketch" @@ -30,9 +29,9 @@ import ( ) var ( - testCounterDesc = metric.NewDescriptor("counter", metric.CounterKind, core.Int64NumberKind) - testMeasureDesc = metric.NewDescriptor("measure", metric.MeasureKind, core.Int64NumberKind) - testObserverDesc = metric.NewDescriptor("observer", metric.ObserverKind, core.Int64NumberKind) + testCounterDesc = metric.NewDescriptor("counter", metric.CounterKind, metric.Int64NumberKind) + testMeasureDesc = metric.NewDescriptor("measure", metric.MeasureKind, metric.Int64NumberKind) + testObserverDesc = metric.NewDescriptor("observer", metric.ObserverKind, metric.Int64NumberKind) ) func TestInexpensiveMeasure(t *testing.T) { @@ -57,7 +56,7 @@ func TestExactMeasure(t *testing.T) { } func TestHistogramMeasure(t *testing.T) { - ex := simple.NewWithHistogramMeasure([]core.Number{}) + ex := simple.NewWithHistogramMeasure([]metric.Number{}) require.NotPanics(t, func() { _ = ex.AggregatorFor(&testCounterDesc).(*sum.Aggregator) }) require.NotPanics(t, func() { _ = ex.AggregatorFor(&testMeasureDesc).(*histogram.Aggregator) }) require.NotPanics(t, func() { _ = ex.AggregatorFor(&testObserverDesc).(*histogram.Aggregator) }) diff --git a/sdk/metric/stress_test.go b/sdk/metric/stress_test.go index fd2d18fd6..7e15e1594 100644 --- a/sdk/metric/stress_test.go +++ b/sdk/metric/stress_test.go @@ -31,8 +31,7 @@ import ( "testing" "time" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/metric" api "go.opentelemetry.io/otel/api/metric" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -74,17 +73,17 @@ type ( testImpl struct { newInstrument func(meter api.Meter, name string) SyncImpler - getUpdateValue func() core.Number - operate func(interface{}, context.Context, core.Number, []core.KeyValue) + getUpdateValue func() api.Number + operate func(interface{}, context.Context, api.Number, []kv.KeyValue) newStore func() interface{} // storeCollect and storeExpect are the same for // counters, different for lastValues, to ensure we are // testing the timestamps correctly. - storeCollect func(store interface{}, value core.Number, ts time.Time) - storeExpect func(store interface{}, value core.Number) - readStore func(store interface{}) core.Number - equalValues func(a, b core.Number) bool + storeCollect func(store interface{}, value api.Number, ts time.Time) + storeExpect func(store interface{}, value api.Number) + readStore func(store interface{}) api.Number + equalValues func(a, b api.Number) bool } SyncImpler interface { @@ -96,7 +95,7 @@ type ( // take the later timestamp. lastValueState struct { // raw has to be aligned for 64-bit atomic operations. - raw core.Number + raw api.Number ts time.Time } ) @@ -105,7 +104,7 @@ func concurrency() int { return concurrencyPerCPU * runtime.NumCPU() } -func canonicalizeLabels(ls []core.KeyValue) string { +func canonicalizeLabels(ls []kv.KeyValue) string { copy := append(ls[0:0:0], ls...) sort.SliceStable(copy, func(i, j int) bool { return copy[i].Key < copy[j].Key @@ -128,9 +127,9 @@ func getPeriod() time.Duration { return time.Duration(dur) } -func (f *testFixture) someLabels() []core.KeyValue { +func (f *testFixture) someLabels() []kv.KeyValue { n := 1 + rand.Intn(3) - l := make([]core.KeyValue, n) + l := make([]kv.KeyValue, n) for { oused := map[string]bool{} @@ -143,7 +142,7 @@ func (f *testFixture) someLabels() []core.KeyValue { break } } - l[i] = key.New(k).String(fmt.Sprint("v", rand.Intn(1000000000))) + l[i] = kv.Key(k).String(fmt.Sprint("v", rand.Intn(1000000000))) } lc := canonicalizeLabels(l) f.lock.Lock() @@ -157,7 +156,7 @@ func (f *testFixture) someLabels() []core.KeyValue { } } -func (f *testFixture) startWorker(impl *SDK, meter api.Meter, wg *sync.WaitGroup, i int) { +func (f *testFixture) startWorker(impl *Accumulator, meter api.Meter, wg *sync.WaitGroup, i int) { ctx := context.Background() name := fmt.Sprint("test_", i) instrument := f.impl.newInstrument(meter, name) @@ -307,7 +306,7 @@ func stressTest(t *testing.T, impl testImpl) { lused: map[string]bool{}, } cc := concurrency() - sdk := New(fixture) + sdk := NewAccumulator(fixture) meter := metric.WrapMeterImpl(sdk, "stress_test") fixture.wg.Add(cc + 1) @@ -340,11 +339,11 @@ func stressTest(t *testing.T, impl testImpl) { fixture.assertTest(numCollect) } -func int64sEqual(a, b core.Number) bool { +func int64sEqual(a, b api.Number) bool { return a.AsInt64() == b.AsInt64() } -func float64sEqual(a, b core.Number) bool { +func float64sEqual(a, b api.Number) bool { diff := math.Abs(a.AsFloat64() - b.AsFloat64()) return diff < math.Abs(a.AsFloat64())*epsilon } @@ -356,30 +355,30 @@ func intCounterTestImpl() testImpl { newInstrument: func(meter api.Meter, name string) SyncImpler { return Must(meter).NewInt64Counter(name + ".counter") }, - getUpdateValue: func() core.Number { + getUpdateValue: func() api.Number { for { x := int64(rand.Intn(100)) if x != 0 { - return core.NewInt64Number(x) + return api.NewInt64Number(x) } } }, - operate: func(inst interface{}, ctx context.Context, value core.Number, labels []core.KeyValue) { + operate: func(inst interface{}, ctx context.Context, value api.Number, labels []kv.KeyValue) { counter := inst.(api.Int64Counter) counter.Add(ctx, value.AsInt64(), labels...) }, newStore: func() interface{} { - n := core.NewInt64Number(0) + n := api.NewInt64Number(0) return &n }, - storeCollect: func(store interface{}, value core.Number, _ time.Time) { - store.(*core.Number).AddInt64Atomic(value.AsInt64()) + storeCollect: func(store interface{}, value api.Number, _ time.Time) { + store.(*api.Number).AddInt64Atomic(value.AsInt64()) }, - storeExpect: func(store interface{}, value core.Number) { - store.(*core.Number).AddInt64Atomic(value.AsInt64()) + storeExpect: func(store interface{}, value api.Number) { + store.(*api.Number).AddInt64Atomic(value.AsInt64()) }, - readStore: func(store interface{}) core.Number { - return store.(*core.Number).AsNumberAtomic() + readStore: func(store interface{}) api.Number { + return store.(*api.Number).AsNumberAtomic() }, equalValues: int64sEqual, } @@ -394,30 +393,30 @@ func floatCounterTestImpl() testImpl { newInstrument: func(meter api.Meter, name string) SyncImpler { return Must(meter).NewFloat64Counter(name + ".counter") }, - getUpdateValue: func() core.Number { + getUpdateValue: func() api.Number { for { x := rand.Float64() if x != 0 { - return core.NewFloat64Number(x) + return api.NewFloat64Number(x) } } }, - operate: func(inst interface{}, ctx context.Context, value core.Number, labels []core.KeyValue) { + operate: func(inst interface{}, ctx context.Context, value api.Number, labels []kv.KeyValue) { counter := inst.(api.Float64Counter) counter.Add(ctx, value.AsFloat64(), labels...) }, newStore: func() interface{} { - n := core.NewFloat64Number(0.0) + n := api.NewFloat64Number(0.0) return &n }, - storeCollect: func(store interface{}, value core.Number, _ time.Time) { - store.(*core.Number).AddFloat64Atomic(value.AsFloat64()) + storeCollect: func(store interface{}, value api.Number, _ time.Time) { + store.(*api.Number).AddFloat64Atomic(value.AsFloat64()) }, - storeExpect: func(store interface{}, value core.Number) { - store.(*core.Number).AddFloat64Atomic(value.AsFloat64()) + storeExpect: func(store interface{}, value api.Number) { + store.(*api.Number).AddFloat64Atomic(value.AsFloat64()) }, - readStore: func(store interface{}) core.Number { - return store.(*core.Number).AsNumberAtomic() + readStore: func(store interface{}) api.Number { + return store.(*api.Number).AsNumberAtomic() }, equalValues: float64sEqual, } @@ -434,20 +433,20 @@ func intLastValueTestImpl() testImpl { newInstrument: func(meter api.Meter, name string) SyncImpler { return Must(meter).NewInt64Measure(name + ".lastvalue") }, - getUpdateValue: func() core.Number { + getUpdateValue: func() api.Number { r1 := rand.Int63() - return core.NewInt64Number(rand.Int63() - r1) + return api.NewInt64Number(rand.Int63() - r1) }, - operate: func(inst interface{}, ctx context.Context, value core.Number, labels []core.KeyValue) { + operate: func(inst interface{}, ctx context.Context, value api.Number, labels []kv.KeyValue) { measure := inst.(api.Int64Measure) measure.Record(ctx, value.AsInt64(), labels...) }, newStore: func() interface{} { return &lastValueState{ - raw: core.NewInt64Number(0), + raw: api.NewInt64Number(0), } }, - storeCollect: func(store interface{}, value core.Number, ts time.Time) { + storeCollect: func(store interface{}, value api.Number, ts time.Time) { gs := store.(*lastValueState) if !ts.Before(gs.ts) { @@ -455,11 +454,11 @@ func intLastValueTestImpl() testImpl { gs.raw.SetInt64Atomic(value.AsInt64()) } }, - storeExpect: func(store interface{}, value core.Number) { + storeExpect: func(store interface{}, value api.Number) { gs := store.(*lastValueState) gs.raw.SetInt64Atomic(value.AsInt64()) }, - readStore: func(store interface{}) core.Number { + readStore: func(store interface{}) api.Number { gs := store.(*lastValueState) return gs.raw.AsNumberAtomic() }, @@ -476,19 +475,19 @@ func floatLastValueTestImpl() testImpl { newInstrument: func(meter api.Meter, name string) SyncImpler { return Must(meter).NewFloat64Measure(name + ".lastvalue") }, - getUpdateValue: func() core.Number { - return core.NewFloat64Number((-0.5 + rand.Float64()) * 100000) + getUpdateValue: func() api.Number { + return api.NewFloat64Number((-0.5 + rand.Float64()) * 100000) }, - operate: func(inst interface{}, ctx context.Context, value core.Number, labels []core.KeyValue) { + operate: func(inst interface{}, ctx context.Context, value api.Number, labels []kv.KeyValue) { measure := inst.(api.Float64Measure) measure.Record(ctx, value.AsFloat64(), labels...) }, newStore: func() interface{} { return &lastValueState{ - raw: core.NewFloat64Number(0), + raw: api.NewFloat64Number(0), } }, - storeCollect: func(store interface{}, value core.Number, ts time.Time) { + storeCollect: func(store interface{}, value api.Number, ts time.Time) { gs := store.(*lastValueState) if !ts.Before(gs.ts) { @@ -496,11 +495,11 @@ func floatLastValueTestImpl() testImpl { gs.raw.SetFloat64Atomic(value.AsFloat64()) } }, - storeExpect: func(store interface{}, value core.Number) { + storeExpect: func(store interface{}, value api.Number) { gs := store.(*lastValueState) gs.raw.SetFloat64Atomic(value.AsFloat64()) }, - readStore: func(store interface{}) core.Number { + readStore: func(store interface{}) api.Number { gs := store.(*lastValueState) return gs.raw.AsNumberAtomic() }, diff --git a/sdk/opentelemetry.go b/sdk/opentelemetry.go index 2393ef770..33a9a9456 100644 --- a/sdk/opentelemetry.go +++ b/sdk/opentelemetry.go @@ -17,5 +17,5 @@ package opentelemetry // import "go.opentelemetry.io/otel/sdk" // Version is the current release version of OpenTelemetry in use. func Version() string { - return "0.4.3" + return "0.5.0" } diff --git a/sdk/resource/resource.go b/sdk/resource/resource.go index c6c71f265..8599f04bd 100644 --- a/sdk/resource/resource.go +++ b/sdk/resource/resource.go @@ -17,7 +17,7 @@ package resource import ( - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/label" ) @@ -34,10 +34,10 @@ type Resource struct { var emptyResource Resource -// New creates a resource from a set of attributes. If there are +// Key creates a resource from a set of attributes. If there are // duplicate keys present in the list of attributes, then the last // value found for the key is preserved. -func New(kvs ...core.KeyValue) *Resource { +func New(kvs ...kv.KeyValue) *Resource { return &Resource{ labels: label.NewSet(kvs...), } @@ -57,7 +57,7 @@ func (r *Resource) String() string { // Attributes returns a copy of attributes from the resource in a sorted order. // To avoid allocating a new slice, use an iterator. -func (r *Resource) Attributes() []core.KeyValue { +func (r *Resource) Attributes() []kv.KeyValue { if r == nil { r = Empty() } @@ -96,7 +96,7 @@ func Merge(a, b *Resource) *Resource { b = Empty() } // Note: 'b' is listed first so that 'a' will overwrite with - // last-value-wins in label.New() + // last-value-wins in label.Key() combine := append(b.Attributes(), a.Attributes()...) return New(combine...) } diff --git a/sdk/resource/resource_test.go b/sdk/resource/resource_test.go index ae45de443..e9b560f1a 100644 --- a/sdk/resource/resource_test.go +++ b/sdk/resource/resource_test.go @@ -19,40 +19,41 @@ import ( "fmt" "testing" + "go.opentelemetry.io/otel/api/kv/value" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/sdk/resource" ) var ( - kv11 = key.String("k1", "v11") - kv12 = key.String("k1", "v12") - kv21 = key.String("k2", "v21") - kv31 = key.String("k3", "v31") - kv41 = key.String("k4", "v41") + kv11 = kv.String("k1", "v11") + kv12 = kv.String("k1", "v12") + kv21 = kv.String("k2", "v21") + kv31 = kv.String("k3", "v31") + kv41 = kv.String("k4", "v41") ) func TestNew(t *testing.T) { cases := []struct { name string - in []core.KeyValue - want []core.KeyValue + in []kv.KeyValue + want []kv.KeyValue }{ { - name: "New with common key order1", - in: []core.KeyValue{kv12, kv11, kv21}, - want: []core.KeyValue{kv11, kv21}, + name: "Key with common key order1", + in: []kv.KeyValue{kv12, kv11, kv21}, + want: []kv.KeyValue{kv11, kv21}, }, { - name: "New with common key order2", - in: []core.KeyValue{kv11, kv12, kv21}, - want: []core.KeyValue{kv12, kv21}, + name: "Key with common key order2", + in: []kv.KeyValue{kv11, kv12, kv21}, + want: []kv.KeyValue{kv12, kv21}, }, { - name: "New with nil", + name: "Key with nil", in: nil, want: nil, }, @@ -63,7 +64,7 @@ func TestNew(t *testing.T) { if diff := cmp.Diff( res.Attributes(), c.want, - cmp.AllowUnexported(core.Value{})); diff != "" { + cmp.AllowUnexported(value.Value{})); diff != "" { t.Fatalf("unwanted result: diff %+v,", diff) } }) @@ -74,37 +75,37 @@ func TestMerge(t *testing.T) { cases := []struct { name string a, b *resource.Resource - want []core.KeyValue + want []kv.KeyValue }{ { name: "Merge with no overlap, no nil", a: resource.New(kv11, kv31), b: resource.New(kv21, kv41), - want: []core.KeyValue{kv11, kv21, kv31, kv41}, + want: []kv.KeyValue{kv11, kv21, kv31, kv41}, }, { name: "Merge with no overlap, no nil, not interleaved", a: resource.New(kv11, kv21), b: resource.New(kv31, kv41), - want: []core.KeyValue{kv11, kv21, kv31, kv41}, + want: []kv.KeyValue{kv11, kv21, kv31, kv41}, }, { name: "Merge with common key order1", a: resource.New(kv11), b: resource.New(kv12, kv21), - want: []core.KeyValue{kv11, kv21}, + want: []kv.KeyValue{kv11, kv21}, }, { name: "Merge with common key order2", a: resource.New(kv12, kv21), b: resource.New(kv11), - want: []core.KeyValue{kv12, kv21}, + want: []kv.KeyValue{kv12, kv21}, }, { name: "Merge with common key order4", a: resource.New(kv11, kv21, kv41), b: resource.New(kv31, kv41), - want: []core.KeyValue{kv11, kv21, kv31, kv41}, + want: []kv.KeyValue{kv11, kv21, kv31, kv41}, }, { name: "Merge with no keys", @@ -116,25 +117,25 @@ func TestMerge(t *testing.T) { name: "Merge with first resource no keys", a: resource.New(), b: resource.New(kv21), - want: []core.KeyValue{kv21}, + want: []kv.KeyValue{kv21}, }, { name: "Merge with second resource no keys", a: resource.New(kv11), b: resource.New(), - want: []core.KeyValue{kv11}, + want: []kv.KeyValue{kv11}, }, { name: "Merge with first resource nil", a: nil, b: resource.New(kv21), - want: []core.KeyValue{kv21}, + want: []kv.KeyValue{kv21}, }, { name: "Merge with second resource nil", a: resource.New(kv11), b: nil, - want: []core.KeyValue{kv11}, + want: []kv.KeyValue{kv11}, }, } for _, c := range cases { @@ -143,7 +144,7 @@ func TestMerge(t *testing.T) { if diff := cmp.Diff( res.Attributes(), c.want, - cmp.AllowUnexported(core.Value{})); diff != "" { + cmp.AllowUnexported(value.Value{})); diff != "" { t.Fatalf("unwanted result: diff %+v,", diff) } }) @@ -152,7 +153,7 @@ func TestMerge(t *testing.T) { func TestString(t *testing.T) { for _, test := range []struct { - kvs []core.KeyValue + kvs []kv.KeyValue want string }{ { @@ -160,51 +161,51 @@ func TestString(t *testing.T) { want: "", }, { - kvs: []core.KeyValue{}, + kvs: []kv.KeyValue{}, want: "", }, { - kvs: []core.KeyValue{kv11}, + kvs: []kv.KeyValue{kv11}, want: "k1=v11", }, { - kvs: []core.KeyValue{kv11, kv12}, + kvs: []kv.KeyValue{kv11, kv12}, want: "k1=v12", }, { - kvs: []core.KeyValue{kv11, kv21}, + kvs: []kv.KeyValue{kv11, kv21}, want: "k1=v11,k2=v21", }, { - kvs: []core.KeyValue{kv21, kv11}, + kvs: []kv.KeyValue{kv21, kv11}, want: "k1=v11,k2=v21", }, { - kvs: []core.KeyValue{kv11, kv21, kv31}, + kvs: []kv.KeyValue{kv11, kv21, kv31}, want: "k1=v11,k2=v21,k3=v31", }, { - kvs: []core.KeyValue{kv31, kv11, kv21}, + kvs: []kv.KeyValue{kv31, kv11, kv21}, want: "k1=v11,k2=v21,k3=v31", }, { - kvs: []core.KeyValue{key.String("A", "a"), key.String("B", "b")}, + kvs: []kv.KeyValue{kv.String("A", "a"), kv.String("B", "b")}, want: "A=a,B=b", }, { - kvs: []core.KeyValue{key.String("A", "a,B=b")}, + kvs: []kv.KeyValue{kv.String("A", "a,B=b")}, want: `A=a\,B\=b`, }, { - kvs: []core.KeyValue{key.String("A", `a,B\=b`)}, + kvs: []kv.KeyValue{kv.String("A", `a,B\=b`)}, want: `A=a\,B\\\=b`, }, { - kvs: []core.KeyValue{key.String("A=a,B", `b`)}, + kvs: []kv.KeyValue{kv.String("A=a,B", `b`)}, want: `A\=a\,B=b`, }, { - kvs: []core.KeyValue{key.String(`A=a\,B`, `b`)}, + kvs: []kv.KeyValue{kv.String(`A=a\,B`, `b`)}, want: `A\=a\\\,B=b`, }, } { @@ -215,7 +216,7 @@ func TestString(t *testing.T) { } func TestMarshalJSON(t *testing.T) { - r := resource.New(key.Int64("A", 1), key.String("C", "D")) + r := resource.New(kv.Int64("A", 1), kv.String("C", "D")) data, err := json.Marshal(r) require.NoError(t, err) require.Equal(t, diff --git a/sdk/trace/attributesMap.go b/sdk/trace/attributesMap.go index 9eea73f1a..aa938d1bc 100644 --- a/sdk/trace/attributesMap.go +++ b/sdk/trace/attributesMap.go @@ -17,7 +17,7 @@ package trace import ( "container/list" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/sdk/export/trace" ) @@ -26,9 +26,9 @@ import ( // Updates are allowed and refreshes the usage of the key. // // This is based from https://github.com/hashicorp/golang-lru/blob/master/simplelru/lru.go -// With a subset of the its operations and specific for holding core.KeyValue +// With a subset of the its operations and specific for holding kv.KeyValue type attributesMap struct { - attributes map[core.Key]*list.Element + attributes map[kv.Key]*list.Element evictList *list.List droppedCount int capacity int @@ -36,14 +36,14 @@ type attributesMap struct { func newAttributesMap(capacity int) *attributesMap { lm := &attributesMap{ - attributes: make(map[core.Key]*list.Element), + attributes: make(map[kv.Key]*list.Element), evictList: list.New(), capacity: capacity, } return lm } -func (am *attributesMap) add(kv core.KeyValue) { +func (am *attributesMap) add(kv kv.KeyValue) { // Check for existing item if ent, ok := am.attributes[kv.Key]; ok { am.evictList.MoveToFront(ent) @@ -68,9 +68,9 @@ func (am *attributesMap) toSpanData(sd *trace.SpanData) { return } - attributes := make([]core.KeyValue, 0, len) + attributes := make([]kv.KeyValue, 0, len) for ent := am.evictList.Back(); ent != nil; ent = ent.Prev() { - if value, ok := ent.Value.(*core.KeyValue); ok { + if value, ok := ent.Value.(*kv.KeyValue); ok { attributes = append(attributes, *value) } } @@ -84,7 +84,7 @@ func (am *attributesMap) removeOldest() { ent := am.evictList.Back() if ent != nil { am.evictList.Remove(ent) - kv := ent.Value.(*core.KeyValue) + kv := ent.Value.(*kv.KeyValue) delete(am.attributes, kv.Key) } } diff --git a/sdk/trace/benchmark_test.go b/sdk/trace/benchmark_test.go index 1690d09f7..70dd374f9 100644 --- a/sdk/trace/benchmark_test.go +++ b/sdk/trace/benchmark_test.go @@ -18,7 +18,8 @@ import ( "context" "testing" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" + apitrace "go.opentelemetry.io/otel/api/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) @@ -42,10 +43,10 @@ func BenchmarkSpanWithAttributes_4(b *testing.B) { for i := 0; i < b.N; i++ { _, span := t.Start(ctx, "/foo") span.SetAttributes( - key.New("key1").Bool(false), - key.New("key2").String("hello"), - key.New("key3").Uint64(123), - key.New("key4").Float64(123.456), + kv.Key("key1").Bool(false), + kv.Key("key2").String("hello"), + kv.Key("key3").Uint64(123), + kv.Key("key4").Float64(123.456), ) span.End() } @@ -60,14 +61,14 @@ func BenchmarkSpanWithAttributes_8(b *testing.B) { for i := 0; i < b.N; i++ { _, span := t.Start(ctx, "/foo") span.SetAttributes( - key.New("key1").Bool(false), - key.New("key2").String("hello"), - key.New("key3").Uint64(123), - key.New("key4").Float64(123.456), - key.New("key21").Bool(false), - key.New("key22").String("hello"), - key.New("key23").Uint64(123), - key.New("key24").Float64(123.456), + kv.Key("key1").Bool(false), + kv.Key("key2").String("hello"), + kv.Key("key3").Uint64(123), + kv.Key("key4").Float64(123.456), + kv.Key("key21").Bool(false), + kv.Key("key22").String("hello"), + kv.Key("key23").Uint64(123), + kv.Key("key24").Float64(123.456), ) span.End() } @@ -82,16 +83,16 @@ func BenchmarkSpanWithAttributes_all(b *testing.B) { for i := 0; i < b.N; i++ { _, span := t.Start(ctx, "/foo") span.SetAttributes( - key.New("key1").Bool(false), - key.New("key2").String("hello"), - key.New("key3").Int64(123), - key.New("key4").Uint64(123), - key.New("key5").Int32(123), - key.New("key6").Uint32(123), - key.New("key7").Float64(123.456), - key.New("key8").Float32(123.456), - key.New("key9").Int(123), - key.New("key10").Uint(123), + kv.Key("key1").Bool(false), + kv.Key("key2").String("hello"), + kv.Key("key3").Int64(123), + kv.Key("key4").Uint64(123), + kv.Key("key5").Int32(123), + kv.Key("key6").Uint32(123), + kv.Key("key7").Float64(123.456), + kv.Key("key8").Float32(123.456), + kv.Key("key9").Int(123), + kv.Key("key10").Uint(123), ) span.End() } @@ -106,26 +107,26 @@ func BenchmarkSpanWithAttributes_all_2x(b *testing.B) { for i := 0; i < b.N; i++ { _, span := t.Start(ctx, "/foo") span.SetAttributes( - key.New("key1").Bool(false), - key.New("key2").String("hello"), - key.New("key3").Int64(123), - key.New("key4").Uint64(123), - key.New("key5").Int32(123), - key.New("key6").Uint32(123), - key.New("key7").Float64(123.456), - key.New("key8").Float32(123.456), - key.New("key10").Int(123), - key.New("key11").Uint(123), - key.New("key21").Bool(false), - key.New("key22").String("hello"), - key.New("key23").Int64(123), - key.New("key24").Uint64(123), - key.New("key25").Int32(123), - key.New("key26").Uint32(123), - key.New("key27").Float64(123.456), - key.New("key28").Float32(123.456), - key.New("key210").Int(123), - key.New("key211").Uint(123), + kv.Key("key1").Bool(false), + kv.Key("key2").String("hello"), + kv.Key("key3").Int64(123), + kv.Key("key4").Uint64(123), + kv.Key("key5").Int32(123), + kv.Key("key6").Uint32(123), + kv.Key("key7").Float64(123.456), + kv.Key("key8").Float32(123.456), + kv.Key("key10").Int(123), + kv.Key("key11").Uint(123), + kv.Key("key21").Bool(false), + kv.Key("key22").String("hello"), + kv.Key("key23").Int64(123), + kv.Key("key24").Uint64(123), + kv.Key("key25").Int32(123), + kv.Key("key26").Uint32(123), + kv.Key("key27").Float64(123.456), + kv.Key("key28").Float32(123.456), + kv.Key("key210").Int(123), + kv.Key("key211").Uint(123), ) span.End() } diff --git a/sdk/trace/provider.go b/sdk/trace/provider.go index fe4b8a7a7..6b596e4d1 100644 --- a/sdk/trace/provider.go +++ b/sdk/trace/provider.go @@ -21,7 +21,7 @@ import ( export "go.opentelemetry.io/otel/sdk/export/trace" "go.opentelemetry.io/otel/sdk/resource" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" apitrace "go.opentelemetry.io/otel/api/trace" ) @@ -197,7 +197,7 @@ func WithConfig(config Config) ProviderOption { // WithResourceAttributes option sets the resource attributes to the provider. // Resource is added to the span when it is started. -func WithResourceAttributes(attrs ...core.KeyValue) ProviderOption { +func WithResourceAttributes(attrs ...kv.KeyValue) ProviderOption { return func(opts *ProviderOptions) { opts.config.Resource = resource.New(attrs...) } diff --git a/sdk/trace/sampling.go b/sdk/trace/sampling.go index 3f33a4733..8cf8248df 100644 --- a/sdk/trace/sampling.go +++ b/sdk/trace/sampling.go @@ -18,7 +18,7 @@ import ( "encoding/binary" "fmt" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" api "go.opentelemetry.io/otel/api/trace" ) @@ -36,7 +36,7 @@ type SamplingParameters struct { Name string HasRemoteParent bool Kind api.SpanKind - Attributes []core.KeyValue + Attributes []kv.KeyValue Links []api.Link } @@ -53,7 +53,7 @@ const ( // SamplingResult conveys a SamplingDecision and a set of Attributes. type SamplingResult struct { Decision SamplingDecision - Attributes []core.KeyValue + Attributes []kv.KeyValue } type probabilitySampler struct { diff --git a/sdk/trace/span.go b/sdk/trace/span.go index 9753968d2..50772115b 100644 --- a/sdk/trace/span.go +++ b/sdk/trace/span.go @@ -23,16 +23,15 @@ import ( "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" apitrace "go.opentelemetry.io/otel/api/trace" export "go.opentelemetry.io/otel/sdk/export/trace" "go.opentelemetry.io/otel/sdk/internal" ) const ( - errorTypeKey = core.Key("error.type") - errorMessageKey = core.Key("error.message") + errorTypeKey = kv.Key("error.type") + errorMessageKey = kv.Key("error.message") errorEventName = "error" ) @@ -94,7 +93,7 @@ func (s *span) SetStatus(code codes.Code, msg string) { s.mu.Unlock() } -func (s *span) SetAttributes(attributes ...core.KeyValue) { +func (s *span) SetAttributes(attributes ...kv.KeyValue) { if !s.IsRecording() { return } @@ -102,7 +101,7 @@ func (s *span) SetAttributes(attributes ...core.KeyValue) { } func (s *span) SetAttribute(k string, v interface{}) { - s.SetAttributes(key.Infer(k, v)) + s.SetAttributes(kv.Infer(k, v)) } func (s *span) End(options ...apitrace.EndOption) { @@ -177,21 +176,21 @@ func (s *span) Tracer() apitrace.Tracer { return s.tracer } -func (s *span) AddEvent(ctx context.Context, name string, attrs ...core.KeyValue) { +func (s *span) AddEvent(ctx context.Context, name string, attrs ...kv.KeyValue) { if !s.IsRecording() { return } s.addEventWithTimestamp(time.Now(), name, attrs...) } -func (s *span) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...core.KeyValue) { +func (s *span) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...kv.KeyValue) { if !s.IsRecording() { return } s.addEventWithTimestamp(timestamp, name, attrs...) } -func (s *span) addEventWithTimestamp(timestamp time.Time, name string, attrs ...core.KeyValue) { +func (s *span) addEventWithTimestamp(timestamp time.Time, name string, attrs ...kv.KeyValue) { s.mu.Lock() defer s.mu.Unlock() s.messageEvents.add(export.Event{ @@ -286,7 +285,7 @@ func (s *span) interfaceArrayToMessageEventArray() []export.Event { return messageEventArr } -func (s *span) copyToCappedAttributes(attributes ...core.KeyValue) { +func (s *span) copyToCappedAttributes(attributes ...kv.KeyValue) { s.mu.Lock() defer s.mu.Unlock() for _, a := range attributes { @@ -374,7 +373,7 @@ type samplingData struct { name string cfg *Config span *span - attributes []core.KeyValue + attributes []kv.KeyValue links []apitrace.Link kind apitrace.SpanKind } diff --git a/sdk/trace/trace_test.go b/sdk/trace/trace_test.go index c96d6bce7..a2dc2af54 100644 --- a/sdk/trace/trace_test.go +++ b/sdk/trace/trace_test.go @@ -24,11 +24,12 @@ import ( "testing" "time" + "go.opentelemetry.io/otel/api/kv/value" + "github.com/google/go-cmp/cmp" "google.golang.org/grpc/codes" - "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/key" + "go.opentelemetry.io/otel/api/kv" "go.opentelemetry.io/otel/api/testharness" "go.opentelemetry.io/otel/api/trace" apitrace "go.opentelemetry.io/otel/api/trace" @@ -81,7 +82,7 @@ func (ts *testSampler) ShouldSample(p SamplingParameters) SamplingResult { if strings.HasPrefix(p.Name, ts.prefix) { decision = RecordAndSampled } - return SamplingResult{Decision: decision, Attributes: []core.KeyValue{key.Int("callCount", ts.callCount)}} + return SamplingResult{Decision: decision, Attributes: []kv.KeyValue{kv.Int("callCount", ts.callCount)}} } func (ts testSampler) Description() string { @@ -274,8 +275,8 @@ func TestSetSpanAttributesOnStart(t *testing.T) { tp, _ := NewProvider(WithSyncer(te)) span := startSpan(tp, "StartSpanAttribute", - apitrace.WithAttributes(key.String("key1", "value1")), - apitrace.WithAttributes(key.String("key2", "value2")), + apitrace.WithAttributes(kv.String("key1", "value1")), + apitrace.WithAttributes(kv.String("key2", "value2")), ) got, err := endSpan(te, span) if err != nil { @@ -289,9 +290,9 @@ func TestSetSpanAttributesOnStart(t *testing.T) { }, ParentSpanID: sid, Name: "span0", - Attributes: []core.KeyValue{ - key.String("key1", "value1"), - key.String("key2", "value2"), + Attributes: []kv.KeyValue{ + kv.String("key1", "value1"), + kv.String("key2", "value2"), }, SpanKind: apitrace.SpanKindInternal, HasRemoteParent: true, @@ -305,7 +306,7 @@ func TestSetSpanAttributes(t *testing.T) { te := &testExporter{} tp, _ := NewProvider(WithSyncer(te)) span := startSpan(tp, "SpanAttribute") - span.SetAttributes(key.New("key1").String("value1")) + span.SetAttributes(kv.Key("key1").String("value1")) got, err := endSpan(te, span) if err != nil { t.Fatal(err) @@ -318,8 +319,8 @@ func TestSetSpanAttributes(t *testing.T) { }, ParentSpanID: sid, Name: "span0", - Attributes: []core.KeyValue{ - key.String("key1", "value1"), + Attributes: []kv.KeyValue{ + kv.String("key1", "value1"), }, SpanKind: apitrace.SpanKindInternal, HasRemoteParent: true, @@ -336,10 +337,10 @@ func TestSetSpanAttributesOverLimit(t *testing.T) { span := startSpan(tp, "SpanAttributesOverLimit") span.SetAttributes( - key.Bool("key1", true), - key.String("key2", "value2"), - key.Bool("key1", false), // Replace key1. - key.Int64("key4", 4), // Remove key2 and add key4 + kv.Bool("key1", true), + kv.String("key2", "value2"), + kv.Bool("key1", false), // Replace key1. + kv.Int64("key4", 4), // Remove key2 and add key4 ) got, err := endSpan(te, span) if err != nil { @@ -353,9 +354,9 @@ func TestSetSpanAttributesOverLimit(t *testing.T) { }, ParentSpanID: sid, Name: "span0", - Attributes: []core.KeyValue{ - key.Bool("key1", false), - key.Int64("key4", 4), + Attributes: []kv.KeyValue{ + kv.Bool("key1", false), + kv.Int64("key4", 4), }, SpanKind: apitrace.SpanKindInternal, HasRemoteParent: true, @@ -371,14 +372,14 @@ func TestEvents(t *testing.T) { tp, _ := NewProvider(WithSyncer(te)) span := startSpan(tp, "Events") - k1v1 := key.New("key1").String("value1") - k2v2 := key.Bool("key2", true) - k3v3 := key.Int64("key3", 3) + k1v1 := kv.Key("key1").String("value1") + k2v2 := kv.Bool("key2", true) + k3v3 := kv.Int64("key3", 3) - span.AddEvent(context.Background(), "foo", key.New("key1").String("value1")) + span.AddEvent(context.Background(), "foo", kv.Key("key1").String("value1")) span.AddEvent(context.Background(), "bar", - key.Bool("key2", true), - key.Int64("key3", 3), + kv.Bool("key2", true), + kv.Int64("key3", 3), ) got, err := endSpan(te, span) if err != nil { @@ -400,8 +401,8 @@ func TestEvents(t *testing.T) { Name: "span0", HasRemoteParent: true, MessageEvents: []export.Event{ - {Name: "foo", Attributes: []core.KeyValue{k1v1}}, - {Name: "bar", Attributes: []core.KeyValue{k2v2, k3v3}}, + {Name: "foo", Attributes: []kv.KeyValue{k1v1}}, + {Name: "bar", Attributes: []kv.KeyValue{k2v2, k3v3}}, }, SpanKind: apitrace.SpanKindInternal, } @@ -416,19 +417,19 @@ func TestEventsOverLimit(t *testing.T) { tp, _ := NewProvider(WithConfig(cfg), WithSyncer(te)) span := startSpan(tp, "EventsOverLimit") - k1v1 := key.New("key1").String("value1") - k2v2 := key.Bool("key2", false) - k3v3 := key.New("key3").String("value3") + k1v1 := kv.Key("key1").String("value1") + k2v2 := kv.Bool("key2", false) + k3v3 := kv.Key("key3").String("value3") - span.AddEvent(context.Background(), "fooDrop", key.New("key1").String("value1")) + span.AddEvent(context.Background(), "fooDrop", kv.Key("key1").String("value1")) span.AddEvent(context.Background(), "barDrop", - key.Bool("key2", true), - key.New("key3").String("value3"), + kv.Bool("key2", true), + kv.Key("key3").String("value3"), ) - span.AddEvent(context.Background(), "foo", key.New("key1").String("value1")) + span.AddEvent(context.Background(), "foo", kv.Key("key1").String("value1")) span.AddEvent(context.Background(), "bar", - key.Bool("key2", false), - key.New("key3").String("value3"), + kv.Bool("key2", false), + kv.Key("key3").String("value3"), ) got, err := endSpan(te, span) if err != nil { @@ -449,8 +450,8 @@ func TestEventsOverLimit(t *testing.T) { ParentSpanID: sid, Name: "span0", MessageEvents: []export.Event{ - {Name: "foo", Attributes: []core.KeyValue{k1v1}}, - {Name: "bar", Attributes: []core.KeyValue{k2v2, k3v3}}, + {Name: "foo", Attributes: []kv.KeyValue{k1v1}}, + {Name: "bar", Attributes: []kv.KeyValue{k2v2, k3v3}}, }, DroppedMessageEventCount: 2, HasRemoteParent: true, @@ -465,18 +466,18 @@ func TestLinks(t *testing.T) { te := &testExporter{} tp, _ := NewProvider(WithSyncer(te)) - k1v1 := key.New("key1").String("value1") - k2v2 := key.New("key2").String("value2") - k3v3 := key.New("key3").String("value3") + k1v1 := kv.Key("key1").String("value1") + k2v2 := kv.Key("key2").String("value2") + k3v3 := kv.Key("key3").String("value3") sc1 := apitrace.SpanContext{TraceID: apitrace.ID([16]byte{1, 1}), SpanID: apitrace.SpanID{3}} sc2 := apitrace.SpanContext{TraceID: apitrace.ID([16]byte{1, 1}), SpanID: apitrace.SpanID{3}} span := startSpan(tp, "Links", - apitrace.LinkedTo(sc1, key.New("key1").String("value1")), + apitrace.LinkedTo(sc1, kv.Key("key1").String("value1")), apitrace.LinkedTo(sc2, - key.New("key2").String("value2"), - key.New("key3").String("value3"), + kv.Key("key2").String("value2"), + kv.Key("key3").String("value3"), ), ) @@ -494,8 +495,8 @@ func TestLinks(t *testing.T) { Name: "span0", HasRemoteParent: true, Links: []apitrace.Link{ - {SpanContext: sc1, Attributes: []core.KeyValue{k1v1}}, - {SpanContext: sc2, Attributes: []core.KeyValue{k2v2, k3v3}}, + {SpanContext: sc1, Attributes: []kv.KeyValue{k1v1}}, + {SpanContext: sc2, Attributes: []kv.KeyValue{k2v2, k3v3}}, }, SpanKind: apitrace.SpanKindInternal, } @@ -515,13 +516,13 @@ func TestLinksOverLimit(t *testing.T) { tp, _ := NewProvider(WithConfig(cfg), WithSyncer(te)) span := startSpan(tp, "LinksOverLimit", - apitrace.LinkedTo(sc1, key.New("key1").String("value1")), - apitrace.LinkedTo(sc2, key.New("key2").String("value2")), - apitrace.LinkedTo(sc3, key.New("key3").String("value3")), + apitrace.LinkedTo(sc1, kv.Key("key1").String("value1")), + apitrace.LinkedTo(sc2, kv.Key("key2").String("value2")), + apitrace.LinkedTo(sc3, kv.Key("key3").String("value3")), ) - k2v2 := key.New("key2").String("value2") - k3v3 := key.New("key3").String("value3") + k2v2 := kv.Key("key2").String("value2") + k3v3 := kv.Key("key3").String("value3") got, err := endSpan(te, span) if err != nil { @@ -536,8 +537,8 @@ func TestLinksOverLimit(t *testing.T) { ParentSpanID: sid, Name: "span0", Links: []apitrace.Link{ - {SpanContext: sc2, Attributes: []core.KeyValue{k2v2}}, - {SpanContext: sc3, Attributes: []core.KeyValue{k3v3}}, + {SpanContext: sc2, Attributes: []kv.KeyValue{k2v2}}, + {SpanContext: sc3, Attributes: []kv.KeyValue{k3v3}}, }, DroppedLinkCount: 1, HasRemoteParent: true, @@ -600,7 +601,7 @@ func TestSetSpanStatus(t *testing.T) { func cmpDiff(x, y interface{}) string { return cmp.Diff(x, y, - cmp.AllowUnexported(core.Value{}), + cmp.AllowUnexported(value.Value{}), cmp.AllowUnexported(export.Event{})) } @@ -937,7 +938,7 @@ func TestRecordError(t *testing.T) { { Name: errorEventName, Time: errTime, - Attributes: []core.KeyValue{ + Attributes: []kv.KeyValue{ errorTypeKey.String(s.typ), errorMessageKey.String(s.msg), }, @@ -983,7 +984,7 @@ func TestRecordErrorWithStatus(t *testing.T) { { Name: errorEventName, Time: errTime, - Attributes: []core.KeyValue{ + Attributes: []kv.KeyValue{ errorTypeKey.String("go.opentelemetry.io/otel/internal/testing.TestError"), errorMessageKey.String("test error"), }, @@ -1066,9 +1067,9 @@ func TestWithResource(t *testing.T) { var te testExporter tp, _ := NewProvider(WithSyncer(&te), WithConfig(Config{DefaultSampler: AlwaysSample()}), - WithResourceAttributes(key.String("rk1", "rv1"), key.Int64("rk2", 5))) + WithResourceAttributes(kv.String("rk1", "rv1"), kv.Int64("rk2", 5))) span := startSpan(tp, "WithResource") - span.SetAttributes(key.String("key1", "value1")) + span.SetAttributes(kv.String("key1", "value1")) got, err := endSpan(&te, span) if err != nil { t.Error(err.Error()) @@ -1081,12 +1082,12 @@ func TestWithResource(t *testing.T) { }, ParentSpanID: sid, Name: "span0", - Attributes: []core.KeyValue{ - key.String("key1", "value1"), + Attributes: []kv.KeyValue{ + kv.String("key1", "value1"), }, SpanKind: apitrace.SpanKindInternal, HasRemoteParent: true, - Resource: resource.New(key.String("rk1", "rv1"), key.Int64("rk2", 5)), + Resource: resource.New(kv.String("rk1", "rv1"), kv.Int64("rk2", 5)), } if diff := cmpDiff(got, want); diff != "" { t.Errorf("WithResource:\n -got +want %s", diff)