router/pkg/metric/circuitbreaker.go (54 lines of code) (raw):
package metric
import (
"context"
"github.com/cep21/circuit/v4"
"github.com/wundergraph/cosmo/router/pkg/otel"
"go.opentelemetry.io/otel/attribute"
otelmetric "go.opentelemetry.io/otel/metric"
"time"
)
type CircuitMetricStore interface {
MeasureCircuitBreakerShortCircuit(ctx context.Context, sliceAttr []attribute.KeyValue, opt otelmetric.AddOption)
SetCircuitBreakerState(ctx context.Context, state bool, sliceAttr []attribute.KeyValue, opt otelmetric.RecordOption)
}
func NewCircuitBreakerMetricsConfig(subgraphNames []string, metrics CircuitMetricStore, baseAttributes []attribute.KeyValue) circuit.Config {
values := []attribute.KeyValue{
otel.WgSubgraphName.StringSlice(subgraphNames),
}
values = append(values, baseAttributes...)
metricsWrapper := &CircuitBreakerMetricsConfig{
metrics: metrics,
attributes: values,
}
return circuit.Config{
Metrics: circuit.MetricsCollectors{
Circuit: []circuit.Metrics{metricsWrapper},
Run: []circuit.RunMetrics{metricsWrapper},
},
}
}
type CircuitBreakerMetricsConfig struct {
metrics CircuitMetricStore
attributes []attribute.KeyValue
}
func (w *CircuitBreakerMetricsConfig) Closed(ctx context.Context, _ time.Time) {
w.metrics.SetCircuitBreakerState(ctx, false, nil, otelmetric.WithAttributes(w.attributes...))
}
func (w *CircuitBreakerMetricsConfig) Opened(ctx context.Context, _ time.Time) {
w.metrics.SetCircuitBreakerState(ctx, true, nil, otelmetric.WithAttributes(w.attributes...))
}
func (w *CircuitBreakerMetricsConfig) ErrShortCircuit(ctx context.Context, _ time.Time) {
w.metrics.MeasureCircuitBreakerShortCircuit(ctx, nil, otelmetric.WithAttributes(w.attributes...))
}
// No-op functions required to satisfy the interface
// We can add them if these make sense later
func (w *CircuitBreakerMetricsConfig) Success(_ context.Context, _ time.Time, _ time.Duration) {
}
func (w *CircuitBreakerMetricsConfig) ErrFailure(_ context.Context, _ time.Time, _ time.Duration) {
}
func (w *CircuitBreakerMetricsConfig) ErrTimeout(_ context.Context, _ time.Time, _ time.Duration) {
}
func (w *CircuitBreakerMetricsConfig) ErrBadRequest(_ context.Context, _ time.Time, _ time.Duration) {
}
func (w *CircuitBreakerMetricsConfig) ErrInterrupt(_ context.Context, _ time.Time, _ time.Duration) {
}
func (w *CircuitBreakerMetricsConfig) ErrConcurrencyLimitReject(_ context.Context, _ time.Time) {
}