ometrics

package module
v0.0.0-...-6c98331 Latest Latest
Warning

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

Go to latest
Published: Mar 14, 2024 License: Apache-2.0 Imports: 10 Imported by: 0

README

ometrics

import "github/getoutreach/gobox/pkg/ometrics"

Package ometrics implements a small wrapper around working with the OpenTelemetry (otel) metrics package. It does not provide any wrappers around the core types provided by otel, but instead provides a way to instantiate them.

Index

Usage

Initialize metrics exporter

In order to ensure the correct provider is used to export the open-telemetry metrics, it is required to call the gobox/pkg/ometrics func InitializeMeterProvider(...) with the expected provider type as well as any other relevant options. Currently, this package only has support for prometheus and otlp (open-telemetry collector) exporter providers. Furthermore, the prometheus provider type is the only type which will be referenced throughout these docs, as it will provide the closest examples to current metric usage.

The below code demonstrates how to initialize the prometheus provider using this package, which only needs to be done once, ideally in some service setup file (main.go, internal/[serviceName]/server.go, etc.) Likely this will be added to a stencil template in the future, but will need to be added manually for now.

// main.go

import (
    "context"

    "github.com/getoutreach/gobox/pkg/ometrics"
)

func main() {
    ctx := context.Background()

    ...

    if err := ometrics.InitializeMeterProvider(ctx, ometrics.ExporterTypePrometheus); err != nil {
        // Handle err
    }
}

[!IMPORTANT] While this function will initialize the default, global provider for the open-telemetry package, it will not automatically create or expose an HTTP handler for consuming these metrics. This will still need to be done by the caller. However, as long as your service is using the stencil-golang module, this should be provided for you through the github.com/getoutreach/httpx package. If your service is not using the template, then you will likely still need to create and configure an HTTP endpoint for your metrics to be consumed through.

In order to setup instruments on which metrics may be recorded, a meter is first required. A meter ties the instrumented recordings to a scope and finally to the configured provider which will handle the exporting of those recorded metrics. An important note here is that these meters are intended to be scoped. According to the open-telemetry documentation, a meter should be scoped to a package. Because of this, it is expected by convention to use the package name of the calling code for this meter. See docs here: https://pkg.go.dev/go.opentelemetry.io/otel/metric#MeterProvider. (The scope name from the meter simply gets added as an attribute on prometheus observations).

[!IMPORTANT] Using the open-telemetry package's global Meter func will use whichever provider is currently configured, and the resulting meter will be tied to that provider. Because of this, it is important that you have called the ometrics.InitializeMeterProvider before creating any meters.

import (
    "context"

    "github.com/getoutreach/gobox/pkg/ometrics"
    "go.opentelemetry.io/otel/metric"
)

// The otel meter's ideally use the package name of the caller to
// scope any instruments created by that meter to this package, as
// opposed to other packages/code.
const packageName = "github.com/getoutreach/serviceName/pkg/pkgName"

// For ease of use, we will have a package-level our meter which
// can be readily accessed.
var meter metric.Meter

// This func ensures our package-level meter is created with any
// necessary configurations. This is especially important in order
// ensure that our meter is not created before we have called the
// `ometrics.InitializeMeterProvider` func.
func createPackageMeter() {
    meter = otel.Meter(packageName)
}
Creating an instrument
import (
    "context"

    "github.com/getoutreach/gobox/pkg/ometrics"
    "go.opentelemetry.io/otel/metric"
)

// The otel meter's ideally use the package name of the caller to
// scope any instruments created by that meter to this package, as
// opposed to other packages/code.
const packageName = "github.com/getoutreach/serviceName/pkg/pkgName"

// For ease of use, we will have a package-level our meter which
// can be readily accessed.
var meter metric.Meter

// We will create a package level histogram instrument for call
// latency.
var exampleLatencyInstr metric.Float64Histogram

func initMetrics() {
    // Ensure the ometrics provider is initialized.
    if err := ometrics.InitializeMeterProvider(ctx, ometrics.ExporterTypePrometheus); err != nil {
        // Handle err
    }

    // Create a package scoped meter.
    meter = otel.Meter(packageName)

    // Create a float64 histogram instrument from out meter with
    // a description and appropriate unit ('s' for seconds).
    exampleLatencyInstr = meter.Float64Histogram(
        "example_call_seconds",
        metric.WithDescription("The latency of example func calls, in seconds"),
        metric.WithUnit("s"),
    )
}
Recording a value using an instrument

This example usage uses the previous section as the implied setup for this usage.

import (
    "context"
    "time"
)

// Setup metrics
...

func exampleFunc(ctx context.Context, req interface{}) error {
    start := time.Now()

    // Do some work
    ...

    // Record the diff in time between start and now with our example
    // func latency histogram instrument.
    took := time.Since(start)
    exampleLatencyInstr.Record(ctx, took.Seconds())
}

Further Reading

These docs provide high level usage examples, and specific information about the usage of otel with this package. However, most metrics instrumentation will ultimately be done directly using the Golang otel package. To get a full understanding of the available instruments and their usage, check out the docs: https://pkg.go.dev/go.opentelemetry.io/otel/metric.

Migrating from gobox/pkg/metrics

