Skip to content

Commit d820d9b

Browse files
authored
Span filtering (#93)
* feat: span filtering * feat(go): span filtering * feat(rust): span filtering * chore: tests * chore: tests * chore: update rust examples * chore: rust examples * fix: set default min duration to 50us * fix: iota go * chore: PR feedback, fix deno test * fix: node test * fix: node test * fix: always include root span, reduce default min duration to 20us * chore: better var naming * chore: use time.Microsecond * 20
1 parent 51ec1d9 commit d820d9b

File tree

38 files changed

+271
-105
lines changed

38 files changed

+271
-105
lines changed

.github/workflows/ci.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
- name: Run Deno test
2727
run: |
2828
cd js/packages/observe-sdk-stdout
29-
npm run build:esm
29+
npm run build
3030
npm run test:deno > out.txt
3131
3232
# test the expected content of the formatted output
@@ -36,7 +36,7 @@ jobs:
3636
- name: Run Node test
3737
run: |
3838
cd js/packages/observe-sdk-stdout
39-
npm run build:cjs
39+
npm run build
4040
npm link
4141
pushd test/node
4242
npm link @dylibso/observe-sdk-stdout

demo-iota/go/main.go

+22-15
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ package main
22

33
import (
44
"bytes"
5+
"context"
56
"fmt"
67
"io"
7-
"io/ioutil"
88
"log"
99
"net/http"
1010
"os"
@@ -24,8 +24,6 @@ type server struct {
2424
}
2525

2626
func main() {
27-
//
28-
// Adapter API
2927
config := datadog.DefaultDatadogConfig()
3028
config.ServiceName = "iota"
3129
config.AgentHost = "http://ddagent:8126"
@@ -97,6 +95,7 @@ func upload(res http.ResponseWriter, req *http.Request) {
9795
}
9896

9997
func (s *server) runModule(res http.ResponseWriter, req *http.Request) {
98+
ctx := context.Background()
10099
if req.Method != http.MethodPost {
101100
res.WriteHeader(http.StatusMethodNotAllowed)
102101
return
@@ -111,40 +110,48 @@ func (s *server) runModule(res http.ResponseWriter, req *http.Request) {
111110
}
112111

113112
path := filepath.Join(os.TempDir(), name)
114-
wasm, err := ioutil.ReadFile(path)
113+
wasm, err := os.ReadFile(path)
115114
if err != nil {
116115
log.Println("name error: no module found", err)
117116
res.WriteHeader(http.StatusNotFound)
118117
res.Write([]byte("Not Found"))
119118
return
120119
}
121120

122-
//
123-
// Collector API
124-
collector := observe.NewCollector(nil)
125-
ctx, r, err := collector.InitRuntime()
121+
s.adapter.Start(ctx)
122+
defer s.adapter.Stop(true)
123+
124+
cfg := wazero.NewRuntimeConfig().WithCustomSections(true)
125+
rt := wazero.NewRuntimeWithConfig(ctx, cfg)
126+
traceCtx, err := s.adapter.NewTraceCtx(ctx, rt, wasm, nil)
126127
if err != nil {
127128
log.Panicln(err)
128129
}
129-
defer r.Close(ctx) // This closes everything this Runtime created.
130-
131-
wasi_snapshot_preview1.MustInstantiate(ctx, r)
130+
wasi_snapshot_preview1.MustInstantiate(ctx, rt)
132131
output := &bytes.Buffer{}
133132
config := wazero.NewModuleConfig().WithStdin(req.Body).WithStdout(output)
134133
defer req.Body.Close()
135134

136-
s.adapter.Start(collector, wasm)
137-
mod, err := r.InstantiateWithConfig(ctx, wasm, config)
135+
mod, err := rt.InstantiateWithConfig(ctx, wasm, config)
138136
if err != nil {
139137
log.Println("module instance error:", err)
140138
res.WriteHeader(http.StatusInternalServerError)
141139
res.Write([]byte("Internal Service Error"))
142140
return
143141
}
144-
s.adapter.Stop(collector)
145-
log.Println("stopped collector, sent to datadog")
146142
defer mod.Close(ctx)
147143

144+
meta := datadog.DatadogMetadata{
145+
ResourceName: "iota-go",
146+
HttpUrl: req.URL.String(),
147+
HttpStatusCode: 200,
148+
SpanKind: datadog.Server,
149+
HttpClientIp: req.RemoteAddr,
150+
}
151+
traceCtx.Metadata(meta)
152+
traceCtx.Finish()
153+
log.Println("stopped collector, sent to datadog")
154+
148155
res.WriteHeader(http.StatusOK)
149156
res.Header().Add("content-type", "application/json")
150157
res.Write(output.Bytes())

go/adapter.go

+26-5
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ type AdapterBase struct {
3434
flusher Flusher
3535
}
3636

37-
func (a *AdapterBase) NewTraceCtx(ctx context.Context, r wazero.Runtime, wasm []byte, config *Config) (*TraceCtx, error) {
38-
if config == nil {
39-
config = NewDefaultConfig()
37+
func (a *AdapterBase) NewTraceCtx(ctx context.Context, r wazero.Runtime, wasm []byte, opts *Options) (*TraceCtx, error) {
38+
if opts == nil {
39+
opts = NewDefaultOptions()
4040
}
41-
return newTraceCtx(ctx, a.TraceEvents, r, wasm, config)
41+
return newTraceCtx(ctx, a.TraceEvents, r, wasm, opts)
4242
}
4343

4444
func NewAdapterBase(batchSize int, flushPeriod time.Duration) AdapterBase {
@@ -57,7 +57,7 @@ func (b *AdapterBase) HandleTraceEvent(te TraceEvent) {
5757
b.eventBucket.addEvent(te, b.flusher)
5858
}
5959

60-
func (b *AdapterBase) Start(a Adapter, ctx context.Context) {
60+
func (b *AdapterBase) Start(ctx context.Context, a Adapter) {
6161
b.stop = make(chan bool)
6262

6363
go func() {
@@ -83,3 +83,24 @@ func (b *AdapterBase) Stop(wait bool) {
8383
b.eventBucket.Wait()
8484
}
8585
}
86+
87+
// Definition of how to filter our Spans to reduce noise
88+
type SpanFilter struct {
89+
MinDuration time.Duration
90+
}
91+
92+
// Specify options to change what or how the adapter receives ObserveEvents
93+
type Options struct {
94+
SpanFilter *SpanFilter
95+
ChannelBufferSize int
96+
}
97+
98+
// Create a default configuration
99+
func NewDefaultOptions() *Options {
100+
return &Options{
101+
ChannelBufferSize: 1024,
102+
SpanFilter: &SpanFilter{
103+
MinDuration: time.Microsecond * 20,
104+
},
105+
}
106+
}

go/adapter/datadog/adapter.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func NewDatadogAdapter(config *DatadogConfig) (*DatadogAdapter, error) {
5656
}
5757

5858
func (d *DatadogAdapter) Start(ctx context.Context) {
59-
d.AdapterBase.Start(d, ctx)
59+
d.AdapterBase.Start(ctx, d)
6060
}
6161

6262
func (d *DatadogAdapter) Stop(wait bool) {

go/adapter/honeycomb/adapter.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func NewHoneycombAdapter(config *HoneycombConfig) *HoneycombAdapter {
4141
}
4242

4343
func (h *HoneycombAdapter) Start(ctx context.Context) {
44-
h.AdapterBase.Start(h, ctx)
44+
h.AdapterBase.Start(ctx, h)
4545
}
4646

4747
func (h *HoneycombAdapter) HandleTraceEvent(te observe.TraceEvent) {

go/adapter/lightstep/adapter.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func NewLightstepAdapter(config *LightstepConfig) *LightstepAdapter {
4141
}
4242

4343
func (h *LightstepAdapter) Start(ctx context.Context) {
44-
h.AdapterBase.Start(h, ctx)
44+
h.AdapterBase.Start(ctx, h)
4545
}
4646

4747
func (h *LightstepAdapter) HandleTraceEvent(te observe.TraceEvent) {

go/adapter/otel_stdout/adapter.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,5 @@ func (o *OtelStdoutAdapter) makeCallSpans(event observe.CallEvent, parentId []by
8686
}
8787

8888
func (o *OtelStdoutAdapter) Start(ctx context.Context) {
89-
o.AdapterBase.Start(o, ctx)
89+
o.AdapterBase.Start(ctx, o)
9090
}

go/adapter/stdout/adapter.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,5 @@ func (s *StdoutAdapter) printEvents(event observe.CallEvent, indentation int) {
5959
}
6060

6161
func (s *StdoutAdapter) Start(ctx context.Context) {
62-
s.AdapterBase.Start(s, ctx)
62+
s.AdapterBase.Start(ctx, s)
6363
}

go/trace_ctx.go

+20-19
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,6 @@ import (
1010
"github.com/tetratelabs/wazero/experimental"
1111
)
1212

13-
// The configuration object for the observe SDK
14-
type Config struct {
15-
ChannelBufferSize int
16-
}
17-
18-
// Create a default configuration
19-
func NewDefaultConfig() *Config {
20-
return &Config{
21-
ChannelBufferSize: 1024,
22-
}
23-
}
24-
2513
// TraceCtx holds the context for a trace, or wasm module invocation.
2614
// It collects holds a channel to the Adapter and from the wazero Listener
2715
// It will collect events throughout the invocation of the function. Calling
@@ -31,25 +19,25 @@ type TraceCtx struct {
3119
raw chan RawEvent
3220
events []Event
3321
stack []CallEvent
34-
Config *Config
22+
Options *Options
3523
names map[uint32]string
3624
telemetryId TelemetryId
3725
adapterMeta interface{}
3826
}
3927

4028
// Creates a new TraceCtx. Used internally by the Adapter. The user should create the trace context from the Adapter.
41-
func newTraceCtx(ctx context.Context, eventsChan chan TraceEvent, r wazero.Runtime, data []byte, config *Config) (*TraceCtx, error) {
29+
func newTraceCtx(ctx context.Context, eventsChan chan TraceEvent, r wazero.Runtime, data []byte, opts *Options) (*TraceCtx, error) {
4230
names, err := parseNames(data)
4331
if err != nil {
4432
return nil, err
4533
}
4634

4735
traceCtx := &TraceCtx{
4836
adapter: eventsChan,
49-
raw: make(chan RawEvent, config.ChannelBufferSize),
37+
raw: make(chan RawEvent, opts.ChannelBufferSize),
5038
names: names,
5139
telemetryId: NewTraceId(),
52-
Config: config,
40+
Options: opts,
5341
}
5442

5543
err = traceCtx.init(ctx, r)
@@ -120,14 +108,27 @@ func (t *TraceCtx) init(ctx context.Context, r wazero.Runtime) error {
120108
fn.Stop(end)
121109
fn.Raw = append(fn.Raw, ev)
122110

123-
f, ok := t.popFunction()
111+
// if there is no function left to pop, we are exiting the root function of the trace
112+
f, ok := t.peekFunction()
124113
if !ok {
125114
t.events = append(t.events, fn)
126115
return
127116
}
128117

129-
f.within = append(f.within, fn)
130-
t.pushFunction(f)
118+
// if the function duration is less than minimum duration, disregard
119+
funcDuration := fn.Duration.Microseconds()
120+
minSpanDuration := t.Options.SpanFilter.MinDuration.Microseconds()
121+
if funcDuration < minSpanDuration {
122+
return
123+
}
124+
125+
// the function is within another function
126+
f, ok = t.popFunction()
127+
if ok {
128+
f.within = append(f.within, fn)
129+
t.pushFunction(f)
130+
}
131+
131132
}).Export("instrument_exit")
132133

133134
functions.WithFunc(func(ctx context.Context, amt int32) {

js/packages/observe-sdk-datadog/test/deno/index.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ import Context from "https://deno.land/[email protected]/wasi/snapshot_preview1.ts";
44
const adapter = new DatadogAdapter();
55

66
const bytes = await Deno.readFile("../../test-data/test.c.instr.wasm");
7-
const traceContext = await adapter.start(bytes);
7+
8+
const opts = {
9+
spanFilter: {
10+
minDurationMicroseconds: 100,
11+
}
12+
};
13+
const traceContext = await adapter.start(bytes, opts);
814
const module = new WebAssembly.Module(bytes);
915

1016
const runtime = new Context({

js/packages/observe-sdk-datadog/test/node/index.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,15 @@ const wasi = new WASI({
1010
});
1111

1212
const adapter = new DatadogAdapter();
13+
const opts = {
14+
spanFilter: {
15+
minDurationMicroseconds: 100,
16+
}
17+
};
1318

1419
const bytes = fs.readFileSync("../../test-data/test.c.instr.wasm");
15-
adapter.start(bytes).then((traceContext) => {
20+
21+
adapter.start(bytes, opts).then((traceContext) => {
1622
const module = new WebAssembly.Module(bytes);
1723

1824
WebAssembly.instantiate(module, {

js/packages/observe-sdk-datadog/test/web/index.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ import { File, OpenFile, WASI } from "@bjorn3/browser_wasi_shim";
33

44
const f = async () => {
55
const adapter = new DatadogAdapter();
6+
const opts = {
7+
spanFilter: {
8+
minDurationMicroseconds: 100,
9+
}
10+
};
611
const resp = await fetch("count_vowels.instr.wasm");
712

813
const bytes = await resp.arrayBuffer();
9-
const traceContext = await adapter.start(bytes);
14+
const traceContext = await adapter.start(bytes, opts);
1015

1116
let fds = [
1217
new OpenFile(

js/packages/observe-sdk-honeycomb/test/deno/index.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@ const config: HoneycombConfig = {
1313
host: 'https://api.honeycomb.io',
1414
}
1515
const adapter = new HoneycombAdapter(config);
16+
const opts = {
17+
spanFilter: {
18+
minDurationMicroseconds: 100,
19+
}
20+
};
1621

1722
const bytes = await Deno.readFile("../../test-data/test.c.instr.wasm");
18-
const traceContext = await adapter.start(bytes);
23+
const traceContext = await adapter.start(bytes, opts);
1924
const module = new WebAssembly.Module(bytes);
2025

2126
const runtime = new Context({

js/packages/observe-sdk-honeycomb/test/node/index.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,14 @@ const config = {
1818
host: 'https://api.honeycomb.io',
1919
}
2020
const adapter = new HoneycombAdapter(config);
21+
const opts = {
22+
spanFilter: {
23+
minDurationMicroseconds: 100,
24+
}
25+
};
2126

2227
const bytes = fs.readFileSync("../../test-data/test.c.instr.wasm");
23-
adapter.start(bytes).then((traceContext) => {
28+
adapter.start(bytes, opts).then((traceContext) => {
2429
const module = new WebAssembly.Module(bytes);
2530

2631
WebAssembly.instantiate(module, {

js/packages/observe-sdk-honeycomb/test/web/index.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@ const f = async () => {
1010
host: 'https://api.honeycomb.io',
1111
}
1212
const adapter = new HoneycombAdapter(config);
13+
const opts = {
14+
spanFilter: {
15+
minDurationMicroseconds: 100,
16+
}
17+
};
1318
const resp = await fetch("test.c.instr.wasm");
1419

1520
const bytes = await resp.arrayBuffer();
16-
const traceContext = await adapter.start(bytes);
21+
const traceContext = await adapter.start(bytes, opts);
1722

1823
let fds = [
1924
new OpenFile(

js/packages/observe-sdk-lightstep/test/deno/index.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ const config: LightstepConfig = {
1313
host: 'https://ingest.lightstep.com',
1414
}
1515
const adapter = new LightstepAdapter(config);
16-
16+
const opts = {
17+
spanFilter: {
18+
minDurationMicroseconds: 100,
19+
}
20+
};
1721
const bytes = await Deno.readFile("../../test-data/test.c.instr.wasm");
18-
const traceContext = await adapter.start(bytes);
22+
const traceContext = await adapter.start(bytes, opts);
1923
const module = new WebAssembly.Module(bytes);
2024

2125
const runtime = new Context({

0 commit comments

Comments
 (0)