Skip to content

Commit

Permalink
Copy spans from memory store, fixes #2719
Browse files Browse the repository at this point in the history
Copying allows spans to be freely modified by adjusters and any other code
without accidentally altering what is stored in the in-memory store itself.
  • Loading branch information
bobrik committed Jan 8, 2021
1 parent e788e55 commit c6014e9
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 1 deletion.
28 changes: 27 additions & 1 deletion plugin/storage/memory/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,37 @@ func (m *Store) GetTrace(ctx context.Context, traceID model.TraceID) (*model.Tra
// Spans may still be added to traces after they are returned to user code, so make copies.
func (m *Store) copyTrace(trace *model.Trace) *model.Trace {
return &model.Trace{
Spans: append([]*model.Span(nil), trace.Spans...),
Spans: m.copySpans(trace),
Warnings: append([]string(nil), trace.Warnings...),
}
}

func (m *Store) copySpans(trace *model.Trace) []*model.Span {
spans := make([]*model.Span, len(trace.Spans))
for i := range trace.Spans {
spans[i] = m.copySpan(trace.Spans[i])
}
return spans
}

// Copy static span attributes and discard the ones that can be altered outside of the store.
func (m *Store) copySpan(span *model.Span) *model.Span {
return &model.Span{
TraceID: span.TraceID,
SpanID: span.SpanID,
OperationName: span.OperationName,
References: span.References,
Flags: span.Flags,
StartTime: span.StartTime,
Duration: span.Duration,
Tags: span.Tags,
Logs: span.Logs,
Process: span.Process,
ProcessID: span.ProcessID,
Warnings: []string(nil),
}
}

// GetServices returns a list of all known services
func (m *Store) GetServices(ctx context.Context) ([]string, error) {
m.RLock()
Expand Down
18 changes: 18 additions & 0 deletions plugin/storage/memory/memory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,24 @@ func TestStoreGetTraceSuccess(t *testing.T) {
})
}

func TestStoreGetAndMutateTrace(t *testing.T) {
withPopulatedMemoryStore(func(store *Store) {
trace, err := store.GetTrace(context.Background(), testingSpan.TraceID)
assert.NoError(t, err)
assert.Len(t, trace.Spans, 1)
assert.Equal(t, testingSpan, trace.Spans[0])
assert.Len(t, trace.Spans[0].Warnings, 0)

trace.Spans[0].Warnings = append(trace.Spans[0].Warnings, "the end is near")

trace, err = store.GetTrace(context.Background(), testingSpan.TraceID)
assert.NoError(t, err)
assert.Len(t, trace.Spans, 1)
assert.Equal(t, testingSpan, trace.Spans[0])
assert.Len(t, trace.Spans[0].Warnings, 0)
})
}

func TestStoreGetTraceFailure(t *testing.T) {
withPopulatedMemoryStore(func(store *Store) {
trace, err := store.GetTrace(context.Background(), model.TraceID{})
Expand Down

0 comments on commit c6014e9

Please sign in to comment.