Today, the current metrics package only exposes a small set of functionality, primarily creating a few basic http/grpc histograms. However, most code outside of the github.com/getoutreach/httpx package do not seem to use the metrics package directly (though all services using Stencil should likely be using the httpx package's default metrics, if applicable). Most seem to use the Prometheus libraries directly. Fortunately, the open-telemetry metrics package should allow for a progressive switch over to the new package, as both direct usage of Prometheus as well as usage through open-telemetry can be done concurrently. New instruments can be created with open-telemetry package while old packages using the Prometheus libraries directly can begin to gradually be moved over.

Below is an example of using the new open-telemetry package using a common pattern found within our own codebases.

new

// github.com/getoutreach/serviceName/internal/metrics/metrics.go
package metrics

import (
    "context"
    "time.Time"

    "github.com/getoutreach/gobox/pkg/ometrics"
    "go.opentelemetry.io/otel/metric"
)

const packageName = "github.com/getoutreach/serviceName/internal/metrics"

var (
    meter metric.Meter
    exampleLatencyInstr metric.Float64Histogram
)

func initMetrics() {
    if err := ometrics.InitializeMeterProvider(ctx, ometrics.ExporterTypePrometheus); err != nil {
        // Handle err
    }

    meter = otel.Meter(packageName)

    exampleLatencyInstr = meter.Float64Histogram(
        "example_call_seconds",
        metric.WithDescription("The latency of example func calls, in seconds"),
        metric.WithUnit("s"),
    )
}

func ReportExampleLatency(ctx context.Context, d time.Duration) {
    exampleLatencyInstr.Record(ctx, d.Seconds())
}

old

// github.com/getoutreach/serviceName/internal/metrics/metrics.go
package metrics

import (
    "strconv"
    "time"

    "github.com/prometheus/client_golang/prometheus"
)

func init() {
    prometheus.MustRegister(exampleLatencyInstr)
}

var exampleLatencyInstr = prometheus.NewHistogramVec(
    prometheus.HistogramOpts{
        Name: "example_call_seconds",
        Help: "The latency of example func calls, in seconds",
    }, []string{})

func ReportExampleLatency(subject, operation string, err error, d time.Duration) {
    exampleLatencyInstr.Observe(d.Seconds())
}

func InitializeMeterProvider

func InitializeMeterProvider(ctx context.Context, t ExporterType, opts ...Option) error

InitializeMeterProvider initializes the global meter provider to be backed by the provided exporter.

type CollectorConfig

CollectorConfig contains configuration for creating a ExporterTypeCollector exporter through InitializeMeterProvider.

type CollectorConfig struct {
    // Interval is the time at which metrics should be read and
    // subsequently pushed to the collector.
    Interval time.Duration
}

type Config

Config is the configuration for a meter provider created by this package. This is meant to be used by InitializeMeterProvider.

type Config struct {
    // Collector contains configuration for the collector exporter. This
    // is only valid when using the ExporterTypeCollector.
    Collector CollectorConfig
}

type ExporterType

ExporterType denotes the type of exporter to use for metrics.

type ExporterType int

Contains the different types of exporters that can be used.

const (
    // ExporterTypePrometheus exports metrics in the prometheus format. It
    // is the caller's responsibility to expose the metrics via an HTTP
    // endpoint (usually through promhttp). Example implementation:
    // https://github.com/open-telemetry/opentelemetry-go/blob/main/example/prometheus/main.go#L99
    ExporterTypePrometheus ExporterType = iota

    // ExporterTypeCollector exports metrics to the otel collector. This
    // is akin to the "push" model of metrics, for those familiar with
    // the prometheus model.
    ExporterTypeCollector
)

type Option

Option is a function that sets a configuration value.

type Option func(c *Config)
func WithConfig
func WithConfig(c Config) Option

WithConfig sets the configuration for a meter provider replacing all default values.

Documentation

Overview

Package ometrics implements a small wrapper around working with the otel metrics package. It does not provide any wrappers around the core types provided by otel, instead provides a way to instantiate them instead.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func InitializeMeterProvider

func InitializeMeterProvider(ctx context.Context, t ExporterType, opts ...Option) error

InitializeMeterProvider initializes the global meter provider to be backed by the provided exporter.

Types

type CollectorConfig

type CollectorConfig struct {
	// Interval is the time at which metrics should be read and
	// subsequently pushed to the collector.
	Interval time.Duration
}

CollectorConfig contains configuration for creating a ExporterTypeCollector exporter through InitializeMeterProvider.

type Config

type Config struct {
	// Collector contains configuration for the collector exporter. This
	// is only valid when using the ExporterTypeCollector.
	Collector CollectorConfig
}

Config is the configuration for a meter provider created by this package. This is meant to be used by InitializeMeterProvider.

type ExporterType

type ExporterType int

ExporterType denotes the type of exporter to use for metrics.

const (
	// ExporterTypePrometheus exports metrics in the prometheus format. It
	// is the caller's responsibility to expose the metrics via an HTTP
	// endpoint (usually through promhttp). Example implementation:
	// https://github.com/open-telemetry/opentelemetry-go/blob/main/example/prometheus/main.go#L99
	ExporterTypePrometheus ExporterType = iota

	// ExporterTypeCollector exports metrics to the otel collector. This
	// is akin to the "push" model of metrics, for those familiar with
	// the prometheus model.
	ExporterTypeCollector
)

Contains the different types of exporters that can be used.

type Option

type Option func(c *Config)

Option is a function that sets a configuration value.

func WithConfig

func WithConfig(c Config) Option

WithConfig sets the configuration for a meter provider replacing all default values.

Jump to

Keyboard shortcuts

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