From 519e021a655cfd73f7a17a87820f5228b680a7d1 Mon Sep 17 00:00:00 2001 From: Samuron Date: Wed, 20 Mar 2024 08:24:23 +0200 Subject: [PATCH] perf(tracer): reduce overhead of attribute sanitization --- .../src/common/attributes.ts | 12 ++++++----- .../src/Tracer.ts | 5 ++--- .../test/performance/benchmark/span.js | 21 +++++++++++++++++-- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/opentelemetry-core/src/common/attributes.ts b/packages/opentelemetry-core/src/common/attributes.ts index 0726acd5813..c3dc1594c12 100644 --- a/packages/opentelemetry-core/src/common/attributes.ts +++ b/packages/opentelemetry-core/src/common/attributes.ts @@ -16,24 +16,26 @@ import { diag, SpanAttributeValue, SpanAttributes } from '@opentelemetry/api'; -export function sanitizeAttributes(attributes: unknown): SpanAttributes { - const out: SpanAttributes = {}; - +export function sanitizeAttributes( + attributes: unknown, + out: SpanAttributes = {} +): SpanAttributes { if (typeof attributes !== 'object' || attributes == null) { return out; } - for (const [key, val] of Object.entries(attributes)) { + for (const key in attributes) { if (!isAttributeKey(key)) { diag.warn(`Invalid attribute key: ${key}`); continue; } + const val = attributes[key as keyof typeof attributes] as unknown; if (!isAttributeValue(val)) { diag.warn(`Invalid attribute value set for key: ${key}`); continue; } if (Array.isArray(val)) { - out[key] = val.slice(); + out[key] = out[key] == val ? val : val.slice(); } else { out[key] = val; } diff --git a/packages/opentelemetry-sdk-trace-base/src/Tracer.ts b/packages/opentelemetry-sdk-trace-base/src/Tracer.ts index f943e6a11cc..454d3ff0fc9 100644 --- a/packages/opentelemetry-sdk-trace-base/src/Tracer.ts +++ b/packages/opentelemetry-sdk-trace-base/src/Tracer.ts @@ -134,9 +134,8 @@ export class Tracer implements api.Tracer { // Set initial span attributes. The attributes object may have been mutated // by the sampler, so we sanitize the merged attributes before setting them. - const initAttributes = sanitizeAttributes( - Object.assign(attributes, samplingResult.attributes) - ); + Object.assign(attributes, samplingResult.attributes); + const initAttributes = sanitizeAttributes(attributes, attributes); const span = new Span( this, diff --git a/packages/opentelemetry-sdk-trace-base/test/performance/benchmark/span.js b/packages/opentelemetry-sdk-trace-base/test/performance/benchmark/span.js index 851123c392f..8f2171a9e37 100644 --- a/packages/opentelemetry-sdk-trace-base/test/performance/benchmark/span.js +++ b/packages/opentelemetry-sdk-trace-base/test/performance/benchmark/span.js @@ -18,7 +18,7 @@ const Benchmark = require('benchmark'); const { BasicTracerProvider } = require('../../../build/src'); const tracerProvider = new BasicTracerProvider(); -const tracer = tracerProvider.getTracer('test') +const tracer = tracerProvider.getTracer('test'); const suite = new Benchmark.Suite(); @@ -26,7 +26,7 @@ suite.on('cycle', event => { console.log(String(event.target)); }); -suite.add('create spans (10 attributes)', function() { +suite.add('create spans (10 attributes)', function () { const span = tracer.startSpan('span'); span.setAttribute('aaaaaaaaaaaaaaaaaaaa', 'aaaaaaaaaaaaaaaaaaaa'); span.setAttribute('bbbbbbbbbbbbbbbbbbbb', 'aaaaaaaaaaaaaaaaaaaa'); @@ -41,4 +41,21 @@ suite.add('create spans (10 attributes)', function() { span.end(); }); +suite.add('create spans (10 attributes) passed as options', function () { + const span = tracer.startSpan('span', { + attributes: { + aaaaaaaaaaaaaaaaaaaa: 'aaaaaaaaaaaaaaaaaaaa', + bbbbbbbbbbbbbbbbbbbb: 'aaaaaaaaaaaaaaaaaaaa', + cccccccccccccccccccc: 'aaaaaaaaaaaaaaaaaaaa', + dddddddddddddddddddd: 'aaaaaaaaaaaaaaaaaaaa', + eeeeeeeeeeeeeeeeeeee: 'aaaaaaaaaaaaaaaaaaaa', + ffffffffffffffffffff: 'aaaaaaaaaaaaaaaaaaaa', + gggggggggggggggggggg: 'aaaaaaaaaaaaaaaaaaaa', + hhhhhhhhhhhhhhhhhhhh: 'aaaaaaaaaaaaaaaaaaaa', + iiiiiiiiiiiiiiiiiiii: 'aaaaaaaaaaaaaaaaaaaa', + jjjjjjjjjjjjjjjjjjjj: 'aaaaaaaaaaaaaaaaaaaa', + }, + }); +}); + suite.run();