Skip to content

Commit 9568b48

Browse files
committed
Add trace datastore
1 parent 51ad837 commit 9568b48

File tree

4 files changed

+259
-1
lines changed

4 files changed

+259
-1
lines changed

Diff for: go.mod

+5
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ require (
55
github.com/ipfs/go-detect-race v0.0.1
66
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8
77
github.com/jbenet/goprocess v0.1.4
8+
go.opentelemetry.io/otel v1.16.0
9+
go.opentelemetry.io/otel/trace v1.16.0
810
go.uber.org/multierr v1.5.0
911
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
1012
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
1113
)
1214

1315
require (
16+
github.com/go-logr/logr v1.2.4 // indirect
17+
github.com/go-logr/stdr v1.2.2 // indirect
1418
github.com/kr/pretty v0.2.0 // indirect
1519
github.com/kr/text v0.1.0 // indirect
20+
go.opentelemetry.io/otel/metric v1.16.0 // indirect
1621
go.uber.org/atomic v1.6.0 // indirect
1722
)
1823

Diff for: go.sum

+14-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
33
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
44
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
55
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
7+
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
8+
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
9+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
10+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
11+
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
612
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
713
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
814
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -24,8 +30,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
2430
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
2531
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
2632
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
27-
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
2833
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
34+
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
35+
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
36+
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
37+
go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
38+
go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
39+
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
40+
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
2941
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
3042
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
3143
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
@@ -55,5 +67,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
5567
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
5668
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
5769
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
70+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
5871
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
5972
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

Diff for: trace/trace.go

