Skip to content

Instantly share code, notes, and snippets.

@yolken-airplane
Created November 16, 2023 20:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yolken-airplane/027867b753840f7d15d622be793f57bb to your computer and use it in GitHub Desktop.
Save yolken-airplane/027867b753840f7d15d622be793f57bb to your computer and use it in GitHub Desktop.
package metrics
import (
"context"
"log"
"sync"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
)
// SynchronousGauge is an implementation of a synchronous otel gauge. Because the golang otel
// SDK only supports asynchronous, callback-based gauges, we need this to simulate a synchronous
// API, which is a lot easier to call and better matches how things work with the prometheus SDK.
type SynchronousGauge struct {
metric.Observable
sync.RWMutex
name string
opts []metric.Float64ObservableGaugeOption
meter metric.Meter
used bool
values map[string]float64
}
func NewSynchronousGauge(
meter metric.Meter,
name string,
opts ...metric.Float64ObservableGaugeOption,
) (*SynchronousGauge, error) {
return &SynchronousGauge{
meter: meter,
name: name,
opts: opts,
used: false,
values: map[string]float64{},
}, nil
}
func (s *SynchronousGauge) Observe(
ctx context.Context,
value float64,
attributes ...attribute.KeyValue,
) {
s.Lock()
defer s.Unlock()
if !s.used {
// Lazily initialize the gauge and callback function
gauge, err := s.meter.Float64ObservableGauge(s.name, s.opts...)
if err != nil {
return
}
if _, err := s.meter.RegisterCallback(
func(innerCtx context.Context, o metric.Observer) error {
s.RLock()
defer s.RUnlock()
for attrStr, value := range s.values {
attributes := StrToAttributes(attrStr)
o.ObserveFloat64(gauge, value, metric.WithAttributes(attributes...))
}
return nil
}, gauge,
); err != nil {
log.Printf("Warning: Failed to register callback for gauge %s: %+v", s.name, err)
return
}
s.used = true
}
s.values[AttributesToStr(attributes)] = value
}
func (s *SynchronousGauge) Delete(
ctx context.Context,
attributes ...attribute.KeyValue,
) {
s.Lock()
defer s.Unlock()
delete(s.values, AttributesToStr(attributes))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment