You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2026-06-03 18:35:08 +02:00
Merge branch 'master' into master
This commit is contained in:
+1
-1
@@ -12,6 +12,6 @@
|
||||
# https://help.github.com/en/articles/about-code-owners
|
||||
#
|
||||
|
||||
* @jmacd @paivagustavo @krnowak @lizthegrey @MrAlias @Aneurysm9 @evantorrie
|
||||
* @jmacd @paivagustavo @lizthegrey @MrAlias @Aneurysm9 @evantorrie
|
||||
|
||||
CODEOWNERS @MrAlias @jmacd
|
||||
|
||||
@@ -139,7 +139,6 @@ 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
|
||||
- [Anthony Mirabella](https://github.com/Aneurysm9), Centene
|
||||
|
||||
@@ -23,7 +23,9 @@ import (
|
||||
"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.
|
||||
|
||||
@@ -89,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)
|
||||
@@ -133,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)
|
||||
@@ -202,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,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -222,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)
|
||||
|
||||
@@ -59,7 +59,7 @@ func (*benchFixture) AggregatorFor(descriptor *metric.Descriptor) export.Aggrega
|
||||
switch descriptor.MetricKind() {
|
||||
case metric.CounterKind:
|
||||
return sum.New()
|
||||
case metric.MeasureKind:
|
||||
case metric.ValueRecorderKind:
|
||||
if strings.HasSuffix(descriptor.Name(), "minmaxsumcount") {
|
||||
return minmaxsumcount.New(descriptor)
|
||||
} else if strings.HasSuffix(descriptor.Name(), "ddsketch") {
|
||||
|
||||
@@ -82,21 +82,21 @@ func TestDirect(t *testing.T) {
|
||||
counter.Add(ctx, 1, labels1...)
|
||||
counter.Add(ctx, 1, labels1...)
|
||||
|
||||
measure := Must(meter1).NewFloat64Measure("test.measure")
|
||||
measure.Record(ctx, 1, labels1...)
|
||||
measure.Record(ctx, 2, labels1...)
|
||||
valuerecorder := Must(meter1).NewFloat64ValueRecorder("test.valuerecorder")
|
||||
valuerecorder.Record(ctx, 1, labels1...)
|
||||
valuerecorder.Record(ctx, 2, labels1...)
|
||||
|
||||
_ = Must(meter1).RegisterFloat64Observer("test.observer.float", func(result metric.Float64ObserverResult) {
|
||||
_ = Must(meter1).RegisterFloat64ValueObserver("test.valueobserver.float", func(result metric.Float64ObserverResult) {
|
||||
result.Observe(1., labels1...)
|
||||
result.Observe(2., labels2...)
|
||||
})
|
||||
|
||||
_ = Must(meter1).RegisterInt64Observer("test.observer.int", func(result metric.Int64ObserverResult) {
|
||||
_ = Must(meter1).RegisterInt64ValueObserver("test.valueobserver.int", func(result metric.Int64ObserverResult) {
|
||||
result.Observe(1, labels1...)
|
||||
result.Observe(2, labels2...)
|
||||
})
|
||||
|
||||
second := Must(meter2).NewFloat64Measure("test.second")
|
||||
second := Must(meter2).NewFloat64ValueRecorder("test.second")
|
||||
second.Record(ctx, 1, labels3...)
|
||||
second.Record(ctx, 2, labels3...)
|
||||
|
||||
@@ -104,7 +104,7 @@ func TestDirect(t *testing.T) {
|
||||
global.SetMeterProvider(provider)
|
||||
|
||||
counter.Add(ctx, 1, labels1...)
|
||||
measure.Record(ctx, 3, labels1...)
|
||||
valuerecorder.Record(ctx, 3, labels1...)
|
||||
second.Record(ctx, 3, labels3...)
|
||||
|
||||
mock.RunAsyncInstruments()
|
||||
@@ -120,7 +120,7 @@ func TestDirect(t *testing.T) {
|
||||
Number: asInt(1),
|
||||
},
|
||||
{
|
||||
Name: "test.measure",
|
||||
Name: "test.valuerecorder",
|
||||
LibraryName: "test1",
|
||||
Labels: asMap(labels1...),
|
||||
Number: asFloat(3),
|
||||
@@ -132,25 +132,25 @@ func TestDirect(t *testing.T) {
|
||||
Number: asFloat(3),
|
||||
},
|
||||
{
|
||||
Name: "test.observer.float",
|
||||
Name: "test.valueobserver.float",
|
||||
LibraryName: "test1",
|
||||
Labels: asMap(labels1...),
|
||||
Number: asFloat(1),
|
||||
},
|
||||
{
|
||||
Name: "test.observer.float",
|
||||
Name: "test.valueobserver.float",
|
||||
LibraryName: "test1",
|
||||
Labels: asMap(labels2...),
|
||||
Number: asFloat(2),
|
||||
},
|
||||
{
|
||||
Name: "test.observer.int",
|
||||
Name: "test.valueobserver.int",
|
||||
LibraryName: "test1",
|
||||
Labels: asMap(labels1...),
|
||||
Number: asInt(1),
|
||||
},
|
||||
{
|
||||
Name: "test.observer.int",
|
||||
Name: "test.valueobserver.int",
|
||||
LibraryName: "test1",
|
||||
Labels: asMap(labels2...),
|
||||
Number: asInt(2),
|
||||
@@ -174,8 +174,8 @@ func TestBound(t *testing.T) {
|
||||
boundC.Add(ctx, 1)
|
||||
boundC.Add(ctx, 1)
|
||||
|
||||
measure := Must(glob).NewInt64Measure("test.measure")
|
||||
boundM := measure.Bind(labels1...)
|
||||
valuerecorder := Must(glob).NewInt64ValueRecorder("test.valuerecorder")
|
||||
boundM := valuerecorder.Bind(labels1...)
|
||||
boundM.Record(ctx, 1)
|
||||
boundM.Record(ctx, 2)
|
||||
|
||||
@@ -194,7 +194,7 @@ func TestBound(t *testing.T) {
|
||||
Number: asFloat(1),
|
||||
},
|
||||
{
|
||||
Name: "test.measure",
|
||||
Name: "test.valuerecorder",
|
||||
LibraryName: "test",
|
||||
Labels: asMap(labels1...),
|
||||
Number: asInt(3),
|
||||
@@ -216,8 +216,8 @@ func TestUnbind(t *testing.T) {
|
||||
counter := Must(glob).NewFloat64Counter("test.counter")
|
||||
boundC := counter.Bind(labels1...)
|
||||
|
||||
measure := Must(glob).NewInt64Measure("test.measure")
|
||||
boundM := measure.Bind(labels1...)
|
||||
valuerecorder := Must(glob).NewInt64ValueRecorder("test.valuerecorder")
|
||||
boundM := valuerecorder.Bind(labels1...)
|
||||
|
||||
boundC.Unbind()
|
||||
boundM.Unbind()
|
||||
@@ -331,12 +331,12 @@ func TestImplementationIndirection(t *testing.T) {
|
||||
require.False(t, ok)
|
||||
|
||||
// Async: no SDK yet
|
||||
observer := Must(meter1).RegisterFloat64Observer(
|
||||
"interface.observer",
|
||||
valueobserver := Must(meter1).RegisterFloat64ValueObserver(
|
||||
"interface.valueobserver",
|
||||
func(result metric.Float64ObserverResult) {},
|
||||
)
|
||||
|
||||
ival = observer.AsyncImpl().Implementation()
|
||||
ival = valueobserver.AsyncImpl().Implementation()
|
||||
require.NotNil(t, ival)
|
||||
|
||||
_, ok = ival.(*metrictest.Async)
|
||||
@@ -356,7 +356,7 @@ func TestImplementationIndirection(t *testing.T) {
|
||||
require.True(t, ok)
|
||||
|
||||
// Async
|
||||
ival = observer.AsyncImpl().Implementation()
|
||||
ival = valueobserver.AsyncImpl().Implementation()
|
||||
require.NotNil(t, ival)
|
||||
|
||||
_, ok = ival.(*metrictest.Async)
|
||||
@@ -407,7 +407,7 @@ func TestRecordBatchRealSDK(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
global.SetMeterProvider(pusher)
|
||||
global.SetMeterProvider(pusher.Provider())
|
||||
|
||||
meter.RecordBatch(context.Background(), nil, counter.Measurement(1))
|
||||
pusher.Stop()
|
||||
|
||||
@@ -36,17 +36,17 @@ var (
|
||||
"counter.float64": func(name, libraryName string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(MeterProvider().Meter(libraryName).NewFloat64Counter(name))
|
||||
},
|
||||
"measure.int64": func(name, libraryName string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(MeterProvider().Meter(libraryName).NewInt64Measure(name))
|
||||
"valuerecorder.int64": func(name, libraryName string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(MeterProvider().Meter(libraryName).NewInt64ValueRecorder(name))
|
||||
},
|
||||
"measure.float64": func(name, libraryName string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(MeterProvider().Meter(libraryName).NewFloat64Measure(name))
|
||||
"valuerecorder.float64": func(name, libraryName string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(MeterProvider().Meter(libraryName).NewFloat64ValueRecorder(name))
|
||||
},
|
||||
"observer.int64": func(name, libraryName string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(MeterProvider().Meter(libraryName).RegisterInt64Observer(name, func(metric.Int64ObserverResult) {}))
|
||||
"valueobserver.int64": func(name, libraryName string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(MeterProvider().Meter(libraryName).RegisterInt64ValueObserver(name, func(metric.Int64ObserverResult) {}))
|
||||
},
|
||||
"observer.float64": func(name, libraryName string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(MeterProvider().Meter(libraryName).RegisterFloat64Observer(name, func(metric.Float64ObserverResult) {}))
|
||||
"valueobserver.float64": func(name, libraryName string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(MeterProvider().Meter(libraryName).RegisterFloat64ValueObserver(name, func(metric.Float64ObserverResult) {}))
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
+17
-17
@@ -119,38 +119,38 @@ func TestCounter(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeasure(t *testing.T) {
|
||||
func TestValueRecorder(t *testing.T) {
|
||||
{
|
||||
mockSDK, meter := mockTest.NewMeter()
|
||||
m := Must(meter).NewFloat64Measure("test.measure.float")
|
||||
m := Must(meter).NewFloat64ValueRecorder("test.valuerecorder.float")
|
||||
ctx := context.Background()
|
||||
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")
|
||||
t.Log("Testing float valuerecorder")
|
||||
checkBatches(t, ctx, labels, mockSDK, metric.Float64NumberKind, m.SyncImpl())
|
||||
}
|
||||
{
|
||||
mockSDK, meter := mockTest.NewMeter()
|
||||
m := Must(meter).NewInt64Measure("test.measure.int")
|
||||
m := Must(meter).NewInt64ValueRecorder("test.valuerecorder.int")
|
||||
ctx := context.Background()
|
||||
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")
|
||||
t.Log("Testing int valuerecorder")
|
||||
checkBatches(t, ctx, labels, mockSDK, metric.Int64NumberKind, m.SyncImpl())
|
||||
}
|
||||
}
|
||||
|
||||
func TestObserver(t *testing.T) {
|
||||
func TestObserverInstruments(t *testing.T) {
|
||||
{
|
||||
labels := []kv.KeyValue{kv.String("O", "P")}
|
||||
mockSDK, meter := mockTest.NewMeter()
|
||||
o := Must(meter).RegisterFloat64Observer("test.observer.float", func(result metric.Float64ObserverResult) {
|
||||
o := Must(meter).RegisterFloat64ValueObserver("test.observer.float", func(result metric.Float64ObserverResult) {
|
||||
result.Observe(42, labels...)
|
||||
})
|
||||
t.Log("Testing float observer")
|
||||
@@ -161,7 +161,7 @@ func TestObserver(t *testing.T) {
|
||||
{
|
||||
labels := []kv.KeyValue{}
|
||||
mockSDK, meter := mockTest.NewMeter()
|
||||
o := Must(meter).RegisterInt64Observer("test.observer.int", func(result metric.Int64ObserverResult) {
|
||||
o := Must(meter).RegisterInt64ValueObserver("test.observer.int", func(result metric.Int64ObserverResult) {
|
||||
result.Observe(42, labels...)
|
||||
})
|
||||
t.Log("Testing int observer")
|
||||
@@ -210,11 +210,11 @@ func checkBatches(t *testing.T, ctx context.Context, labels []kv.KeyValue, mock
|
||||
}
|
||||
}
|
||||
|
||||
func TestBatchObserver(t *testing.T) {
|
||||
func TestBatchObserverInstruments(t *testing.T) {
|
||||
mockSDK, meter := mockTest.NewMeter()
|
||||
|
||||
var obs1 metric.Int64Observer
|
||||
var obs2 metric.Float64Observer
|
||||
var obs1 metric.Int64ValueObserver
|
||||
var obs2 metric.Float64ValueObserver
|
||||
|
||||
labels := []kv.KeyValue{
|
||||
kv.String("A", "B"),
|
||||
@@ -229,8 +229,8 @@ func TestBatchObserver(t *testing.T) {
|
||||
)
|
||||
},
|
||||
)
|
||||
obs1 = cb.RegisterInt64Observer("test.observer.int")
|
||||
obs2 = cb.RegisterFloat64Observer("test.observer.float")
|
||||
obs1 = cb.RegisterInt64ValueObserver("test.observer.int")
|
||||
obs2 = cb.RegisterFloat64ValueObserver("test.observer.float")
|
||||
|
||||
mockSDK.RunAsyncInstruments()
|
||||
|
||||
@@ -309,12 +309,12 @@ func TestWrappedInstrumentError(t *testing.T) {
|
||||
impl := &testWrappedMeter{}
|
||||
meter := metric.WrapMeterImpl(impl, "test")
|
||||
|
||||
measure, err := meter.NewInt64Measure("test.measure")
|
||||
valuerecorder, err := meter.NewInt64ValueRecorder("test.valuerecorder")
|
||||
|
||||
require.Equal(t, err, metric.ErrSDKReturnedNilImpl)
|
||||
require.NotNil(t, measure.SyncImpl())
|
||||
require.NotNil(t, valuerecorder.SyncImpl())
|
||||
|
||||
observer, err := meter.RegisterInt64Observer("test.observer", func(result metric.Int64ObserverResult) {})
|
||||
observer, err := meter.RegisterInt64ValueObserver("test.observer", func(result metric.Int64ObserverResult) {})
|
||||
|
||||
require.NotNil(t, err)
|
||||
require.NotNil(t, observer.AsyncImpl())
|
||||
@@ -324,7 +324,7 @@ func TestNilCallbackObserverNoop(t *testing.T) {
|
||||
// Tests that a nil callback yields a no-op observer without error.
|
||||
_, meter := mockTest.NewMeter()
|
||||
|
||||
observer := Must(meter).RegisterInt64Observer("test.observer", nil)
|
||||
observer := Must(meter).RegisterInt64ValueObserver("test.observer", nil)
|
||||
|
||||
_, ok := observer.AsyncImpl().(metric.NoopAsync)
|
||||
require.True(t, ok)
|
||||
|
||||
+19
-1
@@ -29,7 +29,7 @@ import "go.opentelemetry.io/otel/api/kv"
|
||||
|
||||
// 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()).
|
||||
// instruments (e.g., Int64ValueObserver.Observation()).
|
||||
type Observation struct {
|
||||
// number needs to be aligned for 64-bit atomic operations.
|
||||
number Number
|
||||
@@ -175,3 +175,21 @@ func (b *BatchObserverCallback) Run(function func([]kv.KeyValue, ...Observation)
|
||||
function: function,
|
||||
})
|
||||
}
|
||||
|
||||
// wrapInt64ValueObserverInstrument returns an `Int64ValueObserver` 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 wrapInt64ValueObserverInstrument(asyncInst AsyncImpl, err error) (Int64ValueObserver, error) {
|
||||
common, err := checkNewAsync(asyncInst, err)
|
||||
return Int64ValueObserver{asyncInstrument: common}, err
|
||||
}
|
||||
|
||||
// wrapFloat64ValueObserverInstrument returns an `Float64ValueObserver` 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 wrapFloat64ValueObserverInstrument(asyncInst AsyncImpl, err error) (Float64ValueObserver, error) {
|
||||
common, err := checkNewAsync(asyncInst, err)
|
||||
return Float64ValueObserver{asyncInstrument: common}, err
|
||||
}
|
||||
|
||||
+25
-45
@@ -13,57 +13,37 @@
|
||||
// limitations under the License.
|
||||
|
||||
// metric package provides an API for reporting diagnostic
|
||||
// measurements using four basic kinds of instruments.
|
||||
// measurements using instruments categorized as follows:
|
||||
//
|
||||
// The three basic kinds are:
|
||||
// Synchronous instruments are called by the user with a Context.
|
||||
// Asynchronous instruments are called by the SDK during collection.
|
||||
//
|
||||
// - counters
|
||||
// - measures
|
||||
// - observers
|
||||
// Additive instruments are semantically intended for capturing a sum.
|
||||
// Non-additive instruments are intended for capturing a distribution.
|
||||
//
|
||||
// All instruments report either float64 or int64 values.
|
||||
// Additive instruments may be monotonic, in which case they are
|
||||
// non-descreasing and naturally define a rate.
|
||||
//
|
||||
// The primary object that handles metrics is Meter. Meter can be
|
||||
// obtained from Provider. The implementations of the Meter and
|
||||
// Provider are provided by SDK. Normally, the Meter is used directly
|
||||
// only for the instrument creation and batch recording.
|
||||
// The synchronous instrument names are:
|
||||
//
|
||||
// Counters are instruments that are reporting a quantity or a sum. An
|
||||
// example could be bank account balance or bytes downloaded. Counters
|
||||
// can be created with either NewFloat64Counter or
|
||||
// NewInt64Counter. Counters expect non-negative values by default to
|
||||
// be reported. This can be changed with the WithMonotonic option
|
||||
// (passing false as a parameter) passed to the Meter.New*Counter
|
||||
// function - this allows reporting negative values. To report the new
|
||||
// value, use an Add function.
|
||||
// Counter: additive, monotonic
|
||||
// UpDownCounter: additive
|
||||
// ValueRecorder: non-additive
|
||||
//
|
||||
// Measures are instruments that are reporting values that are
|
||||
// recorded separately to figure out some statistical properties from
|
||||
// those values (like average). An example could be temperature over
|
||||
// time or lines of code in the project over time. Measures can be
|
||||
// created with either NewFloat64Measure or NewInt64Measure. Measures
|
||||
// by default take only non-negative values. This can be changed with
|
||||
// the WithAbsolute option (passing false as a parameter) passed to
|
||||
// the New*Measure function - this allows reporting negative values
|
||||
// too. To report a new value, use the Record function.
|
||||
// and the asynchronous instruments are:
|
||||
//
|
||||
// Observers are instruments that are reporting a current state of a
|
||||
// set of values. An example could be voltage or
|
||||
// temperature. Observers can be created with either
|
||||
// RegisterFloat64Observer or RegisterInt64Observer. Observers by
|
||||
// default have no limitations about reported values - they can be
|
||||
// less or greater than the last reported value. This can be changed
|
||||
// with the WithMonotonic option passed to the Register*Observer
|
||||
// function - this permits the reported values only to go
|
||||
// up. Reporting of the new values happens asynchronously, with the
|
||||
// use of a callback passed to the Register*Observer function. The
|
||||
// callback can report multiple values. There is no unregister function.
|
||||
// SumObserver: additive, monotonic
|
||||
// UpDownSumOnserver: additive
|
||||
// ValueObserver: non-additive
|
||||
//
|
||||
// Counters and measures support creating bound instruments for a
|
||||
// potentially more efficient reporting. The bound instruments have
|
||||
// the same function names as the instruments (so a Counter bound
|
||||
// instrument has Add, and a Measure bound instrument has Record).
|
||||
// Bound Instruments can be created with the Bind function of the
|
||||
// respective instrument. When done with the bound instrument, call
|
||||
// Unbind on it.
|
||||
// All instruments are provided with support for either float64 or
|
||||
// int64 input values.
|
||||
//
|
||||
// The Meter interface supports allocating new instruments as well as
|
||||
// interfaces for recording batches of synchronous measurements or
|
||||
// asynchronous observations. To obtain a Meter, use a Provider.
|
||||
//
|
||||
// The Provider interface supports obtaining a named Meter interface.
|
||||
// To obtain a Provider implementation, initialize and configure any
|
||||
// compatible SDK.
|
||||
package metric // import "go.opentelemetry.io/otel/api/metric"
|
||||
|
||||
+4
-4
@@ -20,10 +20,10 @@ package metric
|
||||
type Kind int8
|
||||
|
||||
const (
|
||||
// MeasureKind indicates a Measure instrument.
|
||||
MeasureKind Kind = iota
|
||||
// ObserverKind indicates an Observer instrument.
|
||||
ObserverKind
|
||||
// ValueRecorderKind indicates a ValueRecorder instrument.
|
||||
ValueRecorderKind Kind = iota
|
||||
// ValueObserverKind indicates an ValueObserver instrument.
|
||||
ValueObserverKind
|
||||
// CounterKind indicates a Counter instrument.
|
||||
CounterKind
|
||||
)
|
||||
|
||||
@@ -8,14 +8,14 @@ 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[MeasureKind-0]
|
||||
_ = x[ObserverKind-1]
|
||||
_ = x[ValueRecorderKind-0]
|
||||
_ = x[ValueObserverKind-1]
|
||||
_ = x[CounterKind-2]
|
||||
}
|
||||
|
||||
const _Kind_name = "MeasureKindObserverKindCounterKind"
|
||||
const _Kind_name = "ValueRecorderKindValueObserverKindCounterKind"
|
||||
|
||||
var _Kind_index = [...]uint8{0, 11, 23, 34}
|
||||
var _Kind_index = [...]uint8{0, 17, 34, 45}
|
||||
|
||||
func (i Kind) String() string {
|
||||
if i < 0 || i >= Kind(len(_Kind_index)-1) {
|
||||
|
||||
+28
-28
@@ -82,72 +82,72 @@ func (m Meter) NewFloat64Counter(name string, options ...Option) (Float64Counter
|
||||
m.newSync(name, CounterKind, Float64NumberKind, options))
|
||||
}
|
||||
|
||||
// NewInt64Measure creates a new integer Measure instrument with the
|
||||
// NewInt64ValueRecorder creates a new integer ValueRecorder 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))
|
||||
func (m Meter) NewInt64ValueRecorder(name string, opts ...Option) (Int64ValueRecorder, error) {
|
||||
return wrapInt64ValueRecorderInstrument(
|
||||
m.newSync(name, ValueRecorderKind, Int64NumberKind, opts))
|
||||
}
|
||||
|
||||
// NewFloat64Measure creates a new floating point Measure with the
|
||||
// NewFloat64ValueRecorder creates a new floating point ValueRecorder 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))
|
||||
func (m Meter) NewFloat64ValueRecorder(name string, opts ...Option) (Float64ValueRecorder, error) {
|
||||
return wrapFloat64ValueRecorderInstrument(
|
||||
m.newSync(name, ValueRecorderKind, Float64NumberKind, opts))
|
||||
}
|
||||
|
||||
// RegisterInt64Observer creates a new integer Observer instrument
|
||||
// RegisterInt64ValueObserver creates a new integer ValueObserver 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) {
|
||||
func (m Meter) RegisterInt64ValueObserver(name string, callback Int64ObserverCallback, opts ...Option) (Int64ValueObserver, error) {
|
||||
if callback == nil {
|
||||
return wrapInt64ObserverInstrument(NoopAsync{}, nil)
|
||||
return wrapInt64ValueObserverInstrument(NoopAsync{}, nil)
|
||||
}
|
||||
return wrapInt64ObserverInstrument(
|
||||
m.newAsync(name, ObserverKind, Int64NumberKind, opts,
|
||||
return wrapInt64ValueObserverInstrument(
|
||||
m.newAsync(name, ValueObserverKind, Int64NumberKind, opts,
|
||||
newInt64AsyncRunner(callback)))
|
||||
}
|
||||
|
||||
// RegisterFloat64Observer creates a new floating point Observer with
|
||||
// RegisterFloat64ValueObserver creates a new floating point ValueObserver 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) {
|
||||
func (m Meter) RegisterFloat64ValueObserver(name string, callback Float64ObserverCallback, opts ...Option) (Float64ValueObserver, error) {
|
||||
if callback == nil {
|
||||
return wrapFloat64ObserverInstrument(NoopAsync{}, nil)
|
||||
return wrapFloat64ValueObserverInstrument(NoopAsync{}, nil)
|
||||
}
|
||||
return wrapFloat64ObserverInstrument(
|
||||
m.newAsync(name, ObserverKind, Float64NumberKind, opts,
|
||||
return wrapFloat64ValueObserverInstrument(
|
||||
m.newAsync(name, ValueObserverKind, Float64NumberKind, opts,
|
||||
newFloat64AsyncRunner(callback)))
|
||||
}
|
||||
|
||||
// RegisterInt64Observer creates a new integer Observer instrument
|
||||
// RegisterInt64ValueObserver creates a new integer ValueObserver 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) {
|
||||
func (b BatchObserver) RegisterInt64ValueObserver(name string, opts ...Option) (Int64ValueObserver, error) {
|
||||
if b.runner == nil {
|
||||
return wrapInt64ObserverInstrument(NoopAsync{}, nil)
|
||||
return wrapInt64ValueObserverInstrument(NoopAsync{}, nil)
|
||||
}
|
||||
return wrapInt64ObserverInstrument(
|
||||
b.meter.newAsync(name, ObserverKind, Int64NumberKind, opts, b.runner))
|
||||
return wrapInt64ValueObserverInstrument(
|
||||
b.meter.newAsync(name, ValueObserverKind, Int64NumberKind, opts, b.runner))
|
||||
}
|
||||
|
||||
// RegisterFloat64Observer creates a new floating point Observer with
|
||||
// RegisterFloat64ValueObserver creates a new floating point ValueObserver 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) {
|
||||
func (b BatchObserver) RegisterFloat64ValueObserver(name string, opts ...Option) (Float64ValueObserver, error) {
|
||||
if b.runner == nil {
|
||||
return wrapFloat64ObserverInstrument(NoopAsync{}, nil)
|
||||
return wrapFloat64ValueObserverInstrument(NoopAsync{}, nil)
|
||||
}
|
||||
return wrapFloat64ObserverInstrument(
|
||||
b.meter.newAsync(name, ObserverKind, Float64NumberKind, opts,
|
||||
return wrapFloat64ValueObserverInstrument(
|
||||
b.meter.newAsync(name, ValueObserverKind, Float64NumberKind, opts,
|
||||
b.runner))
|
||||
}
|
||||
|
||||
|
||||
+18
-18
@@ -53,40 +53,40 @@ func (mm MeterMust) NewFloat64Counter(name string, cos ...Option) Float64Counter
|
||||
}
|
||||
}
|
||||
|
||||
// NewInt64Measure calls `Meter.NewInt64Measure` and returns the
|
||||
// NewInt64ValueRecorder calls `Meter.NewInt64ValueRecorder` and returns the
|
||||
// instrument, panicking if it encounters an error.
|
||||
func (mm MeterMust) NewInt64Measure(name string, mos ...Option) Int64Measure {
|
||||
if inst, err := mm.meter.NewInt64Measure(name, mos...); err != nil {
|
||||
func (mm MeterMust) NewInt64ValueRecorder(name string, mos ...Option) Int64ValueRecorder {
|
||||
if inst, err := mm.meter.NewInt64ValueRecorder(name, mos...); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
return inst
|
||||
}
|
||||
}
|
||||
|
||||
// NewFloat64Measure calls `Meter.NewFloat64Measure` and returns the
|
||||
// NewFloat64ValueRecorder calls `Meter.NewFloat64ValueRecorder` and returns the
|
||||
// instrument, panicking if it encounters an error.
|
||||
func (mm MeterMust) NewFloat64Measure(name string, mos ...Option) Float64Measure {
|
||||
if inst, err := mm.meter.NewFloat64Measure(name, mos...); err != nil {
|
||||
func (mm MeterMust) NewFloat64ValueRecorder(name string, mos ...Option) Float64ValueRecorder {
|
||||
if inst, err := mm.meter.NewFloat64ValueRecorder(name, mos...); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
return inst
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterInt64Observer calls `Meter.RegisterInt64Observer` and
|
||||
// RegisterInt64ValueObserver calls `Meter.RegisterInt64ValueObserver` and
|
||||
// returns the instrument, panicking if it encounters an error.
|
||||
func (mm MeterMust) RegisterInt64Observer(name string, callback Int64ObserverCallback, oos ...Option) Int64Observer {
|
||||
if inst, err := mm.meter.RegisterInt64Observer(name, callback, oos...); err != nil {
|
||||
func (mm MeterMust) RegisterInt64ValueObserver(name string, callback Int64ObserverCallback, oos ...Option) Int64ValueObserver {
|
||||
if inst, err := mm.meter.RegisterInt64ValueObserver(name, callback, oos...); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
return inst
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterFloat64Observer calls `Meter.RegisterFloat64Observer` and
|
||||
// RegisterFloat64ValueObserver calls `Meter.RegisterFloat64ValueObserver` and
|
||||
// returns the instrument, panicking if it encounters an error.
|
||||
func (mm MeterMust) RegisterFloat64Observer(name string, callback Float64ObserverCallback, oos ...Option) Float64Observer {
|
||||
if inst, err := mm.meter.RegisterFloat64Observer(name, callback, oos...); err != nil {
|
||||
func (mm MeterMust) RegisterFloat64ValueObserver(name string, callback Float64ObserverCallback, oos ...Option) Float64ValueObserver {
|
||||
if inst, err := mm.meter.RegisterFloat64ValueObserver(name, callback, oos...); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
return inst
|
||||
@@ -101,20 +101,20 @@ func (mm MeterMust) NewBatchObserver(callback BatchObserverCallback) BatchObserv
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterInt64Observer calls `BatchObserver.RegisterInt64Observer` and
|
||||
// RegisterInt64ValueObserver calls `BatchObserver.RegisterInt64ValueObserver` 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 {
|
||||
func (bm BatchObserverMust) RegisterInt64ValueObserver(name string, oos ...Option) Int64ValueObserver {
|
||||
if inst, err := bm.batch.RegisterInt64ValueObserver(name, oos...); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
return inst
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterFloat64Observer calls `BatchObserver.RegisterFloat64Observer` and
|
||||
// RegisterFloat64ValueObserver calls `BatchObserver.RegisterFloat64ValueObserver` 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 {
|
||||
func (bm BatchObserverMust) RegisterFloat64ValueObserver(name string, oos ...Option) Float64ValueObserver {
|
||||
if inst, err := bm.batch.RegisterFloat64ValueObserver(name, oos...); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
return inst
|
||||
|
||||
@@ -21,15 +21,15 @@ type BatchObserver struct {
|
||||
runner AsyncBatchRunner
|
||||
}
|
||||
|
||||
// Int64Observer is a metric that captures a set of int64 values at a
|
||||
// Int64ValueObserver is a metric that captures a set of int64 values at a
|
||||
// point in time.
|
||||
type Int64Observer struct {
|
||||
type Int64ValueObserver struct {
|
||||
asyncInstrument
|
||||
}
|
||||
|
||||
// Float64Observer is a metric that captures a set of float64 values
|
||||
// Float64ValueObserver is a metric that captures a set of float64 values
|
||||
// at a point in time.
|
||||
type Float64Observer struct {
|
||||
type Float64ValueObserver struct {
|
||||
asyncInstrument
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ type Float64Observer struct {
|
||||
// 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 {
|
||||
func (i Int64ValueObserver) Observation(v int64) Observation {
|
||||
return Observation{
|
||||
number: NewInt64Number(v),
|
||||
instrument: i.instrument,
|
||||
@@ -48,7 +48,7 @@ func (i Int64Observer) Observation(v int64) Observation {
|
||||
// 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 {
|
||||
func (f Float64ValueObserver) Observation(v float64) Observation {
|
||||
return Observation{
|
||||
number: NewFloat64Number(v),
|
||||
instrument: f.instrument,
|
||||
|
||||
@@ -23,6 +23,13 @@ import (
|
||||
"go.opentelemetry.io/otel/api/metric"
|
||||
)
|
||||
|
||||
// Provider is a standard metric.Provider for wrapping `MeterImpl`
|
||||
type Provider struct {
|
||||
impl metric.MeterImpl
|
||||
}
|
||||
|
||||
var _ metric.Provider = (*Provider)(nil)
|
||||
|
||||
// uniqueInstrumentMeterImpl implements the metric.MeterImpl interface, adding
|
||||
// uniqueness checking for instrument descriptors. Use NewUniqueInstrumentMeter
|
||||
// to wrap an implementation with uniqueness checking.
|
||||
@@ -39,6 +46,19 @@ type key struct {
|
||||
libraryName string
|
||||
}
|
||||
|
||||
// NewProvider returns a new provider that implements instrument
|
||||
// name-uniqueness checking.
|
||||
func NewProvider(impl metric.MeterImpl) *Provider {
|
||||
return &Provider{
|
||||
impl: NewUniqueInstrumentMeterImpl(impl),
|
||||
}
|
||||
}
|
||||
|
||||
// Meter implements metric.Provider.
|
||||
func (p *Provider) Meter(name string) metric.Meter {
|
||||
return metric.WrapMeterImpl(p.impl, name)
|
||||
}
|
||||
|
||||
// ErrMetricKindMismatch is the standard error for mismatched metric
|
||||
// instrument definitions.
|
||||
var ErrMetricKindMismatch = fmt.Errorf(
|
||||
|
||||
@@ -37,17 +37,17 @@ var (
|
||||
"counter.float64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(m.NewFloat64Counter(name))
|
||||
},
|
||||
"measure.int64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(m.NewInt64Measure(name))
|
||||
"valuerecorder.int64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(m.NewInt64ValueRecorder(name))
|
||||
},
|
||||
"measure.float64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(m.NewFloat64Measure(name))
|
||||
"valuerecorder.float64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(m.NewFloat64ValueRecorder(name))
|
||||
},
|
||||
"observer.int64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(m.RegisterInt64Observer(name, func(metric.Int64ObserverResult) {}))
|
||||
"valueobserver.int64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(m.RegisterInt64ValueObserver(name, func(metric.Int64ObserverResult) {}))
|
||||
},
|
||||
"observer.float64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(m.RegisterFloat64Observer(name, func(metric.Float64ObserverResult) {}))
|
||||
"valueobserver.float64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) {
|
||||
return unwrap(m.RegisterFloat64ValueObserver(name, func(metric.Float64ObserverResult) {}))
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -118,3 +118,14 @@ func TestRegistryDiffInstruments(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider(t *testing.T) {
|
||||
impl, _ := mockTest.NewMeter()
|
||||
p := registry.NewProvider(impl)
|
||||
m1 := p.Meter("m1")
|
||||
m1p := p.Meter("m1")
|
||||
m2 := p.Meter("m2")
|
||||
|
||||
require.Equal(t, m1, m1p)
|
||||
require.NotEqual(t, m1, m2)
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ type InstrumentImpl interface {
|
||||
}
|
||||
|
||||
// SyncImpl is the implementation-level interface to a generic
|
||||
// synchronous instrument (e.g., Measure and Counter instruments).
|
||||
// synchronous instrument (e.g., ValueRecorder and Counter instruments).
|
||||
type SyncImpl interface {
|
||||
InstrumentImpl
|
||||
|
||||
|
||||
+6
-24
@@ -174,38 +174,20 @@ func wrapFloat64CounterInstrument(syncInst SyncImpl, err error) (Float64Counter,
|
||||
return Float64Counter{syncInstrument: common}, err
|
||||
}
|
||||
|
||||
// wrapInt64MeasureInstrument returns an `Int64Measure` from a
|
||||
// wrapInt64ValueRecorderInstrument returns an `Int64ValueRecorder` 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) {
|
||||
func wrapInt64ValueRecorderInstrument(syncInst SyncImpl, err error) (Int64ValueRecorder, error) {
|
||||
common, err := checkNewSync(syncInst, err)
|
||||
return Int64Measure{syncInstrument: common}, err
|
||||
return Int64ValueRecorder{syncInstrument: common}, err
|
||||
}
|
||||
|
||||
// wrapFloat64MeasureInstrument returns an `Float64Measure` from a
|
||||
// wrapFloat64ValueRecorderInstrument returns an `Float64ValueRecorder` 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) {
|
||||
func wrapFloat64ValueRecorderInstrument(syncInst SyncImpl, err error) (Float64ValueRecorder, 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
|
||||
return Float64ValueRecorder{syncInstrument: common}, err
|
||||
}
|
||||
|
||||
@@ -20,78 +20,78 @@ import (
|
||||
"go.opentelemetry.io/otel/api/kv"
|
||||
)
|
||||
|
||||
// Float64Measure is a metric that records float64 values.
|
||||
type Float64Measure struct {
|
||||
// Float64ValueRecorder is a metric that records float64 values.
|
||||
type Float64ValueRecorder struct {
|
||||
syncInstrument
|
||||
}
|
||||
|
||||
// Int64Measure is a metric that records int64 values.
|
||||
type Int64Measure struct {
|
||||
// Int64ValueRecorder is a metric that records int64 values.
|
||||
type Int64ValueRecorder struct {
|
||||
syncInstrument
|
||||
}
|
||||
|
||||
// BoundFloat64Measure is a bound instrument for Float64Measure.
|
||||
// BoundFloat64ValueRecorder is a bound instrument for Float64ValueRecorder.
|
||||
//
|
||||
// It inherits the Unbind function from syncBoundInstrument.
|
||||
type BoundFloat64Measure struct {
|
||||
type BoundFloat64ValueRecorder struct {
|
||||
syncBoundInstrument
|
||||
}
|
||||
|
||||
// BoundInt64Measure is a bound instrument for Int64Measure.
|
||||
// BoundInt64ValueRecorder is a bound instrument for Int64ValueRecorder.
|
||||
//
|
||||
// It inherits the Unbind function from syncBoundInstrument.
|
||||
type BoundInt64Measure struct {
|
||||
type BoundInt64ValueRecorder struct {
|
||||
syncBoundInstrument
|
||||
}
|
||||
|
||||
// Bind creates a bound instrument for this measure. The labels are
|
||||
// Bind creates a bound instrument for this ValueRecorder. The labels are
|
||||
// associated with values recorded via subsequent calls to Record.
|
||||
func (c Float64Measure) Bind(labels ...kv.KeyValue) (h BoundFloat64Measure) {
|
||||
func (c Float64ValueRecorder) Bind(labels ...kv.KeyValue) (h BoundFloat64ValueRecorder) {
|
||||
h.syncBoundInstrument = c.bind(labels)
|
||||
return
|
||||
}
|
||||
|
||||
// Bind creates a bound instrument for this measure. The labels are
|
||||
// Bind creates a bound instrument for this ValueRecorder. The labels are
|
||||
// associated with values recorded via subsequent calls to Record.
|
||||
func (c Int64Measure) Bind(labels ...kv.KeyValue) (h BoundInt64Measure) {
|
||||
func (c Int64ValueRecorder) Bind(labels ...kv.KeyValue) (h BoundInt64ValueRecorder) {
|
||||
h.syncBoundInstrument = c.bind(labels)
|
||||
return
|
||||
}
|
||||
|
||||
// Measurement creates a Measurement object to use with batch
|
||||
// recording.
|
||||
func (c Float64Measure) Measurement(value float64) Measurement {
|
||||
func (c Float64ValueRecorder) Measurement(value float64) Measurement {
|
||||
return c.float64Measurement(value)
|
||||
}
|
||||
|
||||
// Measurement creates a Measurement object to use with batch
|
||||
// recording.
|
||||
func (c Int64Measure) Measurement(value int64) Measurement {
|
||||
func (c Int64ValueRecorder) Measurement(value int64) Measurement {
|
||||
return c.int64Measurement(value)
|
||||
}
|
||||
|
||||
// Record adds a new value to the list of measure's records. The
|
||||
// Record adds a new value to the list of ValueRecorder'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 ...kv.KeyValue) {
|
||||
func (c Float64ValueRecorder) 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
|
||||
// Record adds a new value to the ValueRecorder's distribution. The
|
||||
// labels should contain the keys and values to be associated with
|
||||
// this value.
|
||||
func (c Int64Measure) Record(ctx context.Context, value int64, labels ...kv.KeyValue) {
|
||||
func (c Int64ValueRecorder) 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) {
|
||||
// Record adds a new value to the ValueRecorder's distribution using the labels
|
||||
// previously bound to the ValueRecorder via Bind().
|
||||
func (b BoundFloat64ValueRecorder) Record(ctx context.Context, value float64) {
|
||||
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) {
|
||||
// Record adds a new value to the ValueRecorder's distribution using the labels
|
||||
// previously bound to the ValueRecorder via Bind().
|
||||
func (b BoundInt64ValueRecorder) Record(ctx context.Context, value int64) {
|
||||
b.directRecord(ctx, NewInt64Number(value))
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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 standard contains keys and values that have been standardized for
|
||||
// use in OpenTelemetry. These standardizations are specified in the
|
||||
// OpenTelemetry specification:
|
||||
//
|
||||
// - https://github.com/open-telemetry/opentelemetry-specification/tree/v0.4.0/specification/resource/semantic_conventions
|
||||
// - https://github.com/open-telemetry/opentelemetry-specification/tree/v0.4.0/specification/trace/semantic_conventions
|
||||
// - https://github.com/open-telemetry/opentelemetry-specification/tree/v0.4.0/specification/metrics/semantic_conventions
|
||||
package standard
|
||||
@@ -0,0 +1,152 @@
|
||||
// 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 standard // import "go.opentelemetry.io/otel/api/standard"
|
||||
|
||||
import "go.opentelemetry.io/otel/api/kv"
|
||||
|
||||
// Standard service resource attribute keys.
|
||||
const (
|
||||
// Name of the service.
|
||||
ServiceNameKey = kv.Key("service.name")
|
||||
|
||||
// A namespace for `service.name`. This needs to have meaning that helps
|
||||
// to distinguish a group of services. For example, the team name that
|
||||
// owns a group of services. `service.name` is expected to be unique
|
||||
// within the same namespace.
|
||||
ServiceNamespaceKey = kv.Key("service.namespace")
|
||||
|
||||
// A unique identifier of the service instance. In conjunction with the
|
||||
// `service.name` and `service.namespace` this must be unique.
|
||||
ServiceInstanceIDKey = kv.Key("service.instance.id")
|
||||
|
||||
// The version of the service API.
|
||||
ServiceVersionKey = kv.Key("service.version")
|
||||
)
|
||||
|
||||
// Standard telemetry SDK resource attribute keys.
|
||||
const (
|
||||
// The name of the telemetry SDK.
|
||||
//
|
||||
// The default OpenTelemetry SDK provided by the OpenTelemetry project
|
||||
// MUST set telemetry.sdk.name to the value `opentelemetry`.
|
||||
//
|
||||
// If another SDK is used, this attribute MUST be set to the import path
|
||||
// of that SDK's package.
|
||||
//
|
||||
// The value `opentelemetry` is reserved and MUST NOT be used by
|
||||
// non-OpenTelemetry SDKs.
|
||||
TelemetrySDKNameKey = kv.Key("telemetry.sdk.name")
|
||||
|
||||
// The language of the telemetry SDK.
|
||||
TelemetrySDKLanguageKey = kv.Key("telemetry.sdk.language")
|
||||
|
||||
// The version string of the telemetry SDK.
|
||||
TelemetrySDKVersionKey = kv.Key("telemetry.sdk.version")
|
||||
)
|
||||
|
||||
// Standard telemetry SDK resource attributes.
|
||||
var (
|
||||
TelemetrySDKLanguageGo = TelemetrySDKLanguageKey.String("go")
|
||||
)
|
||||
|
||||
// Standard container resource attribute keys.
|
||||
const (
|
||||
// A uniquely identifying name for the Container.
|
||||
ContainerNameKey = kv.Key("container.name")
|
||||
|
||||
// Name of the image the container was built on.
|
||||
ContainerImageNameKey = kv.Key("container.image.name")
|
||||
|
||||
// Container image tag.
|
||||
ContainerImageTagKey = kv.Key("container.image.tag")
|
||||
)
|
||||
|
||||
// Standard Function-as-a-Service resource attribute keys.
|
||||
const (
|
||||
// A uniquely identifying name for the FaaS.
|
||||
FaaSName = kv.Key("faas.name")
|
||||
|
||||
// The unique name of the function being executed.
|
||||
FaaSID = kv.Key("faas.id")
|
||||
|
||||
// The version of the function being executed.
|
||||
FaaSVersion = kv.Key("faas.version")
|
||||
|
||||
// The execution environment identifier.
|
||||
FaaSInstance = kv.Key("faas.instance")
|
||||
)
|
||||
|
||||
// Standard Kubernetes resource attribute keys.
|
||||
const (
|
||||
// A uniquely identifying name for the Kubernetes cluster. Kubernetes
|
||||
// does not have cluster names as an internal concept so this may be
|
||||
// set to any meaningful value within the environment. For example,
|
||||
// GKE clusters have a name which can be used for this label.
|
||||
K8SClusterNameKey = kv.Key("k8s.cluster.name")
|
||||
|
||||
// The name of the namespace that the pod is running in.
|
||||
K8SNamespaceNameKey = kv.Key("k8s.namespace.name")
|
||||
|
||||
// The name of the pod.
|
||||
K8SPodNameKey = kv.Key("k8s.pod.name")
|
||||
|
||||
// The name of the deployment.
|
||||
K8SDeploymentNameKey = kv.Key("k8s.deployment.name")
|
||||
)
|
||||
|
||||
// Standard host resource attribute keys.
|
||||
const (
|
||||
// A uniquely identifying name for the host.
|
||||
HostNameKey = kv.Key("host.name")
|
||||
|
||||
// A hostname as returned by the 'hostname' command on host machine.
|
||||
HostHostNameKey = kv.Key("host.hostname")
|
||||
|
||||
// Unique host ID. For cloud environments this will be the instance ID.
|
||||
HostIDKey = kv.Key("host.id")
|
||||
|
||||
// Type of host. For cloud environments this will be the machine type.
|
||||
HostTypeKey = kv.Key("host.type")
|
||||
|
||||
// Name of the OS or VM image the host is running.
|
||||
HostImageNameKey = kv.Key("host.image.name")
|
||||
|
||||
// Identifier of the image the host is running.
|
||||
HostImageIDKey = kv.Key("host.image.id")
|
||||
|
||||
// Version of the image the host is running.
|
||||
HostImageVersionKey = kv.Key("host.image.version")
|
||||
)
|
||||
|
||||
// Standard cloud environment resource attribute keys.
|
||||
const (
|
||||
// Name of the cloud provider.
|
||||
CloudProviderKey = kv.Key("cloud.provider")
|
||||
|
||||
// The account ID from the cloud provider used for authorization.
|
||||
CloudAccountIDKey = kv.Key("cloud.account.id")
|
||||
|
||||
// Geographical region where this resource is.
|
||||
CloudRegionKey = kv.Key("cloud.region")
|
||||
|
||||
// Zone of the region where this resource is.
|
||||
CloudZoneKey = kv.Key("cloud.zone")
|
||||
)
|
||||
|
||||
var (
|
||||
CloudProviderAWS = CloudProviderKey.String("aws")
|
||||
CloudProviderAzure = CloudProviderKey.String("azure")
|
||||
CloudProviderGCP = CloudProviderKey.String("gcp")
|
||||
)
|
||||
@@ -0,0 +1,262 @@
|
||||
// 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 standard
|
||||
|
||||
import "go.opentelemetry.io/otel/api/kv"
|
||||
|
||||
// Standard attribute keys used for network related operations.
|
||||
const (
|
||||
// Transport protocol used.
|
||||
NetTransportKey = kv.Key("net.transport")
|
||||
|
||||
// Remote address of the peer.
|
||||
NetPeerIPKey = kv.Key("net.peer.ip")
|
||||
|
||||
// Remote port number.
|
||||
NetPeerPortKey = kv.Key("net.peer.port")
|
||||
|
||||
// Remote hostname or similar.
|
||||
NetPeerNameKey = kv.Key("net.peer.name")
|
||||
|
||||
// Local host IP. Useful in case of a multi-IP host.
|
||||
NetHostIPKey = kv.Key("net.host.ip")
|
||||
|
||||
// Local host port.
|
||||
NetHostPortKey = kv.Key("net.host.port")
|
||||
|
||||
// Local hostname or similar.
|
||||
NetHostNameKey = kv.Key("net.host.name")
|
||||
)
|
||||
|
||||
var (
|
||||
NetTransportTCP = NetTransportKey.String("IP.TCP")
|
||||
NetTransportUDP = NetTransportKey.String("IP.UDP")
|
||||
NetTransportIP = NetTransportKey.String("IP")
|
||||
NetTransportUnix = NetTransportKey.String("Unix")
|
||||
NetTransportPipe = NetTransportKey.String("pipe")
|
||||
NetTransportInProc = NetTransportKey.String("inproc")
|
||||
NetTransportOther = NetTransportKey.String("other")
|
||||
)
|
||||
|
||||
// Standard attribute keys used to identify an authorized enduser.
|
||||
const (
|
||||
// Username or the client identifier extracted from the access token or
|
||||
// authorization header in the inbound request from outside the system.
|
||||
EnduserIDKey = kv.Key("enduser.id")
|
||||
|
||||
// Actual or assumed role the client is making the request with.
|
||||
EnduserRoleKey = kv.Key("enduser.role")
|
||||
|
||||
// Scopes or granted authorities the client currently possesses.
|
||||
EnduserScopeKey = kv.Key("enduser.scope")
|
||||
)
|
||||
|
||||
// Standard attribute keys for HTTP.
|
||||
const (
|
||||
// HTTP request method.
|
||||
HTTPMethodKey = kv.Key("http.method")
|
||||
|
||||
// Full HTTP request URL in the form:
|
||||
// scheme://host[:port]/path?query[#fragment].
|
||||
HTTPUrlKey = kv.Key("http.url")
|
||||
|
||||
// The full request target as passed in a HTTP request line or
|
||||
// equivalent, e.g. "/path/12314/?q=ddds#123".
|
||||
HTTPTargetKey = kv.Key("http.target")
|
||||
|
||||
// The value of the HTTP host header.
|
||||
HTTPHostKey = kv.Key("http.host")
|
||||
|
||||
// The URI scheme identifying the used protocol.
|
||||
HTTPSchemeKey = kv.Key("http.scheme")
|
||||
|
||||
// HTTP response status code.
|
||||
HTTPStatusCodeKey = kv.Key("http.status_code")
|
||||
|
||||
// HTTP reason phrase.
|
||||
HTTPStatusTextKey = kv.Key("http.status_text")
|
||||
|
||||
// Kind of HTTP protocol used.
|
||||
HTTPFlavorKey = kv.Key("http.flavor")
|
||||
|
||||
// Value of the HTTP User-Agent header sent by the client.
|
||||
HTTPUserAgentKey = kv.Key("http.user_agent")
|
||||
|
||||
// The primary server name of the matched virtual host.
|
||||
HTTPServerNameKey = kv.Key("http.server_name")
|
||||
|
||||
// The matched route served (path template). For example,
|
||||
// "/users/:userID?".
|
||||
HTTPRouteKey = kv.Key("http.route")
|
||||
|
||||
// The IP address of the original client behind all proxies, if known
|
||||
// (e.g. from X-Forwarded-For).
|
||||
HTTPClientIPKey = kv.Key("http.client_ip")
|
||||
)
|
||||
|
||||
var (
|
||||
HTTPSchemeHTTP = HTTPSchemeKey.String("http")
|
||||
HTTPSchemeHTTPS = HTTPSchemeKey.String("https")
|
||||
|
||||
HTTPFlavor1_0 = HTTPFlavorKey.String("1.0")
|
||||
HTTPFlavor1_1 = HTTPFlavorKey.String("1.1")
|
||||
HTTPFlavor2 = HTTPFlavorKey.String("2")
|
||||
HTTPFlavorSPDY = HTTPFlavorKey.String("SPDY")
|
||||
HTTPFlavorQUIC = HTTPFlavorKey.String("QUIC")
|
||||
)
|
||||
|
||||
// Standard attribute keys for database clients.
|
||||
const (
|
||||
// Database type. For any SQL database, "sql". For others, the
|
||||
// lower-case database category, e.g. "cassandra", "hbase", or "redis".
|
||||
DBTypeKey = kv.Key("db.type")
|
||||
|
||||
// Database instance name.
|
||||
DBInstanceKey = kv.Key("db.instance")
|
||||
|
||||
// A database statement for the given database type.
|
||||
DBStatementKey = kv.Key("db.statement")
|
||||
|
||||
// Username for accessing database.
|
||||
DBUserKey = kv.Key("db.user")
|
||||
|
||||
// Database URL.
|
||||
DBUrlKey = kv.Key("db.url")
|
||||
)
|
||||
|
||||
// Standard attribute keys for RPC.
|
||||
const (
|
||||
// The RPC service name.
|
||||
RPCServiceKey = kv.Key("rpc.service")
|
||||
|
||||
// Name of message transmitted or received.
|
||||
RPCNameKey = kv.Key("name")
|
||||
|
||||
// Type of message transmitted or received.
|
||||
RPCMessageTypeKey = kv.Key("message.type")
|
||||
|
||||
// Identifier of message transmitted or received.
|
||||
RPCMessageIDKey = kv.Key("message.id")
|
||||
|
||||
// The compressed size of the message transmitted or received in bytes.
|
||||
RPCMessageCompressedSizeKey = kv.Key("message.compressed_size")
|
||||
|
||||
// The uncompressed size of the message transmitted or received in
|
||||
// bytes.
|
||||
RPCMessageUncompressedSizeKey = kv.Key("message.uncompressed_size")
|
||||
)
|
||||
|
||||
var (
|
||||
RPCNameMessage = RPCNameKey.String("message")
|
||||
|
||||
RPCMessageTypeSent = RPCMessageTypeKey.String("SENT")
|
||||
RPCMessageTypeReceived = RPCMessageTypeKey.String("RECEIVED")
|
||||
)
|
||||
|
||||
// Standard attribute keys for messaging systems.
|
||||
const (
|
||||
// A unique identifier describing the messaging system. For example,
|
||||
// kafka, rabbitmq or activemq.
|
||||
MessagingSystemKey = kv.Key("messaging.system")
|
||||
|
||||
// The message destination name, e.g. MyQueue or MyTopic.
|
||||
MessagingDestinationKey = kv.Key("messaging.destination")
|
||||
|
||||
// The kind of message destination.
|
||||
MessagingDestinationKindKey = kv.Key("messaging.destination_kind")
|
||||
|
||||
// Describes if the destination is temporary or not.
|
||||
MessagingTempDestinationKey = kv.Key("messaging.temp_destination")
|
||||
|
||||
// The name of the transport protocol.
|
||||
MessagingProtocolKey = kv.Key("messaging.protocol")
|
||||
|
||||
// The version of the transport protocol.
|
||||
MessagingProtocolVersionKey = kv.Key("messaging.protocol_version")
|
||||
|
||||
// Messaging service URL.
|
||||
MessagingURLKey = kv.Key("messaging.url")
|
||||
|
||||
// Identifier used by the messaging system for a message.
|
||||
MessagingMessageIDKey = kv.Key("messaging.message_id")
|
||||
|
||||
// Identifier used by the messaging system for a conversation.
|
||||
MessagingConversationIDKey = kv.Key("messaging.conversation_id")
|
||||
|
||||
// The (uncompressed) size of the message payload in bytes.
|
||||
MessagingMessagePayloadSizeBytesKey = kv.Key("messaging.message_payload_size_bytes")
|
||||
|
||||
// The compressed size of the message payload in bytes.
|
||||
MessagingMessagePayloadCompressedSizeBytesKey = kv.Key("messaging.message_payload_compressed_size_bytes")
|
||||
|
||||
// Identifies which part and kind of message consumption is being
|
||||
// preformed.
|
||||
MessagingOperationKey = kv.Key("messaging.operation")
|
||||
|
||||
// RabbitMQ specific attribute describing the destination routing key.
|
||||
MessagingRabbitMQRoutingKeyKey = kv.Key("messaging.rabbitmq.routing_key")
|
||||
)
|
||||
|
||||
var (
|
||||
MessagingDestinationKindKeyQueue = MessagingDestinationKindKey.String("queue")
|
||||
MessagingDestinationKindKeyTopic = MessagingDestinationKindKey.String("topic")
|
||||
|
||||
MessagingTempDestination = MessagingTempDestinationKey.Bool(true)
|
||||
|
||||
MessagingOperationReceive = MessagingOperationKey.String("receive")
|
||||
MessagingOperationProcess = MessagingOperationKey.String("process")
|
||||
)
|
||||
|
||||
// Standard attribute keys for FaaS systems.
|
||||
const (
|
||||
|
||||
// Type of the trigger on which the function is executed.
|
||||
FaaSTriggerKey = kv.Key("faas.trigger")
|
||||
|
||||
// String containing the execution identifier of the function.
|
||||
FaaSExecutionKey = kv.Key("faas.execution")
|
||||
|
||||
// The name of the source on which the operation was performed.
|
||||
// For example, in Cloud Storage or S3 corresponds to the bucket name,
|
||||
// and in Cosmos DB to the database name.
|
||||
FaaSDocumentCollectionKey = kv.Key("faas.document.collection")
|
||||
|
||||
// The type of the operation that was performed on the data.
|
||||
FaaSDocumentOperationKey = kv.Key("faas.document.operation")
|
||||
|
||||
// A string containing the time when the data was accessed.
|
||||
FaaSDocumentTimeKey = kv.Key("faas.document.time")
|
||||
|
||||
// The document name/table subjected to the operation.
|
||||
FaaSDocumentNameKey = kv.Key("faas.document.name")
|
||||
|
||||
// The function invocation time.
|
||||
FaaSTimeKey = kv.Key("faas.time")
|
||||
|
||||
// The schedule period as Cron Expression.
|
||||
FaaSCronKey = kv.Key("faas.cron")
|
||||
)
|
||||
|
||||
var (
|
||||
FaasTriggerDatasource = FaaSTriggerKey.String("datasource")
|
||||
FaasTriggerHTTP = FaaSTriggerKey.String("http")
|
||||
FaasTriggerPubSub = FaaSTriggerKey.String("pubsub")
|
||||
FaasTriggerTimer = FaaSTriggerKey.String("timer")
|
||||
FaasTriggerOther = FaaSTriggerKey.String("other")
|
||||
|
||||
FaaSDocumentOperationInsert = FaaSDocumentOperationKey.String("insert")
|
||||
FaaSDocumentOperationEdit = FaaSDocumentOperationKey.String("edit")
|
||||
FaaSDocumentOperationDelete = FaaSDocumentOperationKey.String("delete")
|
||||
)
|
||||
@@ -76,11 +76,11 @@ func main() {
|
||||
oneMetricCB := func(result metric.Float64ObserverResult) {
|
||||
result.Observe(1, commonLabels...)
|
||||
}
|
||||
_ = metric.Must(meter).RegisterFloat64Observer("ex.com.one", oneMetricCB,
|
||||
metric.WithDescription("An observer set to 1.0"),
|
||||
_ = metric.Must(meter).RegisterFloat64ValueObserver("ex.com.one", oneMetricCB,
|
||||
metric.WithDescription("A ValueObserver set to 1.0"),
|
||||
)
|
||||
|
||||
measureTwo := metric.Must(meter).NewFloat64Measure("ex.com.two")
|
||||
valuerecorderTwo := metric.Must(meter).NewFloat64ValueRecorder("ex.com.two")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -89,8 +89,8 @@ func main() {
|
||||
barKey.String("bar1"),
|
||||
)
|
||||
|
||||
measure := measureTwo.Bind(commonLabels...)
|
||||
defer measure.Unbind()
|
||||
valuerecorder := valuerecorderTwo.Bind(commonLabels...)
|
||||
defer valuerecorder.Unbind()
|
||||
|
||||
err := tracer.WithSpan(ctx, "operation", func(ctx context.Context) error {
|
||||
|
||||
@@ -103,7 +103,7 @@ func main() {
|
||||
correlation.NewContext(ctx, anotherKey.String("xyz")),
|
||||
commonLabels,
|
||||
|
||||
measureTwo.Measurement(2.0),
|
||||
valuerecorderTwo.Measurement(2.0),
|
||||
)
|
||||
|
||||
return tracer.WithSpan(
|
||||
@@ -114,7 +114,7 @@ func main() {
|
||||
|
||||
trace.SpanFromContext(ctx).AddEvent(ctx, "Sub span event")
|
||||
|
||||
measure.Record(ctx, 1.3)
|
||||
valuerecorder.Record(ctx, 1.3)
|
||||
|
||||
return nil
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# 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.
|
||||
FROM golang:alpine AS base
|
||||
FROM golang:1.14-alpine AS base
|
||||
COPY . /go/src/github.com/open-telemetry/opentelemetry-go/
|
||||
WORKDIR /go/src/github.com/open-telemetry/opentelemetry-go/example/http/
|
||||
|
||||
|
||||
+10
-10
@@ -59,12 +59,12 @@ func main() {
|
||||
(*observerLock).RUnlock()
|
||||
result.Observe(value, labels...)
|
||||
}
|
||||
_ = metric.Must(meter).RegisterFloat64Observer("ex.com.one", cb,
|
||||
metric.WithDescription("A measure set to 1.0"),
|
||||
_ = metric.Must(meter).RegisterFloat64ValueObserver("ex.com.one", cb,
|
||||
metric.WithDescription("A ValueObserver set to 1.0"),
|
||||
)
|
||||
|
||||
measureTwo := metric.Must(meter).NewFloat64Measure("ex.com.two")
|
||||
measureThree := metric.Must(meter).NewFloat64Counter("ex.com.three")
|
||||
valuerecorder := metric.Must(meter).NewFloat64ValueRecorder("ex.com.two")
|
||||
counter := metric.Must(meter).NewFloat64Counter("ex.com.three")
|
||||
|
||||
commonLabels := []kv.KeyValue{lemonsKey.Int(10), kv.String("A", "1"), kv.String("B", "2"), kv.String("C", "3")}
|
||||
notSoCommonLabels := []kv.KeyValue{lemonsKey.Int(13)}
|
||||
@@ -78,8 +78,8 @@ func main() {
|
||||
meter.RecordBatch(
|
||||
ctx,
|
||||
commonLabels,
|
||||
measureTwo.Measurement(2.0),
|
||||
measureThree.Measurement(12.0),
|
||||
valuerecorder.Measurement(2.0),
|
||||
counter.Measurement(12.0),
|
||||
)
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
@@ -91,8 +91,8 @@ func main() {
|
||||
meter.RecordBatch(
|
||||
ctx,
|
||||
notSoCommonLabels,
|
||||
measureTwo.Measurement(2.0),
|
||||
measureThree.Measurement(22.0),
|
||||
valuerecorder.Measurement(2.0),
|
||||
counter.Measurement(22.0),
|
||||
)
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
@@ -104,8 +104,8 @@ func main() {
|
||||
meter.RecordBatch(
|
||||
ctx,
|
||||
commonLabels,
|
||||
measureTwo.Measurement(12.0),
|
||||
measureThree.Measurement(13.0),
|
||||
valuerecorder.Measurement(12.0),
|
||||
counter.Measurement(13.0),
|
||||
)
|
||||
|
||||
time.Sleep(100 * time.Second)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# 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.
|
||||
FROM golang:alpine
|
||||
FROM golang:1.14-alpine
|
||||
COPY . /go/src/github.com/open-telemetry/opentelemetry-go/
|
||||
WORKDIR /go/src/github.com/open-telemetry/opentelemetry-go/example/zipkin/
|
||||
RUN go install ./main.go
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
// 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 prometheus_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
||||
"go.opentelemetry.io/otel/api/kv"
|
||||
"go.opentelemetry.io/otel/api/metric"
|
||||
"go.opentelemetry.io/otel/exporters/metric/prometheus"
|
||||
sdk "go.opentelemetry.io/otel/sdk/metric"
|
||||
integrator "go.opentelemetry.io/otel/sdk/metric/integrator/simple"
|
||||
"go.opentelemetry.io/otel/sdk/metric/selector/simple"
|
||||
)
|
||||
|
||||
// This test demonstrates that it is relatively difficult to setup a
|
||||
// Prometheus export pipeline:
|
||||
//
|
||||
// 1. The default boundaries are difficult to pass, should be []float instead of []metric.Number
|
||||
// 2. The push controller doesn't make sense b/c Prometheus is pull-bsaed
|
||||
//
|
||||
// TODO: Address these issues; add Resources to the test.
|
||||
|
||||
func ExampleNewExportPipeline() {
|
||||
// Create a meter
|
||||
selector := simple.NewWithHistogramDistribution(nil)
|
||||
exporter, err := prometheus.NewRawExporter(prometheus.Config{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
integrator := integrator.New(selector, true)
|
||||
meterImpl := sdk.NewAccumulator(integrator)
|
||||
meter := metric.WrapMeterImpl(meterImpl, "example")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Use two instruments
|
||||
counter := metric.Must(meter).NewInt64Counter(
|
||||
"a.counter",
|
||||
metric.WithDescription("Counts things"),
|
||||
)
|
||||
recorder := metric.Must(meter).NewInt64ValueRecorder(
|
||||
"a.valuerecorder",
|
||||
metric.WithDescription("Records values"),
|
||||
)
|
||||
|
||||
counter.Add(ctx, 100, kv.String("key", "value"))
|
||||
recorder.Record(ctx, 100, kv.String("key", "value"))
|
||||
|
||||
// Simulate a push
|
||||
meterImpl.Collect(ctx)
|
||||
err = exporter.Export(ctx, nil, integrator.CheckpointSet())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// GET the HTTP endpoint
|
||||
var input bytes.Buffer
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", &input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
exporter.ServeHTTP(resp, req)
|
||||
data, err := ioutil.ReadAll(resp.Result().Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Print(string(data))
|
||||
|
||||
// Output:
|
||||
// # HELP a_counter Counts things
|
||||
// # TYPE a_counter counter
|
||||
// a_counter{key="value"} 100
|
||||
// # HELP a_valuerecorder Records values
|
||||
// # TYPE a_valuerecorder histogram
|
||||
// a_valuerecorder_bucket{key="value",le="+Inf"} 1
|
||||
// a_valuerecorder_sum{key="value"} 100
|
||||
// a_valuerecorder_count{key="value"} 1
|
||||
}
|
||||
@@ -140,14 +140,14 @@ func InstallNewPipeline(config Config) (*push.Controller, http.HandlerFunc, erro
|
||||
if err != nil {
|
||||
return controller, hf, err
|
||||
}
|
||||
global.SetMeterProvider(controller)
|
||||
global.SetMeterProvider(controller.Provider())
|
||||
return controller, hf, err
|
||||
}
|
||||
|
||||
// NewExportPipeline sets up a complete export pipeline with the recommended setup,
|
||||
// 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)
|
||||
selector := simple.NewWithHistogramDistribution(config.DefaultHistogramBoundaries)
|
||||
exporter, err := NewRawExporter(config)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -220,7 +220,7 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
|
||||
}
|
||||
} else if dist, ok := agg.(aggregator.Distribution); ok {
|
||||
// TODO: summaries values are never being resetted.
|
||||
// As measures are recorded, new records starts to have less impact on these summaries.
|
||||
// As measurements are recorded, new records starts to have less impact on these summaries.
|
||||
// We should implement an solution that is similar to the Prometheus Clients
|
||||
// using a rolling window for summaries could be a solution.
|
||||
//
|
||||
|
||||
@@ -44,11 +44,11 @@ func TestPrometheusExporter(t *testing.T) {
|
||||
counter := metric.NewDescriptor(
|
||||
"counter", metric.CounterKind, metric.Float64NumberKind)
|
||||
lastValue := metric.NewDescriptor(
|
||||
"lastvalue", metric.ObserverKind, metric.Float64NumberKind)
|
||||
measure := metric.NewDescriptor(
|
||||
"measure", metric.MeasureKind, metric.Float64NumberKind)
|
||||
histogramMeasure := metric.NewDescriptor(
|
||||
"histogram_measure", metric.MeasureKind, metric.Float64NumberKind)
|
||||
"lastvalue", metric.ValueObserverKind, metric.Float64NumberKind)
|
||||
valuerecorder := metric.NewDescriptor(
|
||||
"valuerecorder", metric.ValueRecorderKind, metric.Float64NumberKind)
|
||||
histogramValueRecorder := metric.NewDescriptor(
|
||||
"histogram_valuerecorder", metric.ValueRecorderKind, metric.Float64NumberKind)
|
||||
|
||||
labels := []kv.KeyValue{
|
||||
kv.Key("A").String("B"),
|
||||
@@ -61,26 +61,26 @@ func TestPrometheusExporter(t *testing.T) {
|
||||
checkpointSet.AddLastValue(&lastValue, 13.2, labels...)
|
||||
expected = append(expected, `lastvalue{A="B",C="D"} 13.2`)
|
||||
|
||||
checkpointSet.AddMeasure(&measure, 13, labels...)
|
||||
checkpointSet.AddMeasure(&measure, 15, labels...)
|
||||
checkpointSet.AddMeasure(&measure, 17, labels...)
|
||||
expected = append(expected, `measure{A="B",C="D",quantile="0.5"} 15`)
|
||||
expected = append(expected, `measure{A="B",C="D",quantile="0.9"} 17`)
|
||||
expected = append(expected, `measure{A="B",C="D",quantile="0.99"} 17`)
|
||||
expected = append(expected, `measure_sum{A="B",C="D"} 45`)
|
||||
expected = append(expected, `measure_count{A="B",C="D"} 3`)
|
||||
checkpointSet.AddValueRecorder(&valuerecorder, 13, labels...)
|
||||
checkpointSet.AddValueRecorder(&valuerecorder, 15, labels...)
|
||||
checkpointSet.AddValueRecorder(&valuerecorder, 17, labels...)
|
||||
expected = append(expected, `valuerecorder{A="B",C="D",quantile="0.5"} 15`)
|
||||
expected = append(expected, `valuerecorder{A="B",C="D",quantile="0.9"} 17`)
|
||||
expected = append(expected, `valuerecorder{A="B",C="D",quantile="0.99"} 17`)
|
||||
expected = append(expected, `valuerecorder_sum{A="B",C="D"} 45`)
|
||||
expected = append(expected, `valuerecorder_count{A="B",C="D"} 3`)
|
||||
|
||||
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...)
|
||||
checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, 20, labels...)
|
||||
checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, -0.6, labels...)
|
||||
checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, -0.4, labels...)
|
||||
checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, 0.6, labels...)
|
||||
checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, 20, labels...)
|
||||
|
||||
expected = append(expected, `histogram_measure_bucket{A="B",C="D",le="+Inf"} 4`)
|
||||
expected = append(expected, `histogram_measure_bucket{A="B",C="D",le="-0.5"} 1`)
|
||||
expected = append(expected, `histogram_measure_bucket{A="B",C="D",le="1"} 3`)
|
||||
expected = append(expected, `histogram_measure_count{A="B",C="D"} 4`)
|
||||
expected = append(expected, `histogram_measure_sum{A="B",C="D"} 19.6`)
|
||||
expected = append(expected, `histogram_valuerecorder_bucket{A="B",C="D",le="+Inf"} 4`)
|
||||
expected = append(expected, `histogram_valuerecorder_bucket{A="B",C="D",le="-0.5"} 1`)
|
||||
expected = append(expected, `histogram_valuerecorder_bucket{A="B",C="D",le="1"} 3`)
|
||||
expected = append(expected, `histogram_valuerecorder_count{A="B",C="D"} 4`)
|
||||
expected = append(expected, `histogram_valuerecorder_sum{A="B",C="D"} 19.6`)
|
||||
|
||||
missingLabels := []kv.KeyValue{
|
||||
kv.Key("A").String("E"),
|
||||
@@ -93,25 +93,25 @@ func TestPrometheusExporter(t *testing.T) {
|
||||
checkpointSet.AddLastValue(&lastValue, 32, missingLabels...)
|
||||
expected = append(expected, `lastvalue{A="E",C=""} 32`)
|
||||
|
||||
checkpointSet.AddMeasure(&measure, 19, missingLabels...)
|
||||
expected = append(expected, `measure{A="E",C="",quantile="0.5"} 19`)
|
||||
expected = append(expected, `measure{A="E",C="",quantile="0.9"} 19`)
|
||||
expected = append(expected, `measure{A="E",C="",quantile="0.99"} 19`)
|
||||
expected = append(expected, `measure_count{A="E",C=""} 1`)
|
||||
expected = append(expected, `measure_sum{A="E",C=""} 19`)
|
||||
checkpointSet.AddValueRecorder(&valuerecorder, 19, missingLabels...)
|
||||
expected = append(expected, `valuerecorder{A="E",C="",quantile="0.5"} 19`)
|
||||
expected = append(expected, `valuerecorder{A="E",C="",quantile="0.9"} 19`)
|
||||
expected = append(expected, `valuerecorder{A="E",C="",quantile="0.99"} 19`)
|
||||
expected = append(expected, `valuerecorder_count{A="E",C=""} 1`)
|
||||
expected = append(expected, `valuerecorder_sum{A="E",C=""} 19`)
|
||||
|
||||
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...)
|
||||
checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, 15, missingLabels...)
|
||||
checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, 15, missingLabels...)
|
||||
checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, -0.6, missingLabels...)
|
||||
checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, -0.4, missingLabels...)
|
||||
checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, -0.1, missingLabels...)
|
||||
checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, 15, missingLabels...)
|
||||
checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, 15, missingLabels...)
|
||||
|
||||
expected = append(expected, `histogram_measure_bucket{A="E",C="",le="+Inf"} 5`)
|
||||
expected = append(expected, `histogram_measure_bucket{A="E",C="",le="0"} 3`)
|
||||
expected = append(expected, `histogram_measure_bucket{A="E",C="",le="1"} 3`)
|
||||
expected = append(expected, `histogram_measure_count{A="E",C=""} 5`)
|
||||
expected = append(expected, `histogram_measure_sum{A="E",C=""} 28.9`)
|
||||
expected = append(expected, `histogram_valuerecorder_bucket{A="E",C="",le="+Inf"} 5`)
|
||||
expected = append(expected, `histogram_valuerecorder_bucket{A="E",C="",le="0"} 3`)
|
||||
expected = append(expected, `histogram_valuerecorder_bucket{A="E",C="",le="1"} 3`)
|
||||
expected = append(expected, `histogram_valuerecorder_count{A="E",C=""} 5`)
|
||||
expected = append(expected, `histogram_valuerecorder_sum{A="E",C=""} 28.9`)
|
||||
|
||||
compareExport(t, exporter, checkpointSet, expected)
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func ExampleNewExportPipeline() {
|
||||
ctx := context.Background()
|
||||
|
||||
key := kv.Key("key")
|
||||
meter := pusher.Meter("example")
|
||||
meter := pusher.Provider().Meter("example")
|
||||
|
||||
// Create and update a single counter:
|
||||
counter := metric.Must(meter).NewInt64Counter("a.counter")
|
||||
|
||||
@@ -53,8 +53,8 @@ type Config struct {
|
||||
// useful to create deterministic test conditions.
|
||||
DoNotPrintTime bool
|
||||
|
||||
// Quantiles are the desired aggregation quantiles for measure
|
||||
// metric data, used when the configured aggregator supports
|
||||
// Quantiles are the desired aggregation quantiles for distribution
|
||||
// summaries, used when the configured aggregator supports
|
||||
// quantiles.
|
||||
//
|
||||
// Note: this exporter is meant as a demonstration; a real
|
||||
@@ -126,14 +126,14 @@ func InstallNewPipeline(config Config, opts ...push.Option) (*push.Controller, e
|
||||
if err != nil {
|
||||
return controller, err
|
||||
}
|
||||
global.SetMeterProvider(controller)
|
||||
global.SetMeterProvider(controller.Provider())
|
||||
return controller, err
|
||||
}
|
||||
|
||||
// NewExportPipeline sets up a complete export pipeline with the recommended setup,
|
||||
// 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()
|
||||
selector := simple.NewWithExactDistribution()
|
||||
exporter, err := NewRawExporter(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -98,7 +98,7 @@ func TestStdoutTimestamp(t *testing.T) {
|
||||
checkpointSet := test.NewCheckpointSet()
|
||||
|
||||
ctx := context.Background()
|
||||
desc := metric.NewDescriptor("test.name", metric.ObserverKind, metric.Int64NumberKind)
|
||||
desc := metric.NewDescriptor("test.name", metric.ValueObserverKind, metric.Int64NumberKind)
|
||||
lvagg := lastvalue.New()
|
||||
aggtest.CheckedUpdate(t, lvagg, metric.NewInt64Number(321), &desc)
|
||||
lvagg.Checkpoint(ctx, &desc)
|
||||
@@ -160,7 +160,7 @@ func TestStdoutLastValueFormat(t *testing.T) {
|
||||
|
||||
checkpointSet := test.NewCheckpointSet()
|
||||
|
||||
desc := metric.NewDescriptor("test.name", metric.ObserverKind, metric.Float64NumberKind)
|
||||
desc := metric.NewDescriptor("test.name", metric.ValueObserverKind, metric.Float64NumberKind)
|
||||
lvagg := lastvalue.New()
|
||||
aggtest.CheckedUpdate(fix.t, lvagg, metric.NewFloat64Number(123.456), &desc)
|
||||
lvagg.Checkpoint(fix.ctx, &desc)
|
||||
@@ -177,7 +177,7 @@ func TestStdoutMinMaxSumCount(t *testing.T) {
|
||||
|
||||
checkpointSet := test.NewCheckpointSet()
|
||||
|
||||
desc := metric.NewDescriptor("test.name", metric.MeasureKind, metric.Float64NumberKind)
|
||||
desc := metric.NewDescriptor("test.name", metric.ValueRecorderKind, metric.Float64NumberKind)
|
||||
magg := minmaxsumcount.New(&desc)
|
||||
aggtest.CheckedUpdate(fix.t, magg, metric.NewFloat64Number(123.456), &desc)
|
||||
aggtest.CheckedUpdate(fix.t, magg, metric.NewFloat64Number(876.543), &desc)
|
||||
@@ -190,14 +190,14 @@ func TestStdoutMinMaxSumCount(t *testing.T) {
|
||||
require.Equal(t, `{"updates":[{"name":"test.name{A=B,C=D}","min":123.456,"max":876.543,"sum":999.999,"count":2}]}`, fix.Output())
|
||||
}
|
||||
|
||||
func TestStdoutMeasureFormat(t *testing.T) {
|
||||
func TestStdoutValueRecorderFormat(t *testing.T) {
|
||||
fix := newFixture(t, nil, stdout.Config{
|
||||
PrettyPrint: true,
|
||||
})
|
||||
|
||||
checkpointSet := test.NewCheckpointSet()
|
||||
|
||||
desc := metric.NewDescriptor("test.name", metric.MeasureKind, metric.Float64NumberKind)
|
||||
desc := metric.NewDescriptor("test.name", metric.ValueRecorderKind, metric.Float64NumberKind)
|
||||
magg := array.New()
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
@@ -238,7 +238,7 @@ func TestStdoutMeasureFormat(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStdoutNoData(t *testing.T) {
|
||||
desc := metric.NewDescriptor("test.name", metric.MeasureKind, metric.Float64NumberKind)
|
||||
desc := metric.NewDescriptor("test.name", metric.ValueRecorderKind, metric.Float64NumberKind)
|
||||
for name, tc := range map[string]export.Aggregator{
|
||||
"ddsketch": ddsketch.New(ddsketch.NewDefaultConfig(), &desc),
|
||||
"minmaxsumcount": minmaxsumcount.New(&desc),
|
||||
@@ -268,7 +268,7 @@ func TestStdoutLastValueNotSet(t *testing.T) {
|
||||
|
||||
checkpointSet := test.NewCheckpointSet()
|
||||
|
||||
desc := metric.NewDescriptor("test.name", metric.ObserverKind, metric.Float64NumberKind)
|
||||
desc := metric.NewDescriptor("test.name", metric.ValueObserverKind, metric.Float64NumberKind)
|
||||
lvagg := lastvalue.New()
|
||||
lvagg.Checkpoint(fix.ctx, &desc)
|
||||
|
||||
@@ -318,7 +318,7 @@ func TestStdoutResource(t *testing.T) {
|
||||
|
||||
checkpointSet := test.NewCheckpointSet()
|
||||
|
||||
desc := metric.NewDescriptor("test.name", metric.ObserverKind, metric.Float64NumberKind)
|
||||
desc := metric.NewDescriptor("test.name", metric.ValueObserverKind, metric.Float64NumberKind)
|
||||
lvagg := lastvalue.New()
|
||||
aggtest.CheckedUpdate(fix.t, lvagg, metric.NewFloat64Number(123.456), &desc)
|
||||
lvagg.Checkpoint(fix.ctx, &desc)
|
||||
|
||||
@@ -88,11 +88,11 @@ func (p *CheckpointSet) AddCounter(desc *metric.Descriptor, v float64, labels ..
|
||||
p.updateAggregator(desc, sum.New(), v, labels...)
|
||||
}
|
||||
|
||||
func (p *CheckpointSet) AddMeasure(desc *metric.Descriptor, v float64, labels ...kv.KeyValue) {
|
||||
func (p *CheckpointSet) AddValueRecorder(desc *metric.Descriptor, v float64, labels ...kv.KeyValue) {
|
||||
p.updateAggregator(desc, array.New(), v, labels...)
|
||||
}
|
||||
|
||||
func (p *CheckpointSet) AddHistogramMeasure(desc *metric.Descriptor, boundaries []metric.Number, v float64, labels ...kv.KeyValue) {
|
||||
func (p *CheckpointSet) AddHistogramValueRecorder(desc *metric.Descriptor, boundaries []metric.Number, v float64, labels ...kv.KeyValue) {
|
||||
p.updateAggregator(desc, histogram.New(desc, boundaries), v, labels...)
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
"mmsc-test-a",
|
||||
metric.MeasureKind,
|
||||
metric.ValueRecorderKind,
|
||||
"test-a-description",
|
||||
unit.Dimensionless,
|
||||
metric.Int64NumberKind,
|
||||
@@ -160,7 +160,7 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMinMaxSumCountDatapoints(t *testing.T) {
|
||||
desc := metric.NewDescriptor("", metric.MeasureKind, metric.Int64NumberKind)
|
||||
desc := metric.NewDescriptor("", metric.ValueRecorderKind, metric.Int64NumberKind)
|
||||
labels := label.NewSet()
|
||||
mmsc := minmaxsumcount.New(&desc)
|
||||
assert.NoError(t, mmsc.Update(context.Background(), 1, &desc))
|
||||
@@ -228,7 +228,7 @@ func TestSumMetricDescriptor(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"sum-test-b",
|
||||
metric.MeasureKind, // This shouldn't change anything.
|
||||
metric.ValueRecorderKind, // This shouldn't change anything.
|
||||
"test-b-description",
|
||||
unit.Milliseconds,
|
||||
metric.Float64NumberKind,
|
||||
@@ -257,7 +257,7 @@ func TestSumMetricDescriptor(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSumInt64DataPoints(t *testing.T) {
|
||||
desc := metric.NewDescriptor("", metric.MeasureKind, metric.Int64NumberKind)
|
||||
desc := metric.NewDescriptor("", metric.ValueRecorderKind, metric.Int64NumberKind)
|
||||
labels := label.NewSet()
|
||||
s := sumAgg.New()
|
||||
assert.NoError(t, s.Update(context.Background(), metric.Number(1), &desc))
|
||||
@@ -271,7 +271,7 @@ func TestSumInt64DataPoints(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSumFloat64DataPoints(t *testing.T) {
|
||||
desc := metric.NewDescriptor("", metric.MeasureKind, metric.Float64NumberKind)
|
||||
desc := metric.NewDescriptor("", metric.ValueRecorderKind, metric.Float64NumberKind)
|
||||
labels := label.NewSet()
|
||||
s := sumAgg.New()
|
||||
assert.NoError(t, s.Update(context.Background(), metric.NewFloat64Number(1), &desc))
|
||||
@@ -285,7 +285,7 @@ func TestSumFloat64DataPoints(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSumErrUnknownValueType(t *testing.T) {
|
||||
desc := metric.NewDescriptor("", metric.MeasureKind, metric.NumberKind(-1))
|
||||
desc := metric.NewDescriptor("", metric.ValueRecorderKind, metric.NumberKind(-1))
|
||||
labels := label.NewSet()
|
||||
s := sumAgg.New()
|
||||
_, err := sum(&desc, &labels, s)
|
||||
|
||||
@@ -109,13 +109,13 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption)
|
||||
span.End()
|
||||
}
|
||||
|
||||
selector := simple.NewWithExactMeasure()
|
||||
selector := simple.NewWithExactDistribution()
|
||||
integrator := integrator.New(selector, true)
|
||||
pusher := push.New(integrator, exp, 60*time.Second)
|
||||
pusher.Start()
|
||||
|
||||
ctx := context.Background()
|
||||
meter := pusher.Meter("test-meter")
|
||||
meter := pusher.Provider().Meter("test-meter")
|
||||
labels := []kv.KeyValue{kv.Bool("test", true)}
|
||||
|
||||
type data struct {
|
||||
@@ -124,12 +124,12 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption)
|
||||
val int64
|
||||
}
|
||||
instruments := map[string]data{
|
||||
"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},
|
||||
"test-int64-counter": {metric.CounterKind, metricapi.Int64NumberKind, 1},
|
||||
"test-float64-counter": {metric.CounterKind, metricapi.Float64NumberKind, 1},
|
||||
"test-int64-valuerecorder": {metric.ValueRecorderKind, metricapi.Int64NumberKind, 2},
|
||||
"test-float64-valuerecorder": {metric.ValueRecorderKind, metricapi.Float64NumberKind, 2},
|
||||
"test-int64-valueobserver": {metric.ValueObserverKind, metricapi.Int64NumberKind, 3},
|
||||
"test-float64-valueobserver": {metric.ValueObserverKind, metricapi.Float64NumberKind, 3},
|
||||
}
|
||||
for name, data := range instruments {
|
||||
switch data.iKind {
|
||||
@@ -142,27 +142,27 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption)
|
||||
default:
|
||||
assert.Failf(t, "unsupported number testing kind", data.nKind.String())
|
||||
}
|
||||
case metric.MeasureKind:
|
||||
case metric.ValueRecorderKind:
|
||||
switch data.nKind {
|
||||
case metricapi.Int64NumberKind:
|
||||
metricapi.Must(meter).NewInt64Measure(name).Record(ctx, data.val, labels...)
|
||||
metricapi.Must(meter).NewInt64ValueRecorder(name).Record(ctx, data.val, labels...)
|
||||
case metricapi.Float64NumberKind:
|
||||
metricapi.Must(meter).NewFloat64Measure(name).Record(ctx, float64(data.val), labels...)
|
||||
metricapi.Must(meter).NewFloat64ValueRecorder(name).Record(ctx, float64(data.val), labels...)
|
||||
default:
|
||||
assert.Failf(t, "unsupported number testing kind", data.nKind.String())
|
||||
}
|
||||
case metric.ObserverKind:
|
||||
case metric.ValueObserverKind:
|
||||
switch data.nKind {
|
||||
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)
|
||||
metricapi.Must(meter).RegisterInt64ValueObserver(name, callback)
|
||||
case metricapi.Float64NumberKind:
|
||||
callback := func(v float64) metricapi.Float64ObserverCallback {
|
||||
return metricapi.Float64ObserverCallback(func(result metricapi.Float64ObserverResult) { result.Observe(v, labels...) })
|
||||
}(float64(data.val))
|
||||
metricapi.Must(meter).RegisterFloat64Observer(name, callback)
|
||||
metricapi.Must(meter).RegisterFloat64ValueObserver(name, callback)
|
||||
default:
|
||||
assert.Failf(t, "unsupported number testing kind", data.nKind.String())
|
||||
}
|
||||
@@ -246,7 +246,7 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption)
|
||||
default:
|
||||
assert.Failf(t, "invalid number kind", data.nKind.String())
|
||||
}
|
||||
case metric.MeasureKind, metric.ObserverKind:
|
||||
case metric.ValueRecorderKind, metric.ValueObserverKind:
|
||||
assert.Equal(t, metricpb.MetricDescriptor_SUMMARY.String(), desc.GetType().String())
|
||||
m.GetSummaryDataPoints()
|
||||
if dp := m.GetSummaryDataPoints(); assert.Len(t, dp, 1) {
|
||||
|
||||
@@ -188,10 +188,10 @@ func TestNoGroupingExport(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
func TestMeasureMetricGroupingExport(t *testing.T) {
|
||||
func TestValuerecorderMetricGroupingExport(t *testing.T) {
|
||||
r := record{
|
||||
"measure",
|
||||
metric.MeasureKind,
|
||||
"valuerecorder",
|
||||
metric.ValueRecorderKind,
|
||||
metric.Int64NumberKind,
|
||||
nil,
|
||||
nil,
|
||||
@@ -205,7 +205,7 @@ func TestMeasureMetricGroupingExport(t *testing.T) {
|
||||
Metrics: []*metricpb.Metric{
|
||||
{
|
||||
MetricDescriptor: &metricpb.MetricDescriptor{
|
||||
Name: "measure",
|
||||
Name: "valuerecorder",
|
||||
Type: metricpb.MetricDescriptor_SUMMARY,
|
||||
Labels: []*commonpb.StringKeyValue{
|
||||
{
|
||||
|
||||
+1
-25
@@ -38,13 +38,6 @@ type (
|
||||
LibraryName string
|
||||
}
|
||||
|
||||
MeterProvider struct {
|
||||
lock sync.Mutex
|
||||
impl *MeterImpl
|
||||
unique metric.MeterImpl
|
||||
registered map[string]apimetric.Meter
|
||||
}
|
||||
|
||||
MeterImpl struct {
|
||||
lock sync.Mutex
|
||||
|
||||
@@ -123,24 +116,7 @@ func NewProvider() (*MeterImpl, apimetric.Provider) {
|
||||
impl := &MeterImpl{
|
||||
asyncInstruments: NewAsyncInstrumentState(nil),
|
||||
}
|
||||
p := &MeterProvider{
|
||||
impl: impl,
|
||||
unique: registry.NewUniqueInstrumentMeterImpl(impl),
|
||||
registered: map[string]apimetric.Meter{},
|
||||
}
|
||||
return impl, p
|
||||
}
|
||||
|
||||
func (p *MeterProvider) Meter(name string) apimetric.Meter {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
if lookup, ok := p.registered[name]; ok {
|
||||
return lookup
|
||||
}
|
||||
m := apimetric.WrapMeterImpl(p.unique, name)
|
||||
p.registered[name] = m
|
||||
return m
|
||||
return impl, registry.NewProvider(impl)
|
||||
}
|
||||
|
||||
func NewMeter() (*MeterImpl, apimetric.Meter) {
|
||||
|
||||
@@ -15,127 +15,361 @@ package grpctrace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
"go.opentelemetry.io/otel/api/kv"
|
||||
"go.opentelemetry.io/otel/api/kv/value"
|
||||
export "go.opentelemetry.io/otel/sdk/export/trace"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
)
|
||||
|
||||
type testExporter struct {
|
||||
spanMap map[string][]*export.SpanData
|
||||
mu sync.Mutex
|
||||
spanMap map[string]*export.SpanData
|
||||
}
|
||||
|
||||
func (t *testExporter) ExportSpan(ctx context.Context, s *export.SpanData) {
|
||||
t.spanMap[s.Name] = append(t.spanMap[s.Name], s)
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
t.spanMap[s.Name] = s
|
||||
}
|
||||
|
||||
type mockCCInvoker struct {
|
||||
type mockUICInvoker struct {
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (mcci *mockCCInvoker) invoke(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, opts ...grpc.CallOption) error {
|
||||
mcci.ctx = ctx
|
||||
func (mcuici *mockUICInvoker) invoker(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, opts ...grpc.CallOption) error {
|
||||
mcuici.ctx = ctx
|
||||
return nil
|
||||
}
|
||||
|
||||
type mockProtoMessage struct {
|
||||
type mockProtoMessage struct{}
|
||||
|
||||
func (mm *mockProtoMessage) Reset() {
|
||||
}
|
||||
|
||||
func (mm *mockProtoMessage) Reset() {}
|
||||
func (mm *mockProtoMessage) String() string { return "mock" }
|
||||
func (mm *mockProtoMessage) ProtoMessage() {}
|
||||
|
||||
type nameAttributeTestCase struct {
|
||||
testName string
|
||||
expectedName string
|
||||
fullNameFmt string
|
||||
func (mm *mockProtoMessage) String() string {
|
||||
return "mock"
|
||||
}
|
||||
|
||||
func (tc nameAttributeTestCase) fullName() string {
|
||||
return fmt.Sprintf(tc.fullNameFmt, tc.expectedName)
|
||||
func (mm *mockProtoMessage) ProtoMessage() {
|
||||
}
|
||||
|
||||
func TestUCISetsExpectedServiceNameAttribute(t *testing.T) {
|
||||
testCases := []nameAttributeTestCase{
|
||||
{
|
||||
"FullyQualifiedMethodName",
|
||||
"serviceName",
|
||||
"/github.com.foo.%s/bar",
|
||||
},
|
||||
{
|
||||
"SimpleMethodName",
|
||||
"serviceName",
|
||||
"/%s/bar",
|
||||
},
|
||||
{
|
||||
"MethodNameWithoutFullPath",
|
||||
"serviceName",
|
||||
"%s/bar",
|
||||
},
|
||||
{
|
||||
"InvalidMethodName",
|
||||
"",
|
||||
"invalidName",
|
||||
},
|
||||
{
|
||||
"NonAlphanumericMethodName",
|
||||
"serviceName_123",
|
||||
"/github.com.foo.%s/method",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.testName, tc.testUCISetsExpectedNameAttribute)
|
||||
}
|
||||
}
|
||||
|
||||
func (tc nameAttributeTestCase) testUCISetsExpectedNameAttribute(t *testing.T) {
|
||||
exp := &testExporter{make(map[string][]*export.SpanData)}
|
||||
func TestUnaryClientInterceptor(t *testing.T) {
|
||||
exp := &testExporter{spanMap: make(map[string]*export.SpanData)}
|
||||
tp, _ := sdktrace.NewProvider(sdktrace.WithSyncer(exp),
|
||||
sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}))
|
||||
|
||||
tr := tp.Tracer("grpctrace/client")
|
||||
ctx, span := tr.Start(context.Background(), tc.testName)
|
||||
defer span.End()
|
||||
sdktrace.WithConfig(sdktrace.Config{
|
||||
DefaultSampler: sdktrace.AlwaysSample(),
|
||||
},
|
||||
))
|
||||
|
||||
clientConn, err := grpc.Dial("fake:connection", grpc.WithInsecure())
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create client connection: %v", err)
|
||||
}
|
||||
|
||||
unaryInt := UnaryClientInterceptor(tr)
|
||||
tracer := tp.Tracer("grpctrace/client")
|
||||
unaryInterceptor := UnaryClientInterceptor(tracer)
|
||||
|
||||
req := &mockProtoMessage{}
|
||||
reply := &mockProtoMessage{}
|
||||
ccInvoker := &mockCCInvoker{}
|
||||
uniInterceptorInvoker := &mockUICInvoker{}
|
||||
|
||||
err = unaryInt(ctx, tc.fullName(), req, reply, clientConn, ccInvoker.invoke)
|
||||
checks := []struct {
|
||||
name string
|
||||
expectedAttr map[kv.Key]value.Value
|
||||
eventsAttr []map[kv.Key]value.Value
|
||||
}{
|
||||
{
|
||||
name: "/github.com.serviceName/bar",
|
||||
expectedAttr: map[kv.Key]value.Value{
|
||||
rpcServiceKey: value.String("serviceName"),
|
||||
netPeerIPKey: value.String("fake"),
|
||||
netPeerPortKey: value.String("connection"),
|
||||
},
|
||||
eventsAttr: []map[kv.Key]value.Value{
|
||||
{
|
||||
messageTypeKey: value.String("SENT"),
|
||||
messageIDKey: value.Int(1),
|
||||
messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(req))),
|
||||
},
|
||||
{
|
||||
messageTypeKey: value.String("RECEIVED"),
|
||||
messageIDKey: value.Int(1),
|
||||
messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(reply))),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "/serviceName/bar",
|
||||
expectedAttr: map[kv.Key]value.Value{
|
||||
rpcServiceKey: value.String("serviceName"),
|
||||
netPeerIPKey: value.String("fake"),
|
||||
netPeerPortKey: value.String("connection"),
|
||||
},
|
||||
eventsAttr: []map[kv.Key]value.Value{
|
||||
{
|
||||
messageTypeKey: value.String("SENT"),
|
||||
messageIDKey: value.Int(1),
|
||||
messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(req))),
|
||||
},
|
||||
{
|
||||
messageTypeKey: value.String("RECEIVED"),
|
||||
messageIDKey: value.Int(1),
|
||||
messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(reply))),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "serviceName/bar",
|
||||
expectedAttr: map[kv.Key]value.Value{
|
||||
rpcServiceKey: value.String("serviceName"),
|
||||
netPeerIPKey: value.String("fake"),
|
||||
netPeerPortKey: value.String("connection"),
|
||||
},
|
||||
eventsAttr: []map[kv.Key]value.Value{
|
||||
{
|
||||
messageTypeKey: value.String("SENT"),
|
||||
messageIDKey: value.Int(1),
|
||||
messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(req))),
|
||||
},
|
||||
{
|
||||
messageTypeKey: value.String("RECEIVED"),
|
||||
messageIDKey: value.Int(1),
|
||||
messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(reply))),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalidName",
|
||||
expectedAttr: map[kv.Key]value.Value{
|
||||
rpcServiceKey: value.String(""),
|
||||
netPeerIPKey: value.String("fake"),
|
||||
netPeerPortKey: value.String("connection"),
|
||||
},
|
||||
eventsAttr: []map[kv.Key]value.Value{
|
||||
{
|
||||
messageTypeKey: value.String("SENT"),
|
||||
messageIDKey: value.Int(1),
|
||||
messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(req))),
|
||||
},
|
||||
{
|
||||
messageTypeKey: value.String("RECEIVED"),
|
||||
messageIDKey: value.Int(1),
|
||||
messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(reply))),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "/github.com.foo.serviceName_123/method",
|
||||
expectedAttr: map[kv.Key]value.Value{
|
||||
rpcServiceKey: value.String("serviceName_123"),
|
||||
netPeerIPKey: value.String("fake"),
|
||||
netPeerPortKey: value.String("connection"),
|
||||
},
|
||||
eventsAttr: []map[kv.Key]value.Value{
|
||||
{
|
||||
messageTypeKey: value.String("SENT"),
|
||||
messageIDKey: value.Int(1),
|
||||
messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(req))),
|
||||
},
|
||||
{
|
||||
messageTypeKey: value.String("RECEIVED"),
|
||||
messageIDKey: value.Int(1),
|
||||
messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(reply))),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, check := range checks {
|
||||
err = unaryInterceptor(context.Background(), check.name, req, reply, clientConn, uniInterceptorInvoker.invoker)
|
||||
if err != nil {
|
||||
t.Errorf("failed to run unary interceptor: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
spanData, ok := exp.spanMap[check.name]
|
||||
if !ok {
|
||||
t.Errorf("no span data found for name < %s >", check.name)
|
||||
continue
|
||||
}
|
||||
|
||||
attrs := spanData.Attributes
|
||||
if len(check.expectedAttr) > len(attrs) {
|
||||
t.Errorf("attributes received are less than expected attributes, received %d, expected %d",
|
||||
len(attrs), len(check.expectedAttr))
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
expectedAttr, ok := check.expectedAttr[attr.Key]
|
||||
if ok {
|
||||
if expectedAttr != attr.Value {
|
||||
t.Errorf("name: %s invalid %s found. expected %s, actual %s", check.name, string(attr.Key),
|
||||
expectedAttr.AsString(), attr.Value.AsString())
|
||||
}
|
||||
delete(check.expectedAttr, attr.Key)
|
||||
} else {
|
||||
t.Errorf("attribute %s not found in expected attributes map", string(attr.Key))
|
||||
}
|
||||
}
|
||||
|
||||
// Check if any expected attr not seen
|
||||
if len(check.expectedAttr) > 0 {
|
||||
for attr := range check.expectedAttr {
|
||||
t.Errorf("missing attribute %s in span", string(attr))
|
||||
}
|
||||
}
|
||||
|
||||
events := spanData.MessageEvents
|
||||
if len(check.eventsAttr) > len(events) {
|
||||
t.Errorf("events received are less than expected events, received %d, expected %d",
|
||||
len(events), len(check.eventsAttr))
|
||||
}
|
||||
for event := 0; event < len(check.eventsAttr); event++ {
|
||||
for _, attr := range events[event].Attributes {
|
||||
expectedAttr, ok := check.eventsAttr[event][attr.Key]
|
||||
if ok {
|
||||
if attr.Value != expectedAttr {
|
||||
t.Errorf("invalid value for attribute %s in events, expected %s actual %s",
|
||||
string(attr.Key), attr.Value.AsString(), expectedAttr.AsString())
|
||||
}
|
||||
delete(check.eventsAttr[event], attr.Key)
|
||||
} else {
|
||||
t.Errorf("attribute in event %s not found in expected attributes map", string(attr.Key))
|
||||
}
|
||||
}
|
||||
if len(check.eventsAttr[event]) > 0 {
|
||||
for attr := range check.eventsAttr[event] {
|
||||
t.Errorf("missing attribute %s in span event", string(attr))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type mockClientStream struct {
|
||||
Desc *grpc.StreamDesc
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
func (mockClientStream) SendMsg(m interface{}) error { return nil }
|
||||
func (mockClientStream) RecvMsg(m interface{}) error { return nil }
|
||||
func (mockClientStream) CloseSend() error { return nil }
|
||||
func (c mockClientStream) Context() context.Context { return c.Ctx }
|
||||
func (mockClientStream) Header() (metadata.MD, error) { return nil, nil }
|
||||
func (mockClientStream) Trailer() metadata.MD { return nil }
|
||||
|
||||
func TestStreamClientInterceptor(t *testing.T) {
|
||||
exp := &testExporter{spanMap: make(map[string]*export.SpanData)}
|
||||
tp, _ := sdktrace.NewProvider(sdktrace.WithSyncer(exp),
|
||||
sdktrace.WithConfig(sdktrace.Config{
|
||||
DefaultSampler: sdktrace.AlwaysSample(),
|
||||
},
|
||||
))
|
||||
clientConn, err := grpc.Dial("fake:connection", grpc.WithInsecure())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to run unary interceptor: %v", err)
|
||||
t.Fatalf("failed to create client connection: %v", err)
|
||||
}
|
||||
|
||||
spanData, hasSpanData := exp.spanMap[tc.fullName()]
|
||||
// tracer
|
||||
tracer := tp.Tracer("grpctrace/Server")
|
||||
streamCI := StreamClientInterceptor(tracer)
|
||||
|
||||
if !hasSpanData || len(spanData) == 0 {
|
||||
t.Fatalf("no span data found for name < %s >", tc.fullName())
|
||||
var mockClStr mockClientStream
|
||||
methodName := "/github.com.serviceName/bar"
|
||||
|
||||
streamClient, err := streamCI(context.Background(),
|
||||
&grpc.StreamDesc{ServerStreams: true},
|
||||
clientConn,
|
||||
methodName,
|
||||
func(ctx context.Context,
|
||||
desc *grpc.StreamDesc,
|
||||
cc *grpc.ClientConn,
|
||||
method string,
|
||||
opts ...grpc.CallOption) (grpc.ClientStream, error) {
|
||||
mockClStr = mockClientStream{Desc: desc, Ctx: ctx}
|
||||
return mockClStr, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to initialize grpc stream client: %v", err)
|
||||
}
|
||||
|
||||
attributes := spanData[0].Attributes
|
||||
// no span exported while stream is open
|
||||
if _, ok := exp.spanMap[methodName]; ok {
|
||||
t.Fatalf("span shouldn't end while stream is open")
|
||||
}
|
||||
|
||||
var actualServiceName string
|
||||
for _, attr := range attributes {
|
||||
if attr.Key == rpcServiceKey {
|
||||
actualServiceName = attr.Value.AsString()
|
||||
req := &mockProtoMessage{}
|
||||
reply := &mockProtoMessage{}
|
||||
|
||||
// send and receive fake data
|
||||
for i := 0; i < 10; i++ {
|
||||
_ = streamClient.SendMsg(req)
|
||||
_ = streamClient.RecvMsg(reply)
|
||||
}
|
||||
|
||||
// close client and server stream
|
||||
_ = streamClient.CloseSend()
|
||||
mockClStr.Desc.ServerStreams = false
|
||||
_ = streamClient.RecvMsg(reply)
|
||||
|
||||
// added retry because span end is called in separate go routine
|
||||
var spanData *export.SpanData
|
||||
for retry := 0; retry < 5; retry++ {
|
||||
ok := false
|
||||
exp.mu.Lock()
|
||||
spanData, ok = exp.spanMap[methodName]
|
||||
exp.mu.Unlock()
|
||||
if ok {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * 1)
|
||||
}
|
||||
if spanData == nil {
|
||||
t.Fatalf("no span data found for name < %s >", methodName)
|
||||
}
|
||||
|
||||
attrs := spanData.Attributes
|
||||
expectedAttr := map[kv.Key]string{
|
||||
rpcServiceKey: "serviceName",
|
||||
netPeerIPKey: "fake",
|
||||
netPeerPortKey: "connection",
|
||||
}
|
||||
|
||||
for _, attr := range attrs {
|
||||
expected, ok := expectedAttr[attr.Key]
|
||||
if ok {
|
||||
if expected != attr.Value.AsString() {
|
||||
t.Errorf("name: %s invalid %s found. expected %s, actual %s", methodName, string(attr.Key),
|
||||
expected, attr.Value.AsString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if tc.expectedName != actualServiceName {
|
||||
t.Fatalf("invalid service name found. expected %s, actual %s",
|
||||
tc.expectedName, actualServiceName)
|
||||
events := spanData.MessageEvents
|
||||
if len(events) != 20 {
|
||||
t.Fatalf("incorrect number of events expected 20 got %d", len(events))
|
||||
}
|
||||
for i := 0; i < 20; i += 2 {
|
||||
msgID := i/2 + 1
|
||||
validate := func(eventName string, attrs []kv.KeyValue) {
|
||||
for _, attr := range attrs {
|
||||
if attr.Key == messageTypeKey && attr.Value.AsString() != eventName {
|
||||
t.Errorf("invalid event on index: %d expecting %s event, receive %s event", i, eventName, attr.Value.AsString())
|
||||
}
|
||||
if attr.Key == messageIDKey && attr.Value != value.Int(msgID) {
|
||||
t.Errorf("invalid id for message event expected %d received %d", msgID, attr.Value.AsInt32())
|
||||
}
|
||||
}
|
||||
}
|
||||
validate("SENT", events[i].Attributes)
|
||||
validate("RECEIVED", events[i+1].Attributes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ func NewInconsistentMergeError(a1, a2 export.Aggregator) error {
|
||||
// RangeTest is a commmon routine for testing for valid input values.
|
||||
// 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.
|
||||
// monotonic counter metrics and absolute ValueRecorder metrics.
|
||||
func RangeTest(number metric.Number, descriptor *metric.Descriptor) error {
|
||||
numberKind := descriptor.NumberKind()
|
||||
|
||||
|
||||
@@ -86,8 +86,8 @@ func TestNaNTest(t *testing.T) {
|
||||
t.Run(nkind.String(), func(t *testing.T) {
|
||||
for _, mkind := range []metric.Kind{
|
||||
metric.CounterKind,
|
||||
metric.MeasureKind,
|
||||
metric.ObserverKind,
|
||||
metric.ValueRecorderKind,
|
||||
metric.ValueObserverKind,
|
||||
} {
|
||||
desc := metric.NewDescriptor(
|
||||
"name",
|
||||
|
||||
@@ -100,22 +100,16 @@ type AggregationSelector interface {
|
||||
}
|
||||
|
||||
// Aggregator implements a specific aggregation behavior, e.g., a
|
||||
// behavior to track a sequence of updates to a counter, a measure, or
|
||||
// an observer instrument. For the most part, counter semantics are
|
||||
// fixed and the provided implementation should be used. Measure and
|
||||
// observer metrics offer a wide range of potential tradeoffs and
|
||||
// several implementations are provided.
|
||||
//
|
||||
// Aggregators are meant to compute the change (i.e., delta) in state
|
||||
// from one checkpoint to the next, with the exception of LastValue
|
||||
// aggregators. LastValue aggregators are required to maintain the last
|
||||
// value across checkpoints.
|
||||
// behavior to track a sequence of updates to an instrument. Sum-only
|
||||
// instruments commonly use a simple Sum aggregator, but for the
|
||||
// distribution instruments (ValueRecorder, ValueObserver) there are a
|
||||
// number of possible aggregators with different cost and accuracy
|
||||
// tradeoffs.
|
||||
//
|
||||
// Note that any Aggregator may be attached to any instrument--this is
|
||||
// the result of the OpenTelemetry API/SDK separation. It is possible
|
||||
// to attach a counter aggregator to a Measure instrument (to compute
|
||||
// a simple sum) or a LastValue aggregator to a measure instrument (to
|
||||
// compute the last value).
|
||||
// to attach a Sum aggregator to a ValueRecorder instrument or a
|
||||
// MinMaxSumCount aggregator to a Counter instrument.
|
||||
type Aggregator interface {
|
||||
// Update receives a new measured value and incorporates it
|
||||
// into the aggregation. Update() calls may arrive
|
||||
|
||||
@@ -27,6 +27,8 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
// Aggregator aggregates events that form a distribution, keeping
|
||||
// an array with the exact set of values.
|
||||
Aggregator struct {
|
||||
// ckptSum needs to be aligned for 64-bit atomic operations.
|
||||
ckptSum metric.Number
|
||||
|
||||
@@ -50,7 +50,7 @@ type updateTest struct {
|
||||
}
|
||||
|
||||
func (ut *updateTest) run(t *testing.T, profile test.Profile) {
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
|
||||
agg := New()
|
||||
|
||||
@@ -118,7 +118,7 @@ type mergeTest struct {
|
||||
func (mt *mergeTest) run(t *testing.T, profile test.Profile) {
|
||||
ctx := context.Background()
|
||||
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
|
||||
agg1 := New()
|
||||
agg2 := New()
|
||||
@@ -215,7 +215,7 @@ func TestArrayErrors(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
|
||||
test.CheckedUpdate(t, agg, metric.Number(0), descriptor)
|
||||
|
||||
@@ -243,7 +243,7 @@ func TestArrayErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestArrayFloat64(t *testing.T) {
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, metric.Float64NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, metric.Float64NumberKind)
|
||||
|
||||
fpsf := func(sign int) []float64 {
|
||||
// Check behavior of a bunch of odd floating
|
||||
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
// Config is an alias for the underlying DDSketch config object.
|
||||
type Config = sdk.Config
|
||||
|
||||
// Aggregator aggregates measure events.
|
||||
// Aggregator aggregates events into a distribution.
|
||||
type Aggregator struct {
|
||||
lock sync.Mutex
|
||||
cfg *Config
|
||||
|
||||
@@ -33,7 +33,7 @@ type updateTest struct {
|
||||
func (ut *updateTest) run(t *testing.T, profile test.Profile) {
|
||||
ctx := context.Background()
|
||||
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
agg := New(NewDefaultConfig(), descriptor)
|
||||
|
||||
all := test.NewNumbers(profile.NumberKind)
|
||||
@@ -92,7 +92,7 @@ type mergeTest struct {
|
||||
|
||||
func (mt *mergeTest) run(t *testing.T, profile test.Profile) {
|
||||
ctx := context.Background()
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
|
||||
agg1 := New(NewDefaultConfig(), descriptor)
|
||||
agg2 := New(NewDefaultConfig(), descriptor)
|
||||
|
||||
@@ -24,6 +24,11 @@ import (
|
||||
"go.opentelemetry.io/otel/sdk/export/metric/aggregator"
|
||||
)
|
||||
|
||||
// Note: This code uses a Mutex to govern access to the exclusive
|
||||
// aggregator state. This is in contrast to a lock-free approach
|
||||
// (as in the Go prometheus client) that was reverted here:
|
||||
// https://github.com/open-telemetry/opentelemetry-go/pull/669
|
||||
|
||||
type (
|
||||
// Aggregator observe events and counts them in pre-determined buckets.
|
||||
// It also calculates the sum and count of all events.
|
||||
@@ -39,10 +44,9 @@ type (
|
||||
// the sum and counts for all observed values and
|
||||
// the less than equal bucket count for the pre-determined boundaries.
|
||||
state struct {
|
||||
// all fields have to be aligned for 64-bit atomic operations.
|
||||
buckets aggregator.Buckets
|
||||
count metric.Number
|
||||
sum metric.Number
|
||||
bucketCounts []metric.Number
|
||||
count metric.Number
|
||||
sum metric.Number
|
||||
}
|
||||
)
|
||||
|
||||
@@ -51,7 +55,7 @@ var _ aggregator.Sum = &Aggregator{}
|
||||
var _ aggregator.Count = &Aggregator{}
|
||||
var _ aggregator.Histogram = &Aggregator{}
|
||||
|
||||
// New returns a new measure aggregator for computing Histograms.
|
||||
// New returns a new aggregator for computing Histograms.
|
||||
//
|
||||
// A Histogram observe events and counts them in pre-defined buckets.
|
||||
// And also provides the total sum and count of all observations.
|
||||
@@ -71,17 +75,12 @@ func New(desc *metric.Descriptor, boundaries []metric.Number) *Aggregator {
|
||||
sort.Sort(&sortedBoundaries)
|
||||
boundaries = sortedBoundaries.numbers
|
||||
|
||||
agg := Aggregator{
|
||||
return &Aggregator{
|
||||
kind: desc.NumberKind(),
|
||||
boundaries: boundaries,
|
||||
current: state{
|
||||
buckets: aggregator.Buckets{
|
||||
Boundaries: boundaries,
|
||||
Counts: make([]metric.Number, len(boundaries)+1),
|
||||
},
|
||||
},
|
||||
current: emptyState(boundaries),
|
||||
checkpoint: emptyState(boundaries),
|
||||
}
|
||||
return &agg
|
||||
}
|
||||
|
||||
// Sum returns the sum of all values in the checkpoint.
|
||||
@@ -102,7 +101,10 @@ func (c *Aggregator) Count() (int64, error) {
|
||||
func (c *Aggregator) Histogram() (aggregator.Buckets, error) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
return c.checkpoint.buckets, nil
|
||||
return aggregator.Buckets{
|
||||
Boundaries: c.boundaries,
|
||||
Counts: c.checkpoint.bucketCounts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Checkpoint saves the current state and resets the current state to
|
||||
@@ -111,16 +113,13 @@ func (c *Aggregator) Histogram() (aggregator.Buckets, error) {
|
||||
// other.
|
||||
func (c *Aggregator) Checkpoint(ctx context.Context, desc *metric.Descriptor) {
|
||||
c.lock.Lock()
|
||||
c.checkpoint, c.current = c.current, c.emptyState()
|
||||
c.checkpoint, c.current = c.current, emptyState(c.boundaries)
|
||||
c.lock.Unlock()
|
||||
}
|
||||
|
||||
func (c *Aggregator) emptyState() state {
|
||||
func emptyState(boundaries []metric.Number) state {
|
||||
return state{
|
||||
buckets: aggregator.Buckets{
|
||||
Boundaries: c.boundaries,
|
||||
Counts: make([]metric.Number, len(c.boundaries)+1),
|
||||
},
|
||||
bucketCounts: make([]metric.Number, len(boundaries)+1),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +140,7 @@ func (c *Aggregator) Update(_ context.Context, number metric.Number, desc *metri
|
||||
|
||||
c.current.count.AddInt64(1)
|
||||
c.current.sum.AddNumber(kind, number)
|
||||
c.current.buckets.Counts[bucketID].AddUint64(1)
|
||||
c.current.bucketCounts[bucketID].AddUint64(1)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -156,8 +155,8 @@ func (c *Aggregator) Merge(oa export.Aggregator, desc *metric.Descriptor) error
|
||||
c.checkpoint.sum.AddNumber(desc.NumberKind(), o.checkpoint.sum)
|
||||
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(metric.Uint64NumberKind, o.checkpoint.buckets.Counts[i])
|
||||
for i := 0; i < len(c.checkpoint.bucketCounts); i++ {
|
||||
c.checkpoint.bucketCounts[i].AddNumber(metric.Uint64NumberKind, o.checkpoint.bucketCounts[i])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ func TestHistogramPositiveAndNegative(t *testing.T) {
|
||||
// Validates count, sum and buckets for a given profile and policy
|
||||
func histogram(t *testing.T, profile test.Profile, policy policy) {
|
||||
ctx := context.Background()
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
|
||||
agg := New(descriptor, boundaries[profile.NumberKind])
|
||||
|
||||
@@ -113,20 +113,33 @@ func histogram(t *testing.T, profile test.Profile, policy policy) {
|
||||
require.Equal(t, all.Count(), count, "Same count -"+policy.name)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, len(agg.checkpoint.buckets.Counts), len(boundaries[profile.NumberKind])+1, "There should be b + 1 counts, where b is the number of boundaries")
|
||||
require.Equal(t, len(agg.checkpoint.bucketCounts), len(boundaries[profile.NumberKind])+1, "There should be b + 1 counts, where b is the number of boundaries")
|
||||
|
||||
counts := calcBuckets(all.Points(), profile)
|
||||
for i, v := range counts {
|
||||
bCount := agg.checkpoint.buckets.Counts[i].AsUint64()
|
||||
require.Equal(t, v, bCount, "Wrong bucket #%d count: %v != %v", i, counts, agg.checkpoint.buckets.Counts)
|
||||
bCount := agg.checkpoint.bucketCounts[i].AsUint64()
|
||||
require.Equal(t, v, bCount, "Wrong bucket #%d count: %v != %v", i, counts, agg.checkpoint.bucketCounts)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHistogramInitial(t *testing.T) {
|
||||
test.RunProfiles(t, func(t *testing.T, profile test.Profile) {
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
|
||||
agg := New(descriptor, boundaries[profile.NumberKind])
|
||||
buckets, err := agg.Histogram()
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(buckets.Counts), len(boundaries[profile.NumberKind])+1)
|
||||
require.Equal(t, len(buckets.Boundaries), len(boundaries[profile.NumberKind]))
|
||||
})
|
||||
}
|
||||
|
||||
func TestHistogramMerge(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
test.RunProfiles(t, func(t *testing.T, profile test.Profile) {
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
|
||||
agg1 := New(descriptor, boundaries[profile.NumberKind])
|
||||
agg2 := New(descriptor, boundaries[profile.NumberKind])
|
||||
@@ -164,12 +177,12 @@ func TestHistogramMerge(t *testing.T) {
|
||||
require.Equal(t, all.Count(), count, "Same count - absolute")
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, len(agg1.checkpoint.buckets.Counts), len(boundaries[profile.NumberKind])+1, "There should be b + 1 counts, where b is the number of boundaries")
|
||||
require.Equal(t, len(agg1.checkpoint.bucketCounts), len(boundaries[profile.NumberKind])+1, "There should be b + 1 counts, where b is the number of boundaries")
|
||||
|
||||
counts := calcBuckets(all.Points(), profile)
|
||||
for i, v := range counts {
|
||||
bCount := agg1.checkpoint.buckets.Counts[i].AsUint64()
|
||||
require.Equal(t, v, bCount, "Wrong bucket #%d count: %v != %v", i, counts, agg1.checkpoint.buckets.Counts)
|
||||
bCount := agg1.checkpoint.bucketCounts[i].AsUint64()
|
||||
require.Equal(t, v, bCount, "Wrong bucket #%d count: %v != %v", i, counts, agg1.checkpoint.bucketCounts)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -178,7 +191,7 @@ func TestHistogramNotSet(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
test.RunProfiles(t, func(t *testing.T, profile test.Profile) {
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
|
||||
agg := New(descriptor, boundaries[profile.NumberKind])
|
||||
agg.Checkpoint(ctx, descriptor)
|
||||
@@ -191,8 +204,8 @@ func TestHistogramNotSet(t *testing.T) {
|
||||
require.Equal(t, int64(0), count, "Empty checkpoint count = 0")
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, len(agg.checkpoint.buckets.Counts), len(boundaries[profile.NumberKind])+1, "There should be b + 1 counts, where b is the number of boundaries")
|
||||
for i, bCount := range agg.checkpoint.buckets.Counts {
|
||||
require.Equal(t, len(agg.checkpoint.bucketCounts), len(boundaries[profile.NumberKind])+1, "There should be b + 1 counts, where b is the number of boundaries")
|
||||
for i, bCount := range agg.checkpoint.bucketCounts {
|
||||
require.Equal(t, uint64(0), bCount.AsUint64(), "Bucket #%d must have 0 observed values", i)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -55,7 +55,7 @@ func TestLastValueUpdate(t *testing.T) {
|
||||
test.RunProfiles(t, func(t *testing.T, profile test.Profile) {
|
||||
agg := New()
|
||||
|
||||
record := test.NewAggregatorTest(metric.ObserverKind, profile.NumberKind)
|
||||
record := test.NewAggregatorTest(metric.ValueObserverKind, profile.NumberKind)
|
||||
|
||||
var last metric.Number
|
||||
for i := 0; i < count; i++ {
|
||||
@@ -79,7 +79,7 @@ func TestLastValueMerge(t *testing.T) {
|
||||
agg1 := New()
|
||||
agg2 := New()
|
||||
|
||||
descriptor := test.NewAggregatorTest(metric.ObserverKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueObserverKind, profile.NumberKind)
|
||||
|
||||
first1 := profile.Random(+1)
|
||||
first2 := profile.Random(+1)
|
||||
@@ -107,7 +107,7 @@ func TestLastValueMerge(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLastValueNotSet(t *testing.T) {
|
||||
descriptor := test.NewAggregatorTest(metric.ObserverKind, metric.Int64NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueObserverKind, metric.Int64NumberKind)
|
||||
|
||||
g := New()
|
||||
g.Checkpoint(context.Background(), descriptor)
|
||||
|
||||
@@ -24,8 +24,8 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
// Aggregator aggregates measure events, keeping only the min, max,
|
||||
// sum, and count.
|
||||
// Aggregator aggregates events that form a distribution,
|
||||
// keeping only the min, max, sum, and count.
|
||||
Aggregator struct {
|
||||
lock sync.Mutex
|
||||
current state
|
||||
@@ -44,8 +44,9 @@ type (
|
||||
var _ export.Aggregator = &Aggregator{}
|
||||
var _ aggregator.MinMaxSumCount = &Aggregator{}
|
||||
|
||||
// New returns a new measure aggregator for computing min, max, sum, and
|
||||
// count. It does not compute quantile information other than Min and Max.
|
||||
// New returns a new aggregator for computing the min, max, sum, and
|
||||
// count. It does not compute quantile information other than Min and
|
||||
// Max.
|
||||
//
|
||||
// This type uses a mutex for Update() and Checkpoint() concurrency.
|
||||
func New(desc *metric.Descriptor) *Aggregator {
|
||||
|
||||
@@ -79,7 +79,7 @@ func TestMinMaxSumCountPositiveAndNegative(t *testing.T) {
|
||||
// Validates min, max, sum and count for a given profile and policy
|
||||
func minMaxSumCount(t *testing.T, profile test.Profile, policy policy) {
|
||||
ctx := context.Background()
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
|
||||
agg := New(descriptor)
|
||||
|
||||
@@ -127,7 +127,7 @@ func TestMinMaxSumCountMerge(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
test.RunProfiles(t, func(t *testing.T, profile test.Profile) {
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
|
||||
agg1 := New(descriptor)
|
||||
agg2 := New(descriptor)
|
||||
@@ -185,7 +185,7 @@ func TestMaxSumCountNotSet(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
test.RunProfiles(t, func(t *testing.T, profile test.Profile) {
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
|
||||
agg := New(descriptor)
|
||||
agg.Checkpoint(ctx, descriptor)
|
||||
|
||||
@@ -71,13 +71,13 @@ func TestCounterSum(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestMeasureSum(t *testing.T) {
|
||||
func TestValueRecorderSum(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
test.RunProfiles(t, func(t *testing.T, profile test.Profile) {
|
||||
agg := New()
|
||||
|
||||
descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind)
|
||||
descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind)
|
||||
|
||||
sum := metric.Number(0)
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ func BenchmarkInt64LastValueAdd(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
mea := fix.meter.NewInt64Measure("int64.lastvalue")
|
||||
mea := fix.meter.NewInt64ValueRecorder("int64.lastvalue")
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@@ -324,7 +324,7 @@ func BenchmarkInt64LastValueHandleAdd(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
mea := fix.meter.NewInt64Measure("int64.lastvalue")
|
||||
mea := fix.meter.NewInt64ValueRecorder("int64.lastvalue")
|
||||
handle := mea.Bind(labs...)
|
||||
|
||||
b.ResetTimer()
|
||||
@@ -338,7 +338,7 @@ func BenchmarkFloat64LastValueAdd(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
mea := fix.meter.NewFloat64Measure("float64.lastvalue")
|
||||
mea := fix.meter.NewFloat64ValueRecorder("float64.lastvalue")
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@@ -351,7 +351,7 @@ func BenchmarkFloat64LastValueHandleAdd(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
mea := fix.meter.NewFloat64Measure("float64.lastvalue")
|
||||
mea := fix.meter.NewFloat64ValueRecorder("float64.lastvalue")
|
||||
handle := mea.Bind(labs...)
|
||||
|
||||
b.ResetTimer()
|
||||
@@ -361,13 +361,13 @@ func BenchmarkFloat64LastValueHandleAdd(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
// Measures
|
||||
// ValueRecorders
|
||||
|
||||
func benchmarkInt64MeasureAdd(b *testing.B, name string) {
|
||||
func benchmarkInt64ValueRecorderAdd(b *testing.B, name string) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
mea := fix.meter.NewInt64Measure(name)
|
||||
mea := fix.meter.NewInt64ValueRecorder(name)
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@@ -376,11 +376,11 @@ func benchmarkInt64MeasureAdd(b *testing.B, name string) {
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkInt64MeasureHandleAdd(b *testing.B, name string) {
|
||||
func benchmarkInt64ValueRecorderHandleAdd(b *testing.B, name string) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
mea := fix.meter.NewInt64Measure(name)
|
||||
mea := fix.meter.NewInt64ValueRecorder(name)
|
||||
handle := mea.Bind(labs...)
|
||||
|
||||
b.ResetTimer()
|
||||
@@ -390,11 +390,11 @@ func benchmarkInt64MeasureHandleAdd(b *testing.B, name string) {
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkFloat64MeasureAdd(b *testing.B, name string) {
|
||||
func benchmarkFloat64ValueRecorderAdd(b *testing.B, name string) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
mea := fix.meter.NewFloat64Measure(name)
|
||||
mea := fix.meter.NewFloat64ValueRecorder(name)
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@@ -403,11 +403,11 @@ func benchmarkFloat64MeasureAdd(b *testing.B, name string) {
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkFloat64MeasureHandleAdd(b *testing.B, name string) {
|
||||
func benchmarkFloat64ValueRecorderHandleAdd(b *testing.B, name string) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
mea := fix.meter.NewFloat64Measure(name)
|
||||
mea := fix.meter.NewFloat64ValueRecorder(name)
|
||||
handle := mea.Bind(labs...)
|
||||
|
||||
b.ResetTimer()
|
||||
@@ -423,22 +423,22 @@ func BenchmarkObserverRegistration(b *testing.B) {
|
||||
fix := newFixture(b)
|
||||
names := make([]string, 0, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
names = append(names, fmt.Sprintf("test.observer.%d", i))
|
||||
names = append(names, fmt.Sprintf("test.valueobserver.%d", i))
|
||||
}
|
||||
cb := func(result metric.Int64ObserverResult) {}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
fix.meter.RegisterInt64Observer(names[i], cb)
|
||||
fix.meter.RegisterInt64ValueObserver(names[i], cb)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkObserverObservationInt64(b *testing.B) {
|
||||
func BenchmarkValueObserverObservationInt64(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
_ = fix.meter.RegisterInt64Observer("test.observer", func(result metric.Int64ObserverResult) {
|
||||
_ = fix.meter.RegisterInt64ValueObserver("test.valueobserver", func(result metric.Int64ObserverResult) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
result.Observe((int64)(i), labs...)
|
||||
}
|
||||
@@ -449,11 +449,11 @@ func BenchmarkObserverObservationInt64(b *testing.B) {
|
||||
fix.accumulator.Collect(ctx)
|
||||
}
|
||||
|
||||
func BenchmarkObserverObservationFloat64(b *testing.B) {
|
||||
func BenchmarkValueObserverObservationFloat64(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
fix := newFixture(b)
|
||||
labs := makeLabels(1)
|
||||
_ = fix.meter.RegisterFloat64Observer("test.observer", func(result metric.Float64ObserverResult) {
|
||||
_ = fix.meter.RegisterFloat64ValueObserver("test.valueobserver", func(result metric.Float64ObserverResult) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
result.Observe((float64)(i), labs...)
|
||||
}
|
||||
@@ -467,55 +467,55 @@ func BenchmarkObserverObservationFloat64(b *testing.B) {
|
||||
// MaxSumCount
|
||||
|
||||
func BenchmarkInt64MaxSumCountAdd(b *testing.B) {
|
||||
benchmarkInt64MeasureAdd(b, "int64.minmaxsumcount")
|
||||
benchmarkInt64ValueRecorderAdd(b, "int64.minmaxsumcount")
|
||||
}
|
||||
|
||||
func BenchmarkInt64MaxSumCountHandleAdd(b *testing.B) {
|
||||
benchmarkInt64MeasureHandleAdd(b, "int64.minmaxsumcount")
|
||||
benchmarkInt64ValueRecorderHandleAdd(b, "int64.minmaxsumcount")
|
||||
}
|
||||
|
||||
func BenchmarkFloat64MaxSumCountAdd(b *testing.B) {
|
||||
benchmarkFloat64MeasureAdd(b, "float64.minmaxsumcount")
|
||||
benchmarkFloat64ValueRecorderAdd(b, "float64.minmaxsumcount")
|
||||
}
|
||||
|
||||
func BenchmarkFloat64MaxSumCountHandleAdd(b *testing.B) {
|
||||
benchmarkFloat64MeasureHandleAdd(b, "float64.minmaxsumcount")
|
||||
benchmarkFloat64ValueRecorderHandleAdd(b, "float64.minmaxsumcount")
|
||||
}
|
||||
|
||||
// DDSketch
|
||||
|
||||
func BenchmarkInt64DDSketchAdd(b *testing.B) {
|
||||
benchmarkInt64MeasureAdd(b, "int64.ddsketch")
|
||||
benchmarkInt64ValueRecorderAdd(b, "int64.ddsketch")
|
||||
}
|
||||
|
||||
func BenchmarkInt64DDSketchHandleAdd(b *testing.B) {
|
||||
benchmarkInt64MeasureHandleAdd(b, "int64.ddsketch")
|
||||
benchmarkInt64ValueRecorderHandleAdd(b, "int64.ddsketch")
|
||||
}
|
||||
|
||||
func BenchmarkFloat64DDSketchAdd(b *testing.B) {
|
||||
benchmarkFloat64MeasureAdd(b, "float64.ddsketch")
|
||||
benchmarkFloat64ValueRecorderAdd(b, "float64.ddsketch")
|
||||
}
|
||||
|
||||
func BenchmarkFloat64DDSketchHandleAdd(b *testing.B) {
|
||||
benchmarkFloat64MeasureHandleAdd(b, "float64.ddsketch")
|
||||
benchmarkFloat64ValueRecorderHandleAdd(b, "float64.ddsketch")
|
||||
}
|
||||
|
||||
// Array
|
||||
|
||||
func BenchmarkInt64ArrayAdd(b *testing.B) {
|
||||
benchmarkInt64MeasureAdd(b, "int64.array")
|
||||
benchmarkInt64ValueRecorderAdd(b, "int64.array")
|
||||
}
|
||||
|
||||
func BenchmarkInt64ArrayHandleAdd(b *testing.B) {
|
||||
benchmarkInt64MeasureHandleAdd(b, "int64.array")
|
||||
benchmarkInt64ValueRecorderHandleAdd(b, "int64.array")
|
||||
}
|
||||
|
||||
func BenchmarkFloat64ArrayAdd(b *testing.B) {
|
||||
benchmarkFloat64MeasureAdd(b, "float64.array")
|
||||
benchmarkFloat64ValueRecorderAdd(b, "float64.array")
|
||||
}
|
||||
|
||||
func BenchmarkFloat64ArrayHandleAdd(b *testing.B) {
|
||||
benchmarkFloat64MeasureHandleAdd(b, "float64.array")
|
||||
benchmarkFloat64ValueRecorderHandleAdd(b, "float64.array")
|
||||
}
|
||||
|
||||
// BatchRecord
|
||||
|
||||
@@ -32,8 +32,6 @@ type Controller struct {
|
||||
collectLock sync.Mutex
|
||||
accumulator *sdk.Accumulator
|
||||
resource *resource.Resource
|
||||
uniq metric.MeterImpl
|
||||
named map[string]metric.Meter
|
||||
errorHandler sdk.ErrorHandler
|
||||
integrator export.Integrator
|
||||
exporter export.Exporter
|
||||
@@ -42,10 +40,9 @@ type Controller struct {
|
||||
period time.Duration
|
||||
ticker Ticker
|
||||
clock Clock
|
||||
provider *registry.Provider
|
||||
}
|
||||
|
||||
var _ metric.Provider = &Controller{}
|
||||
|
||||
// Several types below are created to match "github.com/benbjohnson/clock"
|
||||
// so that it remains a test-only dependency.
|
||||
|
||||
@@ -83,8 +80,7 @@ func New(integrator export.Integrator, exporter export.Exporter, period time.Dur
|
||||
return &Controller{
|
||||
accumulator: impl,
|
||||
resource: c.Resource,
|
||||
uniq: registry.NewUniqueInstrumentMeterImpl(impl),
|
||||
named: map[string]metric.Meter{},
|
||||
provider: registry.NewProvider(impl),
|
||||
errorHandler: c.ErrorHandler,
|
||||
integrator: integrator,
|
||||
exporter: exporter,
|
||||
@@ -102,6 +98,8 @@ func (c *Controller) SetClock(clock Clock) {
|
||||
c.clock = clock
|
||||
}
|
||||
|
||||
// SetErrorHandler sets the handler for errors. If none has been set, the
|
||||
// SDK default error handler is used.
|
||||
func (c *Controller) SetErrorHandler(errorHandler sdk.ErrorHandler) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
@@ -109,19 +107,9 @@ func (c *Controller) SetErrorHandler(errorHandler sdk.ErrorHandler) {
|
||||
c.accumulator.SetErrorHandler(errorHandler)
|
||||
}
|
||||
|
||||
// Meter returns a named Meter, satisifying the metric.Provider
|
||||
// interface.
|
||||
func (c *Controller) Meter(name string) metric.Meter {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
if meter, ok := c.named[name]; ok {
|
||||
return meter
|
||||
}
|
||||
|
||||
meter := metric.WrapMeterImpl(c.uniq, name)
|
||||
c.named[name] = meter
|
||||
return meter
|
||||
// Provider returns a metric.Provider instance for this controller.
|
||||
func (c *Controller) Provider() metric.Provider {
|
||||
return c.provider
|
||||
}
|
||||
|
||||
// Start begins a ticker that periodically collects and exports
|
||||
|
||||
@@ -183,7 +183,7 @@ func TestPushTicker(t *testing.T) {
|
||||
fix := newFixture(t)
|
||||
|
||||
p := push.New(fix.integrator, fix.exporter, time.Second)
|
||||
meter := p.Meter("name")
|
||||
meter := p.Provider().Meter("name")
|
||||
|
||||
mock := mockClock{clock.NewMock()}
|
||||
p.SetClock(mock)
|
||||
@@ -280,7 +280,7 @@ func TestPushExportError(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
meter := p.Meter("name")
|
||||
meter := p.Provider().Meter("name")
|
||||
counter1 := metric.Must(meter).NewInt64Counter("counter1")
|
||||
counter2 := metric.Must(meter).NewInt64Counter("counter2")
|
||||
|
||||
|
||||
+30
-30
@@ -107,7 +107,7 @@ func TestInputRangeTestCounter(t *testing.T) {
|
||||
require.Nil(t, sdkErr)
|
||||
}
|
||||
|
||||
func TestInputRangeTestMeasure(t *testing.T) {
|
||||
func TestInputRangeTestValueRecorder(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
integrator := &correctnessIntegrator{
|
||||
t: t,
|
||||
@@ -120,17 +120,17 @@ func TestInputRangeTestMeasure(t *testing.T) {
|
||||
sdkErr = handleErr
|
||||
})
|
||||
|
||||
measure := Must(meter).NewFloat64Measure("name.measure")
|
||||
valuerecorder := Must(meter).NewFloat64ValueRecorder("name.valuerecorder")
|
||||
|
||||
measure.Record(ctx, math.NaN())
|
||||
valuerecorder.Record(ctx, math.NaN())
|
||||
require.Equal(t, aggregator.ErrNaNInput, sdkErr)
|
||||
sdkErr = nil
|
||||
|
||||
checkpointed := sdk.Collect(ctx)
|
||||
require.Equal(t, 0, checkpointed)
|
||||
|
||||
measure.Record(ctx, 1)
|
||||
measure.Record(ctx, 2)
|
||||
valuerecorder.Record(ctx, 1)
|
||||
valuerecorder.Record(ctx, 2)
|
||||
|
||||
integrator.records = nil
|
||||
checkpointed = sdk.Collect(ctx)
|
||||
@@ -150,9 +150,9 @@ func TestDisabledInstrument(t *testing.T) {
|
||||
sdk := metricsdk.NewAccumulator(integrator)
|
||||
meter := metric.WrapMeterImpl(sdk, "test")
|
||||
|
||||
measure := Must(meter).NewFloat64Measure("name.disabled")
|
||||
valuerecorder := Must(meter).NewFloat64ValueRecorder("name.disabled")
|
||||
|
||||
measure.Record(ctx, -1)
|
||||
valuerecorder.Record(ctx, -1)
|
||||
checkpointed := sdk.Collect(ctx)
|
||||
|
||||
require.Equal(t, 0, checkpointed)
|
||||
@@ -291,20 +291,20 @@ func TestObserverCollection(t *testing.T) {
|
||||
sdk := metricsdk.NewAccumulator(integrator)
|
||||
meter := metric.WrapMeterImpl(sdk, "test")
|
||||
|
||||
_ = Must(meter).RegisterFloat64Observer("float.observer", func(result metric.Float64ObserverResult) {
|
||||
_ = Must(meter).RegisterFloat64ValueObserver("float.valueobserver", func(result metric.Float64ObserverResult) {
|
||||
result.Observe(1, kv.String("A", "B"))
|
||||
// last value wins
|
||||
result.Observe(-1, kv.String("A", "B"))
|
||||
result.Observe(-1, kv.String("C", "D"))
|
||||
})
|
||||
_ = Must(meter).RegisterInt64Observer("int.observer", func(result metric.Int64ObserverResult) {
|
||||
_ = Must(meter).RegisterInt64ValueObserver("int.valueobserver", func(result metric.Int64ObserverResult) {
|
||||
result.Observe(-1, kv.String("A", "B"))
|
||||
result.Observe(1)
|
||||
// last value wins
|
||||
result.Observe(1, kv.String("A", "B"))
|
||||
result.Observe(1)
|
||||
})
|
||||
_ = Must(meter).RegisterInt64Observer("empty.observer", func(result metric.Int64ObserverResult) {
|
||||
_ = Must(meter).RegisterInt64ValueObserver("empty.valueobserver", func(result metric.Int64ObserverResult) {
|
||||
})
|
||||
|
||||
collected := sdk.Collect(ctx)
|
||||
@@ -317,10 +317,10 @@ func TestObserverCollection(t *testing.T) {
|
||||
_ = 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,
|
||||
"float.valueobserver/A=B": -1,
|
||||
"float.valueobserver/C=D": -1,
|
||||
"int.valueobserver/": 1,
|
||||
"int.valueobserver/A=B": 1,
|
||||
}, out.Map)
|
||||
}
|
||||
|
||||
@@ -333,8 +333,8 @@ func TestObserverBatch(t *testing.T) {
|
||||
sdk := metricsdk.NewAccumulator(integrator)
|
||||
meter := metric.WrapMeterImpl(sdk, "test")
|
||||
|
||||
var floatObs metric.Float64Observer
|
||||
var intObs metric.Int64Observer
|
||||
var floatObs metric.Float64ValueObserver
|
||||
var intObs metric.Int64ValueObserver
|
||||
var batch = Must(meter).NewBatchObserver(
|
||||
func(result metric.BatchObserverResult) {
|
||||
result.Observe(
|
||||
@@ -358,8 +358,8 @@ func TestObserverBatch(t *testing.T) {
|
||||
intObs.Observation(1),
|
||||
)
|
||||
})
|
||||
floatObs = batch.RegisterFloat64Observer("float.observer")
|
||||
intObs = batch.RegisterInt64Observer("int.observer")
|
||||
floatObs = batch.RegisterFloat64ValueObserver("float.valueobserver")
|
||||
intObs = batch.RegisterInt64ValueObserver("int.valueobserver")
|
||||
|
||||
collected := sdk.Collect(ctx)
|
||||
|
||||
@@ -371,10 +371,10 @@ func TestObserverBatch(t *testing.T) {
|
||||
_ = 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,
|
||||
"float.valueobserver/A=B": -1,
|
||||
"float.valueobserver/C=D": -1,
|
||||
"int.valueobserver/": 1,
|
||||
"int.valueobserver/A=B": 1,
|
||||
}, out.Map)
|
||||
}
|
||||
|
||||
@@ -389,8 +389,8 @@ func TestRecordBatch(t *testing.T) {
|
||||
|
||||
counter1 := Must(meter).NewInt64Counter("int64.counter")
|
||||
counter2 := Must(meter).NewFloat64Counter("float64.counter")
|
||||
measure1 := Must(meter).NewInt64Measure("int64.measure")
|
||||
measure2 := Must(meter).NewFloat64Measure("float64.measure")
|
||||
valuerecorder1 := Must(meter).NewInt64ValueRecorder("int64.valuerecorder")
|
||||
valuerecorder2 := Must(meter).NewFloat64ValueRecorder("float64.valuerecorder")
|
||||
|
||||
sdk.RecordBatch(
|
||||
ctx,
|
||||
@@ -400,8 +400,8 @@ func TestRecordBatch(t *testing.T) {
|
||||
},
|
||||
counter1.Measurement(1),
|
||||
counter2.Measurement(2),
|
||||
measure1.Measurement(3),
|
||||
measure2.Measurement(4),
|
||||
valuerecorder1.Measurement(3),
|
||||
valuerecorder2.Measurement(4),
|
||||
)
|
||||
|
||||
sdk.Collect(ctx)
|
||||
@@ -411,10 +411,10 @@ func TestRecordBatch(t *testing.T) {
|
||||
_ = out.AddTo(rec)
|
||||
}
|
||||
require.EqualValues(t, map[string]float64{
|
||||
"int64.counter/A=B,C=D": 1,
|
||||
"float64.counter/A=B,C=D": 2,
|
||||
"int64.measure/A=B,C=D": 3,
|
||||
"float64.measure/A=B,C=D": 4,
|
||||
"int64.counter/A=B,C=D": 1,
|
||||
"float64.counter/A=B,C=D": 2,
|
||||
"int64.valuerecorder/A=B,C=D": 3,
|
||||
"float64.valuerecorder/A=B,C=D": 4,
|
||||
}, out.Map)
|
||||
}
|
||||
|
||||
|
||||
+24
-55
@@ -13,57 +13,34 @@
|
||||
// limitations under the License.
|
||||
|
||||
/*
|
||||
Package metric implements the OpenTelemetry metric.Meter API. The SDK
|
||||
supports configurable metrics export behavior through a collection of
|
||||
export interfaces that support various export strategies, described below.
|
||||
Package metric implements the OpenTelemetry metric.MeterImpl
|
||||
interface. The Accumulator type supports configurable metrics export
|
||||
behavior through a collection of export interfaces that support
|
||||
various export strategies, described below.
|
||||
|
||||
The metric.Meter API consists of methods for constructing each of the basic
|
||||
kinds of metric instrument. There are six types of instrument available to
|
||||
the end user, comprised of three basic kinds of metric instrument (Counter,
|
||||
Measure, Observer) crossed with two kinds of number (int64, float64).
|
||||
The metric.MeterImpl API consists of methods for constructing
|
||||
synchronous and asynchronous instruments. There are two constructors
|
||||
per instrument for the two kinds of number (int64, float64).
|
||||
|
||||
The API assists the SDK by consolidating the variety of metric instruments
|
||||
into a narrower interface, allowing the SDK to avoid repetition of
|
||||
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.
|
||||
Synchronous instruments are managed by a sync.Map containing a *record
|
||||
with the current state for each synchronous instrument. A bound
|
||||
instrument encapsulates a direct pointer to the record, allowing
|
||||
bound metric events to bypass a sync.Map lookup. A lock-free
|
||||
algorithm is used to protect against races when adding and removing
|
||||
items from the sync.Map.
|
||||
|
||||
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
|
||||
their handles, metric.HandleImpl. For observers, the API defines
|
||||
interfaces, for which the SDK provides an implementation.
|
||||
|
||||
There are four entry points for events in the Metrics API - three for
|
||||
synchronous instruments (counters and measures) and one for asynchronous
|
||||
instruments (observers). The entry points for synchronous instruments are:
|
||||
via instrument handles, via direct instrument calls, and via BatchRecord.
|
||||
The SDK is designed with handles as the primary entry point, the other two
|
||||
entry points are implemented in terms of short-lived handles. For example,
|
||||
the implementation of a direct call allocates a handle, operates on the
|
||||
handle, and releases the handle. Similarly, the implementation of
|
||||
RecordBatch uses a short-lived handle for each measurement in the batch.
|
||||
The entry point for asynchronous instruments is via observer callbacks.
|
||||
Observer callbacks behave like a set of instrument handles - one for each
|
||||
observation for a distinct label set. The observer handles are alive as
|
||||
long as they are used. If the callback stops reporting values for a
|
||||
certain label set, the associated handle is dropped.
|
||||
Asynchronous instruments are managed by an internal
|
||||
AsyncInstrumentState, which coordinates calling batch and single
|
||||
instrument callbacks.
|
||||
|
||||
Internal Structure
|
||||
|
||||
The SDK is designed with minimal use of locking, to avoid adding
|
||||
contention for user-level code. For each handle, whether it is held by
|
||||
user-level code or a short-lived device, there exists an internal record
|
||||
managed by the SDK. Each internal record corresponds to a specific
|
||||
instrument and label set combination.
|
||||
|
||||
Each observer also has its own kind of record stored in the SDK. This
|
||||
record contains a set of recorders for every specific label set used in the
|
||||
callback.
|
||||
|
||||
A sync.Map maintains the mapping of current instruments and label sets to
|
||||
internal records. To create a new handle, the SDK consults the Map to
|
||||
internal records. To create a new bound instrument, the SDK consults the Map to
|
||||
locate an existing record, otherwise it constructs a new record. The SDK
|
||||
maintains a count of the number of references to each record, ensuring
|
||||
that records are not reclaimed from the Map while they are still active
|
||||
@@ -74,12 +51,7 @@ sweeps through all records in the SDK, checkpointing their state. When a
|
||||
record is discovered that has no references and has not been updated since
|
||||
the prior collection pass, it is removed from the Map.
|
||||
|
||||
The SDK maintains a current epoch number, corresponding to the number of
|
||||
completed collections. Each recorder of an observer record contains the
|
||||
last epoch during which it was updated. This variable allows the collection
|
||||
code path to detect stale recorders and remove them.
|
||||
|
||||
Each record of a handle and recorder of an observer has an associated
|
||||
Both synchronous and asynchronous instruments have an associated
|
||||
aggregator, which maintains the current state resulting from all metric
|
||||
events since its last checkpoint. Aggregators may be lock-free or they may
|
||||
use locking, but they should expect to be called concurrently. Aggregators
|
||||
@@ -97,21 +69,18 @@ enters the SDK resulting in a new record, and collection context,
|
||||
where a system-level thread performs a collection pass through the
|
||||
SDK.
|
||||
|
||||
Descriptor is a struct that describes the metric instrument to the export
|
||||
pipeline, containing the name, recommended aggregation keys, units,
|
||||
description, metric kind (counter or measure), number kind (int64 or
|
||||
float64), and whether the instrument has alternate semantics or not (i.e.,
|
||||
monotonic=false counter, absolute=false measure). A Descriptor accompanies
|
||||
metric data as it passes through the export pipeline.
|
||||
Descriptor is a struct that describes the metric instrument to the
|
||||
export pipeline, containing the name, units, description, metric kind,
|
||||
number kind (int64 or float64). A Descriptor accompanies metric data
|
||||
as it passes through the export pipeline.
|
||||
|
||||
The AggregationSelector interface supports choosing the method of
|
||||
aggregation to apply to a particular instrument. Given the Descriptor,
|
||||
this AggregatorFor method returns an implementation of Aggregator. If this
|
||||
interface returns nil, the metric will be disabled. The aggregator should
|
||||
be matched to the capabilities of the exporter. Selecting the aggregator
|
||||
for counter instruments is relatively straightforward, but for measure and
|
||||
observer instruments there are numerous choices with different cost and
|
||||
quality tradeoffs.
|
||||
for sum-only instruments is relatively straightforward, but many options
|
||||
are available for aggregating distributions from ValueRecorder instruments.
|
||||
|
||||
Aggregator is an interface which implements a concrete strategy for
|
||||
aggregating metric updates. Several Aggregator implementations are
|
||||
|
||||
@@ -38,7 +38,7 @@ func ExampleNew() {
|
||||
ctx := context.Background()
|
||||
|
||||
key := kv.Key("key")
|
||||
meter := pusher.Meter("example")
|
||||
meter := pusher.Provider().Meter("example")
|
||||
|
||||
counter := metric.Must(meter).NewInt64Counter("a.counter")
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
)
|
||||
|
||||
func TestStressInt64Histogram(t *testing.T) {
|
||||
desc := metric.NewDescriptor("some_metric", metric.MeasureKind, metric.Int64NumberKind)
|
||||
desc := metric.NewDescriptor("some_metric", metric.ValueRecorderKind, metric.Int64NumberKind)
|
||||
h := histogram.New(&desc, []metric.Number{metric.NewInt64Number(25), metric.NewInt64Number(50), metric.NewInt64Number(75)})
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
|
||||
@@ -47,9 +47,9 @@ type (
|
||||
var (
|
||||
// LastValueADesc and LastValueBDesc group by "G"
|
||||
LastValueADesc = metric.NewDescriptor(
|
||||
"lastvalue.a", metric.ObserverKind, metric.Int64NumberKind)
|
||||
"lastvalue.a", metric.ValueObserverKind, metric.Int64NumberKind)
|
||||
LastValueBDesc = metric.NewDescriptor(
|
||||
"lastvalue.b", metric.ObserverKind, metric.Int64NumberKind)
|
||||
"lastvalue.b", metric.ValueObserverKind, metric.Int64NumberKind)
|
||||
// CounterADesc and CounterBDesc group by "C"
|
||||
CounterADesc = metric.NewDescriptor(
|
||||
"sum.a", metric.CounterKind, metric.Int64NumberKind)
|
||||
@@ -92,7 +92,7 @@ func (*testAggregationSelector) AggregatorFor(desc *metric.Descriptor) export.Ag
|
||||
switch desc.MetricKind() {
|
||||
case metric.CounterKind:
|
||||
return sum.New()
|
||||
case metric.ObserverKind:
|
||||
case metric.ValueObserverKind:
|
||||
return lastvalue.New()
|
||||
default:
|
||||
panic("Invalid descriptor MetricKind for this test")
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
)
|
||||
|
||||
func TestStressInt64MinMaxSumCount(t *testing.T) {
|
||||
desc := metric.NewDescriptor("some_metric", metric.MeasureKind, metric.Int64NumberKind)
|
||||
desc := metric.NewDescriptor("some_metric", metric.ValueRecorderKind, metric.Int64NumberKind)
|
||||
mmsc := minmaxsumcount.New(&desc)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
@@ -42,48 +42,48 @@ var (
|
||||
_ export.AggregationSelector = selectorHistogram{}
|
||||
)
|
||||
|
||||
// NewWithInexpensiveMeasure returns a simple aggregation selector
|
||||
// NewWithInexpensiveDistribution returns a simple aggregation selector
|
||||
// that uses counter, minmaxsumcount and minmaxsumcount aggregators
|
||||
// for the three kinds of metric. This selector is faster and uses
|
||||
// less memory than the others because minmaxsumcount does not
|
||||
// aggregate quantile information.
|
||||
func NewWithInexpensiveMeasure() export.AggregationSelector {
|
||||
func NewWithInexpensiveDistribution() export.AggregationSelector {
|
||||
return selectorInexpensive{}
|
||||
}
|
||||
|
||||
// NewWithSketchMeasure returns a simple aggregation selector that
|
||||
// NewWithSketchDistribution returns a simple aggregation selector that
|
||||
// uses counter, ddsketch, and ddsketch aggregators for the three
|
||||
// kinds of metric. This selector uses more cpu and memory than the
|
||||
// NewWithInexpensiveMeasure because it uses one DDSketch per distinct
|
||||
// measure/observer and labelset.
|
||||
func NewWithSketchMeasure(config *ddsketch.Config) export.AggregationSelector {
|
||||
// NewWithInexpensiveDistribution because it uses one DDSketch per distinct
|
||||
// instrument and label set.
|
||||
func NewWithSketchDistribution(config *ddsketch.Config) export.AggregationSelector {
|
||||
return selectorSketch{
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// NewWithExactMeasure returns a simple aggregation selector that uses
|
||||
// NewWithExactDistribution returns a simple aggregation selector that uses
|
||||
// counter, array, and array aggregators for the three kinds of metric.
|
||||
// This selector uses more memory than the NewWithSketchMeasure
|
||||
// This selector uses more memory than the NewWithSketchDistribution
|
||||
// because it aggregates an array of all values, therefore is able to
|
||||
// compute exact quantiles.
|
||||
func NewWithExactMeasure() export.AggregationSelector {
|
||||
func NewWithExactDistribution() export.AggregationSelector {
|
||||
return selectorExact{}
|
||||
}
|
||||
|
||||
// NewWithHistogramMeasure returns a simple aggregation selector that uses counter,
|
||||
// NewWithHistogramDistribution returns a simple aggregation selector that uses counter,
|
||||
// histogram, and histogram aggregators for the three kinds of metric. This
|
||||
// selector uses more memory than the NewWithInexpensiveMeasure because it
|
||||
// selector uses more memory than the NewWithInexpensiveDistribution because it
|
||||
// uses a counter per bucket.
|
||||
func NewWithHistogramMeasure(boundaries []metric.Number) export.AggregationSelector {
|
||||
func NewWithHistogramDistribution(boundaries []metric.Number) export.AggregationSelector {
|
||||
return selectorHistogram{boundaries: boundaries}
|
||||
}
|
||||
|
||||
func (selectorInexpensive) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator {
|
||||
switch descriptor.MetricKind() {
|
||||
case metric.ObserverKind:
|
||||
case metric.ValueObserverKind:
|
||||
fallthrough
|
||||
case metric.MeasureKind:
|
||||
case metric.ValueRecorderKind:
|
||||
return minmaxsumcount.New(descriptor)
|
||||
default:
|
||||
return sum.New()
|
||||
@@ -92,9 +92,9 @@ func (selectorInexpensive) AggregatorFor(descriptor *metric.Descriptor) export.A
|
||||
|
||||
func (s selectorSketch) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator {
|
||||
switch descriptor.MetricKind() {
|
||||
case metric.ObserverKind:
|
||||
case metric.ValueObserverKind:
|
||||
fallthrough
|
||||
case metric.MeasureKind:
|
||||
case metric.ValueRecorderKind:
|
||||
return ddsketch.New(s.config, descriptor)
|
||||
default:
|
||||
return sum.New()
|
||||
@@ -103,9 +103,9 @@ func (s selectorSketch) AggregatorFor(descriptor *metric.Descriptor) export.Aggr
|
||||
|
||||
func (selectorExact) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator {
|
||||
switch descriptor.MetricKind() {
|
||||
case metric.ObserverKind:
|
||||
case metric.ValueObserverKind:
|
||||
fallthrough
|
||||
case metric.MeasureKind:
|
||||
case metric.ValueRecorderKind:
|
||||
return array.New()
|
||||
default:
|
||||
return sum.New()
|
||||
@@ -114,9 +114,9 @@ func (selectorExact) AggregatorFor(descriptor *metric.Descriptor) export.Aggrega
|
||||
|
||||
func (s selectorHistogram) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator {
|
||||
switch descriptor.MetricKind() {
|
||||
case metric.ObserverKind:
|
||||
case metric.ValueObserverKind:
|
||||
fallthrough
|
||||
case metric.MeasureKind:
|
||||
case metric.ValueRecorderKind:
|
||||
return histogram.New(descriptor, s.boundaries)
|
||||
default:
|
||||
return sum.New()
|
||||
|
||||
@@ -29,35 +29,35 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
testCounterDesc = metric.NewDescriptor("counter", metric.CounterKind, metric.Int64NumberKind)
|
||||
testMeasureDesc = metric.NewDescriptor("measure", metric.MeasureKind, metric.Int64NumberKind)
|
||||
testObserverDesc = metric.NewDescriptor("observer", metric.ObserverKind, metric.Int64NumberKind)
|
||||
testCounterDesc = metric.NewDescriptor("counter", metric.CounterKind, metric.Int64NumberKind)
|
||||
testValueRecorderDesc = metric.NewDescriptor("valuerecorder", metric.ValueRecorderKind, metric.Int64NumberKind)
|
||||
testValueObserverDesc = metric.NewDescriptor("valueobserver", metric.ValueObserverKind, metric.Int64NumberKind)
|
||||
)
|
||||
|
||||
func TestInexpensiveMeasure(t *testing.T) {
|
||||
inex := simple.NewWithInexpensiveMeasure()
|
||||
func TestInexpensiveDistribution(t *testing.T) {
|
||||
inex := simple.NewWithInexpensiveDistribution()
|
||||
require.NotPanics(t, func() { _ = inex.AggregatorFor(&testCounterDesc).(*sum.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = inex.AggregatorFor(&testMeasureDesc).(*minmaxsumcount.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = inex.AggregatorFor(&testObserverDesc).(*minmaxsumcount.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = inex.AggregatorFor(&testValueRecorderDesc).(*minmaxsumcount.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = inex.AggregatorFor(&testValueObserverDesc).(*minmaxsumcount.Aggregator) })
|
||||
}
|
||||
|
||||
func TestSketchMeasure(t *testing.T) {
|
||||
sk := simple.NewWithSketchMeasure(ddsketch.NewDefaultConfig())
|
||||
func TestSketchDistribution(t *testing.T) {
|
||||
sk := simple.NewWithSketchDistribution(ddsketch.NewDefaultConfig())
|
||||
require.NotPanics(t, func() { _ = sk.AggregatorFor(&testCounterDesc).(*sum.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = sk.AggregatorFor(&testMeasureDesc).(*ddsketch.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = sk.AggregatorFor(&testObserverDesc).(*ddsketch.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = sk.AggregatorFor(&testValueRecorderDesc).(*ddsketch.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = sk.AggregatorFor(&testValueObserverDesc).(*ddsketch.Aggregator) })
|
||||
}
|
||||
|
||||
func TestExactMeasure(t *testing.T) {
|
||||
ex := simple.NewWithExactMeasure()
|
||||
func TestExactDistribution(t *testing.T) {
|
||||
ex := simple.NewWithExactDistribution()
|
||||
require.NotPanics(t, func() { _ = ex.AggregatorFor(&testCounterDesc).(*sum.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = ex.AggregatorFor(&testMeasureDesc).(*array.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = ex.AggregatorFor(&testObserverDesc).(*array.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = ex.AggregatorFor(&testValueRecorderDesc).(*array.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = ex.AggregatorFor(&testValueObserverDesc).(*array.Aggregator) })
|
||||
}
|
||||
|
||||
func TestHistogramMeasure(t *testing.T) {
|
||||
ex := simple.NewWithHistogramMeasure([]metric.Number{})
|
||||
func TestHistogramDistribution(t *testing.T) {
|
||||
ex := simple.NewWithHistogramDistribution([]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) })
|
||||
require.NotPanics(t, func() { _ = ex.AggregatorFor(&testValueRecorderDesc).(*histogram.Aggregator) })
|
||||
require.NotPanics(t, func() { _ = ex.AggregatorFor(&testValueObserverDesc).(*histogram.Aggregator) })
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ func (f *testFixture) Process(_ context.Context, record export.Record) error {
|
||||
f.T.Fatal("Sum error: ", err)
|
||||
}
|
||||
f.impl.storeCollect(actual, sum, time.Time{})
|
||||
case metric.MeasureKind:
|
||||
case metric.ValueRecorderKind:
|
||||
lv, ts, err := agg.(aggregator.LastValue).LastValue()
|
||||
if err != nil && err != aggregator.ErrNoData {
|
||||
f.T.Fatal("Last value error: ", err)
|
||||
@@ -431,15 +431,15 @@ func TestStressFloat64Counter(t *testing.T) {
|
||||
func intLastValueTestImpl() testImpl {
|
||||
return testImpl{
|
||||
newInstrument: func(meter api.Meter, name string) SyncImpler {
|
||||
return Must(meter).NewInt64Measure(name + ".lastvalue")
|
||||
return Must(meter).NewInt64ValueRecorder(name + ".lastvalue")
|
||||
},
|
||||
getUpdateValue: func() api.Number {
|
||||
r1 := rand.Int63()
|
||||
return api.NewInt64Number(rand.Int63() - r1)
|
||||
},
|
||||
operate: func(inst interface{}, ctx context.Context, value api.Number, labels []kv.KeyValue) {
|
||||
measure := inst.(api.Int64Measure)
|
||||
measure.Record(ctx, value.AsInt64(), labels...)
|
||||
valuerecorder := inst.(api.Int64ValueRecorder)
|
||||
valuerecorder.Record(ctx, value.AsInt64(), labels...)
|
||||
},
|
||||
newStore: func() interface{} {
|
||||
return &lastValueState{
|
||||
@@ -473,14 +473,14 @@ func TestStressInt64LastValue(t *testing.T) {
|
||||
func floatLastValueTestImpl() testImpl {
|
||||
return testImpl{
|
||||
newInstrument: func(meter api.Meter, name string) SyncImpler {
|
||||
return Must(meter).NewFloat64Measure(name + ".lastvalue")
|
||||
return Must(meter).NewFloat64ValueRecorder(name + ".lastvalue")
|
||||
},
|
||||
getUpdateValue: func() api.Number {
|
||||
return api.NewFloat64Number((-0.5 + rand.Float64()) * 100000)
|
||||
},
|
||||
operate: func(inst interface{}, ctx context.Context, value api.Number, labels []kv.KeyValue) {
|
||||
measure := inst.(api.Float64Measure)
|
||||
measure.Record(ctx, value.AsFloat64(), labels...)
|
||||
valuerecorder := inst.(api.Float64ValueRecorder)
|
||||
valuerecorder.Record(ctx, value.AsFloat64(), labels...)
|
||||
},
|
||||
newStore: func() interface{} {
|
||||
return &lastValueState{
|
||||
|
||||
@@ -1,80 +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 resourcekeys contains well known type and label keys for resources.
|
||||
package resourcekeys // import "go.opentelemetry.io/otel/sdk/resource/resourcekeys"
|
||||
|
||||
// Constants for Service resources.
|
||||
const (
|
||||
// A uniquely identifying name for a Service.
|
||||
ServiceKeyName = "service.name"
|
||||
ServiceKeyNamespace = "service.namespace"
|
||||
ServiceKeyInstanceID = "service.instance.id"
|
||||
ServiceKeyVersion = "service.version"
|
||||
)
|
||||
|
||||
// Constants for Library resources.
|
||||
const (
|
||||
// A uniquely identifying name for a Library.
|
||||
LibraryKeyName = "library.name"
|
||||
LibraryKeyLanguage = "library.language"
|
||||
LibraryKeyVersion = "library.version"
|
||||
)
|
||||
|
||||
// Constants for Kubernetes resources.
|
||||
const (
|
||||
// A uniquely identifying name for the Kubernetes cluster. Kubernetes
|
||||
// does not have cluster names as an internal concept so this may be
|
||||
// set to any meaningful value within the environment. For example,
|
||||
// GKE clusters have a name which can be used for this label.
|
||||
K8SKeyClusterName = "k8s.cluster.name"
|
||||
K8SKeyNamespaceName = "k8s.namespace.name"
|
||||
K8SKeyPodName = "k8s.pod.name"
|
||||
K8SKeyDeploymentName = "k8s.deployment.name"
|
||||
)
|
||||
|
||||
// Constants for Container resources.
|
||||
const (
|
||||
// A uniquely identifying name for the Container.
|
||||
ContainerKeyName = "container.name"
|
||||
ContainerKeyImageName = "container.image.name"
|
||||
ContainerKeyImageTag = "container.image.tag"
|
||||
)
|
||||
|
||||
// Constants for Cloud resources.
|
||||
const (
|
||||
CloudKeyProvider = "cloud.provider"
|
||||
CloudKeyAccountID = "cloud.account.id"
|
||||
CloudKeyRegion = "cloud.region"
|
||||
CloudKeyZone = "cloud.zone"
|
||||
|
||||
// Cloud Providers
|
||||
CloudProviderAWS = "aws"
|
||||
CloudProviderGCP = "gcp"
|
||||
CloudProviderAZURE = "azure"
|
||||
)
|
||||
|
||||
// Constants for Host resources.
|
||||
const (
|
||||
// A uniquely identifying name for the host.
|
||||
HostKeyName = "host.name"
|
||||
|
||||
// A hostname as returned by the 'hostname' command on host machine.
|
||||
HostKeyHostName = "host.hostname"
|
||||
HostKeyID = "host.id"
|
||||
HostKeyType = "host.type"
|
||||
HostKeyImageName = "host.image.name"
|
||||
HostKeyImageID = "host.image.id"
|
||||
HostKeyImageVersion = "host.image.version"
|
||||
)
|
||||
Reference in New Issue
Block a user