@@ -24,6 +24,8 @@ import (
2424 "github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/number"
2525 "github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/sdkinstrument"
2626 "go.opentelemetry.io/otel"
27+ "go.opentelemetry.io/otel/attribute"
28+ "go.opentelemetry.io/otel/trace"
2729)
2830
2931// Sentinel errors for Aggregator interface.
3335 ErrInfInput = fmt .Errorf ("±Inf value is an invalid input" )
3436)
3537
38+ // ExemplarFilterKind determines which events are eligible for
39+ // becoming exemplars.
40+ type ExemplarFilterKind int
41+
42+ const (
43+ // AlwaysOffKind is the default when aggregator.Config{} is
44+ // used with a zero value. This is a good default because
45+ // exemplars require additional synchronization.
46+ AlwaysOffKind ExemplarFilterKind = iota
47+
48+ // AlwaysOnKind considers all events for exemplar sampling.
49+ AlwaysOnKind
50+
51+ // WhenTracedKind considers events only in sampled trace
52+ // contexts for exemplar sampling.
53+ WhenTracedKind
54+ )
55+
56+ // DefaultExemplarReservoirSize determines how many exemplars will be
57+ // selected per instrument.
58+ const DefaultExemplarReservoirSize = 10
59+
3660// RangeTest is a common routine for testing for valid input values.
3761// This rejects NaN and Inf values. This rejects negative values when the
3862// aggregation does not support negative values, including
@@ -68,6 +92,20 @@ func RangeTest[N number.Any, Traits number.Traits[N]](num N, desc sdkinstrument.
6892 return true
6993}
7094
95+ // ExemplarConfig configures exemplar selection.
96+ type ExemplarConfig struct {
97+ // Filter determines which contexts are selected.
98+ Filter ExemplarFilterKind
99+ // Size determines limits how many exemplars per timeseries.
100+ Size uint32
101+ }
102+
103+ // JSONExemplarConfig configures exemplar selection.
104+ type JSONExemplarConfig struct {
105+ Filter string `json:"filter"`
106+ Size uint32 `json:"size"`
107+ }
108+
71109// JSONHistogramConfig configures the exponential histogram.
72110type JSONHistogramConfig struct {
73111 MaxSize int32 `json:"max_size"`
@@ -77,6 +115,7 @@ type JSONHistogramConfig struct {
77115type JSONConfig struct {
78116 Histogram JSONHistogramConfig `json:"histogram"`
79117 CardinalityLimit uint32 `json:"cardinality_limit"`
118+ Exemplar JSONExemplarConfig `json:"exemplar"`
80119}
81120
82121// Config supports the configuration for all aggregators in a single struct.
@@ -87,6 +126,9 @@ type Config struct {
87126 // CardinalityLimit limits the number of instances of this
88127 // aggregator in a given view.
89128 CardinalityLimit uint32
129+
130+ // ExemplarFilter enables or disables exemplars
131+ Exemplar ExemplarConfig
90132}
91133
92134// Valid returns true for valid configurations.
@@ -140,7 +182,7 @@ type Methods[N number.Any, Storage any] interface {
140182
141183 // Update modifies Storage concurrently with respect to
142184 // concurrent Move(), Copy(), and Update() operations.
143- Update (ptr * Storage , number N )
185+ Update (ptr * Storage , number N , ex ExemplarBits )
144186
145187 // Move atomically copies `input` to `output` and resets
146188 // `input` to the zero state. The change to `input` is
@@ -181,7 +223,44 @@ type Methods[N number.Any, Storage any] interface {
181223 // aggregation. If the instrument is asynchronous, this will
182224 // be called after subtraction. Not synchronized.
183225 HasChange (ptr * Storage ) bool
226+
227+ // Exemplars returns sample points included in this aggregation.
228+ Exemplars (ptr * Storage , in []WeightedExemplarBits ) []WeightedExemplarBits
229+
230+ // Weight is the sample weight. It is 1 for histogram and
231+ // gauge aggregations, and it is the value for sum data
232+ // aggregations.
233+ Weight (number N ) float64
184234}
185235
186236// ConfigSelector is a per-instrument-kind, per-number-kind Config choice.
187237type ConfigSelector func (sdkinstrument.Kind ) (int64Config , float64Config Config )
238+
239+ // ExemplarBits conducts extra information into the aggregation pipeline.
240+ //
241+ // Note: we could opt for an allocation instead of copying this struct
242+ // by value through the pipeline.
243+ type ExemplarBits struct {
244+ // Time of the event.
245+ Time time.Time
246+
247+ // Attributes are the complete original set of attributes.
248+ Attributes []attribute.KeyValue
249+
250+ // Span has a reference to the span context, which has the 24
251+ // bytes of ID. We keep a span reference here because it is
252+ // slightly smaller.
253+ Span trace.Span
254+
255+ // Number is the input value.
256+ Number number.Number
257+ }
258+
259+ // WeightedExemplarBits are the exemplar and its calculated sample weight.
260+ type WeightedExemplarBits struct {
261+ // ExemplarBits calculated at the event.
262+ ExemplarBits
263+
264+ // Weight calculated by aggregation pipeline.
265+ Weight float64
266+ }
0 commit comments