-
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support custom metrics and trace labels provided from the context
- Loading branch information
Showing
18 changed files
with
425 additions
and
110 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package otelsql | ||
|
||
import ( | ||
"context" | ||
"sync" | ||
|
||
"go.opentelemetry.io/otel/attribute" | ||
) | ||
|
||
// Labeler is a helper to add attributes to a context. | ||
type Labeler struct { | ||
mu sync.Mutex | ||
attributes []attribute.KeyValue | ||
} | ||
|
||
// Add attributes to a Labeler. | ||
func (l *Labeler) Add(ls ...attribute.KeyValue) { | ||
l.mu.Lock() | ||
defer l.mu.Unlock() | ||
|
||
l.attributes = append(l.attributes, ls...) | ||
} | ||
|
||
// Get returns a copy of the attributes added to the Labeler. | ||
func (l *Labeler) Get() []attribute.KeyValue { | ||
l.mu.Lock() | ||
defer l.mu.Unlock() | ||
|
||
ret := make([]attribute.KeyValue, len(l.attributes)) | ||
copy(ret, l.attributes) | ||
|
||
return ret | ||
} | ||
|
||
const ( | ||
labelerCtxMetrics = labelerContextKey("metrics") | ||
labelerCtxTrace = labelerContextKey("trace") | ||
) | ||
|
||
type labelerContextKey string | ||
|
||
// MetricsLabelsFromContext retrieves the labels from the provided context. | ||
func MetricsLabelsFromContext(ctx context.Context) []attribute.KeyValue { | ||
l, _ := labelerFromContext(ctx, labelerCtxMetrics) | ||
|
||
return l.Get() | ||
} | ||
|
||
// ContextWithMetricsLabels returns a new context with the labels added to the Labeler. | ||
func ContextWithMetricsLabels(ctx context.Context, labels ...attribute.KeyValue) context.Context { | ||
return contextWithLabels(ctx, labelerCtxMetrics, labels...) | ||
} | ||
|
||
// TraceLabelsFromContext retrieves the labels from the provided context. | ||
func TraceLabelsFromContext(ctx context.Context) []attribute.KeyValue { | ||
l, _ := labelerFromContext(ctx, labelerCtxTrace) | ||
|
||
return l.Get() | ||
} | ||
|
||
// ContextWithTraceLabels returns a new context with the labels added to the Labeler. | ||
func ContextWithTraceLabels(ctx context.Context, labels ...attribute.KeyValue) context.Context { | ||
return contextWithLabels(ctx, labelerCtxTrace, labels...) | ||
} | ||
|
||
// ContextWithTraceAndMetricsLabels returns a new context with the labels added to the Labeler. | ||
func ContextWithTraceAndMetricsLabels(ctx context.Context, labels ...attribute.KeyValue) context.Context { | ||
ctx = ContextWithMetricsLabels(ctx, labels...) | ||
ctx = ContextWithTraceLabels(ctx, labels...) | ||
|
||
return ctx | ||
} | ||
|
||
func labelerFromContext(ctx context.Context, key labelerContextKey) (*Labeler, bool) { //nolint: unparam | ||
l, ok := ctx.Value(key).(*Labeler) | ||
if !ok { | ||
l = &Labeler{} | ||
} | ||
|
||
return l, ok | ||
} | ||
|
||
func contextWithLabels(ctx context.Context, key labelerContextKey, labels ...attribute.KeyValue) context.Context { | ||
l, _ := labelerFromContext(ctx, key) | ||
|
||
l.Add(labels...) | ||
|
||
return context.WithValue(ctx, key, l) | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package otelsql_test | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"go.opentelemetry.io/otel/attribute" | ||
|
||
"go.nhat.io/otelsql" | ||
) | ||
|
||
var ( | ||
label1 = attribute.String("key1", "value1") | ||
label2 = attribute.Int("key2", 2) | ||
label3 = attribute.Bool("key3", true) | ||
) | ||
|
||
func TestMetricsLabeler(t *testing.T) { | ||
t.Parallel() | ||
|
||
ctx := context.Background() | ||
|
||
labels := otelsql.MetricsLabelsFromContext(ctx) | ||
assert.Empty(t, labels) | ||
|
||
ctx = otelsql.ContextWithMetricsLabels(ctx, label1, label2) | ||
|
||
labels = otelsql.MetricsLabelsFromContext(ctx) | ||
assert.Equal(t, []attribute.KeyValue{label1, label2}, labels) | ||
|
||
ctx = otelsql.ContextWithMetricsLabels(ctx, label3) | ||
assert.Equal(t, []attribute.KeyValue{label1, label2, label3}, otelsql.MetricsLabelsFromContext(ctx)) | ||
|
||
assert.Empty(t, otelsql.TraceLabelsFromContext(ctx)) | ||
} | ||
|
||
func TestTraceLabeler(t *testing.T) { | ||
t.Parallel() | ||
|
||
ctx := context.Background() | ||
|
||
labels := otelsql.TraceLabelsFromContext(ctx) | ||
assert.Empty(t, labels) | ||
|
||
ctx = otelsql.ContextWithTraceLabels(ctx, label1, label2) | ||
|
||
labels = otelsql.TraceLabelsFromContext(ctx) | ||
assert.Equal(t, []attribute.KeyValue{label1, label2}, labels) | ||
|
||
ctx = otelsql.ContextWithTraceLabels(ctx, label3) | ||
assert.Equal(t, []attribute.KeyValue{label1, label2, label3}, otelsql.TraceLabelsFromContext(ctx)) | ||
|
||
assert.Empty(t, otelsql.MetricsLabelsFromContext(ctx)) | ||
} | ||
|
||
func TestMetricsAndTraceLabeler(t *testing.T) { | ||
t.Parallel() | ||
|
||
ctx := context.Background() | ||
|
||
labels := otelsql.MetricsLabelsFromContext(ctx) | ||
assert.Empty(t, labels) | ||
|
||
labels = otelsql.TraceLabelsFromContext(ctx) | ||
assert.Empty(t, labels) | ||
|
||
ctx = otelsql.ContextWithTraceAndMetricsLabels(ctx, label1, label2) | ||
|
||
assert.Equal(t, []attribute.KeyValue{label1, label2}, otelsql.MetricsLabelsFromContext(ctx)) | ||
assert.Equal(t, []attribute.KeyValue{label1, label2}, otelsql.TraceLabelsFromContext(ctx)) | ||
|
||
ctx = otelsql.ContextWithTraceAndMetricsLabels(ctx, label3) | ||
|
||
assert.Equal(t, []attribute.KeyValue{label1, label2, label3}, otelsql.MetricsLabelsFromContext(ctx)) | ||
assert.Equal(t, []attribute.KeyValue{label1, label2, label3}, otelsql.TraceLabelsFromContext(ctx)) | ||
} |
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
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
Oops, something went wrong.