Skip to content

Commit

Permalink
chore(opentelemetry-sdk-trace-base): implemented option to limit leng…
Browse files Browse the repository at this point in the history
…th of values of attributes

Signed-off-by: Banothu Ramesh Naik <[email protected]>
  • Loading branch information
banothurameshnaik committed Aug 18, 2021
1 parent 40d0423 commit c6b4981
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 1 deletion.
2 changes: 2 additions & 0 deletions packages/opentelemetry-core/src/utils/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const ENVIRONMENT_NUMBERS_KEYS = [
'OTEL_BSP_MAX_EXPORT_BATCH_SIZE',
'OTEL_BSP_MAX_QUEUE_SIZE',
'OTEL_BSP_SCHEDULE_DELAY',
'OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT',
'OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT',
'OTEL_SPAN_EVENT_COUNT_LIMIT',
'OTEL_SPAN_LINK_COUNT_LIMIT',
Expand Down Expand Up @@ -117,6 +118,7 @@ export const DEFAULT_ENVIRONMENT: Required<ENVIRONMENT> = {
OTEL_PROPAGATORS: ['tracecontext', 'baggage'],
OTEL_RESOURCE_ATTRIBUTES: '',
OTEL_SERVICE_NAME: '',
OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT: Infinity,
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT: 128,
OTEL_SPAN_EVENT_COUNT_LIMIT: 128,
OTEL_SPAN_LINK_COUNT_LIMIT: 128,
Expand Down
2 changes: 2 additions & 0 deletions packages/opentelemetry-core/test/utils/environment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ describe('environment', () => {
OTEL_LOG_LEVEL: 'ERROR',
OTEL_NO_PATCH_MODULES: 'a,b,c',
OTEL_RESOURCE_ATTRIBUTES: '<attrs>',
OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT: 100,
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT: 10,
OTEL_SPAN_EVENT_COUNT_LIMIT: 20,
OTEL_SPAN_LINK_COUNT_LIMIT: 30,
Expand All @@ -93,6 +94,7 @@ describe('environment', () => {
const env = getEnv();
assert.deepStrictEqual(env.OTEL_NO_PATCH_MODULES, ['a', 'b', 'c']);
assert.strictEqual(env.OTEL_LOG_LEVEL, DiagLogLevel.ERROR);
assert.strictEqual(env.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT, 100);
assert.strictEqual(env.OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, 10);
assert.strictEqual(env.OTEL_SPAN_EVENT_COUNT_LIMIT, 20);
assert.strictEqual(env.OTEL_SPAN_LINK_COUNT_LIMIT, 30);
Expand Down
60 changes: 59 additions & 1 deletion packages/opentelemetry-sdk-trace-base/src/Span.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class Span implements api.Span, ReadableSpan {
) {
return this;
}
this.attributes[key] = value;
this.attributes[key] = this._truncateToSize(value);
return this;
}

Expand Down Expand Up @@ -235,4 +235,62 @@ export class Span implements api.Span, ReadableSpan {
}
return this._ended;
}

// Utility function to truncate given value within size
// for value type of string, will truncate to given limit
// for type of non-string, will return same value
private _truncateToLimitUtil(value: string, limit: number): string {
if (typeof value != 'string' || value.length <= limit) {
return value;
}
return value.substr(0, limit);
}

// Check whether given value is array of strings or not
private _isArrayOfStrings(value: unknown): boolean {
if (!Array.isArray(value)) {
return false
}
return value.every(val => typeof val == 'string')
}

/**
* If the given attribute value is of type string and has more characters than given {@code attributeValueLengthLimit} then
* return string with trucated to {@code attributeValueLengthLimit} characters
*
* If the given attribute value is array of strings then
* return new array of strings with each element truncated to {@code attributeValueLengthLimit} characters
*
* Otherwise return same Attribute {@code value}
*
* @param value Attribute value
* @returns truncated attribute value if required, otherwise same value
*/
private _truncateToSize(value?: SpanAttributeValue): SpanAttributeValue | undefined {
const limit = this._spanLimits.attributeValueLengthLimit!
// Check limit
if (typeof limit != 'number' || limit <= 0) {
api.diag.warn(`Attribute value limit must be positive, got ${limit}`);
return value;
}

// Check type of values
// Allowed types are string, array of strings
if (value == null || (typeof value != 'string' && !Array.isArray(value))) {
return value;
}

// String
if (typeof value == 'string') {
return this._truncateToLimitUtil(value, limit);
}

// Array of strings
if (this._isArrayOfStrings(value)) {
return value.map(val => this._truncateToLimitUtil(val as string, limit));
}

// Other types, no need to apply value length limit
return value;
}
}
1 change: 1 addition & 0 deletions packages/opentelemetry-sdk-trace-base/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const DEFAULT_CONFIG = {
sampler: buildSamplerFromEnv(env),
forceFlushTimeoutMillis: 30000,
spanLimits: {
attributeValueLengthLimit: getEnv().OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT,
attributeCountLimit: getEnv().OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT,
linkCountLimit: getEnv().OTEL_SPAN_LINK_COUNT_LIMIT,
eventCountLimit: getEnv().OTEL_SPAN_EVENT_COUNT_LIMIT,
Expand Down
2 changes: 2 additions & 0 deletions packages/opentelemetry-sdk-trace-base/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ export interface SDKRegistrationConfig {

/** Global configuration of trace service */
export interface SpanLimits {
/** attributeValueLengthLimit is maximum allowed attribute value size */
attributeValueLengthLimit?: number;
/** attributeCountLimit is number of attributes per span */
attributeCountLimit?: number;
/** linkCountLimit is number of links per span */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ describe('BasicTracerProvider', () => {
it('should construct an instance with default span limits', () => {
const tracer = new BasicTracerProvider({}).getTracer('default');
assert.deepStrictEqual(tracer.getSpanLimits(), {
attributeValueLengthLimit: Infinity,
attributeCountLimit: 128,
eventCountLimit: 128,
linkCountLimit: 128,
Expand All @@ -92,19 +93,35 @@ describe('BasicTracerProvider', () => {
},
}).getTracer('default');
assert.deepStrictEqual(tracer.getSpanLimits(), {
attributeValueLengthLimit: Infinity,
attributeCountLimit: 100,
eventCountLimit: 128,
linkCountLimit: 128,
});
});

it('should construct an instance with customized attributeValueLengthLimit span limits', () => {
const tracer = new BasicTracerProvider({
spanLimits: {
attributeValueLengthLimit: 10,
},
}).getTracer('default');
assert.deepStrictEqual(tracer.getSpanLimits(), {
attributeValueLengthLimit: 10,
attributeCountLimit: 128,
eventCountLimit: 128,
linkCountLimit: 128,
});
});

it('should construct an instance with customized eventCountLimit span limits', () => {
const tracer = new BasicTracerProvider({
spanLimits: {
eventCountLimit: 300,
},
}).getTracer('default');
assert.deepStrictEqual(tracer.getSpanLimits(), {
attributeValueLengthLimit: Infinity,
attributeCountLimit: 128,
eventCountLimit: 300,
linkCountLimit: 128,
Expand All @@ -118,6 +135,7 @@ describe('BasicTracerProvider', () => {
},
}).getTracer('default');
assert.deepStrictEqual(tracer.getSpanLimits(), {
attributeValueLengthLimit: Infinity,
attributeCountLimit: 128,
eventCountLimit: 128,
linkCountLimit: 10,
Expand Down
34 changes: 34 additions & 0 deletions packages/opentelemetry-sdk-trace-base/test/common/Span.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const performanceTimeOrigin = hrTime();
describe('Span', () => {
const tracer = new BasicTracerProvider({
spanLimits: {
attributeValueLengthLimit: 100,
attributeCountLimit: 100,
eventCountLimit: 100,
},
Expand Down Expand Up @@ -261,6 +262,39 @@ describe('Span', () => {
});
});

it('should truncate values more than attribute value length limit', () => {
const tracer = new BasicTracerProvider({
spanLimits: {
// Setting attribute value length limit
attributeValueLengthLimit: 5,
attributeCountLimit: 100,
eventCountLimit: 100,
},
}).getTracer('default');

const span = new Span(
tracer,
ROOT_CONTEXT,
name,
spanContext,
SpanKind.CLIENT
);

span.setAttribute('attr-with-more-length', 'abcdefgh');
span.setAttribute('attr-with-less-length', 'abc');
span.setAttribute('attr-empty-string', '');
span.setAttribute('attr-non-string', true);
span.setAttribute('attr-array-of-strings', ['abcdefgh', 'abc', 'abcde', '']);

assert.deepStrictEqual(span.attributes, {
'attr-with-more-length': 'abcde',
'attr-with-less-length': 'abc',
'attr-empty-string': '',
'attr-non-string': true,
'attr-array-of-strings': ['abcde', 'abc', 'abcde', ''],
});
});

it('should set attributes', () => {
const span = new Span(
tracer,
Expand Down

0 comments on commit c6b4981

Please sign in to comment.