Skip to content
This repository was archived by the owner on Oct 3, 2023. It is now read-only.

Commit e95a418

Browse files
authored
Enforce Links limit (#331)
* Enforce Links limit * add more tests * nit fix
1 parent 923148a commit e95a418

File tree

6 files changed

+229
-11
lines changed

6 files changed

+229
-11
lines changed

packages/opencensus-core/src/trace/model/span-base.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ export abstract class SpanBase implements types.Span {
6565
/** The number of dropped attributes. */
6666
droppedAttributesCount = 0;
6767

68+
/** The number of dropped links. */
69+
droppedLinksCount = 0;
70+
6871
/** Constructs a new SpanBaseModel instance. */
6972
constructor() {
7073
this.className = this.constructor.name;
@@ -180,6 +183,11 @@ export abstract class SpanBase implements types.Span {
180183
addLink(
181184
traceId: string, spanId: string, type: string,
182185
attributes?: types.Attributes) {
186+
if (this.links.length >= this.activeTraceParams.numberOfLinksPerSpan) {
187+
this.links.shift();
188+
this.droppedLinksCount++;
189+
}
190+
183191
this.links.push({
184192
'traceId': traceId,
185193
'spanId': spanId,

packages/opencensus-core/src/trace/model/types.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,11 +320,14 @@ export interface Span {
320320
/** Gives the TraceContext of the span. */
321321
readonly spanContext: SpanContext;
322322

323+
/** Trace Parameters */
324+
activeTraceParams: configTypes.TraceParams;
325+
323326
/** The number of dropped attributes. */
324327
droppedAttributesCount: number;
325328

326-
/** Trace Parameters */
327-
activeTraceParams: configTypes.TraceParams;
329+
/** The number of dropped links. */
330+
droppedLinksCount: number;
328331

329332
/**
330333
* Adds an atribute to the span.

packages/opencensus-core/test/test-root-span.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ describe('RootSpan', () => {
230230
rootSpan.addLink(rootSpan.traceId, span.id, LINK_TYPE);
231231

232232
assert.ok(rootSpan.links.length > 0);
233+
assert.equal(rootSpan.droppedLinksCount, 0);
233234
assert.ok(instanceOfLink(rootSpan.links[0]));
234235
});
235236
});

packages/opencensus-core/test/test-span.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ import {Annotation, Attributes, Link} from '../src/trace/model/types';
2626
// rootspan
2727

2828
const tracer = new CoreTracer();
29+
tracer.activeTraceParams = {
30+
numberOfAttributesPerSpan: 32,
31+
numberOfLinksPerSpan: 32
32+
};
2933

3034
describe('Span', () => {
3135
/**
@@ -186,6 +190,20 @@ describe('Span', () => {
186190
span.attributes['testKey' + attType], 'testValue' + attType);
187191
});
188192
});
193+
194+
it('should drop extra attributes', () => {
195+
const rootSpan = new RootSpan(tracer);
196+
rootSpan.start();
197+
198+
const span = new Span(rootSpan);
199+
span.start();
200+
for (let i = 0; i < 40; i++) {
201+
span.addAttribute('attr' + i, 100);
202+
}
203+
204+
assert.equal(Object.keys(span.attributes).length, 32);
205+
assert.equal(span.droppedAttributesCount, 8);
206+
});
189207
});
190208

191209
/**
@@ -232,8 +250,24 @@ describe('Span', () => {
232250
span.addLink(span.traceId, rootSpan.id, LINK_TYPE);
233251

234252
assert.ok(span.links.length > 0);
253+
assert.equal(span.droppedLinksCount, 0);
235254
assert.ok(instanceOfLink(span.links[0]));
236255
});
256+
257+
it('should drop extra links', () => {
258+
const rootSpan = new RootSpan(tracer);
259+
rootSpan.start();
260+
const span = new Span(rootSpan);
261+
span.start();
262+
263+
const LINK_TYPE = 'PARENT_LINKED_SPAN';
264+
for (let i = 0; i < 35; i++) {
265+
span.addLink(span.traceId, rootSpan.id, LINK_TYPE);
266+
}
267+
268+
assert.equal(span.links.length, 32);
269+
assert.equal(span.droppedLinksCount, 3);
270+
});
237271
});
238272

239273
/**

packages/opencensus-exporter-ocagent/src/adapters.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616

1717
import {Annotation, Attributes, Link, MessageEvent, RootSpan, Span} from '@opencensus/core';
18-
1918
import {google, opencensus} from './types';
2019

2120
/**
@@ -246,10 +245,10 @@ const adaptLink = (link: Link): opencensus.proto.trace.v1.Span.Link => {
246245
* @param links Link[]
247246
* @returns opencensus.proto.trace.v1.Span.Links
248247
*/
249-
const adaptLinks =
250-
(links: Link[] = []): opencensus.proto.trace.v1.Span.Links => {
251-
return {link: links.map(adaptLink), droppedLinksCount: null};
252-
};
248+
const adaptLinks = (links: Link[] = [], droppedLinksCount: number):
249+
opencensus.proto.trace.v1.Span.Links => {
250+
return {link: links.map(adaptLink), droppedLinksCount};
251+
};
253252

254253
/**
255254
* Adapts a boolean to a `google.protobuf.BoolValue` type.
@@ -276,7 +275,7 @@ export const adaptSpan = (span: Span): opencensus.proto.trace.v1.Span => {
276275
attributes: adaptAttributes(span.attributes, span.droppedAttributesCount),
277276
stackTrace: null, // Unsupported by nodejs
278277
timeEvents: adaptTimeEvents(span.annotations, span.messageEvents),
279-
links: adaptLinks(span.links),
278+
links: adaptLinks(span.links, span.droppedLinksCount),
280279
status: span.status,
281280
sameProcessAsParentSpan: adaptBoolean(!span.remoteParent),
282281
childSpanCount: null,

packages/opencensus-exporter-ocagent/test/test-ocagent.ts

Lines changed: 176 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ describe('OpenCensus Agent Exporter', () => {
175175
tracing = nodeTracing.start({
176176
exporter: ocAgentExporter,
177177
samplingRate: INITIAL_SAMPLER_PROBABILITY,
178-
traceParams: {numberOfAttributesPerSpan: 4}
178+
traceParams: {numberOfAttributesPerSpan: 4, numberOfLinksPerSpan: 3}
179179
});
180180
});
181181

@@ -345,7 +345,7 @@ describe('OpenCensus Agent Exporter', () => {
345345
rootSpan.addAnnotation(
346346
'my_annotation', {myString: 'bar', myNumber: 123, myBoolean: true});
347347

348-
// Metric Event
348+
// Message Event
349349
const timeStamp = 123456789;
350350
rootSpan.addMessageEvent('MessageEventTypeSent', 'ffff', timeStamp);
351351
rootSpan.addMessageEvent('MessageEventTypeRecv', 'ffff', timeStamp);
@@ -354,6 +354,8 @@ describe('OpenCensus Agent Exporter', () => {
354354
rootSpan.addMessageEvent(null as any, 'ffff', timeStamp);
355355

356356
// Links
357+
rootSpan.addLink('aaaaa', 'aaa', 'CHILD_LINKED_SPAN');
358+
rootSpan.addLink('bbbbb', 'bbbbb', 'CHILD_LINKED_SPAN');
357359
rootSpan.addLink('ffff', 'ffff', 'CHILD_LINKED_SPAN', {
358360
'child_link_attribute_string': 'foo1',
359361
'child_link_attribute_number': 123,
@@ -476,7 +478,7 @@ describe('OpenCensus Agent Exporter', () => {
476478
// Links
477479
const buff = Buffer.from([255, 255]);
478480
assert.deepEqual(span.links, {
479-
droppedLinksCount: 0,
481+
droppedLinksCount: 2,
480482
link: [
481483
{
482484
type: 'CHILD_LINKED_SPAN',
@@ -517,4 +519,175 @@ describe('OpenCensus Agent Exporter', () => {
517519
rootSpan.end();
518520
});
519521
});
522+
523+
it('should adapt a span correctly without overflowing trace param limits',
524+
(done) => {
525+
const rootSpanOptions: TraceOptions = {
526+
name: 'root',
527+
kind: 'SERVER',
528+
spanContext: {
529+
traceId: hexId(),
530+
spanId: hexId(),
531+
traceState: 'foo=bar,baz=buzz',
532+
options: 0x1
533+
}
534+
};
535+
536+
tracing.tracer.startRootSpan(rootSpanOptions, (rootSpan: RootSpan) => {
537+
// Status
538+
rootSpan.setStatus(CanonicalCode.OK);
539+
540+
// Attribute
541+
rootSpan.addAttribute('my_first_attribute', 'foo');
542+
rootSpan.addAttribute('my_second_attribute', 'foo2');
543+
544+
// Annotation
545+
rootSpan.addAnnotation(
546+
'my_annotation',
547+
{myString: 'bar', myNumber: 123, myBoolean: true});
548+
549+
// Message Event
550+
const timeStamp = 123456789;
551+
rootSpan.addMessageEvent('MessageEventTypeSent', 'ffff', timeStamp);
552+
rootSpan.addMessageEvent('MessageEventTypeRecv', 'ffff', timeStamp);
553+
554+
// Links
555+
rootSpan.addLink('ffff', 'ffff', 'CHILD_LINKED_SPAN', {
556+
'child_link_attribute_string': 'foo1',
557+
'child_link_attribute_number': 123,
558+
'child_link_attribute_boolean': true,
559+
});
560+
rootSpan.addLink('ffff', 'ffff', 'PARENT_LINKED_SPAN');
561+
562+
server.on(
563+
MockAgentEvent.ExportStreamMessageReceived,
564+
(message: opencensus.proto.agent.trace.v1
565+
.ExportTraceServiceRequest) => {
566+
assert.equal(message.spans.length, 1);
567+
const span = message.spans[0];
568+
// Name / Context
569+
if (!span.name) {
570+
assert.fail('span.name is null or undefined');
571+
return;
572+
}
573+
assert.equal(span.name.value, 'root');
574+
assert.equal(span.kind, 'SERVER');
575+
576+
if (!span.tracestate) {
577+
assert.fail('span.tracestate is null or undefined');
578+
return;
579+
}
580+
assert.deepEqual(
581+
span.tracestate.entries,
582+
[{key: 'foo', value: 'bar'}, {key: 'baz', value: 'buzz'}]);
583+
584+
if (!span.status) {
585+
assert.fail('span.status is null or undefined');
586+
} else {
587+
assert.deepEqual(span.status, {code: 0, message: ''});
588+
}
589+
590+
// Attributes
591+
if (!span.attributes) {
592+
assert.fail('span.attributes is null or undefined');
593+
return;
594+
}
595+
assert.deepEqual(span.attributes.attributeMap, {
596+
my_first_attribute: {
597+
value: 'stringValue',
598+
stringValue: {value: 'foo', truncatedByteCount: 0}
599+
},
600+
my_second_attribute: {
601+
value: 'stringValue',
602+
stringValue: {value: 'foo2', truncatedByteCount: 0}
603+
}
604+
});
605+
assert.equal(span.attributes.droppedAttributesCount, 0);
606+
607+
// Time Events
608+
assert.deepEqual(span.timeEvents, {
609+
droppedAnnotationsCount: 0,
610+
droppedMessageEventsCount: 0,
611+
timeEvent: [
612+
{
613+
value: 'annotation',
614+
time: null,
615+
annotation: {
616+
description:
617+
{value: 'my_annotation', truncatedByteCount: 0},
618+
attributes: {
619+
attributeMap: {
620+
myString: {
621+
value: 'stringValue',
622+
stringValue:
623+
{value: 'bar', truncatedByteCount: 0}
624+
},
625+
myNumber: {value: 'intValue', intValue: '123'},
626+
myBoolean: {value: 'boolValue', boolValue: true}
627+
},
628+
droppedAttributesCount: 0
629+
}
630+
}
631+
},
632+
{
633+
messageEvent: {
634+
compressedSize: '0',
635+
id: '65535',
636+
type: 'SENT',
637+
uncompressedSize: '0'
638+
},
639+
time: {seconds: '123456', nanos: 789000000},
640+
value: 'messageEvent'
641+
},
642+
{
643+
value: 'messageEvent',
644+
messageEvent: {
645+
compressedSize: '0',
646+
id: '65535',
647+
type: 'RECEIVED',
648+
uncompressedSize: '0'
649+
},
650+
time: {seconds: '123456', nanos: 789000000},
651+
}
652+
]
653+
});
654+
655+
// Links
656+
const buff = Buffer.from([255, 255]);
657+
assert.deepEqual(span.links, {
658+
droppedLinksCount: 0,
659+
link: [
660+
{
661+
type: 'CHILD_LINKED_SPAN',
662+
traceId: buff,
663+
spanId: buff,
664+
attributes: {
665+
droppedAttributesCount: 0,
666+
attributeMap: {
667+
child_link_attribute_string: {
668+
value: 'stringValue',
669+
stringValue: {value: 'foo1', truncatedByteCount: 0}
670+
},
671+
child_link_attribute_number:
672+
{value: 'intValue', intValue: '123'},
673+
child_link_attribute_boolean:
674+
{value: 'boolValue', boolValue: true}
675+
}
676+
}
677+
},
678+
{
679+
type: 'PARENT_LINKED_SPAN',
680+
traceId: buff,
681+
spanId: buff,
682+
attributes: null
683+
}
684+
]
685+
});
686+
687+
done();
688+
});
689+
690+
rootSpan.end();
691+
});
692+
});
520693
});

0 commit comments

Comments
 (0)