opencensus

package module
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Jul 12, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

README

opencensus-go-metrics-optimized

CI Go Reference License

Generic, sharded pre-aggregation for OpenCensus Go metrics.

Calling stats.Record on every event builds a tag.Map and enqueues a recordReq to OpenCensus's single global worker goroutine — under high throughput that worker becomes a bottleneck and a point of lock contention. This library accumulates values per label key across N in-memory shards and flushes them to OpenCensus in bursts on a configurable interval, cutting the number of stats.Record calls (and their allocations) by orders of magnitude without changing the semantics of the underlying views.

Features

  • Generic over your label key. Define any comparable struct K as your label set and a Schema[K] that knows how to project it onto OpenCensus — no map[string]interface{} or reflection involved.
  • Generic over the measure value type N. Each config takes a second type parameter N (~int64 | ~float64), so a variant can be backed by either a *stats.Float64Measure or a *stats.Int64Measure.
  • Four aggregator variants behind one interface (Aggregator[K, N]): Count, Sum, Distribution (with optional bounded reservoir sampling), and LastValue (for gauges).
  • Multi-metric aggregation. Fold many Count/Sum/LastValue metrics over the same key into one shared store and a single stats.Record per key — see Multi-metric aggregation.
  • Sharded, lock-striped storage. Writes only lock the shard for their key, not a single global mutex.
  • Allocation-free hot path. After a key has been seen once, Add does not allocate; the per-key context.Context (with tags already applied) is memoized and reused across flushes.
  • Non-blocking flush. Each shard's map is swapped out under its own lock so writers are never blocked by a flush in progress.

Installation

go get github.com/mresti/opencensus-go-metrics-optimized

Requires Go 1.26+ (uses generics and sync.WaitGroup.Go).

Quick start

  1. Define your label key and a Schema[K] for it:
package main

import "go.opencensus.io/tag"

type HTTPLabels struct {
	User   string
	Route  string
	Status string
}

type HTTPSchema struct {
	KeyUser   tag.Key
	KeyRoute  tag.Key
	KeyStatus tag.Key
}

// Hash is called on every Add: keep it cheap and non-allocating.
func (HTTPSchema) Hash(k HTTPLabels) uint64 {
	return hashStrings(k.User, k.Route, k.Status)
}

// Mutators is called only on flush, once per distinct combination.
func (s HTTPSchema) Mutators(k HTTPLabels) []tag.Mutator {
	return []tag.Mutator{
		tag.Upsert(s.KeyUser, k.User),
		tag.Upsert(s.KeyRoute, k.Route),
		tag.Upsert(s.KeyStatus, k.Status),
	}
}
  1. Create an aggregator and record events against it instead of calling stats.Record directly:
package main

import (
	"time"

	oc "github.com/mresti/opencensus-go-metrics-optimized"
	"go.opencensus.io/stats"
)

var requestCount = stats.Float64("myapp/requests", "HTTP requests", stats.UnitDimensionless)

func main() {
	schema := HTTPSchema{ /* register tag.Key's via tag.NewKey */ }

	agg := oc.NewCountAggregator(oc.CountConfig[HTTPLabels, float64]{
		Config: oc.Config[HTTPLabels]{
			Shards:   16,               // default 16, rounded up to a power of 2
			Interval: 10 * time.Second, // default 10s
			Schema:   schema,
		},
		CountMeasure: requestCount,
	})
	defer agg.Stop() // flushes any remaining data before returning

	agg.Add(HTTPLabels{User: "alice", Route: "/orders", Status: "200"}, 1)
}

Stop performs a final flush before returning, so no data is lost on shutdown.

Aggregator variants

All variants implement the same interface:

type Aggregator[K comparable, N Number] interface {
	Add(k K, value N)
	Stop()
}
Constructor Config Use case
NewCountAggregator[K, N] CountConfig[K, N] Counting occurrences per key (equivalent to view.Count()).
NewSumAggregator[K, N] SumConfig[K, N] Summing a numeric value per key (equivalent to view.Sum()).
NewDistributionAggregator[K, N] DistributionConfig[K, N] Latency/size histograms; supports MaxSamplesPerKey reservoir sampling to bound memory under high/unbounded cardinality per key.
NewLastValueAggregator[K, N] LastValueConfig[K, N] Gauges; the measure's view must use view.LastValue().

The value type N is inferred from the config literal, e.g. SumConfig[HTTPLabels, float64] (Float64 measure) or SumConfig[HTTPLabels, int64] (Int64 measure).

