Created
November 16, 2023 20:15
-
-
Save yolken-airplane/027867b753840f7d15d622be793f57bb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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