-
Notifications
You must be signed in to change notification settings - Fork 327
trace: add buffer limit #824
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -73,4 +73,11 @@ type SpanData struct { | |
| Status | ||
| Links []Link | ||
| HasRemoteParent bool | ||
|
|
||
| // The count of all span.bufferLimit overflows. | ||
| // See trace.WithBufferLimit for more info. | ||
| // TODO: This is not currently exported anywhere (e.g. tracez page). | ||
| DroppedAnnotations int | ||
|
||
| DroppedMessageEvents int | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add godoc.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| DroppedLinks int | ||
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,6 +46,7 @@ type Span struct { | |
| endOnce sync.Once | ||
|
|
||
| executionTracerTaskEnd func() // ends the execution tracer span | ||
| bufferLimit int // limits all variable span data (slices) | ||
| } | ||
|
|
||
| // IsRecordingEvents returns true if events are being recorded for this span. | ||
|
|
@@ -110,6 +111,9 @@ const ( | |
| SpanKindClient | ||
| ) | ||
|
|
||
| // DefaultBufferLimit is the default value for trace.StartOptions.BufferLimit. | ||
| const DefaultBufferLimit = 1000 | ||
|
||
|
|
||
| // StartOptions contains options concerning how a span is started. | ||
| type StartOptions struct { | ||
| // Sampler to consult for this Span. If provided, it is always consulted. | ||
|
|
@@ -125,6 +129,11 @@ type StartOptions struct { | |
| // SpanKind represents the kind of a span. If none is set, | ||
| // SpanKindUnspecified is used. | ||
| SpanKind int | ||
|
|
||
| // BufferLimit makes new spans with a custom buffer limit. | ||
| // This limits variable span data: Message Events, Links, and Annotations. | ||
| // The default is 1000 (trace.DefaultBufferLimit) and the minimum is 1. | ||
| BufferLimit int | ||
|
||
| } | ||
|
|
||
| // StartOption apply changes to StartOptions. | ||
|
|
@@ -145,13 +154,25 @@ func WithSampler(sampler Sampler) StartOption { | |
| } | ||
| } | ||
|
|
||
| // WithBufferLimit makes new spans with a custom buffer limit. | ||
| // This limits variable trace span data: Message Events, Links, and Annotations. | ||
| // The default is 1000 (trace.DefaultBufferLimit) and the minimum is 1. | ||
| func WithBufferLimit(limit int) StartOption { | ||
| return func(o *StartOptions) { | ||
| o.BufferLimit = limit | ||
| if o.BufferLimit <= 0 { | ||
| o.BufferLimit = 1 | ||
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| // StartSpan starts a new child span of the current span in the context. If | ||
| // there is no span in the context, creates a new trace and span. | ||
| // | ||
| // Returned context contains the newly created span. You can use it to | ||
| // propagate the returned span in process. | ||
| func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Context, *Span) { | ||
| var opts StartOptions | ||
| opts := StartOptions{BufferLimit: DefaultBufferLimit} | ||
|
||
| var parent SpanContext | ||
| if p := FromContext(ctx); p != nil { | ||
| parent = p.spanContext | ||
|
|
@@ -174,7 +195,7 @@ func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Cont | |
| // Returned context contains the newly created span. You can use it to | ||
| // propagate the returned span in process. | ||
| func StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanContext, o ...StartOption) (context.Context, *Span) { | ||
| var opts StartOptions | ||
| opts := StartOptions{BufferLimit: DefaultBufferLimit} | ||
|
||
| for _, op := range o { | ||
| op(&opts) | ||
| } | ||
|
|
@@ -185,7 +206,7 @@ func StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanCont | |
| } | ||
|
|
||
| func startSpanInternal(name string, hasParent bool, parent SpanContext, remoteParent bool, o StartOptions) *Span { | ||
| span := &Span{} | ||
| span := &Span{bufferLimit: o.BufferLimit} | ||
| span.spanContext = parent | ||
|
|
||
| cfg := config.Load().(*Config) | ||
|
|
@@ -340,6 +361,10 @@ func (s *Span) lazyPrintfInternal(attributes []Attribute, format string, a ...in | |
| m = make(map[string]interface{}) | ||
| copyAttributes(m, attributes) | ||
| } | ||
| if l := len(s.data.Annotations); l > 0 && l >= s.bufferLimit { | ||
|
||
| s.data.Annotations = s.data.Annotations[1:] | ||
| s.data.DroppedAnnotations++ | ||
| } | ||
| s.data.Annotations = append(s.data.Annotations, Annotation{ | ||
| Time: now, | ||
| Message: msg, | ||
|
|
@@ -356,6 +381,10 @@ func (s *Span) printStringInternal(attributes []Attribute, str string) { | |
| a = make(map[string]interface{}) | ||
| copyAttributes(a, attributes) | ||
| } | ||
| if l := len(s.data.Annotations); l > 0 && l >= s.bufferLimit { | ||
| s.data.Annotations = s.data.Annotations[1:] | ||
|
||
| s.data.DroppedAnnotations++ | ||
| } | ||
| s.data.Annotations = append(s.data.Annotations, Annotation{ | ||
| Time: now, | ||
| Message: str, | ||
|
|
@@ -393,6 +422,10 @@ func (s *Span) AddMessageSendEvent(messageID, uncompressedByteSize, compressedBy | |
| } | ||
| now := time.Now() | ||
| s.mu.Lock() | ||
| if l := len(s.data.MessageEvents); l > 0 && l >= s.bufferLimit { | ||
|
||
| s.data.MessageEvents = s.data.MessageEvents[1:] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally once we hit the max number of attributes, we would not allocate any more when you add attributes. I believe as written, we will allocate even when we have reached the maximum. How about copying the message events to the beginning of the slice: Then the subsequent append should never allocate once we reach the max. Would be really awesome to run some benchmarks before and after this change. Not sure any of the existing ones would work since they don't add lots of attributes/events. |
||
| s.data.DroppedMessageEvents++ | ||
| } | ||
| s.data.MessageEvents = append(s.data.MessageEvents, MessageEvent{ | ||
| Time: now, | ||
| EventType: MessageEventTypeSent, | ||
|
|
@@ -415,6 +448,10 @@ func (s *Span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compresse | |
| } | ||
| now := time.Now() | ||
| s.mu.Lock() | ||
| if l := len(s.data.MessageEvents); l > 0 && l >= s.bufferLimit { | ||
| s.data.MessageEvents = s.data.MessageEvents[1:] | ||
| s.data.DroppedMessageEvents++ | ||
| } | ||
| s.data.MessageEvents = append(s.data.MessageEvents, MessageEvent{ | ||
| Time: now, | ||
| EventType: MessageEventTypeRecv, | ||
|
|
@@ -431,6 +468,10 @@ func (s *Span) AddLink(l Link) { | |
| return | ||
| } | ||
| s.mu.Lock() | ||
| if l := len(s.data.Links); l > 0 && l >= s.bufferLimit { | ||
| s.data.Links = s.data.Links[1:] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto |
||
| s.data.DroppedLinks++ | ||
| } | ||
| s.data.Links = append(s.data.Links, l) | ||
| s.mu.Unlock() | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
golint your code.
// DroppedAnnotations represents all the annotations dropped
// due to the annotations limit.
DroppedAnnotations int
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I'm a Xoogler that misses the Critique golint badges.