Multi-metric aggregation

When several metrics share the same label key K, running one aggregator each means N shard lookups, N locks and N ctxCache entries per event, plus N stats.Record calls per key on every flush. MultiAggregator folds up to 64 Count/Sum/LastValue metrics over the same K into a single sharded store, flusher and ctxCache, emitting one stats.Record per key carrying every metric at once.

Declare metrics with a builder; each registration returns a lightweight handle you record against:

b := oc.NewMultiBuilder[HTTPLabels, float64](oc.MultiConfig[HTTPLabels, float64]{
	Config:    oc.Config[HTTPLabels]{Shards: 16, Interval: 10 * time.Second, Schema: schema},
	SkipZeros: false, // if true, omit Count/Sum slots still 0 at flush time
})

requests := b.Count(requestMeasure)     // Count ignores the value: each Add is +1
bytesOut := b.Sum(bytesMeasure)         // Sum accumulates the value
inflight := b.LastValue(gaugeMeasure)   // LastValue keeps the last write

agg := b.Build() // applies defaults, starts the flusher
defer agg.Stop() // final flush on shutdown

k := HTTPLabels{User: "alice", Route: "/orders", Status: "200"}
requests.Add(k, 1)
bytesOut.Add(k, 2048)
inflight.Add(k, 3)
Semantics
  • Count ignores the value passed to Add and increments by one.
  • Sum accumulates the value.
  • LastValue overwrites (last-write-wins under the shard lock) and is emitted on flush only if its slot was written that window — an untouched gauge is never fabricated as 0, but an explicit Add(k, 0) is emitted (0 is a legitimate gauge reading).
  • SkipZeros applies only to Count/Sum: when true, slots still at 0 at flush time are omitted. It never affects LastValue.
  • Handles are values — copy them freely; every copy writes the same slot. Only MultiAggregator has Stop(); handles are pure write endpoints and do not implement Aggregator[K, N].
  • Registering a metric after Build, calling Build twice, exceeding 64 metrics, or passing a nil measure all panic (programming errors, surfaced early).
One multi per schema

Group into a single MultiAggregator the metrics that share the same key K / Schema. For metrics whose labels differ — e.g. HTTP request metrics vs. database query metrics — use one MultiAggregator per domain; do not merge schemas. stats.Record carries a single context.Context, so metrics with different tag sets can never share a Record, and a unified store would only move tag projection onto the hot path and risk emitting empty/zero tags into the wrong views. The extra cost of a second aggregator is just one goroutine/ticker per schema, while separate stores improve parallel-write throughput (see Performance) and let each flusher keep its own anti-burst startup jitter. See the ExampleNewMultiBuilder two-schemas example in the Go reference.

Cardinality

The shared ctxCache holds one context per distinct key regardless of metric count, so memory scales with keys, not keys×metrics — roughly 1/N the ctxCache footprint of N separate aggregators, and N× fewer stats.Record calls per flush. This directly eases the high-cardinality guidance in Configuration about not dropping Interval too low.

Performance

Benchmarks on the target 4-Count + 9-Sum layout (-benchmem), multi vs. the equivalent 13 separate aggregators:

Scenario Multi Separate Notes
Single-metric Add (one metric per event) ~47 ns/op, 0 allocs ~51 ns/op, 0 allocs Handle adds no measurable overhead.
One event → all 13 metrics ~446 ns/op, 0 allocs ~589 ns/op, 0 allocs Multi ~24% faster (one accumulator slice, better locality).
Flush 1 000 keys × 13 metrics ~2.7 ms/op ~6.0 ms/op Multi ~2.2× faster, ~half the allocs (one record + ctx lookup per key).
Parallel Add, 8 cores ~40 ns/op ~23 ns/op Separate wins: 13 independent stores spread lock contention across 13×Shards mutexes.

The parallel-write result is the cost of a single shared store. If write contention dominates your workload, raise Shards on the MultiConfig to widen the one store (e.g. 64–128) — the flush and locality benefits are unaffected.

Configuration

Config[K] is embedded in every variant's config struct:

