From f0039d60ac8b6766861ff78e9b6e6fa7e4c74957 Mon Sep 17 00:00:00 2001 From: Mayur Kale Date: Wed, 6 Feb 2019 11:54:22 -0800 Subject: [PATCH 1/3] Enforce Links limit --- .../src/trace/model/span-base.ts | 8 + .../opencensus-core/src/trace/model/types.ts | 7 +- .../opencensus-core/test/test-root-span.ts | 1 + packages/opencensus-core/test/test-span.ts | 1 + .../src/adapters.ts | 11 +- .../test/test-ocagent.ts | 177 +++++++++++++++++- 6 files changed, 195 insertions(+), 10 deletions(-) diff --git a/packages/opencensus-core/src/trace/model/span-base.ts b/packages/opencensus-core/src/trace/model/span-base.ts index bb72efccb..bd9a71ef2 100644 --- a/packages/opencensus-core/src/trace/model/span-base.ts +++ b/packages/opencensus-core/src/trace/model/span-base.ts @@ -65,6 +65,9 @@ export abstract class SpanBase implements types.Span { /** The number of dropped attributes. */ droppedAttributesCount = 0; + /** The number of dropped links. */ + droppedLinksCount = 0; + /** Constructs a new SpanBaseModel instance. */ constructor() { this.className = this.constructor.name; @@ -180,6 +183,11 @@ export abstract class SpanBase implements types.Span { addLink( traceId: string, spanId: string, type: string, attributes?: types.Attributes) { + if (this.links.length >= this.activeTraceParams.numberOfLinksPerSpan) { + this.links.shift(); + this.droppedLinksCount++; + } + this.links.push({ 'traceId': traceId, 'spanId': spanId, diff --git a/packages/opencensus-core/src/trace/model/types.ts b/packages/opencensus-core/src/trace/model/types.ts index d2d60d2f1..efb51b345 100644 --- a/packages/opencensus-core/src/trace/model/types.ts +++ b/packages/opencensus-core/src/trace/model/types.ts @@ -320,11 +320,14 @@ export interface Span { /** Gives the TraceContext of the span. */ readonly spanContext: SpanContext; + /** Trace Parameters */ + activeTraceParams: configTypes.TraceParams; + /** The number of dropped attributes. */ droppedAttributesCount: number; - /** Trace Parameters */ - activeTraceParams: configTypes.TraceParams; + /** The number of dropped links. */ + droppedLinksCount: number; /** * Adds an atribute to the span. diff --git a/packages/opencensus-core/test/test-root-span.ts b/packages/opencensus-core/test/test-root-span.ts index 9d5657110..fe2ff92d4 100644 --- a/packages/opencensus-core/test/test-root-span.ts +++ b/packages/opencensus-core/test/test-root-span.ts @@ -230,6 +230,7 @@ describe('RootSpan', () => { rootSpan.addLink(rootSpan.traceId, span.id, LINK_TYPE); assert.ok(rootSpan.links.length > 0); + assert.equal(rootSpan.droppedLinksCount, 0); assert.ok(instanceOfLink(rootSpan.links[0])); }); }); diff --git a/packages/opencensus-core/test/test-span.ts b/packages/opencensus-core/test/test-span.ts index 04162cfbd..6e4dfc84e 100644 --- a/packages/opencensus-core/test/test-span.ts +++ b/packages/opencensus-core/test/test-span.ts @@ -232,6 +232,7 @@ describe('Span', () => { span.addLink(span.traceId, rootSpan.id, LINK_TYPE); assert.ok(span.links.length > 0); + assert.equal(span.droppedLinksCount, 0); assert.ok(instanceOfLink(span.links[0])); }); }); diff --git a/packages/opencensus-exporter-ocagent/src/adapters.ts b/packages/opencensus-exporter-ocagent/src/adapters.ts index f55b630f4..8dec96ac0 100644 --- a/packages/opencensus-exporter-ocagent/src/adapters.ts +++ b/packages/opencensus-exporter-ocagent/src/adapters.ts @@ -15,7 +15,6 @@ */ import {Annotation, Attributes, Link, MessageEvent, RootSpan, Span} from '@opencensus/core'; - import {google, opencensus} from './types'; /** @@ -246,10 +245,10 @@ const adaptLink = (link: Link): opencensus.proto.trace.v1.Span.Link => { * @param links Link[] * @returns opencensus.proto.trace.v1.Span.Links */ -const adaptLinks = - (links: Link[] = []): opencensus.proto.trace.v1.Span.Links => { - return {link: links.map(adaptLink), droppedLinksCount: null}; - }; +const adaptLinks = (links: Link[] = [], droppedLinksCount: number): + opencensus.proto.trace.v1.Span.Links => { + return {link: links.map(adaptLink), droppedLinksCount}; +}; /** * Adapts a boolean to a `google.protobuf.BoolValue` type. @@ -276,7 +275,7 @@ export const adaptSpan = (span: Span): opencensus.proto.trace.v1.Span => { attributes: adaptAttributes(span.attributes, span.droppedAttributesCount), stackTrace: null, // Unsupported by nodejs timeEvents: adaptTimeEvents(span.annotations, span.messageEvents), - links: adaptLinks(span.links), + links: adaptLinks(span.links, span.droppedLinksCount), status: span.status, sameProcessAsParentSpan: adaptBoolean(!span.remoteParent), childSpanCount: null, diff --git a/packages/opencensus-exporter-ocagent/test/test-ocagent.ts b/packages/opencensus-exporter-ocagent/test/test-ocagent.ts index b944d1a44..7996925fa 100644 --- a/packages/opencensus-exporter-ocagent/test/test-ocagent.ts +++ b/packages/opencensus-exporter-ocagent/test/test-ocagent.ts @@ -175,7 +175,7 @@ describe('OpenCensus Agent Exporter', () => { tracing = nodeTracing.start({ exporter: ocAgentExporter, samplingRate: INITIAL_SAMPLER_PROBABILITY, - traceParams: {numberOfAttributesPerSpan: 4} + traceParams: {numberOfAttributesPerSpan: 4, numberOfLinksPerSpan: 3} }); }); @@ -354,6 +354,8 @@ describe('OpenCensus Agent Exporter', () => { rootSpan.addMessageEvent(null as any, 'ffff', timeStamp); // Links + rootSpan.addLink('aaaaa', 'aaa', 'CHILD_LINKED_SPAN'); + rootSpan.addLink('bbbbb', 'bbbbb', 'CHILD_LINKED_SPAN'); rootSpan.addLink('ffff', 'ffff', 'CHILD_LINKED_SPAN', { 'child_link_attribute_string': 'foo1', 'child_link_attribute_number': 123, @@ -476,7 +478,7 @@ describe('OpenCensus Agent Exporter', () => { // Links const buff = Buffer.from([255, 255]); assert.deepEqual(span.links, { - droppedLinksCount: 0, + droppedLinksCount: 2, link: [ { type: 'CHILD_LINKED_SPAN', @@ -517,4 +519,175 @@ describe('OpenCensus Agent Exporter', () => { rootSpan.end(); }); }); + + it('should adapt a span correctly without overflowing trace param limits', + (done) => { + const rootSpanOptions: TraceOptions = { + name: 'root', + kind: 'SERVER', + spanContext: { + traceId: hexId(), + spanId: hexId(), + traceState: 'foo=bar,baz=buzz', + options: 0x1 + } + }; + + tracing.tracer.startRootSpan(rootSpanOptions, (rootSpan: RootSpan) => { + // Status + rootSpan.setStatus(CanonicalCode.OK); + + // Attribute + rootSpan.addAttribute('my_first_attribute', 'foo'); + rootSpan.addAttribute('my_second_attribute', 'foo2'); + + // Annotation + rootSpan.addAnnotation( + 'my_annotation', + {myString: 'bar', myNumber: 123, myBoolean: true}); + + // Metric Event + const timeStamp = 123456789; + rootSpan.addMessageEvent('MessageEventTypeSent', 'ffff', timeStamp); + rootSpan.addMessageEvent('MessageEventTypeRecv', 'ffff', timeStamp); + + // Links + rootSpan.addLink('ffff', 'ffff', 'CHILD_LINKED_SPAN', { + 'child_link_attribute_string': 'foo1', + 'child_link_attribute_number': 123, + 'child_link_attribute_boolean': true, + }); + rootSpan.addLink('ffff', 'ffff', 'PARENT_LINKED_SPAN'); + + server.on( + MockAgentEvent.ExportStreamMessageReceived, + (message: opencensus.proto.agent.trace.v1 + .ExportTraceServiceRequest) => { + assert.equal(message.spans.length, 1); + const span = message.spans[0]; + // Name / Context + if (!span.name) { + assert.fail('span.name is null or undefined'); + return; + } + assert.equal(span.name.value, 'root'); + assert.equal(span.kind, 'SERVER'); + + if (!span.tracestate) { + assert.fail('span.tracestate is null or undefined'); + return; + } + assert.deepEqual( + span.tracestate.entries, + [{key: 'foo', value: 'bar'}, {key: 'baz', value: 'buzz'}]); + + if (!span.status) { + assert.fail('span.status is null or undefined'); + } else { + assert.deepEqual(span.status, {code: 0, message: ''}); + } + + // Attributes + if (!span.attributes) { + assert.fail('span.attributes is null or undefined'); + return; + } + assert.deepEqual(span.attributes.attributeMap, { + my_first_attribute: { + value: 'stringValue', + stringValue: {value: 'foo', truncatedByteCount: 0} + }, + my_second_attribute: { + value: 'stringValue', + stringValue: {value: 'foo2', truncatedByteCount: 0} + } + }); + assert.equal(span.attributes.droppedAttributesCount, 0); + + // Time Events + assert.deepEqual(span.timeEvents, { + droppedAnnotationsCount: 0, + droppedMessageEventsCount: 0, + timeEvent: [ + { + value: 'annotation', + time: null, + annotation: { + description: + {value: 'my_annotation', truncatedByteCount: 0}, + attributes: { + attributeMap: { + myString: { + value: 'stringValue', + stringValue: + {value: 'bar', truncatedByteCount: 0} + }, + myNumber: {value: 'intValue', intValue: '123'}, + myBoolean: {value: 'boolValue', boolValue: true} + }, + droppedAttributesCount: 0 + } + } + }, + { + messageEvent: { + compressedSize: '0', + id: '65535', + type: 'SENT', + uncompressedSize: '0' + }, + time: {seconds: '123456', nanos: 789000000}, + value: 'messageEvent' + }, + { + value: 'messageEvent', + messageEvent: { + compressedSize: '0', + id: '65535', + type: 'RECEIVED', + uncompressedSize: '0' + }, + time: {seconds: '123456', nanos: 789000000}, + } + ] + }); + + // Links + const buff = Buffer.from([255, 255]); + assert.deepEqual(span.links, { + droppedLinksCount: 0, + link: [ + { + type: 'CHILD_LINKED_SPAN', + traceId: buff, + spanId: buff, + attributes: { + droppedAttributesCount: 0, + attributeMap: { + child_link_attribute_string: { + value: 'stringValue', + stringValue: {value: 'foo1', truncatedByteCount: 0} + }, + child_link_attribute_number: + {value: 'intValue', intValue: '123'}, + child_link_attribute_boolean: + {value: 'boolValue', boolValue: true} + } + } + }, + { + type: 'PARENT_LINKED_SPAN', + traceId: buff, + spanId: buff, + attributes: null + } + ] + }); + + done(); + }); + + rootSpan.end(); + }); + }); }); From cda23603f65debda9053e02ca9f98ebdf23362e5 Mon Sep 17 00:00:00 2001 From: Mayur Kale Date: Wed, 6 Feb 2019 15:58:41 -0800 Subject: [PATCH 2/3] add more tests --- packages/opencensus-core/test/test-span.ts | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/packages/opencensus-core/test/test-span.ts b/packages/opencensus-core/test/test-span.ts index 6e4dfc84e..868bca087 100644 --- a/packages/opencensus-core/test/test-span.ts +++ b/packages/opencensus-core/test/test-span.ts @@ -26,6 +26,10 @@ import {Annotation, Attributes, Link} from '../src/trace/model/types'; // rootspan const tracer = new CoreTracer(); +tracer.activeTraceParams = { + numberOfAttributesPerSpan: 32, + numberOfLinksPerSpan: 32 +}; describe('Span', () => { /** @@ -186,6 +190,20 @@ describe('Span', () => { span.attributes['testKey' + attType], 'testValue' + attType); }); }); + + it('should drop extra attributes', () => { + const rootSpan = new RootSpan(tracer); + rootSpan.start(); + + const span = new Span(rootSpan); + span.start(); + for (let i = 0; i < 40; i++) { + span.addAttribute('attr' + i, 100); + } + + assert.equal(Object.keys(span.attributes).length, 32); + assert.equal(span.droppedAttributesCount, 8); + }); }); /** @@ -235,6 +253,21 @@ describe('Span', () => { assert.equal(span.droppedLinksCount, 0); assert.ok(instanceOfLink(span.links[0])); }); + + it('should drop extra links', () => { + const rootSpan = new RootSpan(tracer); + rootSpan.start(); + const span = new Span(rootSpan); + span.start(); + + const LINK_TYPE = 'PARENT_LINKED_SPAN'; + for (let i = 0; i < 35; i++) { + span.addLink(span.traceId, rootSpan.id, LINK_TYPE); + } + + assert.equal(span.links.length, 32); + assert.equal(span.droppedLinksCount, 3); + }); }); /** From 34ea4cf501e1838a1201b856e93ae277c31e182a Mon Sep 17 00:00:00 2001 From: Mayur Kale Date: Thu, 7 Feb 2019 10:21:14 -0800 Subject: [PATCH 3/3] nit fix --- packages/opencensus-exporter-ocagent/test/test-ocagent.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opencensus-exporter-ocagent/test/test-ocagent.ts b/packages/opencensus-exporter-ocagent/test/test-ocagent.ts index 7996925fa..e3ccb4d3a 100644 --- a/packages/opencensus-exporter-ocagent/test/test-ocagent.ts +++ b/packages/opencensus-exporter-ocagent/test/test-ocagent.ts @@ -345,7 +345,7 @@ describe('OpenCensus Agent Exporter', () => { rootSpan.addAnnotation( 'my_annotation', {myString: 'bar', myNumber: 123, myBoolean: true}); - // Metric Event + // Message Event const timeStamp = 123456789; rootSpan.addMessageEvent('MessageEventTypeSent', 'ffff', timeStamp); rootSpan.addMessageEvent('MessageEventTypeRecv', 'ffff', timeStamp); @@ -546,7 +546,7 @@ describe('OpenCensus Agent Exporter', () => { 'my_annotation', {myString: 'bar', myNumber: 123, myBoolean: true}); - // Metric Event + // Message Event const timeStamp = 123456789; rootSpan.addMessageEvent('MessageEventTypeSent', 'ffff', timeStamp); rootSpan.addMessageEvent('MessageEventTypeRecv', 'ffff', timeStamp);