diff --git a/CHANGELOG.md b/CHANGELOG.md index f2980539eb..3c68dec71a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/ ### :rocket: (Enhancement) +* perf(sdk-trace-base): do not allocate arrays if resource has no pending async attributes + ### :bug: (Bug Fix) * fix(sdk-metrics): increase the depth of the output to the console such that objects in the metric are printed fully to the console [#4522](https://github.com/open-telemetry/opentelemetry-js/pull/4522) @JacksonWeber diff --git a/packages/opentelemetry-sdk-trace-base/src/export/BatchSpanProcessorBase.ts b/packages/opentelemetry-sdk-trace-base/src/export/BatchSpanProcessorBase.ts index f069aac0c7..19e616dc08 100644 --- a/packages/opentelemetry-sdk-trace-base/src/export/BatchSpanProcessorBase.ts +++ b/packages/opentelemetry-sdk-trace-base/src/export/BatchSpanProcessorBase.ts @@ -181,7 +181,13 @@ export abstract class BatchSpanProcessorBase // Reset the finished spans buffer here because the next invocations of the _flush method // could pass the same finished spans to the exporter if the buffer is cleared // outside the execution of this callback. - const spans = this._finishedSpans.splice(0, this._maxExportBatchSize); + let spans: ReadableSpan[]; + if (this._finishedSpans.length <= this._maxExportBatchSize) { + spans = this._finishedSpans; + this._finishedSpans = []; + } else { + spans = this._finishedSpans.splice(0, this._maxExportBatchSize); + } const doExport = () => this._exporter.export(spans, result => { @@ -195,19 +201,24 @@ export abstract class BatchSpanProcessorBase ); } }); - const pendingResources = spans - .map(span => span.resource) - .filter(resource => resource.asyncAttributesPending); + + let pendingResources: Array> | null = null; + for (let i = 0, len = spans.length; i < len; i++) { + const span = spans[i]; + if ( + span.resource.asyncAttributesPending && + span.resource.waitForAsyncAttributes + ) { + pendingResources ??= []; + pendingResources.push(span.resource.waitForAsyncAttributes()); + } + } // Avoid scheduling a promise to make the behavior more predictable and easier to test - if (pendingResources.length === 0) { + if (pendingResources === null) { doExport(); } else { - Promise.all( - pendingResources.map( - resource => resource.waitForAsyncAttributes?.() - ) - ).then(doExport, err => { + Promise.all(pendingResources).then(doExport, err => { globalErrorHandler(err); reject(err); });