type Config[K comparable] struct {
	Shards   int           // rounded up to a power of 2. Default 16.
	Interval time.Duration // flush cadence. Default 10s.
	Schema   Schema[K]     // key -> OpenCensus projection strategy
}
  • Shards trades memory/lock granularity for contention: more shards means less contention under concurrent Add calls from many goroutines.
  • Interval trades staleness for the volume of stats.Record traffic sent to the OpenCensus worker (default 10s). Set it to an exact divisor of the exporter reporting period (view.SetReportingPeriod) and at most half of it — e.g. 10s or 15s for a 30s period; 10s also divides the common 60s period. A non-divisor interval causes sawtooth in delta/rate charts. Aggregators apply a random startup delay in [0, Interval) so instances created together don't all flush on the same tick and burst the OpenCensus worker.

Design notes

  • The per-key context.Context cache (ctxCache) grows with the number of distinct keys observed. It is stable under bounded label cardinality; for unbounded/high-cardinality label sets, keep K's cardinality bounded upstream (e.g. bucket free-form values) or clear the aggregator periodically.
  • Distribution's MaxSamplesPerKey (when > 0) uses reservoir sampling so memory per key is bounded regardless of how many samples arrive between flushes, trading exactness for a bounded, uniformly-sampled subset.
  • Concurrency-sensitive internals (sharded store, contract behavior across the three variants) are covered by a shared contract test suite and fuzz tests; see Testing.

Testing

The project uses make for all common workflows — run make help to list targets. The most relevant ones:

make test           # go test -race -cover ./...
make test-bench     # benchmarks across the aggregator variants
make test-fuzz       # replay the committed Fuzz* seed corpus (fast, CI-safe)
make test-fuzz-one FUZZ=FuzzCountAggregator_Add FUZZTIME=1m  # fuzz one target
make lint            # golangci-lint (run `make tools` once to install it)
make ci              # vet + lint + test — what CI runs

Contributing

Issues and pull requests are welcome. Please run make ci locally before submitting a PR — the same target gates CI on GitHub Actions.

License

