OpenTelemetry Metrics API for Go

Instruments

To get started with metrics, you need a MeterProvider which provides access to Meters:

import "go.opentelemetry.io/otel/metric/global"

// Meter can be a global/package variable.
var Meter = metric.Must(global.Meter("app_or_package_name"))

Using the meter, you can create instruments to measure performance. The simplest Counter instrument looks like this:

import "go.opentelemetry.io/otel/metric"

counter := Meter.NewInt64Counter("test.my_counter",
	metric.WithDescription("Just a test counter"),
)

// Increment the counter.
counter.Add(ctx, 1)
counter.Add(ctx, 10)

You can find more examplesopen in new window at GitHub.

Counter

Counter is a synchronous instrument that measures additive non-decreasing values.

// counter demonstrates how to measure non-decreasing numbers, for example,
// number of requests or connections.
func counter(ctx context.Context) {
	counter := meter.NewInt64Counter("app_or_package_name.component1.requests",
		metric.WithDescription("Number of requests"),
	)

	for {
		counter.Add(ctx, 1)
		time.Sleep(time.Millisecond)
	}
}

You can get more interesting results by adding attributes to your measurements:

// counterWithLabels demonstrates how to add different attributes ("hits" and "misses")
// to measurements. Using this simple trick, you can get number of hits, misses,
// sum = hits + misses, and hit_rate = hits / (hits + misses).
func counterWithLabels(ctx context.Context) {
	counter := meter.NewInt64Counter("app_or_package_name.component1.cache",
		metric.WithDescription("Cache hits and misses"),
	)
	// Bind the counter to some labels.
	hits := counter.Bind(attribute.String("type", "hits"))
	misses := counter.Bind(attribute.String("type", "misses"))

	for {
		if rand.Float64() < 0.3 {
			misses.Add(ctx, 1)
		} else {
			hits.Add(ctx, 1)
		}

		time.Sleep(time.Millisecond)
	}
}

UpDownCounter

UpDownCounter is a synchronous instrument which measures additive values that increase or decrease with time.

// upDownCounter demonstrates how to measure numbers that can go up and down, for example,
// number of goroutines or customers.
//
// See upDownCounterObserver for a better example how to measure number of goroutines.
func upDownCounter(ctx context.Context) {
	counter := meter.NewInt64Counter("app_or_package_name.component1.goroutines",
		metric.WithDescription("Number of goroutines"),
	)

	for {
		counter.Add(ctx, int64(runtime.NumGoroutine()))

		time.Sleep(time.Second)
	}
}

Histogram

Histogram is a synchronous instrument that produces a histogram from recorded values.

// valueRecorder demonstrates how to record a distribution of individual values, for example,
// request or query timings. With this instrument you get total number of records,
// avg/min/max values, and heatmaps/percentiles.
func valueRecorder(ctx context.Context) {
	durRecorder := meter.NewInt64Histogram("app_or_package_name.component1.request_duration",
		metric.WithUnit("microseconds"),
		metric.WithDescription("Duration of requests"),
	)

	for {
		dur := time.Duration(rand.NormFloat64()*10000+100000) * time.Microsecond
		durRecorder.Record(ctx, dur.Microseconds())

		time.Sleep(time.Millisecond)
	}
}

CounterObserver

CounterObserver is an asynchronous instrument that measures additive non-decreasing values.

// sumObserver demonstrates how to measure monotonic (non-decreasing) numbers,
// for example, number of requests or connections.
func sumObserver(ctx context.Context) {
	// stats is our data source updated by some library.
	var stats struct {
		Hits   int64 // atomic
		Misses int64 // atomic
	}

	var hitsCounter, missesCounter metric.Int64CounterObserver

	batchObserver := meter.NewBatchObserver(
		// SDK periodically calls this function to grab results.
		func(ctx context.Context, result metric.BatchObserverResult) {
			result.Observe(nil,
				hitsCounter.Observation(atomic.LoadInt64(&stats.Hits)),
				missesCounter.Observation(atomic.LoadInt64(&stats.Misses)),
			)
		})

	hitsCounter = batchObserver.NewInt64CounterObserver("app_or_package_name.component2.cache_hits")
	missesCounter = batchObserver.NewInt64CounterObserver("app_or_package_name.component2.cache_misses")

	for {
		if rand.Float64() < 0.3 {
			atomic.AddInt64(&stats.Misses, 1)
		} else {
			atomic.AddInt64(&stats.Hits, 1)
		}

		time.Sleep(time.Millisecond)
	}
}

UpDownCounterOserver

UpDownCounterOserver is an asynchronous instrument that measures additive values that can increase or decrease with time.

// upDownCounterObserver demonstrates how to measure numbers that can go up and down,
// for example, number of goroutines or customers.
func upDownCounterObserver(ctx context.Context) {
	_ = meter.NewInt64UpDownCounterObserver("app_or_package_name.component2.goroutines",
		func(ctx context.Context, result metric.Int64ObserverResult) {
			num := runtime.NumGoroutine()
			result.Observe(int64(num))
		},
		metric.WithDescription("Number of goroutines"),
	)
}

GaugeObserver

GaugeObserver is an asynchronous instrument that measures non-additive values for which sum does not produce a meaningful correct result.

// valueObserver demonstrates how to measure numbers that can go up and down,
// for example, number of goroutines or customers.
func valueObserver(ctx context.Context) {
	_ = meter.NewInt64GaugeObserver("app_or_package_name.component2.goroutines2",
		func(ctx context.Context, result metric.Int64ObserverResult) {
			num := runtime.NumGoroutine()
			result.Observe(int64(num))
		},
		metric.WithDescription("Number of goroutines"),
	)
}