@@ -96,6 +96,17 @@ type Exporter struct {
9696 operationDurationMetric otelconv.SDKExporterOperationDuration
9797}
9898
99+ var measureAttrsPool = sync.Pool {
100+ New : func () any {
101+ // "component.name" + "component.type" + "error.type"
102+ const n = 1 + 1 + 1
103+ s := make ([]attribute.KeyValue , 0 , n )
104+ // Return a pointer to a slice instead of a slice itself
105+ // to avoid allocations on every call.
106+ return & s
107+ },
108+ }
109+
99110// ExportSpans writes spans in json format to stdout.
100111func (e * Exporter ) ExportSpans (ctx context.Context , spans []trace.ReadOnlySpan ) (err error ) {
101112 var success int64
@@ -116,11 +127,14 @@ func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan)
116127 if err != nil {
117128 // additional attributes for self-observability,
118129 // only spanExportedMetric and operationDurationMetric are supported.
119- //
120- // TODO: use a pool to amortize allocations.
121- attr = make ([]attribute.KeyValue , len (e .selfObservabilityAttrs ), len (e .selfObservabilityAttrs )+ 1 )
122- copy (attr , e .selfObservabilityAttrs )
123- attr = append (attr , semconv .ErrorType (err ))
130+ attrs := measureAttrsPool .Get ().(* []attribute.KeyValue )
131+ defer func () {
132+ * attrs = (* attrs )[:0 ] // reset the slice for reuse
133+ measureAttrsPool .Put (attrs )
134+ }()
135+ * attrs = append (* attrs , e .selfObservabilityAttrs ... )
136+ * attrs = append (* attrs , semconv .ErrorType (err ))
137+ attr = * attrs
124138
125139 e .spanExportedMetric .Add (ctx , count - success , attr ... )
126140 }
0 commit comments