metric

package
v0.4.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 31, 2020 License: Apache-2.0 Imports: 14 Imported by: 631

Documentation

Overview

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.

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 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.

To this end, the API uses a core.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.

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 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 from the user's perspective.

Metric collection is performed via a single-threaded call to Collect that 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 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 must be capable of merging with another aggregator of the same type.

Export Pipeline

While the SDK serves to maintain a current set of records and coordinate collection, the behavior of a metrics export pipeline is configured through the export types in go.opentelemetry.io/otel/sdk/export/metric. It is important to keep in mind the context these interfaces are called from. There are two contexts, instrumentation context, where a user-level goroutine that 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.

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.

Aggregator is an interface which implements a concrete strategy for aggregating metric updates. Several Aggregator implementations are provided by the SDK. Aggregators may be lock-free or use locking, depending on their structure and semantics. Aggregators implement an Update method, called in instrumentation context, to receive a single metric event. Aggregators implement a Checkpoint method, called in collection context, to save a checkpoint of the current state. Aggregators implement a Merge method, also called in collection context, that combines state from two aggregators into one. Each SDK record has an associated aggregator.

Batcher is an interface which sits between the SDK and an exporter. The Batcher embeds an AggregationSelector, used by the SDK to assign new Aggregators. The Batcher supports a Process() API for submitting checkpointed aggregators to the batcher, and a CheckpointSet() API for producing a complete checkpoint for the exporter. Two default Batcher implementations are provided, the "defaultkeys" Batcher groups aggregate metrics by their recommended Descriptor.Keys(), the "ungrouped" Batcher aggregates metrics at full dimensionality.

LabelEncoder is an optional optimization that allows an exporter to provide the serialization logic for labels. This allows avoiding duplicate serialization of labels, once as a unique key in the SDK (or Batcher) and once in the exporter.

CheckpointSet is an interface between the Batcher and the Exporter. After completing a collection pass, the Batcher.CheckpointSet() method returns a CheckpointSet, which the Exporter uses to iterate over all the updated metrics.

Record is a struct containing the state of an individual exported metric. This is the result of one collection interface for one instrument and one label set.

Labels is a struct containing an ordered set of labels, the corresponding unique encoding, and the encoder that produced it.

Exporter is the final stage of an export pipeline. It is called with a CheckpointSet capable of enumerating all the updated metrics.

Controller is not an export interface per se, but it orchestrates the export pipeline. For example, a "push" controller will establish a periodic timer to regularly collect and export metrics. A "pull" controller will await a pull request before initiating metric collection. Either way, the job of the controller is to call the SDK Collect() method, then read the checkpoint, then invoke the exporter. Controllers are expected to implement the public metric.MeterProvider API, meaning they can be installed as the global Meter provider.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AtomicFieldOffsets added in v0.4.0

func AtomicFieldOffsets() map[string]uintptr

func DefaultErrorHandler added in v0.1.1

func DefaultErrorHandler(err error)

Types

type Config added in v0.3.0

type Config struct {
	// ErrorHandler is the function called when the SDK encounters an error.
	//
	// This option can be overridden after instantiation of the SDK
	// with the `SetErrorHandler` method.
	ErrorHandler ErrorHandler

	// Resource is the OpenTelemetry resource associated with all Meters
	// created by the SDK.
	Resource resource.Resource
}

Config contains configuration for an SDK.

type ErrorHandler added in v0.1.1

type ErrorHandler func(error)

type Option added in v0.3.0

type Option interface {
	// Apply sets the Option value of a Config.
	Apply(*Config)
}

Option is the interface that applies the value to a configuration option.

func WithErrorHandler added in v0.3.0

func WithErrorHandler(fn ErrorHandler) Option

WithErrorHandler sets the ErrorHandler configuration option of a Config.

func WithResource added in v0.3.0

func WithResource(r resource.Resource) Option

WithResource sets the Resource configuration option of a Config.

type SDK

type SDK struct {
	// contains filtered or unexported fields
}

SDK implements the OpenTelemetry Meter API. The SDK is bound to a single export.Batcher in `New()`.

The SDK supports a Collect() API to gather and export current data. Collect() should be arranged according to the batcher model. Push-based batchers will setup a timer to call Collect() periodically. Pull-based batchers will call Collect() when a pull request arrives.

func New

func New(batcher export.Batcher, opts ...Option) *SDK

New constructs a new SDK for the given batcher. This SDK supports only a single batcher.

The SDK does not start any background process to collect itself periodically, this responsbility lies with the batcher, typically, depending on the type of export. For example, a pull-based batcher will call Collect() when it receives a request to scrape current metric values. A push-based batcher should configure its own periodic collection.

Example
package main

import (
	"context"
	"fmt"
	"time"

	"go.opentelemetry.io/otel/api/key"
	"go.opentelemetry.io/otel/api/metric"
	"go.opentelemetry.io/otel/exporters/metric/stdout"
)

func main() {
	pusher, err := stdout.NewExportPipeline(stdout.Config{
		PrettyPrint:    true,
		DoNotPrintTime: true, // This makes the output deterministic
	}, time.Minute)
	if err != nil {
		panic(fmt.Sprintln("Could not initialize stdout exporter:", err))
	}
	defer pusher.Stop()

	ctx := context.Background()

	key := key.New("key")
	meter := pusher.Meter("example")

	counter := metric.Must(meter).NewInt64Counter("a.counter", metric.WithKeys(key))

	counter.Add(ctx, 100, key.String("value"))

}
Output:

{
	"updates": [
		{
			"name": "a.counter{key=value}",
			"sum": 100
		}
	]
}

func (*SDK) Collect

func (m *SDK) Collect(ctx context.Context) int

Collect traverses the list of active records and observers and exports data for each active instrument. Collect() may not be called concurrently.

During the collection pass, the export.Batcher will receive one Export() call per current aggregation.

Returns the number of records that were checkpointed.

func (*SDK) NewAsyncInstrument added in v0.3.0

func (m *SDK) NewAsyncInstrument(descriptor api.Descriptor, callback func(func(core.Number, []core.KeyValue))) (api.AsyncImpl, error)

func (*SDK) NewSyncInstrument added in v0.3.0

func (m *SDK) NewSyncInstrument(descriptor api.Descriptor) (api.SyncImpl, error)

func (*SDK) RecordBatch

func (m *SDK) RecordBatch(ctx context.Context, kvs []core.KeyValue, measurements ...api.Measurement)

RecordBatch enters a batch of metric events.

func (*SDK) Resource added in v0.3.0

func (m *SDK) Resource() resource.Resource

Resource returns the Resource this SDK was created with describing the entity for which it creates instruments for.

Resource means that the SDK implements the Resourcer interface and therefore all metric instruments it creates will inherit its Resource by default unless explicitly overwritten.

func (*SDK) SetErrorHandler added in v0.1.1

func (m *SDK) SetErrorHandler(f ErrorHandler)

Directories

Path Synopsis
aggregator
sum
batcher
controller
selector

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL