Skip to content

Commit 3db1056

Browse files
fix(sdk-trace-base): fix spanLimits attribute length/count to consider env values (#3068)
Co-authored-by: Marc Pichler <[email protected]>
1 parent 776656b commit 3db1056

File tree

6 files changed

+160
-28
lines changed

6 files changed

+160
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ All notable changes to this project will be documented in this file.
2626

2727
* fix(resources): fix browser compatibility for host and os detectors [#3004](https://github.com/open-telemetry/opentelemetry-js/pull/3004) @legendecas
2828
* fix(sdk-trace-base): fix crash on environments without global document [#3000](https://github.com/open-telemetry/opentelemetry-js/pull/3000) @legendecas
29+
* fix(sdk-trace-base): fix spanLimits attribute length/count to consider env values [#3068](https://github.com/open-telemetry/opentelemetry-js/pull/3068) @svetlanabrennan
2930

3031
### :house: (Internal)
3132

packages/opentelemetry-core/src/utils/environment.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import { DiagLogLevel } from '@opentelemetry/api';
1818
import { TracesSamplerValues } from './sampling';
19+
import { _globalThis } from '../platform/browser/globalThis';
1920

2021
const DEFAULT_LIST_SEPARATOR = ',';
2122

@@ -283,3 +284,13 @@ export function parseEnvironment(values: RAW_ENVIRONMENT): ENVIRONMENT {
283284

284285
return environment;
285286
}
287+
288+
/**
289+
* Get environment in node or browser without
290+
* populating default values.
291+
*/
292+
export function getEnvWithoutDefaults(): ENVIRONMENT {
293+
return typeof process !== 'undefined' ?
294+
parseEnvironment(process.env as RAW_ENVIRONMENT) :
295+
parseEnvironment(_globalThis as typeof globalThis & RAW_ENVIRONMENT);
296+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {
3131
} from '@opentelemetry/core';
3232
import { Resource } from '@opentelemetry/resources';
3333
import { SpanProcessor, Tracer } from '.';
34-
import { DEFAULT_CONFIG } from './config';
34+
import { loadDefaultConfig } from './config';
3535
import { MultiSpanProcessor } from './MultiSpanProcessor';
3636
import { NoopSpanProcessor } from './export/NoopSpanProcessor';
3737
import { SDKRegistrationConfig, TracerConfig } from './types';
@@ -74,7 +74,7 @@ export class BasicTracerProvider implements TracerProvider {
7474
readonly resource: Resource;
7575

7676
constructor(config: TracerConfig = {}) {
77-
const mergedConfig = merge({}, DEFAULT_CONFIG, reconfigureLimits(config));
77+
const mergedConfig = merge({}, loadDefaultConfig(), reconfigureLimits(config));
7878
this.resource = mergedConfig.resource ?? Resource.empty();
7979
this.resource = Resource.default().merge(this.resource);
8080
this._config = Object.assign({}, mergedConfig, {

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

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,30 @@ const FALLBACK_OTEL_TRACES_SAMPLER = TracesSamplerValues.AlwaysOn;
3030
const DEFAULT_RATIO = 1;
3131

3232
/**
33-
* Default configuration. For fields with primitive values, any user-provided
33+
* Load default configuration. For fields with primitive values, any user-provided
3434
* value will override the corresponding default value. For fields with
3535
* non-primitive values (like `spanLimits`), the user-provided value will be
3636
* used to extend the default value.
3737
*/
38-
export const DEFAULT_CONFIG = {
39-
sampler: buildSamplerFromEnv(env),
40-
forceFlushTimeoutMillis: 30000,
41-
generalLimits: {
42-
attributeValueLengthLimit: getEnv().OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT,
43-
attributeCountLimit: getEnv().OTEL_ATTRIBUTE_COUNT_LIMIT,
44-
},
45-
spanLimits: {
46-
attributeValueLengthLimit: getEnv().OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT,
47-
attributeCountLimit: getEnv().OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT,
48-
linkCountLimit: getEnv().OTEL_SPAN_LINK_COUNT_LIMIT,
49-
eventCountLimit: getEnv().OTEL_SPAN_EVENT_COUNT_LIMIT,
50-
},
51-
};
38+
39+
// object needs to be wrapped in this function and called when needed otherwise
40+
// envs are parsed before tests are ran - causes tests using these envs to fail
41+
export function loadDefaultConfig() {
42+
return {
43+
sampler: buildSamplerFromEnv(env),
44+
forceFlushTimeoutMillis: 30000,
45+
generalLimits: {
46+
attributeValueLengthLimit: getEnv().OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT,
47+
attributeCountLimit: getEnv().OTEL_ATTRIBUTE_COUNT_LIMIT,
48+
},
49+
spanLimits: {
50+
attributeValueLengthLimit: getEnv().OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT,
51+
attributeCountLimit: getEnv().OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT,
52+
linkCountLimit: getEnv().OTEL_SPAN_LINK_COUNT_LIMIT,
53+
eventCountLimit: getEnv().OTEL_SPAN_EVENT_COUNT_LIMIT,
54+
},
55+
};
56+
}
5257

5358
/**
5459
* Based on environment, builds a sampler, complies with specification.

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

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@
1515
*/
1616

1717
import { Sampler } from '@opentelemetry/api';
18-
import { buildSamplerFromEnv, DEFAULT_CONFIG } from './config';
18+
import { buildSamplerFromEnv, loadDefaultConfig } from './config';
1919
import { SpanLimits, TracerConfig, GeneralLimits } from './types';
20+
import {
21+
DEFAULT_ATTRIBUTE_COUNT_LIMIT,
22+
DEFAULT_ATTRIBUTE_VALUE_LENGTH_LIMIT,
23+
getEnvWithoutDefaults,
24+
} from '@opentelemetry/core';
2025

2126
/**
2227
* Function to merge Default configuration (as specified in './config') with
@@ -31,6 +36,8 @@ export function mergeConfig(userConfig: TracerConfig): TracerConfig & {
3136
sampler: buildSamplerFromEnv(),
3237
};
3338

39+
const DEFAULT_CONFIG = loadDefaultConfig();
40+
3441
const target = Object.assign(
3542
{},
3643
DEFAULT_CONFIG,
@@ -61,21 +68,27 @@ export function mergeConfig(userConfig: TracerConfig): TracerConfig & {
6168
export function reconfigureLimits(userConfig: TracerConfig): TracerConfig {
6269
const spanLimits = Object.assign({}, userConfig.spanLimits);
6370

71+
const parsedEnvConfig = getEnvWithoutDefaults();
72+
6473
/**
65-
* When span attribute count limit is not defined, but general attribute count limit is defined
66-
* Then, span attribute count limit will be same as general one
74+
* Reassign span attribute count limit to use first non null value defined by user or use default value
6775
*/
68-
if (spanLimits.attributeCountLimit == null && userConfig.generalLimits?.attributeCountLimit != null) {
69-
spanLimits.attributeCountLimit = userConfig.generalLimits.attributeCountLimit;
70-
}
76+
spanLimits.attributeCountLimit =
77+
userConfig.spanLimits?.attributeCountLimit ??
78+
userConfig.generalLimits?.attributeCountLimit ??
79+
parsedEnvConfig.OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT ??
80+
parsedEnvConfig.OTEL_ATTRIBUTE_COUNT_LIMIT ??
81+
DEFAULT_ATTRIBUTE_COUNT_LIMIT;
7182

7283
/**
73-
* When span attribute value length limit is not defined, but general attribute value length limit is defined
74-
* Then, span attribute value length limit will be same as general one
84+
* Reassign span attribute value length limit to use first non null value defined by user or use default value
7585
*/
76-
if (spanLimits.attributeValueLengthLimit == null && userConfig.generalLimits?.attributeValueLengthLimit != null) {
77-
spanLimits.attributeValueLengthLimit = userConfig.generalLimits.attributeValueLengthLimit;
78-
}
86+
spanLimits.attributeValueLengthLimit =
87+
userConfig.spanLimits?.attributeValueLengthLimit ??
88+
userConfig.generalLimits?.attributeValueLengthLimit ??
89+
parsedEnvConfig.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT ??
90+
parsedEnvConfig.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT ??
91+
DEFAULT_ATTRIBUTE_VALUE_LENGTH_LIMIT;
7992

8093
return Object.assign({}, userConfig, { spanLimits });
8194
}

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

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,108 @@ describe('BasicTracerProvider', () => {
208208
});
209209
});
210210

211+
describe('when attribute value length limit is defined via env', () => {
212+
it('should have general attribute value length limits value as defined with env', () => {
213+
envSource.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = '115';
214+
const tracer = new BasicTracerProvider().getTracer('default');
215+
const generalLimits = tracer.getGeneralLimits();
216+
assert.strictEqual(generalLimits.attributeValueLengthLimit, 115);
217+
delete envSource.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT;
218+
});
219+
it('should have span attribute value length limit value same as general limit value', () => {
220+
envSource.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = '125';
221+
const tracer = new BasicTracerProvider().getTracer('default');
222+
const generalLimits = tracer.getGeneralLimits();
223+
const spanLimits = tracer.getSpanLimits();
224+
assert.strictEqual(generalLimits.attributeValueLengthLimit, 125);
225+
assert.strictEqual(spanLimits.attributeValueLengthLimit, 125);
226+
delete envSource.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT;
227+
});
228+
it('should have span and general attribute value length limits as defined in env', () => {
229+
envSource.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = '125';
230+
envSource.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT = '109';
231+
const tracer = new BasicTracerProvider().getTracer('default');
232+
const spanLimits = tracer.getSpanLimits();
233+
const generalLimits = tracer.getGeneralLimits();
234+
assert.strictEqual(generalLimits.attributeValueLengthLimit, 125);
235+
assert.strictEqual(spanLimits.attributeValueLengthLimit, 109);
236+
delete envSource.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT;
237+
delete envSource.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT;
238+
});
239+
it('should have span attribute value length limit as deafult of Infinity', () => {
240+
envSource.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = '125';
241+
envSource.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT = 'Infinity';
242+
const tracer = new BasicTracerProvider().getTracer('default');
243+
const spanLimits = tracer.getSpanLimits();
244+
const generalLimits = tracer.getGeneralLimits();
245+
assert.strictEqual(generalLimits.attributeValueLengthLimit, 125);
246+
assert.strictEqual(spanLimits.attributeValueLengthLimit, Infinity);
247+
delete envSource.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT;
248+
delete envSource.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT;
249+
});
250+
});
251+
252+
describe('when attribute value length limit is not defined via env', () => {
253+
it('should use default value of Infinity', () => {
254+
const tracer = new BasicTracerProvider().getTracer('default');
255+
const spanLimits = tracer.getSpanLimits();
256+
const generalLimits = tracer.getGeneralLimits();
257+
assert.strictEqual(generalLimits.attributeValueLengthLimit, Infinity);
258+
assert.strictEqual(spanLimits.attributeValueLengthLimit, Infinity);
259+
});
260+
});
261+
262+
describe('when attribute count limit is defined via env', () => {
263+
it('should general attribute count limit as defined with env', () => {
264+
envSource.OTEL_ATTRIBUTE_COUNT_LIMIT = '25';
265+
const tracer = new BasicTracerProvider({}).getTracer('default');
266+
const generalLimits = tracer.getGeneralLimits();
267+
assert.strictEqual(generalLimits.attributeCountLimit, 25);
268+
delete envSource.OTEL_ATTRIBUTE_COUNT_LIMIT;
269+
});
270+
it('should have span attribute count limit value same as general limit value', () => {
271+
envSource.OTEL_ATTRIBUTE_COUNT_LIMIT = '20';
272+
const tracer = new BasicTracerProvider().getTracer('default');
273+
const generalLimits = tracer.getGeneralLimits();
274+
const spanLimits = tracer.getSpanLimits();
275+
assert.strictEqual(generalLimits.attributeCountLimit, 20);
276+
assert.strictEqual(spanLimits.attributeCountLimit, 20);
277+
delete envSource.OTEL_ATTRIBUTE_COUNT_LIMIT;
278+
});
279+
it('should have span and general attribute count limits as defined in env', () => {
280+
envSource.OTEL_ATTRIBUTE_COUNT_LIMIT = '20';
281+
envSource.OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT = '35';
282+
const tracer = new BasicTracerProvider().getTracer('default');
283+
const spanLimits = tracer.getSpanLimits();
284+
const generalLimits = tracer.getGeneralLimits();
285+
assert.strictEqual(generalLimits.attributeCountLimit, 20);
286+
assert.strictEqual(spanLimits.attributeCountLimit, 35);
287+
delete envSource.OTEL_ATTRIBUTE_COUNT_LIMIT;
288+
delete envSource.OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT;
289+
});
290+
it('should have span attribute count limit as default of 128', () => {
291+
envSource.OTEL_ATTRIBUTE_COUNT_LIMIT = '20';
292+
envSource.OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT = '128';
293+
const tracer = new BasicTracerProvider().getTracer('default');
294+
const spanLimits = tracer.getSpanLimits();
295+
const generalLimits = tracer.getGeneralLimits();
296+
assert.strictEqual(generalLimits.attributeCountLimit, 20);
297+
assert.strictEqual(spanLimits.attributeCountLimit, 128);
298+
delete envSource.OTEL_ATTRIBUTE_COUNT_LIMIT;
299+
delete envSource.OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT;
300+
});
301+
});
302+
303+
describe('when attribute count limit is not defined via env', () => {
304+
it('should use default value of 128', () => {
305+
const tracer = new BasicTracerProvider().getTracer('default');
306+
const spanLimits = tracer.getSpanLimits();
307+
const generalLimits = tracer.getGeneralLimits();
308+
assert.strictEqual(generalLimits.attributeCountLimit, 128);
309+
assert.strictEqual(spanLimits.attributeCountLimit, 128);
310+
});
311+
});
312+
211313
describe('when "eventCountLimit" is defined', () => {
212314
it('should have tracer with defined value', () => {
213315
const tracer = new BasicTracerProvider({

0 commit comments

Comments
 (0)