Skip to content

Commit d315b0a

Browse files
Bataranrauno56dyladanvmarchaudlegendecas
authored
fix: span attribute count and value limits (#2671) (#2678)
Co-authored-by: Rauno Viskus <[email protected]> Co-authored-by: Daniel Dyla <[email protected]> Co-authored-by: Valentin Marchaud <[email protected]> Co-authored-by: legendecas <[email protected]>
1 parent 82e39c4 commit d315b0a

File tree

3 files changed

+90
-8
lines changed

3 files changed

+90
-8
lines changed

packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { NoopSpanProcessor } from './export/NoopSpanProcessor';
3737
import { SDKRegistrationConfig, TracerConfig } from './types';
3838
import { SpanExporter } from './export/SpanExporter';
3939
import { BatchSpanProcessor } from './platform';
40+
import { reconfigureLimits } from './utility';
4041

4142
export type PROPAGATOR_FACTORY = () => TextMapPropagator;
4243
export type EXPORTER_FACTORY = () => SpanExporter;
@@ -73,7 +74,7 @@ export class BasicTracerProvider implements TracerProvider {
7374
readonly resource: Resource;
7475

7576
constructor(config: TracerConfig = {}) {
76-
const mergedConfig = merge({}, DEFAULT_CONFIG, config);
77+
const mergedConfig = merge({}, DEFAULT_CONFIG, reconfigureLimits(config));
7778
this.resource = mergedConfig.resource ?? Resource.empty();
7879
this.resource = Resource.default().merge(this.resource);
7980
this._config = Object.assign({}, mergedConfig, {

packages/opentelemetry-sdk-trace-base/src/utility.ts

+16-7
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { DEFAULT_ATTRIBUTE_VALUE_LENGTH_LIMIT, DEFAULT_ATTRIBUTE_COUNT_LIMIT } from '@opentelemetry/core';
18-
1917
import { Sampler } from '@opentelemetry/api';
2018
import { buildSamplerFromEnv, DEFAULT_CONFIG } from './config';
2119
import { SpanLimits, TracerConfig, GeneralLimits } from './types';
@@ -52,21 +50,32 @@ export function mergeConfig(userConfig: TracerConfig): TracerConfig & {
5250
userConfig.spanLimits || {}
5351
);
5452

53+
return target;
54+
}
55+
56+
/**
57+
* When general limits are provided and model specific limits are not,
58+
* configures the model specific limits by using the values from the general ones.
59+
* @param userConfig User provided tracer configuration
60+
*/
61+
export function reconfigureLimits(userConfig: TracerConfig): TracerConfig {
62+
const spanLimits = Object.assign({}, userConfig.spanLimits);
63+
5564
/**
5665
* When span attribute count limit is not defined, but general attribute count limit is defined
5766
* Then, span attribute count limit will be same as general one
5867
*/
59-
if (target.spanLimits.attributeCountLimit === DEFAULT_ATTRIBUTE_COUNT_LIMIT && target.generalLimits.attributeCountLimit !== DEFAULT_ATTRIBUTE_COUNT_LIMIT) {
60-
target.spanLimits.attributeCountLimit = target.generalLimits.attributeCountLimit;
68+
if (spanLimits.attributeCountLimit == null && userConfig.generalLimits?.attributeCountLimit != null) {
69+
spanLimits.attributeCountLimit = userConfig.generalLimits.attributeCountLimit;
6170
}
6271

6372
/**
6473
* When span attribute value length limit is not defined, but general attribute value length limit is defined
6574
* Then, span attribute value length limit will be same as general one
6675
*/
67-
if (target.spanLimits.attributeValueLengthLimit === DEFAULT_ATTRIBUTE_VALUE_LENGTH_LIMIT && target.generalLimits.attributeValueLengthLimit !== DEFAULT_ATTRIBUTE_VALUE_LENGTH_LIMIT) {
68-
target.spanLimits.attributeValueLengthLimit = target.generalLimits.attributeValueLengthLimit;
76+
if (spanLimits.attributeValueLengthLimit == null && userConfig.generalLimits?.attributeValueLengthLimit != null) {
77+
spanLimits.attributeValueLengthLimit = userConfig.generalLimits.attributeValueLengthLimit;
6978
}
7079

71-
return target;
80+
return Object.assign({}, userConfig, { spanLimits });
7281
}

packages/opentelemetry-sdk-trace-base/test/common/Span.test.ts

+72
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import {
2323
TraceFlags,
2424
} from '@opentelemetry/api';
2525
import {
26+
DEFAULT_ATTRIBUTE_COUNT_LIMIT,
27+
DEFAULT_ATTRIBUTE_VALUE_LENGTH_LIMIT,
2628
hrTime,
2729
hrTimeDuration,
2830
hrTimeToMilliseconds,
@@ -486,6 +488,38 @@ describe('Span', () => {
486488
});
487489
});
488490

491+
describe('when span "attributeCountLimit" set to the default value and general "attributeCountLimit" option defined', () => {
492+
const tracer = new BasicTracerProvider({
493+
generalLimits: {
494+
// Setting count limit
495+
attributeCountLimit: 10,
496+
},
497+
spanLimits: {
498+
attributeCountLimit: DEFAULT_ATTRIBUTE_COUNT_LIMIT,
499+
}
500+
}).getTracer('default');
501+
502+
const span = new Span(
503+
tracer,
504+
ROOT_CONTEXT,
505+
name,
506+
spanContext,
507+
SpanKind.CLIENT
508+
);
509+
for (let i = 0; i < 150; i++) {
510+
span.setAttribute('foo' + i, 'bar' + i);
511+
}
512+
span.end();
513+
514+
it('should remove / drop all remaining values after the number of values exceeds the span limit', () => {
515+
assert.strictEqual(Object.keys(span.attributes).length, DEFAULT_ATTRIBUTE_COUNT_LIMIT);
516+
assert.strictEqual(span.attributes['foo0'], 'bar0');
517+
assert.strictEqual(span.attributes['foo10'], 'bar10');
518+
assert.strictEqual(span.attributes['foo127'], 'bar127');
519+
assert.strictEqual(span.attributes['foo128'], undefined);
520+
});
521+
});
522+
489523
describe('when "attributeValueLengthLimit" option defined', () => {
490524
const tracer = new BasicTracerProvider({
491525
generalLimits: {
@@ -528,6 +562,44 @@ describe('Span', () => {
528562
assert.strictEqual(span.attributes['attr-non-string'], true);
529563
});
530564
});
565+
566+
describe('when span "attributeValueLengthLimit" set to the default value and general "attributeValueLengthLimit" option defined', () => {
567+
const tracer = new BasicTracerProvider({
568+
generalLimits: {
569+
// Setting attribute value length limit
570+
attributeValueLengthLimit: 10,
571+
},
572+
spanLimits: {
573+
// Setting attribute value length limit
574+
attributeValueLengthLimit: DEFAULT_ATTRIBUTE_VALUE_LENGTH_LIMIT,
575+
},
576+
}).getTracer('default');
577+
578+
const span = new Span(
579+
tracer,
580+
ROOT_CONTEXT,
581+
name,
582+
spanContext,
583+
SpanKind.CLIENT
584+
);
585+
586+
it('should not truncate value', () => {
587+
span.setAttribute('attr-with-more-length', 'abcdefghijklmn');
588+
assert.strictEqual(span.attributes['attr-with-more-length'], 'abcdefghijklmn');
589+
});
590+
591+
it('should not truncate value of arrays', () => {
592+
span.setAttribute('attr-array-of-strings', ['abcdefghijklmn', 'abc', 'abcde', '']);
593+
span.setAttribute('attr-array-of-bool', [true, false]);
594+
assert.deepStrictEqual(span.attributes['attr-array-of-strings'], ['abcdefghijklmn', 'abc', 'abcde', '']);
595+
assert.deepStrictEqual(span.attributes['attr-array-of-bool'], [true, false]);
596+
});
597+
598+
it('should return same value for non-string values', () => {
599+
span.setAttribute('attr-non-string', true);
600+
assert.strictEqual(span.attributes['attr-non-string'], true);
601+
});
602+
});
531603
});
532604
});
533605

0 commit comments

Comments
 (0)