Licensed under either of Apache License, Version 2.0 (LICENSE or http://www.apache.org/licenses/LICENSE-2.0)

Documentation

Overview

Package opencensus normalizes the use of OpenCensus through local, "sharded" aggregation that is GENERIC over the labels key K.

Instead of calling stats.Record per event (each call builds a tag.Map and sends a recordReq to the global worker), we accumulate per key K across N shards and emit in bursts every `interval`. The key K is any comparable struct you define; a Schema[K] (Strategy pattern) projects it onto OpenCensus.

Three variants behind the SAME Aggregator[K, N] interface (SumCount and Distribution here; LastValue in lastvalue.go), plus a multi-metric aggregator (multi.go) that shares one store, flusher and ctxCache across several Count/Sum/LastValue metrics on the same key K. The hot path (Add) does not allocate on the heap after a key is seen for the first time; the flush swaps the map to avoid blocking writers and reuses the per-key context via ctxCache.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Aggregator

type Aggregator[K comparable, N Number] interface {
	Add(k K, value N)
	Stop()
}

Aggregator is the common interface, generic over the labels key K and the measure value type N.

type Config

type Config[K comparable] struct {
	Shards int // rounded up to a power of 2. Default 16.

	// Interval is the flush cadence. Default 10s.
	//
	// Tuning rule: set Interval to an exact divisor of the exporter reporting
	// period (view.SetReportingPeriod) and at most half of it. For the common
	// 30s period use 10s or 15s; 10s also divides the common 60s period, hence
	// the default. Interval equal to the reporting period causes phase races
	// (export windows with no fresh flush); non-divisor intervals cause sawtooth
	// in delta/rate charts.
	//
	// For LastValue gauges, Interval is the maximum staleness at export time.
	// For distributions with MaxSamplesPerKey, the reservoir resets each flush,
	// so shorter intervals improve percentile fidelity.
	Interval time.Duration

	Schema Schema[K] // key projection strategy

	// CtxCacheSize caps the number of distinct keys whose tagged context.Context
	// stays resident in the ctxCache LRU. Beyond it the least-recently-used entries
	// are evicted and rebuilt (tag.New) the next time their key flushes — a CPU-for-RAM
	// trade-off that bounds cache memory under unbounded label cardinality. Default
	// 200_000 when <= 0.
	CtxCacheSize int
}

Config holds the settings shared by every aggregator variant: the shard count, the flush interval and the key projection Schema.

Cardinality is the dimension that drives cost. Flush is O(distinct keys): each flush does one ctxCache lookup plus one stats.Record per key, and every record is funneled to the single global OpenCensus worker goroutine. The ctxCache (see ctxcache.go) is a bounded LRU of at most CtxCacheSize tagged contexts, so its memory is capped even under unbounded label cardinality; keys evicted past that bound simply rebuild their context (tag.New) on the next flush that touches them. Rough guidance:

  • ≲1k keys: Interval 5–10s is fine.
  • 10k–100k+ keys: prefer Interval 10–15s and set MaxSamplesPerKey on distributions to bound memory.
  • Do not go below ~5s at high cardinality: flush bursts can saturate the OpenCensus worker channel and block the flusher goroutine.

Shards affect writer contention (concurrent Add goroutines), not key count.

type CountAggregator

type CountAggregator[K comparable, N Number] struct {
	// contains filtered or unexported fields
}

CountAggregator accumulates the running count per key K across sharded stores and flushes both to OpenCensus on the configured interval.

func NewCountAggregator

func NewCountAggregator[K comparable, N Number](cfg CountConfig[K, N]) *CountAggregator[K, N]

NewCountAggregator builds a CountAggregator from cfg, applying defaults and starting the background flusher.

func (*CountAggregator[K, N]) Add

func (a *CountAggregator[K, N]) Add(k K, _ N)

Add adds value to the running increments its count.

func (*CountAggregator[K, N]) Stop

func (a *CountAggregator[K, N]) Stop()

Stop halts the background flusher.

type CountConfig

type CountConfig[K comparable, N Number] struct {
	Config[K]
	CountMeasure Measure[N]
}

CountConfig configures a SumCountAggregator, pairing the shared Config with the measures used to record the accumulated count.

type DistributionAggregator

type DistributionAggregator[K comparable, N Number] struct {
	// contains filtered or unexported fields
}

DistributionAggregator collects per-key samples across sharded stores and flushes them to OpenCensus on the configured interval. When MaxSamplesPerKey is set it keeps a bounded reservoir sample per key.

func NewDistributionAggregator

func NewDistributionAggregator[K comparable, N Number](cfg DistributionConfig[K, N]) *DistributionAggregator[K, N]

NewDistributionAggregator builds a DistributionAggregator from cfg, applying defaults and starting the background flusher.

func (*DistributionAggregator[K, N]) Add

func (a *DistributionAggregator[K, N]) Add(k K, value N)

Add records value as a sample for k, using reservoir sampling once the per-key sample cap is reached.

func (*DistributionAggregator[K, N]) Stop

func (a *DistributionAggregator[K, N]) Stop()

Stop halts the background flusher.

type DistributionConfig

type DistributionConfig[K comparable, N Number] struct {
	Config[K]
	Measure          Measure[N]
	MaxSamplesPerKey int // 0 = exact; >0 = reservoir sampling (bounded memory)
}

DistributionConfig configures a DistributionAggregator with the shared Config, the measure to record samples against and the optional per-key sample cap.

type LastValueAggregator

type LastValueAggregator[K comparable, N Number] struct {
	// contains filtered or unexported fields
}

LastValueAggregator keeps the last value recorded per key K across sharded stores and flushes it to OpenCensus on the configured interval.

func NewLastValueAggregator

func NewLastValueAggregator[K comparable, N Number](cfg LastValueConfig[K, N]) *LastValueAggregator[K, N]

NewLastValueAggregator builds a LastValueAggregator from cfg, applying defaults and starting the background flusher.

func (*LastValueAggregator[K, N]) Add

func (a *LastValueAggregator[K, N]) Add(k K, value N)

Add overwrites the value of the key. The shard lock serializes the writes: "last-write-wins" is well defined by the acquisition order.

func (*LastValueAggregator[K, N]) Stop

func (a *LastValueAggregator[K, N]) Stop()

Stop halts the background flusher.

type LastValueConfig

type LastValueConfig[K comparable, N Number] struct {
	Config[K]
	// Measure must be backed by a view of type view.LastValue().
	Measure Measure[N]
}

LastValueConfig configures a LastValueAggregator: it embeds the shared Config and the measure whose view must be of type view.LastValue().

type Measure added in v1.1.0

type Measure[N Number] interface {
	M(v N) stats.Measurement
}

Measure is satisfied by *stats.Float64Measure (N=float64) and *stats.Int64Measure (N=int64). A parametrized interface is needed because M has a different signature on each concrete measure, so a union constraint alone cannot expose it directly.

type MultiAggregator added in v1.3.0

type MultiAggregator[K comparable, N Number] struct {
	// contains filtered or unexported fields
}

MultiAggregator accumulates several Count/Sum/LastValue metrics per key K in one sharded store and flushes them together to OpenCensus on the configured interval.

func (*MultiAggregator[K, N]) Stop added in v1.3.0

func (a *MultiAggregator[K, N]) Stop()

Stop halts the background flusher after a final flush.

type MultiBuilder added in v1.3.0

type MultiBuilder[K comparable, N Number] struct {
	// contains filtered or unexported fields
}

MultiBuilder registers the metrics of a MultiAggregator and freezes them on Build. It is single-use: registering after Build or calling Build twice panics.

func NewMultiBuilder added in v1.3.0

func NewMultiBuilder[K comparable, N Number](cfg MultiConfig[K, N]) *MultiBuilder[K, N]

NewMultiBuilder starts a builder for a MultiAggregator over key K and value type N. Register metrics with Count/Sum/LastValue, then call Build.

Example

ExampleNewMultiBuilder folds several metrics over the same HTTPLabels key into one aggregator: a single sharded store, flusher and ctxCache, and one stats.Record per key on flush. Each Count/Sum/LastValue registration returns a lightweight handle.

schema := HTTPSchema{
	KeyUser:   tag.MustNewKey("user"),
	KeyRoute:  tag.MustNewKey("route"),
	KeyStatus: tag.MustNewKey("status"),
}

requestMeasure := stats.Float64("myapp/requests", "HTTP requests", stats.UnitDimensionless)
bytesMeasure := stats.Float64("myapp/bytes_out", "response bytes", stats.UnitBytes)
inflightMeasure := stats.Float64("myapp/inflight", "in-flight requests", stats.UnitDimensionless)

b := NewMultiBuilder[HTTPLabels, float64](MultiConfig[HTTPLabels, float64]{
	Config: Config[HTTPLabels]{
		Shards:   16,
		Interval: 10 * time.Second,
		Schema:   schema,
	},
	// SkipZeros: true, // omit Count/Sum slots still 0 at flush time
})

// Register every metric before Build; each call returns a handle to record against.
requests := b.Count(requestMeasure)      // Count ignores the value: each Add is +1
bytesOut := b.Sum(bytesMeasure)          // Sum accumulates the value
inflight := b.LastValue(inflightMeasure) // LastValue keeps the last write

agg := b.Build() // applies defaults, starts the background flusher
defer agg.Stop() // final flush before returning

k := HTTPLabels{User: "alice", Route: "/orders", Status: "200"}
requests.Add(k, 1)
bytesOut.Add(k, 2048)
inflight.Add(k, 3)
Example (TwoSchemas)

ExampleNewMultiBuilder_twoSchemas runs two MultiAggregators side by side, one per label schema (HTTP and Database). The rule is to group metrics by the key they share: use ONE MultiAggregator per schema, never a single aggregator spanning schemas. stats.Record carries a single context, so metrics with different tag sets can never share a Record; keeping stores separate also spreads write contention and lets each flusher keep its own anti-burst startup jitter.

httpSchema := HTTPSchema{
	KeyUser:   tag.MustNewKey("user"),
	KeyRoute:  tag.MustNewKey("route"),
	KeyStatus: tag.MustNewKey("status"),
}
dbSchema := DatabaseSchema{
	KeyUser:     tag.MustNewKey("db_user"),
	KeyDatabase: tag.MustNewKey("database"),
	KeyStatus:   tag.MustNewKey("db_status"),
}

// HTTP domain: metrics keyed by HTTPLabels.
httpRequests := stats.Float64("myapp/http_requests", "HTTP requests", stats.UnitDimensionless)
httpB := NewMultiBuilder[HTTPLabels, float64](MultiConfig[HTTPLabels, float64]{
	Config: Config[HTTPLabels]{Interval: 10 * time.Second, Schema: httpSchema},
})
requests := httpB.Count(httpRequests)
httpAgg := httpB.Build()
defer httpAgg.Stop()

// Database domain: metrics keyed by DatabaseLabels.
dbQueries := stats.Float64("myapp/db_queries", "database queries", stats.UnitDimensionless)
dbErrors := stats.Float64("myapp/db_query_errors", "failed queries", stats.UnitDimensionless)
dbRows := stats.Float64("myapp/db_rows_read", "rows read", stats.UnitDimensionless)
dbConns := stats.Float64("myapp/db_open_conns", "open connections", stats.UnitDimensionless)
dbB := NewMultiBuilder[DatabaseLabels, float64](MultiConfig[DatabaseLabels, float64]{
	Config: Config[DatabaseLabels]{Interval: 10 * time.Second, Schema: dbSchema},
})
queries := dbB.Count(dbQueries)
queryErrors := dbB.Count(dbErrors)
rowsRead := dbB.Sum(dbRows)
openConns := dbB.LastValue(dbConns)
dbAgg := dbB.Build()
defer dbAgg.Stop()

requests.Add(HTTPLabels{User: "alice", Route: "/orders", Status: "200"}, 1)

ok := DatabaseLabels{User: "alice", Database: "orders", Status: "ok"}
queries.Add(ok, 1)   // one query
rowsRead.Add(ok, 42) // that read 42 rows
openConns.Add(ok, 7) // 7 connections open right now

// Count ignores the value; call it once per failed query.
queryErrors.Add(DatabaseLabels{User: "alice", Database: "orders", Status: "error"}, 1)

func (*MultiBuilder[K, N]) Build added in v1.3.0

func (b *MultiBuilder[K, N]) Build() *MultiAggregator[K, N]

Build freezes the registered metrics, applies Config defaults, starts the background flusher and returns the aggregator. It panics if called twice.

func (*MultiBuilder[K, N]) Count added in v1.3.0

func (b *MultiBuilder[K, N]) Count(m Measure[N]) MultiHandle[K, N]

Count registers a count metric and returns its handle. Each Add increments the slot by one regardless of the value passed.

func (*MultiBuilder[K, N]) LastValue added in v1.3.0

func (b *MultiBuilder[K, N]) LastValue(m Measure[N]) MultiHandle[K, N]

LastValue registers a gauge metric and returns its handle. Each Add overwrites the slot; the measure must be backed by a view of type view.LastValue().

func (*MultiBuilder[K, N]) Sum added in v1.3.0

func (b *MultiBuilder[K, N]) Sum(m Measure[N]) MultiHandle[K, N]

Sum registers a sum metric and returns its handle. Each Add accumulates the value into the slot.

type MultiConfig added in v1.3.0

type MultiConfig[K comparable, N Number] struct {
	Config[K]

	// SkipZeros, when true, omits Count/Sum slots whose value is 0 from the flush.
	// It never affects LastValue: a gauge of 0 is a legitimate reading and is
	// emitted whenever its slot was written this window (see multiAcc.touched).
	SkipZeros bool
}

MultiConfig configures a MultiAggregator with the shared Config plus the zero-slot policy applied to Count/Sum on flush.

type MultiHandle added in v1.3.0

type MultiHandle[K comparable, N Number] struct {
	// contains filtered or unexported fields
}

MultiHandle is the write endpoint for one registered metric. It is a lightweight value (a shared aggregator pointer plus the slot coordinates) meant to be copied freely; every copy writes the same underlying slot. It intentionally lacks Stop, so it does not satisfy Aggregator[K, N].

func (MultiHandle[K, N]) Add added in v1.3.0

func (h MultiHandle[K, N]) Add(k K, value N)

Add folds value into this metric's slot for key k under the shard lock: Count increments by one (value ignored), Sum accumulates, LastValue overwrites.

type Number added in v1.1.0

type Number interface{ ~int64 | ~float64 }

Number are the value types supported by OpenCensus measures.

type Schema

type Schema[K comparable] interface {
	Hash(k K) uint64
	Mutators(k K) []tag.Mutator
}

Schema is the strategy that projects a labels key K onto OpenCensus: Hash distributes the key across shards on the hot path, and Mutators builds the tag.Mutator values used to derive the recording context.

type SumAggregator

type SumAggregator[K comparable, N Number] struct {
	// contains filtered or unexported fields
}

SumAggregator accumulates the running sum per key K across sharded stores and flushes both to OpenCensus on the configured interval.

func NewSumAggregator

func NewSumAggregator[K comparable, N Number](cfg SumConfig[K, N]) *SumAggregator[K, N]

NewSumAggregator builds a SumCountAggregator from cfg, applying defaults and starting the background flusher.

func (*SumAggregator[K, N]) Add

func (a *SumAggregator[K, N]) Add(k K, value N)

Add adds value to the running sum for k.

func (*SumAggregator[K, N]) Stop

func (a *SumAggregator[K, N]) Stop()

Stop halts the background flusher.

type SumConfig

type SumConfig[K comparable, N Number] struct {
	Config[K]
	SumMeasure Measure[N]
}

SumConfig configures a SumAggregator, pairing the shared Config with the measures used to record the accumulated sum and count.

Jump to

Keyboard shortcuts

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