+226
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
// Package trace wraps a datastore where all datastore interactions are traced
2+
// with open telemetry.
3+
package trace
4+
5+
import (
6+
"context"
7+
"fmt"
8+
"io"
9+
10+
ds "github.com/ipfs/go-datastore"
11+
dsq "github.com/ipfs/go-datastore/query"
12+
"go.opentelemetry.io/otel/attribute"
13+
otel "go.opentelemetry.io/otel/trace"
14+
)
15+
16+
// New returns a new traced datastore. All datastore interactions are traced.
17+
func New(ds ds.Datastore, tracer otel.Tracer) *Datastore {
18+
return &Datastore{ds: ds, tracer: tracer}
19+
}
20+
21+
// Datastore is an adapter that traces inner datastore interactions.
22+
type Datastore struct {
23+
ds ds.Datastore
24+
tracer otel.Tracer
25+
}
26+
27+
var _ ds.Datastore = (*Datastore)(nil)
28+
var _ ds.Batching = (*Datastore)(nil)
29+
var _ ds.PersistentDatastore = (*Datastore)(nil)
30+
var _ ds.TxnDatastore = (*Datastore)(nil)
31+
var _ ds.CheckedDatastore = (*Datastore)(nil)
32+
var _ ds.ScrubbedDatastore = (*Datastore)(nil)
33+
var _ ds.GCDatastore = (*Datastore)(nil)
34+
var _ io.Closer = (*Datastore)(nil)
35+
36+
// Put implements the ds.Datastore interface.
37+
func (t *Datastore) Put(ctx context.Context, key ds.Key, value []byte) (err error) {
38+
ctx, span := t.tracer.Start(ctx, "Put", otel.WithAttributes(attribute.String("key", key.String())))
39+
defer span.End()
40+
return t.ds.Put(ctx, key, value)
41+
}
42+
43+
// Sync implements Datastore.Sync
44+
func (t *Datastore) Sync(ctx context.Context, key ds.Key) error {
45+
ctx, span := t.tracer.Start(ctx, "Sync", otel.WithAttributes(attribute.String("key", key.String())))
46+
defer span.End()
47+
return t.ds.Sync(ctx, key)
48+
}
49+
50+
// Get implements the ds.Datastore interface.
51+
func (t *Datastore) Get(ctx context.Context, key ds.Key) (value []byte, err error) {
52+
ctx, span := t.tracer.Start(ctx, "Get", otel.WithAttributes(attribute.String("key", key.String())))
53+
defer span.End()
54+
return t.ds.Get(ctx, key)
55+
}
56+
57+
// Has implements the ds.Datastore interface.
58+
func (t *Datastore) Has(ctx context.Context, key ds.Key) (exists bool, err error) {
59+
ctx, span := t.tracer.Start(ctx, "Has", otel.WithAttributes(attribute.String("key", key.String())))
60+
defer span.End()
61+
return t.ds.Has(ctx, key)
62+
}
63+
64+
// GetSize implements the ds.Datastore interface.
65+
func (t *Datastore) GetSize(ctx context.Context, key ds.Key) (size int, err error) {
66+
ctx, span := t.tracer.Start(ctx, "GetSize", otel.WithAttributes(attribute.String("key", key.String())))
67+
defer span.End()
68+
return t.ds.GetSize(ctx, key)
69+
}
70+
71+
// Delete implements the ds.Datastore interface.
72+
func (t *Datastore) Delete(ctx context.Context, key ds.Key) (err error) {
73+
ctx, span := t.tracer.Start(ctx, "Delete", otel.WithAttributes(attribute.String("key", key.String())))
74+
defer span.End()
75+
return t.ds.Delete(ctx, key)
76+
}
77+
78+
// Query implements the ds.Datastore interface.
79+
func (t *Datastore) Query(ctx context.Context, q dsq.Query) (dsq.Results, error) {
80+
ctx, span := t.tracer.Start(ctx, "Query", otel.WithAttributes(attribute.String("query", q.String())))
81+
defer span.End()
82+
return t.ds.Query(ctx, q)
83+
}
84+
85+
// Batch implements the ds.Batching interface.
86+
func (t *Datastore) Batch(ctx context.Context) (ds.Batch, error) {
87+
ctx, span := t.tracer.Start(ctx, "Batch")
88+
defer span.End()
89+
90+
if batch, ok := t.ds.(ds.Batching); ok {
91+
return batch.Batch(ctx)
92+
}
93+
94+
return ds.NewBasicBatch(t), nil
95+
}
96+
97+
// DiskUsage implements the ds.PersistentDatastore interface.
98+
func (t *Datastore) DiskUsage(ctx context.Context) (uint64, error) {
99+
ctx, span := t.tracer.Start(ctx, "DiskUsage")
100+
defer span.End()
101+
return ds.DiskUsage(ctx, t.ds)
102+
}
103+
104+
// Scrub implements the ds.ScrubbedDatastore interface.
105+
func (t *Datastore) Scrub(ctx context.Context) error {
106+
ctx, span := t.tracer.Start(ctx, "Scrub")
107+
defer span.End()
108+
109+
if dstore, ok := t.tracer.(ds.ScrubbedDatastore); ok {
110+
return dstore.Scrub(ctx)
111+
}
112+
113+
return nil
114+
}
115+
116+
// CollectGarbage implements the ds.GCDatastore interface.
117+
func (t *Datastore) CollectGarbage(ctx context.Context) error {
118+
ctx, span := t.tracer.Start(ctx, "CollectGarbage")
119+
defer span.End()
120+
121+
if dstore, ok := t.tracer.(ds.GCDatastore); ok {
122+
return dstore.CollectGarbage(ctx)
123+
}
124+
125+
return nil
126+
}
127+
128+
// Check implements the ds.CheckedDatastore interface.
129+
func (t *Datastore) Check(ctx context.Context) error {
130+
ctx, span := t.tracer.Start(ctx, "Check")
131+
defer span.End()
132+
133+
if dstore, ok := t.tracer.(ds.CheckedDatastore); ok {
134+
return dstore.Check(ctx)
135+
}
136+
137+
return nil
138+
}
139+
140+
// NewTransaction implements the ds.TxnDatastore interface.
141+
func (t *Datastore) NewTransaction(ctx context.Context, readOnly bool) (ds.Txn, error) {
142+
ctx, span := t.tracer.Start(ctx, "NewTransaction", otel.WithAttributes(attribute.Bool("readOnly", readOnly)))
143+
defer span.End()
144+
145+
if txnDs, ok := t.tracer.(ds.TxnDatastore); ok {
146+
txn, err := txnDs.NewTransaction(ctx, readOnly)
147+
if err != nil {
148+
return nil, err
149+
}
150+
return &Txn{txn: txn, tracer: t.tracer}, nil
151+
}
152+
153+
return nil, fmt.Errorf("transactions are unsupported by traced datastore")
154+
}
155+
156+
// Close closes the inner datastore (if it implements the io.Closer interface).
157+
func (t *Datastore) Close() error {
158+
if closer, ok := t.ds.(io.Closer); ok {
159+
return closer.Close()
160+
}
161+
return nil
162+
}
163+
164+
// Txn is an adapter that traces datastore transactions
165+
type Txn struct {
166+
txn ds.Txn
167+
tracer otel.Tracer
168+
}
169+
170+
var _ ds.Txn = (*Txn)(nil)
171+
172+
// Put implements the ds.Txn interface.
173+
func (t *Txn) Put(ctx context.Context, key ds.Key, value []byte) (err error) {
174+
ctx, span := t.tracer.Start(ctx, "Put", otel.WithAttributes(attribute.String("key", key.String())))
175+
defer span.End()
176+
return t.txn.Put(ctx, key, value)
177+
}
178+
179+
// Get implements the ds.Txn interface.
180+
func (t *Txn) Get(ctx context.Context, key ds.Key) (value []byte, err error) {
181+
ctx, span := t.tracer.Start(ctx, "Get", otel.WithAttributes(attribute.String("key", key.String())))
182+
defer span.End()
183+
return t.txn.Get(ctx, key)
184+
}
185+
186+
// Has implements the ds.Txn interface.
187+
func (t *Txn) Has(ctx context.Context, key ds.Key) (exists bool, err error) {
188+
ctx, span := t.tracer.Start(ctx, "Has", otel.WithAttributes(attribute.String("key", key.String())))
189+
defer span.End()
190+
return t.txn.Has(ctx, key)
191+
}
192+
193+
// GetSize implements the ds.Txn interface.
194+
func (t *Txn) GetSize(ctx context.Context, key ds.Key) (size int, err error) {
195+
ctx, span := t.tracer.Start(ctx, "GetSize", otel.WithAttributes(attribute.String("key", key.String())))
196+
defer span.End()
197+
return t.txn.GetSize(ctx, key)
198+
}
199+
200+
// Delete implements the ds.Txn interface.
201+
func (t *Txn) Delete(ctx context.Context, key ds.Key) (err error) {
202+
ctx, span := t.tracer.Start(ctx, "Delete", otel.WithAttributes(attribute.String("key", key.String())))
203+
defer span.End()
204+
return t.txn.Delete(ctx, key)
205+
}
206+
207+
// Query implements the ds.Txn interface.
208+
func (t *Txn) Query(ctx context.Context, q dsq.Query) (dsq.Results, error) {
209+
ctx, span := t.tracer.Start(ctx, "Query", otel.WithAttributes(attribute.String("query", q.String())))
210+
defer span.End()
211+
return t.txn.Query(ctx, q)
212+
}
213+
214+
// Commit implements the ds.Txn interface.
215+
func (t *Txn) Commit(ctx context.Context) error {
216+
ctx, span := t.tracer.Start(ctx, "Commit")
217+
defer span.End()
218+
return t.txn.Commit(ctx)
219+
}
220+
221+
// Discard implements the ds.Txn interface.
222+
func (t *Txn) Discard(ctx context.Context) {
223+
ctx, span := t.tracer.Start(ctx, "Discard")
224+
defer span.End()
225+
t.txn.Discard(ctx)
226+
}

Diff for: trace/trace_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package trace
2+
3+
import (
4+
"testing"
5+
6+
"github.com/ipfs/go-datastore"
7+
dstest "github.com/ipfs/go-datastore/test"
8+
"go.opentelemetry.io/otel"
9+
)
10+
11+
func TestTraceAll(t *testing.T) {
12+
tracer := otel.Tracer("tracer")
13+
dstest.SubtestAll(t, New(datastore.NewMapDatastore(), tracer))
14+
}

0 commit comments

Comments
 (0)