2024-03-28 13:09:42 +00:00
|
|
|
package kvtrace
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"github.com/royalcat/kv"
|
|
|
|
"go.opentelemetry.io/otel"
|
|
|
|
"go.opentelemetry.io/otel/attribute"
|
2024-06-16 21:34:46 +00:00
|
|
|
"go.opentelemetry.io/otel/codes"
|
2024-03-28 13:09:42 +00:00
|
|
|
"go.opentelemetry.io/otel/trace"
|
|
|
|
)
|
|
|
|
|
|
|
|
var tracer = otel.Tracer("github.com/royalcat/kv/tracer")
|
|
|
|
|
2024-06-16 21:34:46 +00:00
|
|
|
type traceStore[K, V any] struct {
|
2024-03-28 13:09:42 +00:00
|
|
|
kv kv.Store[K, V]
|
|
|
|
attrs []attribute.KeyValue
|
|
|
|
}
|
|
|
|
|
|
|
|
func WrapTracing[K, V any](kv kv.Store[K, V], attrs ...attribute.KeyValue) kv.Store[K, V] {
|
2024-06-16 21:34:46 +00:00
|
|
|
return &traceStore[K, V]{
|
2024-03-28 13:09:42 +00:00
|
|
|
kv: kv,
|
|
|
|
attrs: attrs,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close implements kv.Store.
|
2024-06-16 21:34:46 +00:00
|
|
|
func (m *traceStore[K, V]) Close(ctx context.Context) (err error) {
|
2024-03-28 13:09:42 +00:00
|
|
|
ctx, span := tracer.Start(ctx, "Close", trace.WithAttributes(m.attrs...))
|
|
|
|
defer span.End()
|
2024-06-16 21:34:46 +00:00
|
|
|
defer func() {
|
|
|
|
if err != nil && err != kv.ErrKeyNotFound {
|
|
|
|
span.SetStatus(codes.Error, err.Error())
|
|
|
|
} else {
|
|
|
|
span.SetStatus(codes.Ok, "")
|
|
|
|
}
|
|
|
|
}()
|
2024-03-28 13:09:42 +00:00
|
|
|
|
|
|
|
return m.kv.Close(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete implements kv.Store.
|
2024-06-16 21:34:46 +00:00
|
|
|
func (m *traceStore[K, V]) Delete(ctx context.Context, k K) (err error) {
|
2024-03-28 13:09:42 +00:00
|
|
|
ctx, span := tracer.Start(ctx, "Delete", trace.WithAttributes(m.attrs...))
|
|
|
|
defer span.End()
|
2024-06-16 21:34:46 +00:00
|
|
|
defer func() {
|
|
|
|
if err != nil && err != kv.ErrKeyNotFound {
|
|
|
|
span.SetStatus(codes.Error, err.Error())
|
|
|
|
} else {
|
|
|
|
span.SetStatus(codes.Ok, "")
|
|
|
|
}
|
|
|
|
}()
|
2024-03-28 13:09:42 +00:00
|
|
|
|
|
|
|
return m.kv.Delete(ctx, k)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get implements kv.Store.
|
2024-06-16 21:34:46 +00:00
|
|
|
func (m *traceStore[K, V]) Get(ctx context.Context, k K) (v V, err error) {
|
2024-03-28 13:09:42 +00:00
|
|
|
ctx, span := tracer.Start(ctx, "Get", trace.WithAttributes(m.attrs...))
|
|
|
|
defer span.End()
|
2024-06-16 21:34:46 +00:00
|
|
|
defer func() {
|
|
|
|
if err != nil && err != kv.ErrKeyNotFound {
|
|
|
|
span.SetStatus(codes.Error, err.Error())
|
|
|
|
} else {
|
|
|
|
span.SetStatus(codes.Ok, "")
|
|
|
|
}
|
|
|
|
}()
|
2024-03-28 13:09:42 +00:00
|
|
|
|
|
|
|
return m.kv.Get(ctx, k)
|
|
|
|
}
|
|
|
|
|
2024-06-16 21:34:46 +00:00
|
|
|
// Get implements kv.Store.
|
|
|
|
func (m *traceStore[K, V]) Edit(ctx context.Context, k K, edit kv.Edit[V]) (err error) {
|
|
|
|
ctx, span := tracer.Start(ctx, "Get", trace.WithAttributes(m.attrs...))
|
|
|
|
defer span.End()
|
|
|
|
defer func() {
|
|
|
|
if err != nil && err != kv.ErrKeyNotFound {
|
|
|
|
span.SetStatus(codes.Error, err.Error())
|
|
|
|
} else {
|
|
|
|
span.SetStatus(codes.Ok, "")
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
return m.kv.Edit(ctx, k, edit)
|
|
|
|
}
|
|
|
|
|
2024-03-28 13:09:42 +00:00
|
|
|
// Range implements kv.Store.
|
2024-06-16 21:34:46 +00:00
|
|
|
func (m *traceStore[K, V]) Range(ctx context.Context, iter kv.Iter[K, V]) (err error) {
|
2024-03-28 13:09:42 +00:00
|
|
|
ctx, span := tracer.Start(ctx, "Range", trace.WithAttributes(m.attrs...))
|
|
|
|
defer span.End()
|
2024-06-16 21:34:46 +00:00
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
span.SetStatus(codes.Error, err.Error())
|
|
|
|
} else {
|
|
|
|
span.SetStatus(codes.Ok, "")
|
|
|
|
}
|
|
|
|
}()
|
2024-03-28 13:09:42 +00:00
|
|
|
|
|
|
|
count := 0
|
2024-06-14 22:14:44 +00:00
|
|
|
iterCount := func(k K, v V) error {
|
2024-03-28 13:09:42 +00:00
|
|
|
count++
|
|
|
|
return iter(k, v)
|
|
|
|
}
|
2024-06-16 21:34:46 +00:00
|
|
|
defer func() {
|
|
|
|
span.SetAttributes(attribute.Int("count", count))
|
|
|
|
}()
|
2024-03-28 13:09:42 +00:00
|
|
|
|
2024-06-16 21:34:46 +00:00
|
|
|
return m.kv.Range(ctx, iterCount)
|
2024-03-28 13:09:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// RangeWithPrefix implements kv.Store.
|
2024-06-16 21:34:46 +00:00
|
|
|
func (m *traceStore[K, V]) RangeWithPrefix(ctx context.Context, k K, iter kv.Iter[K, V]) (err error) {
|
2024-03-28 13:09:42 +00:00
|
|
|
ctx, span := tracer.Start(ctx, "RangeWithPrefix", trace.WithAttributes(m.attrs...))
|
|
|
|
defer span.End()
|
2024-06-16 21:34:46 +00:00
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
span.SetStatus(codes.Error, err.Error())
|
|
|
|
} else {
|
|
|
|
span.SetStatus(codes.Ok, "")
|
|
|
|
}
|
|
|
|
}()
|
2024-03-28 13:09:42 +00:00
|
|
|
|
|
|
|
count := 0
|
2024-06-14 22:14:44 +00:00
|
|
|
iterCount := func(k K, v V) error {
|
2024-03-28 13:09:42 +00:00
|
|
|
count++
|
|
|
|
return iter(k, v)
|
|
|
|
}
|
2024-06-16 21:34:46 +00:00
|
|
|
defer func() {
|
|
|
|
span.SetAttributes(attribute.Int("count", count))
|
|
|
|
}()
|
2024-03-28 13:09:42 +00:00
|
|
|
|
2024-06-16 21:34:46 +00:00
|
|
|
return m.kv.Range(ctx, iterCount)
|
2024-03-28 13:09:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set implements kv.Store.
|
2024-06-16 21:34:46 +00:00
|
|
|
func (m *traceStore[K, V]) Set(ctx context.Context, k K, v V) (err error) {
|
2024-03-28 13:09:42 +00:00
|
|
|
ctx, span := tracer.Start(ctx, "Set", trace.WithAttributes(m.attrs...))
|
|
|
|
defer span.End()
|
2024-06-16 21:34:46 +00:00
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
span.SetStatus(codes.Error, err.Error())
|
|
|
|
} else {
|
|
|
|
span.SetStatus(codes.Ok, "")
|
|
|
|
}
|
|
|
|
}()
|
2024-03-28 13:09:42 +00:00
|
|
|
|
|
|
|
return m.kv.Set(ctx, k, v)
|
|
|
|
}
|
|
|
|
|
2024-06-16 21:34:46 +00:00
|
|
|
var _ kv.Store[any, any] = (*traceStore[any, any])(nil)
|