1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-01-01 22:09:57 +02:00

Update metrics API to match current spec (#228)

* Update metrics API to match current spec

* update options to match the spec

* drop the global meter API

* more docs

* get rid of leftover mentions about descriptor
This commit is contained in:
Krzesimir Nowak 2019-10-23 08:29:24 +02:00 committed by rghetia
parent a6e139e1d4
commit b3247f04fc
15 changed files with 643 additions and 591 deletions

View File

@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//go:generate stringer -type=Kind,ValueKind
package metric
import (
@ -23,25 +21,24 @@ import (
"go.opentelemetry.io/api/unit"
)
// Kind categorizes different kinds of metric.
type Kind int
const (
// Invalid describes an invalid metric.
Invalid Kind = iota
// CounterKind describes a metric that supports Add().
CounterKind
// GaugeKind describes a metric that supports Set().
GaugeKind
// MeasureKind describes a metric that supports Record().
MeasureKind
)
// Instrument is the implementation-level interface Set/Add/Record
// individual metrics without precomputed labels.
type Instrument interface {
// AcquireHandle creates a Handle to record metrics with
// precomputed labels.
AcquireHandle(labels LabelSet) Handle
// RecordOne allows the SDK to observe a single metric event.
RecordOne(ctx context.Context, value MeasurementValue, labels LabelSet)
}
// Handle is the implementation-level interface to Set/Add/Record
// individual metrics.
// individual metrics with precomputed labels.
type Handle interface {
// RecordOne allows the SDK to observe a single metric event
// RecordOne allows the SDK to observe a single metric event.
RecordOne(ctx context.Context, value MeasurementValue)
// Release frees the resources associated with this handle. It
// does not affect the metric this handle was created through.
Release()
}
// TODO this belongs outside the metrics API, in some sense, but that
@ -49,135 +46,115 @@ type Handle interface {
// a LabelSet between metrics and tracing, even when they are the same
// SDK.
// LabelSet represents a []core.KeyValue for use as pre-defined labels
// in the metrics API.
// TODO(krnowak): I wonder if this should just be:
//
// type LabelSet interface{}
//
// Not sure how the Meter function is useful.
// LabelSet is an implementation-level interface that represents a
// []core.KeyValue for use as pre-defined labels in the metrics API.
type LabelSet interface {
Meter() Meter
}
// WithDescriptor is an interface that all metric implement.
type WithDescriptor interface {
// Descriptor returns a descriptor of this metric.
Descriptor() *Descriptor
// Options contains some options for metrics of any kind.
type Options struct {
// Description is an optional field describing the metric
// instrument.
Description string
// Unit is an optional field describing the metric instrument.
Unit unit.Unit
// Keys are recommended keys determined in the handles
// obtained for the metric.
Keys []core.Key
// Alternate defines the property of metric value dependent on
// a metric type.
//
// - for Counter, true implies that the metric is an up-down
// Counter
//
// - for Gauge, true implies that the metric is a
// non-descending Gauge
//
// - for Measure, true implies that the metric supports
// positive and negative values
Alternate bool
}
type hiddenType struct{}
// CounterOptionApplier is an interface for applying metric options
// that are valid only for counter metrics.
type CounterOptionApplier interface {
// ApplyCounterOption is used to make some general or
// counter-specific changes in the Options.
ApplyCounterOption(*Options)
}
// ExplicitReportingMetric is an interface that is implemented only by
// metrics that support getting a Handle.
type ExplicitReportingMetric interface {
WithDescriptor
// SupportHandle is a dummy function that can be only
// implemented in this package.
SupportHandle() hiddenType
// GaugeOptionApplier is an interface for applying metric options that
// are valid only for gauge metrics.
type GaugeOptionApplier interface {
// ApplyGaugeOption is used to make some general or
// gauge-specific changes in the Options.
ApplyGaugeOption(*Options)
}
// MeasureOptionApplier is an interface for applying metric options
// that are valid only for measure metrics.
type MeasureOptionApplier interface {
// ApplyMeasureOption is used to make some general or
// measure-specific changes in the Options.
ApplyMeasureOption(*Options)
}
// Measurement is used for reporting a batch of metric
// values. Instances of this type should be created by instruments
// (Int64Counter.Measurement()).
type Measurement struct {
instrument Instrument
value MeasurementValue
}
// Instrument returns an instrument that created this measurement.
func (m Measurement) Instrument() Instrument {
return m.instrument
}
// Value returns a value recorded in this measurement.
func (m Measurement) Value() MeasurementValue {
return m.value
}
// Meter is an interface to the metrics portion of the OpenTelemetry SDK.
type Meter interface {
// DefineLabels returns a reference to a set of labels that
// cannot be read by the application.
DefineLabels(context.Context, ...core.KeyValue) LabelSet
// Labels returns a reference to a set of labels that cannot
// be read by the application.
Labels(context.Context, ...core.KeyValue) LabelSet
// NewInt64Counter creates a new integral counter with a given
// name and customized with passed options.
NewInt64Counter(name string, cos ...CounterOptionApplier) Int64Counter
// NewFloat64Counter creates a new floating point counter with
// a given name and customized with passed options.
NewFloat64Counter(name string, cos ...CounterOptionApplier) Float64Counter
// NewInt64Gauge creates a new integral gauge with a given
// name and customized with passed options.
NewInt64Gauge(name string, gos ...GaugeOptionApplier) Int64Gauge
// NewFloat64Gauge creates a new floating point gauge with a
// given name and customized with passed options.
NewFloat64Gauge(name string, gos ...GaugeOptionApplier) Float64Gauge
// NewInt64Measure creates a new integral measure with a given
// name and customized with passed options.
NewInt64Measure(name string, mos ...MeasureOptionApplier) Int64Measure
// NewFloat64Measure creates a new floating point measure with
// a given name and customized with passed options.
NewFloat64Measure(name string, mos ...MeasureOptionApplier) Float64Measure
// RecordBatch atomically records a batch of measurements.
RecordBatch(context.Context, LabelSet, ...Measurement)
// NewHandle creates a Handle that contains the passed
// key-value pairs. This should not be used directly - prefer
// using GetHandle function of a metric.
NewHandle(ExplicitReportingMetric, LabelSet) Handle
// DeleteHandle destroys the Handle and does a cleanup of the
// underlying resources.
DeleteHandle(Handle)
}
// DescriptorID is a unique identifier of a metric.
type DescriptorID uint64
// ValueKind describes the data type of the measurement value the
// metric generates.
type ValueKind int8
const (
// Int64ValueKind means that the metric generates values of
// type int64.
Int64ValueKind ValueKind = iota
// Float64ValueKind means that the metric generates values of
// type float64.
Float64ValueKind
)
// Descriptor represents a named metric with recommended
// local-aggregation keys.
type Descriptor struct {
name string
kind Kind
keys []core.Key
id DescriptorID
description string
unit unit.Unit
valueKind ValueKind
alternate bool
}
// Name is a required field describing this metric descriptor, should
// have length > 0.
func (d *Descriptor) Name() string {
return d.name
}
// Kind is the metric kind of this descriptor.
func (d *Descriptor) Kind() Kind {
return d.kind
}
// Keys are recommended keys determined in the handles obtained for
// this metric.
func (d *Descriptor) Keys() []core.Key {
return d.keys
}
// ID is uniquely assigned to support per-SDK registration.
func (d *Descriptor) ID() DescriptorID {
return d.id
}
// Description is an optional field describing this metric descriptor.
func (d *Descriptor) Description() string {
return d.description
}
// Unit is an optional field describing this metric descriptor.
func (d *Descriptor) Unit() unit.Unit {
return d.unit
}
// ValueKind describes the type of values the metric produces.
func (d *Descriptor) ValueKind() ValueKind {
return d.valueKind
}
// Alternate defines the property of metric value dependent on a
// metric type.
//
// - for Counter, true implies that the metric is an up-down Counter
//
// - for Gauge, true implies that the metric is a
// non-descending Gauge
//
// - for Measure, true implies that the metric supports positive and
// negative values
func (d *Descriptor) Alternate() bool {
return d.alternate
}
// Measurement is used for reporting a batch of metric values.
type Measurement struct {
Descriptor *Descriptor
Value MeasurementValue
}
// Option supports specifying the various metric options.
type Option func(*Descriptor)
type Option func(*Options)
// OptionApplier is an interface for applying metric options that are
// valid for all the kinds of metrics.
@ -185,37 +162,87 @@ type OptionApplier interface {
CounterOptionApplier
GaugeOptionApplier
MeasureOptionApplier
// ApplyOption is used to make some changes in the Descriptor.
ApplyOption(*Descriptor)
// ApplyOption is used to make some general changes in the
// Options.
ApplyOption(*Options)
}
// CounterGaugeOptionApplier is an interface for applying metric
// options that are valid for counter or gauge metrics.
type CounterGaugeOptionApplier interface {
CounterOptionApplier
GaugeOptionApplier
}
type optionWrapper struct {
F Option
}
var _ OptionApplier = optionWrapper{}
func (o optionWrapper) ApplyCounterOption(d *Descriptor) {
o.ApplyOption(d)
type counterOptionWrapper struct {
F Option
}
func (o optionWrapper) ApplyGaugeOption(d *Descriptor) {
o.ApplyOption(d)
type gaugeOptionWrapper struct {
F Option
}
func (o optionWrapper) ApplyMeasureOption(d *Descriptor) {
o.ApplyOption(d)
type measureOptionWrapper struct {
F Option
}
func (o optionWrapper) ApplyOption(d *Descriptor) {
o.F(d)
type counterGaugeOptionWrapper struct {
FC Option
FG Option
}
var (
_ OptionApplier = optionWrapper{}
_ CounterOptionApplier = counterOptionWrapper{}
_ GaugeOptionApplier = gaugeOptionWrapper{}
_ MeasureOptionApplier = measureOptionWrapper{}
)
func (o optionWrapper) ApplyCounterOption(opts *Options) {
o.ApplyOption(opts)
}
func (o optionWrapper) ApplyGaugeOption(opts *Options) {
o.ApplyOption(opts)
}
func (o optionWrapper) ApplyMeasureOption(opts *Options) {
o.ApplyOption(opts)
}
func (o optionWrapper) ApplyOption(opts *Options) {
o.F(opts)
}
func (o counterOptionWrapper) ApplyCounterOption(opts *Options) {
o.F(opts)
}
func (o gaugeOptionWrapper) ApplyGaugeOption(opts *Options) {
o.F(opts)
}
func (o measureOptionWrapper) ApplyMeasureOption(opts *Options) {
o.F(opts)
}
func (o counterGaugeOptionWrapper) ApplyCounterOption(opts *Options) {
o.FC(opts)
}
func (o counterGaugeOptionWrapper) ApplyGaugeOption(opts *Options) {
o.FG(opts)
}
// WithDescription applies provided description.
func WithDescription(desc string) OptionApplier {
return optionWrapper{
F: func(d *Descriptor) {
d.description = desc
F: func(opts *Options) {
opts.Description = desc
},
}
}
@ -223,56 +250,41 @@ func WithDescription(desc string) OptionApplier {
// WithUnit applies provided unit.
func WithUnit(unit unit.Unit) OptionApplier {
return optionWrapper{
F: func(d *Descriptor) {
d.unit = unit
F: func(opts *Options) {
opts.Unit = unit
},
}
}
// WithKeys applies required label keys. Multiple `WithKeys` options
// accumulate.
// WithKeys applies recommended label keys. Multiple `WithKeys`
// options accumulate.
func WithKeys(keys ...core.Key) OptionApplier {
return optionWrapper{
F: func(d *Descriptor) {
d.keys = append(d.keys, keys...)
F: func(opts *Options) {
opts.Keys = append(opts.Keys, keys...)
},
}
}
// WithNonMonotonic sets whether a counter is permitted to go up AND
// down.
func WithNonMonotonic(nm bool) CounterOptionApplier {
return counterOptionWrapper{
F: func(d *Descriptor) {
d.alternate = nm
// WithMonotonic sets whether a counter or a gauge is not permitted to
// go down.
func WithMonotonic(monotonic bool) CounterGaugeOptionApplier {
return counterGaugeOptionWrapper{
FC: func(opts *Options) {
opts.Alternate = !monotonic
},
FG: func(opts *Options) {
opts.Alternate = monotonic
},
}
}
// WithMonotonic sets whether a gauge is not permitted to go down.
func WithMonotonic(m bool) GaugeOptionApplier {
return gaugeOptionWrapper{
F: func(d *Descriptor) {
d.alternate = m
},
}
}
// WithSigned sets whether a measure is permitted to be negative.
func WithSigned(s bool) MeasureOptionApplier {
// WithAbsolute sets whether a measure is not permitted to be
// negative.
func WithAbsolute(absolute bool) MeasureOptionApplier {
return measureOptionWrapper{
F: func(d *Descriptor) {
d.alternate = s
F: func(opts *Options) {
opts.Alternate = !absolute
},
}
}
// Defined returns true when the descriptor has been registered.
func (d Descriptor) Defined() bool {
return len(d.name) != 0
}
// RecordBatch reports to the global Meter.
func RecordBatch(ctx context.Context, labels LabelSet, batch ...Measurement) {
GlobalMeter().RecordBatch(ctx, labels, batch...)
}

View File

@ -22,6 +22,8 @@ import (
"go.opentelemetry.io/api/core"
"go.opentelemetry.io/api/key"
"go.opentelemetry.io/api/unit"
"github.com/google/go-cmp/cmp"
)
func TestCounterOptions(t *testing.T) {
@ -103,7 +105,7 @@ func TestCounterOptions(t *testing.T) {
{
name: "nonmonotonic",
opts: []CounterOptionApplier{
WithNonMonotonic(true),
WithMonotonic(false),
},
keys: nil,
desc: "",
@ -113,8 +115,8 @@ func TestCounterOptions(t *testing.T) {
{
name: "nonmonotonic, but not really",
opts: []CounterOptionApplier{
WithNonMonotonic(true),
WithNonMonotonic(false),
WithMonotonic(false),
WithMonotonic(true),
},
keys: nil,
desc: "",
@ -122,24 +124,16 @@ func TestCounterOptions(t *testing.T) {
alt: false,
},
}
checkCounterDescriptor := func(tt testcase, vk ValueKind, d *Descriptor) {
e := descriptor{
name: tt.name,
keys: tt.keys,
desc: tt.desc,
unit: tt.unit,
alt: tt.alt,
kind: CounterKind,
vk: vk,
}
checkDescriptor(t, e, d)
}
for idx, tt := range testcases {
t.Logf("Testing counter case %s (%d)", tt.name, idx)
f := NewFloat64Counter(tt.name, tt.opts...)
checkCounterDescriptor(tt, Float64ValueKind, f.Descriptor())
i := NewInt64Counter(tt.name, tt.opts...)
checkCounterDescriptor(tt, Int64ValueKind, i.Descriptor())
opts := &Options{}
ApplyCounterOptions(opts, tt.opts...)
checkOptions(t, opts, &Options{
Description: tt.desc,
Unit: tt.unit,
Keys: tt.keys,
Alternate: tt.alt,
})
}
}
@ -241,24 +235,16 @@ func TestGaugeOptions(t *testing.T) {
alt: false,
},
}
checkGaugeDescriptor := func(tt testcase, vk ValueKind, d *Descriptor) {
e := descriptor{
name: tt.name,
keys: tt.keys,
desc: tt.desc,
unit: tt.unit,
alt: tt.alt,
kind: GaugeKind,
vk: vk,
}
checkDescriptor(t, e, d)
}
for idx, tt := range testcases {
t.Logf("Testing gauge case %s (%d)", tt.name, idx)
f := NewFloat64Gauge(tt.name, tt.opts...)
checkGaugeDescriptor(tt, Float64ValueKind, f.Descriptor())
i := NewInt64Gauge(tt.name, tt.opts...)
checkGaugeDescriptor(tt, Int64ValueKind, i.Descriptor())
opts := &Options{}
ApplyGaugeOptions(opts, tt.opts...)
checkOptions(t, opts, &Options{
Description: tt.desc,
Unit: tt.unit,
Keys: tt.keys,
Alternate: tt.alt,
})
}
}
@ -339,9 +325,9 @@ func TestMeasureOptions(t *testing.T) {
alt: false,
},
{
name: "signed",
name: "not absolute",
opts: []MeasureOptionApplier{
WithSigned(true),
WithAbsolute(false),
},
keys: nil,
desc: "",
@ -349,10 +335,10 @@ func TestMeasureOptions(t *testing.T) {
alt: true,
},
{
name: "signed, but not really",
name: "not absolute, but not really",
opts: []MeasureOptionApplier{
WithSigned(true),
WithSigned(false),
WithAbsolute(false),
WithAbsolute(true),
},
keys: nil,
desc: "",
@ -360,156 +346,112 @@ func TestMeasureOptions(t *testing.T) {
alt: false,
},
}
checkMeasureDescriptor := func(tt testcase, vk ValueKind, d *Descriptor) {
e := descriptor{
name: tt.name,
keys: tt.keys,
desc: tt.desc,
unit: tt.unit,
alt: tt.alt,
kind: MeasureKind,
vk: vk,
}
checkDescriptor(t, e, d)
}
for idx, tt := range testcases {
t.Logf("Testing measure case %s (%d)", tt.name, idx)
f := NewFloat64Measure(tt.name, tt.opts...)
checkMeasureDescriptor(tt, Float64ValueKind, f.Descriptor())
i := NewInt64Measure(tt.name, tt.opts...)
checkMeasureDescriptor(tt, Int64ValueKind, i.Descriptor())
opts := &Options{}
ApplyMeasureOptions(opts, tt.opts...)
checkOptions(t, opts, &Options{
Description: tt.desc,
Unit: tt.unit,
Keys: tt.keys,
Alternate: tt.alt,
})
}
}
type descriptor struct {
name string
keys []core.Key
desc string
unit unit.Unit
alt bool
kind Kind
vk ValueKind
}
func checkDescriptor(t *testing.T, e descriptor, d *Descriptor) {
if e.name != d.Name() {
t.Errorf("Expected name %q, got %q", e.name, d.Name())
}
if len(e.keys) != len(d.Keys()) {
t.Errorf("Expected %d key(s), got %d", len(e.keys), len(d.Keys()))
}
minLen := len(e.keys)
if minLen > len(d.Keys()) {
minLen = len(d.Keys())
}
for i := 0; i < minLen; i++ {
if e.keys[i] != d.Keys()[i] {
t.Errorf("Expected key %q, got %q", e.keys[i], d.Keys()[i])
}
}
if e.desc != d.Description() {
t.Errorf("Expected description %q, got %q", e.desc, d.Description())
}
if e.unit != d.Unit() {
t.Errorf("Expected unit %q, got %q", e.unit, d.Unit())
}
if e.alt != d.Alternate() {
t.Errorf("Expected alternate %v, got %v", e.alt, d.Alternate())
}
if e.vk != d.ValueKind() {
t.Errorf("Expected value kind %q, got %q", e.vk, d.ValueKind())
}
if e.kind != d.Kind() {
t.Errorf("Expected kind %q, got %q", e.kind, d.Kind())
func checkOptions(t *testing.T, got *Options, expected *Options) {
if diff := cmp.Diff(got, expected); diff != "" {
t.Errorf("Compare options: -got +want %s", diff)
}
}
func TestCounter(t *testing.T) {
{
c := NewFloat64Counter("ajwaj")
meter := newMockMeter()
c := meter.NewFloat64Counter("ajwaj")
ctx := context.Background()
labels := meter.DefineLabels(ctx)
labels := meter.Labels(ctx)
c.Add(ctx, 42, labels)
handle := c.GetHandle(labels)
handle := c.AcquireHandle(labels)
handle.Add(ctx, 42)
meter.RecordBatch(ctx, labels, c.Measurement(42))
t.Log("Testing float counter")
checkBatches(t, ctx, labels, meter, c.Descriptor())
checkBatches(t, ctx, labels, meter, Float64ValueKind, c.instrument)
}
{
c := NewInt64Counter("ajwaj")
meter := newMockMeter()
c := meter.NewInt64Counter("ajwaj")
ctx := context.Background()
labels := meter.DefineLabels(ctx)
labels := meter.Labels(ctx)
c.Add(ctx, 42, labels)
handle := c.GetHandle(labels)
handle := c.AcquireHandle(labels)
handle.Add(ctx, 42)
meter.RecordBatch(ctx, labels, c.Measurement(42))
t.Log("Testing int counter")
checkBatches(t, ctx, labels, meter, c.Descriptor())
checkBatches(t, ctx, labels, meter, Int64ValueKind, c.instrument)
}
}
func TestGauge(t *testing.T) {
{
g := NewFloat64Gauge("ajwaj")
meter := newMockMeter()
g := meter.NewFloat64Gauge("ajwaj")
ctx := context.Background()
labels := meter.DefineLabels(ctx)
labels := meter.Labels(ctx)
g.Set(ctx, 42, labels)
handle := g.GetHandle(labels)
handle := g.AcquireHandle(labels)
handle.Set(ctx, 42)
meter.RecordBatch(ctx, labels, g.Measurement(42))
t.Log("Testing float gauge")
checkBatches(t, ctx, labels, meter, g.Descriptor())
checkBatches(t, ctx, labels, meter, Float64ValueKind, g.instrument)
}
{
g := NewInt64Gauge("ajwaj")
meter := newMockMeter()
g := meter.NewInt64Gauge("ajwaj")
ctx := context.Background()
labels := meter.DefineLabels(ctx)
labels := meter.Labels(ctx)
g.Set(ctx, 42, labels)
handle := g.GetHandle(labels)
handle := g.AcquireHandle(labels)
handle.Set(ctx, 42)
meter.RecordBatch(ctx, labels, g.Measurement(42))
t.Log("Testing int gauge")
checkBatches(t, ctx, labels, meter, g.Descriptor())
checkBatches(t, ctx, labels, meter, Int64ValueKind, g.instrument)
}
}
func TestMeasure(t *testing.T) {
{
m := NewFloat64Measure("ajwaj")
meter := newMockMeter()
m := meter.NewFloat64Measure("ajwaj")
ctx := context.Background()
labels := meter.DefineLabels(ctx)
labels := meter.Labels(ctx)
m.Record(ctx, 42, labels)
handle := m.GetHandle(labels)
handle := m.AcquireHandle(labels)
handle.Record(ctx, 42)
meter.RecordBatch(ctx, labels, m.Measurement(42))
t.Log("Testing float measure")
checkBatches(t, ctx, labels, meter, m.Descriptor())
checkBatches(t, ctx, labels, meter, Float64ValueKind, m.instrument)
}
{
m := NewInt64Measure("ajwaj")
meter := newMockMeter()
m := meter.NewInt64Measure("ajwaj")
ctx := context.Background()
labels := meter.DefineLabels(ctx)
labels := meter.Labels(ctx)
m.Record(ctx, 42, labels)
handle := m.GetHandle(labels)
handle := m.AcquireHandle(labels)
handle.Record(ctx, 42)
meter.RecordBatch(ctx, labels, m.Measurement(42))
t.Log("Testing int measure")
checkBatches(t, ctx, labels, meter, m.Descriptor())
checkBatches(t, ctx, labels, meter, Int64ValueKind, m.instrument)
}
}
func checkBatches(t *testing.T, ctx context.Context, labels LabelSet, meter *mockMeter, descriptor *Descriptor) {
func checkBatches(t *testing.T, ctx context.Context, labels LabelSet, meter *mockMeter, kind ValueKind, instrument Instrument) {
t.Helper()
if len(meter.measurementBatches) != 3 {
t.Errorf("Expected 3 recorded measurement batches, got %d", len(meter.measurementBatches))
}
ourInstrument := instrument.(*mockInstrument)
ourLabelSet := labels.(*mockLabelSet)
minLen := 3
if minLen > len(meter.measurementBatches) {
@ -538,15 +480,15 @@ func checkBatches(t *testing.T, ctx context.Context, labels LabelSet, meter *moc
}
for j := 0; j < minMLen; j++ {
measurement := got.measurements[j]
if measurement.Descriptor != descriptor {
d := func(d *Descriptor) string {
return fmt.Sprintf("(ptr: %p, descriptor %#v)", d, d)
if measurement.instrument != ourInstrument {
d := func(i *mockInstrument) string {
return fmt.Sprintf("(ptr: %p, instrument %#v)", i, i)
}
t.Errorf("Wrong recorded descriptor in measurement %d in batch %d, expected %s, got %s", j, i, d(descriptor), d(measurement.Descriptor))
t.Errorf("Wrong recorded instrument in measurement %d in batch %d, expected %s, got %s", j, i, d(ourInstrument), d(measurement.instrument))
}
ft := fortyTwo(t, descriptor.ValueKind())
if measurement.Value.RawCompare(ft.AsRaw(), descriptor.ValueKind()) != 0 {
t.Errorf("Wrong recorded value in measurement %d in batch %d, expected %s, got %s", j, i, ft.Emit(descriptor.ValueKind()), measurement.Value.Emit(descriptor.ValueKind()))
ft := fortyTwo(t, kind)
if measurement.value.RawCompare(ft.AsRaw(), kind) != 0 {
t.Errorf("Wrong recorded value in measurement %d in batch %d, expected %s, got %s", j, i, ft.Emit(kind), measurement.value.Emit(kind))
}
}
}

View File

@ -16,63 +16,55 @@ package metric
import (
"context"
"sync/atomic"
)
var (
descriptorID uint64
)
type commonMetric struct {
d *Descriptor
instrument Instrument
}
var _ ExplicitReportingMetric = commonMetric{}
func (m commonMetric) Descriptor() *Descriptor {
return m.d
type commonHandle struct {
handle Handle
}
func (m commonMetric) SupportHandle() hiddenType {
return hiddenType{}
}
func (m commonMetric) getHandle(labels LabelSet) Handle {
return labels.Meter().NewHandle(m, labels)
func (m commonMetric) acquireCommonHandle(labels LabelSet) commonHandle {
return newCommonHandle(m.instrument.AcquireHandle(labels))
}
func (m commonMetric) float64Measurement(value float64) Measurement {
return Measurement{
Descriptor: m.d,
Value: NewFloat64MeasurementValue(value),
}
return newMeasurement(m.instrument, NewFloat64MeasurementValue(value))
}
func (m commonMetric) int64Measurement(value int64) Measurement {
return Measurement{
Descriptor: m.d,
Value: NewInt64MeasurementValue(value),
}
return newMeasurement(m.instrument, NewInt64MeasurementValue(value))
}
func (m commonMetric) recordOne(ctx context.Context, value MeasurementValue, labels LabelSet) {
labels.Meter().RecordBatch(ctx, labels, Measurement{
Descriptor: m.d,
Value: value,
})
m.instrument.RecordOne(ctx, value, labels)
}
func registerCommonMetric(name string, kind Kind, valueKind ValueKind) commonMetric {
func (h commonHandle) recordOne(ctx context.Context, value MeasurementValue) {
h.handle.RecordOne(ctx, value)
}
func (h commonHandle) Release() {
h.handle.Release()
}
func newCommonMetric(instrument Instrument) commonMetric {
return commonMetric{
d: registerDescriptor(name, kind, valueKind),
instrument: instrument,
}
}
func registerDescriptor(name string, kind Kind, valueKind ValueKind) *Descriptor {
return &Descriptor{
name: name,
kind: kind,
valueKind: valueKind,
id: DescriptorID(atomic.AddUint64(&descriptorID, 1)),
func newCommonHandle(handle Handle) commonHandle {
return commonHandle{
handle: handle,
}
}
func newMeasurement(instrument Instrument, value MeasurementValue) Measurement {
return Measurement{
instrument: instrument,
value: value,
}
}

View File

@ -29,78 +29,40 @@ type Int64Counter struct {
}
// Float64CounterHandle is a handle for Float64Counter.
//
// It inherits the Release function from commonHandle.
type Float64CounterHandle struct {
Handle
commonHandle
}
// Int64CounterHandle is a handle for Int64Counter.
//
// It inherits the Release function from commonHandle.
type Int64CounterHandle struct {
Handle
commonHandle
}
// CounterOptionApplier is an interface for applying metric options
// that are valid only for counter metrics.
type CounterOptionApplier interface {
// ApplyCounterOption is used to make some counter-specific
// changes in the Descriptor.
ApplyCounterOption(*Descriptor)
}
type counterOptionWrapper struct {
F Option
}
var (
_ CounterOptionApplier = counterOptionWrapper{}
_ ExplicitReportingMetric = Float64Counter{}
_ ExplicitReportingMetric = Int64Counter{}
)
func (o counterOptionWrapper) ApplyCounterOption(d *Descriptor) {
o.F(d)
}
func newCounter(name string, valueKind ValueKind, mos ...CounterOptionApplier) commonMetric {
m := registerCommonMetric(name, CounterKind, valueKind)
for _, opt := range mos {
opt.ApplyCounterOption(m.Descriptor())
}
return m
}
// NewFloat64Counter creates a new counter for float64.
func NewFloat64Counter(name string, mos ...CounterOptionApplier) (c Float64Counter) {
c.commonMetric = newCounter(name, Float64ValueKind, mos...)
return
}
// NewInt64Counter creates a new counter for int64.
func NewInt64Counter(name string, mos ...CounterOptionApplier) (c Int64Counter) {
c.commonMetric = newCounter(name, Int64ValueKind, mos...)
return
}
// GetHandle creates a handle for this counter. The labels should
// AcquireHandle creates a handle for this counter. The labels should
// contain the keys and values for each key specified in the counter
// with the WithKeys option.
//
// If the labels do not contain a value for the key specified in the
// counter with the WithKeys option, then the missing value will be
// treated as unspecified.
func (c *Float64Counter) GetHandle(labels LabelSet) (h Float64CounterHandle) {
h.Handle = c.getHandle(labels)
func (c *Float64Counter) AcquireHandle(labels LabelSet) (h Float64CounterHandle) {
h.commonHandle = c.acquireCommonHandle(labels)
return
}
// GetHandle creates a handle for this counter. The labels should
// AcquireHandle creates a handle for this counter. The labels should
// contain the keys and values for each key specified in the counter
// with the WithKeys option.
//
// If the labels do not contain a value for the key specified in the
// counter with the WithKeys option, then the missing value will be
// treated as unspecified.
func (c *Int64Counter) GetHandle(labels LabelSet) (h Int64CounterHandle) {
h.Handle = c.getHandle(labels)
func (c *Int64Counter) AcquireHandle(labels LabelSet) (h Int64CounterHandle) {
h.commonHandle = c.acquireCommonHandle(labels)
return
}
@ -140,10 +102,10 @@ func (c *Int64Counter) Add(ctx context.Context, value int64, labels LabelSet) {
// Add adds the value to the counter's sum.
func (h *Float64CounterHandle) Add(ctx context.Context, value float64) {
h.RecordOne(ctx, NewFloat64MeasurementValue(value))
h.recordOne(ctx, NewFloat64MeasurementValue(value))
}
// Add adds the value to the counter's sum.
func (h *Int64CounterHandle) Add(ctx context.Context, value int64) {
h.RecordOne(ctx, NewInt64MeasurementValue(value))
h.recordOne(ctx, NewInt64MeasurementValue(value))
}

View File

@ -36,9 +36,10 @@
// 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 WithNonMonotonic option
// passed to the New*Counter function - this allows reporting negative
// values. To report the new value, use an Add function.
// 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.
//
// Gauges are instruments that are reporting a current state of a
// value. An example could be voltage or temperature. Gauges can be
@ -55,13 +56,14 @@
// 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 WithSigned option passed to the New*Measure function - this
// allows reporting negative values too. To report a new value, use
// the Record function.
// 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.
//
// All the basic kinds of instruments also support creating handles
// for a potentially more efficient reporting. The handles have the
// same function names as the instruments (so counter handle has Add,
// gauge handle has Set and measure handle has Record). Handles can be
// created with the GetHandle function of the respective instrument.
// created with the AcquireHandle function of the respective
// instrument. When done with the handle, call Release on it.
package metric // import "go.opentelemetry.io/api/metric"

View File

@ -29,78 +29,40 @@ type Int64Gauge struct {
}
// Float64GaugeHandle is a handle for Float64Gauge.
//
// It inherits the Release function from commonHandle.
type Float64GaugeHandle struct {
Handle
commonHandle
}
// Int64GaugeHandle is a handle for Int64Gauge.
//
// It inherits the Release function from commonHandle.
type Int64GaugeHandle struct {
Handle
commonHandle
}
// GaugeOptionApplier is an interface for applying metric options that
// are valid only for gauge metrics.
type GaugeOptionApplier interface {
// ApplyGaugeOption is used to make some gauge-specific
// changes in the Descriptor.
ApplyGaugeOption(*Descriptor)
}
type gaugeOptionWrapper struct {
F Option
}
var (
_ GaugeOptionApplier = gaugeOptionWrapper{}
_ ExplicitReportingMetric = Float64Gauge{}
_ ExplicitReportingMetric = Int64Gauge{}
)
func (o gaugeOptionWrapper) ApplyGaugeOption(d *Descriptor) {
o.F(d)
}
func newGauge(name string, valueKind ValueKind, mos ...GaugeOptionApplier) commonMetric {
m := registerCommonMetric(name, GaugeKind, valueKind)
for _, opt := range mos {
opt.ApplyGaugeOption(m.Descriptor())
}
return m
}
// NewFloat64Gauge creates a new gauge for float64.
func NewFloat64Gauge(name string, mos ...GaugeOptionApplier) (g Float64Gauge) {
g.commonMetric = newGauge(name, Float64ValueKind, mos...)
return
}
// NewInt64Gauge creates a new gauge for int64.
func NewInt64Gauge(name string, mos ...GaugeOptionApplier) (g Int64Gauge) {
g.commonMetric = newGauge(name, Int64ValueKind, mos...)
return
}
// GetHandle creates a handle for this gauge. The labels should
// AcquireHandle creates a handle for this gauge. The labels should
// contain the keys and values for each key specified in the gauge
// with the WithKeys option.
//
// If the labels do not contain a value for the key specified in the
// gauge with the WithKeys option, then the missing value will be
// treated as unspecified.
func (g *Float64Gauge) GetHandle(labels LabelSet) (h Float64GaugeHandle) {
h.Handle = g.getHandle(labels)
func (g *Float64Gauge) AcquireHandle(labels LabelSet) (h Float64GaugeHandle) {
h.commonHandle = g.acquireCommonHandle(labels)
return
}
// GetHandle creates a handle for this gauge. The labels should
// AcquireHandle creates a handle for this gauge. The labels should
// contain the keys and values for each key specified in the gauge
// with the WithKeys option.
//
// If the labels do not contain a value for the key specified in the
// gauge with the WithKeys option, then the missing value will be
// treated as unspecified.
func (g *Int64Gauge) GetHandle(labels LabelSet) (h Int64GaugeHandle) {
h.Handle = g.getHandle(labels)
func (g *Int64Gauge) AcquireHandle(labels LabelSet) (h Int64GaugeHandle) {
h.commonHandle = g.acquireCommonHandle(labels)
return
}
@ -140,10 +102,10 @@ func (g *Int64Gauge) Set(ctx context.Context, value int64, labels LabelSet) {
// Set assigns the passed value to the value of the gauge.
func (h *Float64GaugeHandle) Set(ctx context.Context, value float64) {
h.RecordOne(ctx, NewFloat64MeasurementValue(value))
h.recordOne(ctx, NewFloat64MeasurementValue(value))
}
// Set assigns the passed value to the value of the gauge.
func (h *Int64GaugeHandle) Set(ctx context.Context, value int64) {
h.RecordOne(ctx, NewInt64MeasurementValue(value))
h.recordOne(ctx, NewInt64MeasurementValue(value))
}

View File

@ -14,7 +14,9 @@
package metric
import "sync/atomic"
import (
"sync/atomic"
)
var global atomic.Value

View File

@ -1,44 +0,0 @@
// Code generated by "stringer -type=Kind,ValueKind"; DO NOT EDIT.
package metric
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Invalid-0]
_ = x[CounterKind-1]
_ = x[GaugeKind-2]
_ = x[MeasureKind-3]
}
const _Kind_name = "InvalidCounterKindGaugeKindMeasureKind"
var _Kind_index = [...]uint8{0, 7, 18, 27, 38}
func (i Kind) String() string {
if i < 0 || i >= Kind(len(_Kind_index)-1) {
return "Kind(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Kind_name[_Kind_index[i]:_Kind_index[i+1]]
}
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[Int64ValueKind-0]
_ = x[Float64ValueKind-1]
}
const _ValueKind_name = "Int64ValueKindFloat64ValueKind"
var _ValueKind_index = [...]uint8{0, 14, 30}
func (i ValueKind) String() string {
if i < 0 || i >= ValueKind(len(_ValueKind_index)-1) {
return "ValueKind(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _ValueKind_name[_ValueKind_index[i]:_ValueKind_index[i+1]]
}

View File

@ -29,78 +29,40 @@ type Int64Measure struct {
}
// Float64MeasureHandle is a handle for Float64Measure.
//
// It inherits the Release function from commonHandle.
type Float64MeasureHandle struct {
Handle
commonHandle
}
// Int64MeasureHandle is a handle for Int64Measure.
//
// It inherits the Release function from commonHandle.
type Int64MeasureHandle struct {
Handle
commonHandle
}
// MeasureOptionApplier is an interface for applying metric options
// that are valid only for measure metrics.
type MeasureOptionApplier interface {
// ApplyMeasureOption is used to make some measure-specific
// changes in the Descriptor.
ApplyMeasureOption(*Descriptor)
}
type measureOptionWrapper struct {
F Option
}
var (
_ MeasureOptionApplier = measureOptionWrapper{}
_ ExplicitReportingMetric = Float64Measure{}
_ ExplicitReportingMetric = Int64Measure{}
)
func (o measureOptionWrapper) ApplyMeasureOption(d *Descriptor) {
o.F(d)
}
func newMeasure(name string, valueKind ValueKind, mos ...MeasureOptionApplier) commonMetric {
m := registerCommonMetric(name, MeasureKind, valueKind)
for _, opt := range mos {
opt.ApplyMeasureOption(m.Descriptor())
}
return m
}
// NewFloat64Measure creates a new measure for float64.
func NewFloat64Measure(name string, mos ...MeasureOptionApplier) (c Float64Measure) {
c.commonMetric = newMeasure(name, Float64ValueKind, mos...)
return
}
// NewInt64Measure creates a new measure for int64.
func NewInt64Measure(name string, mos ...MeasureOptionApplier) (c Int64Measure) {
c.commonMetric = newMeasure(name, Int64ValueKind, mos...)
return
}
// GetHandle creates a handle for this measure. The labels should
// AcquireHandle creates a handle for this measure. The labels should
// contain the keys and values for each key specified in the measure
// with the WithKeys option.
//
// If the labels do not contain a value for the key specified in the
// measure with the WithKeys option, then the missing value will be
// treated as unspecified.
func (c *Float64Measure) GetHandle(labels LabelSet) (h Float64MeasureHandle) {
h.Handle = c.getHandle(labels)
func (c *Float64Measure) AcquireHandle(labels LabelSet) (h Float64MeasureHandle) {
h.commonHandle = c.acquireCommonHandle(labels)
return
}
// GetHandle creates a handle for this measure. The labels should
// AcquireHandle creates a handle for this measure. The labels should
// contain the keys and values for each key specified in the measure
// with the WithKeys option.
//
// If the labels do not contain a value for the key specified in the
// measure with the WithKeys option, then the missing value will be
// treated as unspecified.
func (c *Int64Measure) GetHandle(labels LabelSet) (h Int64MeasureHandle) {
h.Handle = c.getHandle(labels)
func (c *Int64Measure) AcquireHandle(labels LabelSet) (h Int64MeasureHandle) {
h.commonHandle = c.acquireCommonHandle(labels)
return
}
@ -140,10 +102,10 @@ func (c *Int64Measure) Record(ctx context.Context, value int64, labels LabelSet)
// Record adds a new value to the list of measure's records.
func (h *Float64MeasureHandle) Record(ctx context.Context, value float64) {
h.RecordOne(ctx, NewFloat64MeasurementValue(value))
h.recordOne(ctx, NewFloat64MeasurementValue(value))
}
// Record adds a new value to the list of measure's records.
func (h *Int64MeasureHandle) Record(ctx context.Context, value int64) {
h.RecordOne(ctx, NewInt64MeasurementValue(value))
h.recordOne(ctx, NewInt64MeasurementValue(value))
}

View File

@ -22,10 +22,17 @@ import (
type (
mockHandle struct {
descriptor *Descriptor
instrument *mockInstrument
labelSet *mockLabelSet
}
mockInstrument struct {
name string
kind mockKind
valueKind ValueKind
opts Options
}
mockLabelSet struct {
meter *mockMeter
labels map[core.Key]core.Value
@ -34,24 +41,56 @@ type (
batch struct {
ctx context.Context
labelSet *mockLabelSet
measurements []Measurement
measurements []mockMeasurement
}
mockMeter struct {
measurementBatches []batch
}
mockKind int8
mockMeasurement struct {
instrument *mockInstrument
value MeasurementValue
}
)
var (
_ Handle = &mockHandle{}
_ LabelSet = &mockLabelSet{}
_ Meter = &mockMeter{}
_ Instrument = &mockInstrument{}
_ Handle = &mockHandle{}
_ LabelSet = &mockLabelSet{}
_ Meter = &mockMeter{}
)
const (
mockKindCounter mockKind = iota
mockKindGauge
mockKindMeasure
)
func (i *mockInstrument) AcquireHandle(labels LabelSet) Handle {
return &mockHandle{
instrument: i,
labelSet: labels.(*mockLabelSet),
}
}
func (i *mockInstrument) RecordOne(ctx context.Context, value MeasurementValue, labels LabelSet) {
doRecordBatch(labels.(*mockLabelSet), ctx, i, value)
}
func (h *mockHandle) RecordOne(ctx context.Context, value MeasurementValue) {
h.labelSet.meter.RecordBatch(ctx, h.labelSet, Measurement{
Descriptor: h.descriptor,
Value: value,
doRecordBatch(h.labelSet, ctx, h.instrument, value)
}
func (h *mockHandle) Release() {
}
func doRecordBatch(labelSet *mockLabelSet, ctx context.Context, instrument *mockInstrument, value MeasurementValue) {
labelSet.meter.recordMockBatch(ctx, labelSet, mockMeasurement{
instrument: instrument,
value: value,
})
}
@ -63,7 +102,7 @@ func newMockMeter() *mockMeter {
return &mockMeter{}
}
func (m *mockMeter) DefineLabels(ctx context.Context, labels ...core.KeyValue) LabelSet {
func (m *mockMeter) Labels(ctx context.Context, labels ...core.KeyValue) LabelSet {
ul := make(map[core.Key]core.Value)
for _, kv := range labels {
ul[kv.Key] = kv.Value
@ -74,24 +113,86 @@ func (m *mockMeter) DefineLabels(ctx context.Context, labels ...core.KeyValue) L
}
}
func (m *mockMeter) RecordBatch(ctx context.Context, labels LabelSet, measurements ...Measurement) {
ourLabelSet := labels.(*mockLabelSet)
m.measurementBatches = append(m.measurementBatches, batch{
ctx: ctx,
labelSet: ourLabelSet,
measurements: measurements,
})
func (m *mockMeter) NewInt64Counter(name string, cos ...CounterOptionApplier) Int64Counter {
instrument := m.newCounterInstrument(name, Int64ValueKind, cos...)
return WrapInt64CounterInstrument(instrument)
}
func (m *mockMeter) NewHandle(erm ExplicitReportingMetric, labels LabelSet) Handle {
descriptor := erm.Descriptor()
ourLabels := labels.(*mockLabelSet)
func (m *mockMeter) NewFloat64Counter(name string, cos ...CounterOptionApplier) Float64Counter {
instrument := m.newCounterInstrument(name, Float64ValueKind, cos...)
return WrapFloat64CounterInstrument(instrument)
}
return &mockHandle{
descriptor: descriptor,
labelSet: ourLabels,
func (m *mockMeter) newCounterInstrument(name string, valueKind ValueKind, cos ...CounterOptionApplier) *mockInstrument {
opts := Options{}
ApplyCounterOptions(&opts, cos...)
return &mockInstrument{
name: name,
kind: mockKindCounter,
valueKind: valueKind,
opts: opts,
}
}
func (m *mockMeter) DeleteHandle(Handle) {
func (m *mockMeter) NewInt64Gauge(name string, gos ...GaugeOptionApplier) Int64Gauge {
instrument := m.newGaugeInstrument(name, Int64ValueKind, gos...)
return WrapInt64GaugeInstrument(instrument)
}
func (m *mockMeter) NewFloat64Gauge(name string, gos ...GaugeOptionApplier) Float64Gauge {
instrument := m.newGaugeInstrument(name, Float64ValueKind, gos...)
return WrapFloat64GaugeInstrument(instrument)
}
func (m *mockMeter) newGaugeInstrument(name string, valueKind ValueKind, gos ...GaugeOptionApplier) *mockInstrument {
opts := Options{}
ApplyGaugeOptions(&opts, gos...)
return &mockInstrument{
name: name,
kind: mockKindGauge,
valueKind: valueKind,
opts: opts,
}
}
func (m *mockMeter) NewInt64Measure(name string, mos ...MeasureOptionApplier) Int64Measure {
instrument := m.newMeasureInstrument(name, Int64ValueKind, mos...)
return WrapInt64MeasureInstrument(instrument)
}
func (m *mockMeter) NewFloat64Measure(name string, mos ...MeasureOptionApplier) Float64Measure {
instrument := m.newMeasureInstrument(name, Float64ValueKind, mos...)
return WrapFloat64MeasureInstrument(instrument)
}
func (m *mockMeter) newMeasureInstrument(name string, valueKind ValueKind, mos ...MeasureOptionApplier) *mockInstrument {
opts := Options{}
ApplyMeasureOptions(&opts, mos...)
return &mockInstrument{
name: name,
kind: mockKindMeasure,
valueKind: valueKind,
opts: opts,
}
}
func (m *mockMeter) RecordBatch(ctx context.Context, labels LabelSet, measurements ...Measurement) {
ourLabelSet := labels.(*mockLabelSet)
mm := make([]mockMeasurement, len(measurements))
for i := 0; i < len(measurements); i++ {
m := measurements[i]
mm[i] = mockMeasurement{
instrument: m.Instrument().(*mockInstrument),
value: m.Value(),
}
}
m.recordMockBatch(ctx, ourLabelSet, mm...)
}
func (m *mockMeter) recordMockBatch(ctx context.Context, labelSet *mockLabelSet, measurements ...mockMeasurement) {
m.measurementBatches = append(m.measurementBatches, batch{
ctx: ctx,
labelSet: labelSet,
measurements: measurements,
})
}

View File

@ -9,27 +9,56 @@ import (
type noopMeter struct{}
type noopHandle struct{}
type noopLabelSet struct{}
type noopInstrument struct{}
var _ Meter = noopMeter{}
var _ Instrument = noopInstrument{}
var _ Handle = noopHandle{}
var _ LabelSet = noopLabelSet{}
func (noopHandle) RecordOne(context.Context, MeasurementValue) {
}
func (noopHandle) Release() {
}
func (noopInstrument) AcquireHandle(LabelSet) Handle {
return noopHandle{}
}
func (noopInstrument) RecordOne(context.Context, MeasurementValue, LabelSet) {
}
func (noopLabelSet) Meter() Meter {
return noopMeter{}
}
func (noopMeter) DefineLabels(context.Context, ...core.KeyValue) LabelSet {
func (noopMeter) Labels(context.Context, ...core.KeyValue) LabelSet {
return noopLabelSet{}
}
func (noopMeter) NewHandle(ExplicitReportingMetric, LabelSet) Handle {
return noopHandle{}
func (noopMeter) NewInt64Counter(name string, cos ...CounterOptionApplier) Int64Counter {
return WrapInt64CounterInstrument(noopInstrument{})
}
func (noopMeter) DeleteHandle(Handle) {
func (noopMeter) NewFloat64Counter(name string, cos ...CounterOptionApplier) Float64Counter {
return WrapFloat64CounterInstrument(noopInstrument{})
}
func (noopMeter) NewInt64Gauge(name string, gos ...GaugeOptionApplier) Int64Gauge {
return WrapInt64GaugeInstrument(noopInstrument{})
}
func (noopMeter) NewFloat64Gauge(name string, gos ...GaugeOptionApplier) Float64Gauge {
return WrapFloat64GaugeInstrument(noopInstrument{})
}
func (noopMeter) NewInt64Measure(name string, mos ...MeasureOptionApplier) Int64Measure {
return WrapInt64MeasureInstrument(noopInstrument{})
}
func (noopMeter) NewFloat64Measure(name string, mos ...MeasureOptionApplier) Float64Measure {
return WrapFloat64MeasureInstrument(noopInstrument{})
}
func (noopMeter) RecordBatch(context.Context, LabelSet, ...Measurement) {

87
api/metric/sdkhelpers.go Normal file
View File

@ -0,0 +1,87 @@
// Copyright 2019, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package metric
// WrapInt64CounterInstrument wraps the instrument in the type-safe
// wrapper as an integral counter.
//
// It is mostly intended for SDKs.
func WrapInt64CounterInstrument(instrument Instrument) Int64Counter {
return Int64Counter{commonMetric: newCommonMetric(instrument)}
}
// WrapFloat64CounterInstrument wraps the instrument in the type-safe
// wrapper as an floating point counter.
//
// It is mostly intended for SDKs.
func WrapFloat64CounterInstrument(instrument Instrument) Float64Counter {
return Float64Counter{commonMetric: newCommonMetric(instrument)}
}
// WrapInt64GaugeInstrument wraps the instrument in the type-safe
// wrapper as an integral gauge.
//
// It is mostly intended for SDKs.
func WrapInt64GaugeInstrument(instrument Instrument) Int64Gauge {
return Int64Gauge{commonMetric: newCommonMetric(instrument)}
}
// WrapFloat64GaugeInstrument wraps the instrument in the type-safe
// wrapper as an floating point gauge.
//
// It is mostly intended for SDKs.
func WrapFloat64GaugeInstrument(instrument Instrument) Float64Gauge {
return Float64Gauge{commonMetric: newCommonMetric(instrument)}
}
// WrapInt64MeasureInstrument wraps the instrument in the type-safe
// wrapper as an integral measure.
//
// It is mostly intended for SDKs.
func WrapInt64MeasureInstrument(instrument Instrument) Int64Measure {
return Int64Measure{commonMetric: newCommonMetric(instrument)}
}
// WrapFloat64MeasureInstrument wraps the instrument in the type-safe
// wrapper as an floating point measure.
//
// It is mostly intended for SDKs.
func WrapFloat64MeasureInstrument(instrument Instrument) Float64Measure {
return Float64Measure{commonMetric: newCommonMetric(instrument)}
}
// ApplyCounterOptions is a helper that applies all the counter
// options to passed opts.
func ApplyCounterOptions(opts *Options, cos ...CounterOptionApplier) {
for _, o := range cos {
o.ApplyCounterOption(opts)
}
}
// ApplyGaugeOptions is a helper that applies all the gauge options to
// passed opts.
func ApplyGaugeOptions(opts *Options, gos ...GaugeOptionApplier) {
for _, o := range gos {
o.ApplyGaugeOption(opts)
}
}
// ApplyMeasureOptions is a helper that applies all the measure
// options to passed opts.
func ApplyMeasureOptions(opts *Options, mos ...MeasureOptionApplier) {
for _, o := range mos {
o.ApplyMeasureOption(opts)
}
}

View File

@ -19,10 +19,25 @@ import (
"math"
)
//go:generate stringer -type=ValueKind
// ValueKind describes the data type of the measurement value the
// metric generates.
type ValueKind int8
const (
// Int64ValueKind means that the metric generates values of
// type int64.
Int64ValueKind ValueKind = iota
// Float64ValueKind means that the metric generates values of
// type float64.
Float64ValueKind
)
// MeasurementValue represents either an integral or a floating point
// value of a measurement. It needs to be accompanied with a
// descriptor of a metric that generated this value to decide what
// type of value it represents.
// value of a measurement. It needs to be accompanied with a value
// kind or some source that provides a value kind describing this
// measurement value.
type MeasurementValue uint64
// NewInt64MeasurementValue creates an integral MeasurementValue.
@ -41,15 +56,17 @@ func newFromRaw(raw uint64) MeasurementValue {
}
// AsInt64 assumes that the measurement value contains an int64 and
// returns it as such. Make sure that metric that generated this value
// has indeed Int64ValueKind in its descriptor.
// returns it as such. Make sure that the accompanying source of value
// kind indeed tells you its a 64 bit integral measurement value,
// otherwise the returned int64 will be wrong.
func (v MeasurementValue) AsInt64() int64 {
return rawToInt64(v.AsRaw())
}
// AsFloat64 assumes that the measurement value contains a float64 and
// returns it as such. Make sure that metric that generated this value
// has indeed Int64ValueKind in its descriptor.
// returns it as such. Make sure that the accompanying source of value
// kind indeed tells you its a 64 bit floating point measurement
// value, otherwise the returned float64 will be wrong.
func (v MeasurementValue) AsFloat64() float64 {
return rawToFloat64(v.AsRaw())
}

View File

@ -0,0 +1,24 @@
// Code generated by "stringer -type=ValueKind"; DO NOT EDIT.
package metric
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Int64ValueKind-0]
_ = x[Float64ValueKind-1]
}
const _ValueKind_name = "Int64ValueKindFloat64ValueKind"
var _ValueKind_index = [...]uint8{0, 14, 30}
func (i ValueKind) String() string {
if i < 0 || i >= ValueKind(len(_ValueKind_index)-1) {
return "ValueKind(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _ValueKind_name[_ValueKind_index[i]:_ValueKind_index[i+1]]
}

View File

@ -32,16 +32,16 @@ var (
barKey = key.New("ex.com/bar")
lemonsKey = key.New("ex.com/lemons")
anotherKey = key.New("ex.com/another")
)
oneMetric = metric.NewFloat64Gauge("ex.com/one",
func main() {
oneMetric := meter.NewFloat64Gauge("ex.com.one",
metric.WithKeys(fooKey, barKey, lemonsKey),
metric.WithDescription("A gauge set to 1.0"),
)
measureTwo = metric.NewFloat64Measure("ex.com/two")
)
measureTwo := meter.NewFloat64Measure("ex.com.two")
func main() {
ctx := context.Background()
ctx = distributedcontext.NewContext(ctx,
@ -49,11 +49,13 @@ func main() {
distributedcontext.Insert(barKey.String("bar1")),
)
commonLabels := meter.DefineLabels(ctx, lemonsKey.Int(10))
commonLabels := meter.Labels(ctx, lemonsKey.Int(10))
gauge := oneMetric.GetHandle(commonLabels)
gauge := oneMetric.AcquireHandle(commonLabels)
defer gauge.Release()
measure := measureTwo.GetHandle(commonLabels)
measure := measureTwo.AcquireHandle(commonLabels)
defer measure.Release()
err := tracer.WithSpan(ctx, "operation", func(ctx context.Context) error {