Last active
February 22, 2024 12:51
-
-
Save qrealka/2c1757819972a320c42786fc32ee7219 to your computer and use it in GitHub Desktop.
PoC half-auto OTEL metrics creation
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 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