Skip to content

Instantly share code, notes, and snippets.

@qrealka
Last active February 22, 2024 12:51
Show Gist options
  • Save qrealka/2c1757819972a320c42786fc32ee7219 to your computer and use it in GitHub Desktop.
Save qrealka/2c1757819972a320c42786fc32ee7219 to your computer and use it in GitHub Desktop.
PoC half-auto OTEL metrics creation
package main
import (
"context"
"fmt"
"log"
"sync/atomic"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/metric"
)
// splitted into two enums but for go they will be fully implicit convertible
type MetricIntCounterID int
const (
OnStartError MetricIntCounterID = iota
OnStopError
OnProbeError
// please add metrics for integer counters before this line
numberOfIntCounters
)
type MetricFloatCounterID int
const (
// below should be enums for Float counters
FirstFloatCounterID MetricFloatCounterID = MetricFloatCounterID(numberOfIntCounters)
numberOfAllCounters
)
var (
allCounterValues = make([]atomic.Value, numberOfAllCounters)
allCounterObservers = make([]metric.Observable, numberOfAllCounters)
)
func initMetrics(m metric.Meter) metric.Registration {
// NOTICE: UpDown counter is more common type of counter. It fully cover only growing counter
// but we need to test it in terms how it looks for Prometheus or other exporters
// it is implementation details. and problems like that doesn't look like a blocker for now
for i := OnStartError; i < numberOfIntCounters; i++ {
if observer, err := m.Int64ObservableUpDownCounter(fmt.Sprintf("%v", MetricIntCounterID(i))); err == nil {
allCounterObservers[i] = observer
} else {
log.Fatalf("Failed to create int64 metric: %v", err)
}
}
for i := FirstFloatCounterID; i < numberOfAllCounters; i++ {
if observer, err := m.Float64ObservableUpDownCounter(fmt.Sprintf("%v", MetricFloatCounterID(i))); err == nil {
allCounterObservers[i] = observer
} else {
log.Fatalf("Failed to create float64 metric: %v", err)
}
}
r, err := m.RegisterCallback(func(_ context.Context, o metric.Observer) error {
// TODO: could be slow. Esy to fix by RCU array
for i, c := range allCounterValues {
if i < int(numberOfIntCounters) {
o.ObserveInt64(allCounterObservers[i].(metric.Int64Observable), c.Load().(int64))
} else if i > int(numberOfIntCounters) {
o.ObserveFloat64(allCounterObservers[i].(metric.Float64Observable), c.Load().(float64))
}
}
return nil
}, allCounterObservers...)
if err != nil {
log.Fatalf("Failed to register callback: %v", err)
}
return r
}
// in case if we have two enums
// it probably could be more readable
func IntCounterAdd(id MetricIntCounterID, delta int32) {
if id < numberOfIntCounters {
allCounterValues[id].Store(allCounterValues[id].Load().(int64) + int64(delta))
}
}
func FloatCounterAdd(id MetricFloatCounterID, delta float32) {
if id >= FirstFloatCounterID {
allCounterValues[id].Store(allCounterValues[id].Load().(float64) + float64(delta))
}
}
func main() {
fmt.Println("Hello, World!")
r := initMetrics(otel.Meter("test"))
// if we have error, we just need to add value for specific counter
IntCounterAdd(OnStartError, 1)
defer r.Unregister()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment