From cf0217d5efce4740f0a371edcc5ea88571087e4f Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Wed, 17 Mar 2021 22:54:46 +0000 Subject: [PATCH 01/40] fix: added support for Opentelemetry 0.18 Introduces support for Opentelemetry 0.18 API which implements the Tracing 1.0 specification. --- package.json | 4 ++-- src/opentelemetry-tracing.ts | 29 ++++++++++++++++++++++------- src/subscriber.ts | 2 +- test/opentelemetry-tracing.ts | 2 +- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index a74fb923f..c4f82a066 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,7 @@ "@google-cloud/precise-date": "^2.0.0", "@google-cloud/projectify": "^2.0.0", "@google-cloud/promisify": "^2.0.0", - "@opentelemetry/api": "^0.12.0", - "@opentelemetry/tracing": "^0.12.0", + "@opentelemetry/api": "^0.18.0", "@types/duplexify": "^3.6.0", "@types/long": "^4.0.0", "arrify": "^2.0.0", @@ -66,6 +65,7 @@ "p-defer": "^3.0.0" }, "devDependencies": { + "@opentelemetry/tracing": "^0.18.0", "@grpc/proto-loader": "^0.5.4", "@types/execa": "^0.9.0", "@types/extend": "^3.0.0", diff --git a/src/opentelemetry-tracing.ts b/src/opentelemetry-tracing.ts index 3c51dd440..fbc5ecf78 100644 --- a/src/opentelemetry-tracing.ts +++ b/src/opentelemetry-tracing.ts @@ -13,8 +13,15 @@ * limitations under the License. */ -import {Attributes, SpanContext, Span, trace} from '@opentelemetry/api'; -import {Tracer} from '@opentelemetry/tracing'; +import { + Tracer, + SpanAttributes, + SpanContext, + Span, + context, + trace, + setSpanContext, +} from '@opentelemetry/api'; /** * Wrapper for creating OpenTelemetry Spans @@ -31,13 +38,21 @@ export class OpenTelemetryTracer { */ createSpan( spanName: string, - attributes?: Attributes, + attributes?: SpanAttributes, parent?: SpanContext ): Span { const tracerProvider: Tracer = trace.getTracer('default') as Tracer; - return tracerProvider.startSpan(spanName, { - parent: parent, - attributes: attributes, - }); + + let spanContext = undefined; + if (parent) { + spanContext = setSpanContext(context.active(), parent); + } + return tracerProvider.startSpan( + spanName, + { + attributes: attributes, + }, + spanContext + ); } } diff --git a/src/subscriber.ts b/src/subscriber.ts index 97b863094..269190c31 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -18,7 +18,7 @@ import {DateStruct, PreciseDate} from '@google-cloud/precise-date'; import {replaceProjectIdToken} from '@google-cloud/projectify'; import {promisify} from '@google-cloud/promisify'; import {EventEmitter} from 'events'; -import {SpanContext, Span} from '@opentelemetry/api'; +import {SpanContext, Span, setSpanContext} from '@opentelemetry/api'; import {google} from '../protos/protos'; import {Histogram} from './histogram'; diff --git a/test/opentelemetry-tracing.ts b/test/opentelemetry-tracing.ts index 032a23533..f51be0bc5 100644 --- a/test/opentelemetry-tracing.ts +++ b/test/opentelemetry-tracing.ts @@ -31,7 +31,7 @@ describe('OpenTelemetryTracer', () => { spanId: '6e0c63257de34c92', traceFlags: api.TraceFlags.SAMPLED, }; - const spanAttributes: api.Attributes = { + const spanAttributes: api.SpanAttributes = { foo: 'bar', }; From c01a210d2d6e897429efecc02fef19a707239041 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Wed, 17 Mar 2021 23:00:41 +0000 Subject: [PATCH 02/40] style: remove unused import declaration --- src/subscriber.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/subscriber.ts b/src/subscriber.ts index 269190c31..97b863094 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -18,7 +18,7 @@ import {DateStruct, PreciseDate} from '@google-cloud/precise-date'; import {replaceProjectIdToken} from '@google-cloud/projectify'; import {promisify} from '@google-cloud/promisify'; import {EventEmitter} from 'events'; -import {SpanContext, Span, setSpanContext} from '@opentelemetry/api'; +import {SpanContext, Span} from '@opentelemetry/api'; import {google} from '../protos/protos'; import {Histogram} from './histogram'; From 0de436ef9a55efd2934ce9e85f16402a41a741a6 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Wed, 17 Mar 2021 23:54:07 +0000 Subject: [PATCH 03/40] refactor: removed the `OpenTelemetryTracer`-class and just expose createSpan as function --- src/opentelemetry-tracing.ts | 45 +++++++++++++---------------------- src/publisher/index.ts | 15 +++--------- src/subscriber.ts | 10 +++----- test/opentelemetry-tracing.ts | 15 +++--------- test/publisher/index.ts | 30 ----------------------- test/subscriber.ts | 31 +----------------------- 6 files changed, 27 insertions(+), 119 deletions(-) diff --git a/src/opentelemetry-tracing.ts b/src/opentelemetry-tracing.ts index fbc5ecf78..f0122d390 100644 --- a/src/opentelemetry-tracing.ts +++ b/src/opentelemetry-tracing.ts @@ -24,35 +24,24 @@ import { } from '@opentelemetry/api'; /** - * Wrapper for creating OpenTelemetry Spans + * Creates a new span with the given properties * - * @class + * @param {string} spanName the name for the span + * @param {Attributes?} attributes an object containing the attributes to be set for the span + * @param {SpanContext?} parent the context of the parent span to link to the span */ -export class OpenTelemetryTracer { - /** - * Creates a new span with the given properties - * - * @param {string} spanName the name for the span - * @param {Attributes?} attributes an object containing the attributes to be set for the span - * @param {SpanContext?} parent the context of the parent span to link to the span - */ - createSpan( - spanName: string, - attributes?: SpanAttributes, - parent?: SpanContext - ): Span { - const tracerProvider: Tracer = trace.getTracer('default') as Tracer; +export function createSpan( + spanName: string, + attributes?: SpanAttributes, + parent?: SpanContext +): Span { + const tracerProvider: Tracer = trace.getTracer('default') as Tracer; - let spanContext = undefined; - if (parent) { - spanContext = setSpanContext(context.active(), parent); - } - return tracerProvider.startSpan( - spanName, - { - attributes: attributes, - }, - spanContext - ); - } + return tracerProvider.startSpan( + spanName, + { + attributes: attributes, + }, + parent ? setSpanContext(context.active(), parent) : undefined + ); } diff --git a/src/publisher/index.ts b/src/publisher/index.ts index 483990f96..41095717d 100644 --- a/src/publisher/index.ts +++ b/src/publisher/index.ts @@ -25,7 +25,7 @@ import {Topic} from '../topic'; import {RequestCallback, EmptyCallback} from '../pubsub'; import {google} from '../../protos/protos'; import {defaultOptions} from '../default-options'; -import {OpenTelemetryTracer} from '../opentelemetry-tracing'; +import {createSpan} from '../opentelemetry-tracing'; export type PubsubMessage = google.pubsub.v1.IPubsubMessage; @@ -75,16 +75,11 @@ export class Publisher { settings!: PublishOptions; queue: Queue; orderedQueues: Map; - tracing: OpenTelemetryTracer | undefined; constructor(topic: Topic, options?: PublishOptions) { this.setOptions(options); this.topic = topic; this.queue = new Queue(this); this.orderedQueues = new Map(); - this.tracing = - this.settings && this.settings.enableOpenTelemetryTracing - ? new OpenTelemetryTracer() - : undefined; } flush(): Promise; @@ -238,10 +233,6 @@ export class Publisher { enableOpenTelemetryTracing, } = extend(true, defaults, options); - this.tracing = enableOpenTelemetryTracing - ? new OpenTelemetryTracer() - : undefined; - this.settings = { batching: { maxBytes: Math.min(batching.maxBytes, BATCH_LIMITS.maxBytes!), @@ -265,8 +256,8 @@ export class Publisher { const spanAttributes = { data: message.data, } as Attributes; - const span: Span | undefined = this.tracing - ? this.tracing.createSpan(`${this.topic.name} publisher`, spanAttributes) + const span: Span | undefined = this.settings.enableOpenTelemetryTracing + ? createSpan(`${this.topic.name} publisher`, spanAttributes) : undefined; if (span) { if ( diff --git a/src/subscriber.ts b/src/subscriber.ts index 97b863094..41f6dc9e0 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -28,7 +28,7 @@ import {MessageStream, MessageStreamOptions} from './message-stream'; import {Subscription} from './subscription'; import {defaultOptions} from './default-options'; import {SubscriberClient} from './v1'; -import {OpenTelemetryTracer} from './opentelemetry-tracing'; +import {createSpan} from './opentelemetry-tracing'; export type PullResponse = google.pubsub.v1.IPullResponse; @@ -245,7 +245,6 @@ export class Subscriber extends EventEmitter { private _options!: SubscriberOptions; private _stream!: MessageStream; private _subscription: Subscription; - private _tracing: OpenTelemetryTracer | undefined; constructor(subscription: Subscription, options = {}) { super(); @@ -433,9 +432,6 @@ export class Subscriber extends EventEmitter { this.maxMessages ); } - this._tracing = options.enableOpenTelemetryTracing - ? new OpenTelemetryTracer() - : undefined; } /** @@ -447,7 +443,7 @@ export class Subscriber extends EventEmitter { private _constructSpan(message: Message): Span | undefined { // Handle cases where OpenTelemetry is disabled or no span context was sent through message if ( - !this._tracing || + !this._options.enableOpenTelemetryTracing || !message.attributes || !message.attributes['googclient_OpenTelemetrySpanContext'] ) { @@ -464,7 +460,7 @@ export class Subscriber extends EventEmitter { // Subscriber spans should always have a publisher span as a parent. // Return undefined if no parent is provided const span = parentSpanContext - ? this._tracing.createSpan(this._name, spanAttributes, parentSpanContext) + ? createSpan(this._name, spanAttributes, parentSpanContext) : undefined; return span; } diff --git a/test/opentelemetry-tracing.ts b/test/opentelemetry-tracing.ts index f51be0bc5..d39a543d8 100644 --- a/test/opentelemetry-tracing.ts +++ b/test/opentelemetry-tracing.ts @@ -15,15 +15,14 @@ */ import * as assert from 'assert'; -import {describe, it, before, beforeEach, afterEach} from 'mocha'; +import {describe, it, before, afterEach} from 'mocha'; import * as api from '@opentelemetry/api'; import * as trace from '@opentelemetry/tracing'; -import {OpenTelemetryTracer} from '../src/opentelemetry-tracing'; +import {createSpan} from '../src/opentelemetry-tracing'; import {SimpleSpanProcessor} from '@opentelemetry/tracing'; describe('OpenTelemetryTracer', () => { - let tracing: OpenTelemetryTracer; let span: trace.Span; const spanName = 'test-span'; const spanContext: api.SpanContext = { @@ -42,20 +41,12 @@ describe('OpenTelemetryTracer', () => { api.trace.setGlobalTracerProvider(provider); }); - beforeEach(() => { - tracing = new OpenTelemetryTracer(); - }); - afterEach(() => { span.end(); }); it('creates a span', () => { - span = tracing.createSpan( - spanName, - spanAttributes, - spanContext - ) as trace.Span; + span = createSpan(spanName, spanAttributes, spanContext) as trace.Span; assert.strictEqual(span.name, spanName); assert.deepStrictEqual(span.attributes, spanAttributes); assert.strictEqual(span.parentSpanId, spanContext.spanId); diff --git a/test/publisher/index.ts b/test/publisher/index.ts index ad59e3604..3d9860704 100644 --- a/test/publisher/index.ts +++ b/test/publisher/index.ts @@ -180,38 +180,8 @@ describe('Publisher', () => { const enableTracing: p.PublishOptions = { enableOpenTelemetryTracing: true, }; - const disableTracing: p.PublishOptions = { - enableOpenTelemetryTracing: false, - }; const buffer = Buffer.from('Hello, world!'); - beforeEach(() => { - // Declare tracingPublisher as type any and pre-define _tracing - // to gain access to the private field after publisher init - tracingPublisher['tracing'] = undefined; - }); - it('should not instantiate a tracer when tracing is disabled', () => { - tracingPublisher = new Publisher(topic); - assert.strictEqual(tracingPublisher['tracing'], undefined); - }); - - it('should instantiate a tracer when tracing is enabled through constructor', () => { - tracingPublisher = new Publisher(topic, enableTracing); - assert.ok(tracingPublisher['tracing']); - }); - - it('should instantiate a tracer when tracing is enabled through setOptions', () => { - tracingPublisher = new Publisher(topic); - tracingPublisher.setOptions(enableTracing); - assert.ok(tracingPublisher['tracing']); - }); - - it('should disable tracing when tracing is disabled through setOptions', () => { - tracingPublisher = new Publisher(topic, enableTracing); - tracingPublisher.setOptions(disableTracing); - assert.strictEqual(tracingPublisher['tracing'], undefined); - }); - it('export created spans', () => { tracingPublisher = new Publisher(topic, enableTracing); diff --git a/test/subscriber.ts b/test/subscriber.ts index 82064954f..e91085899 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -642,39 +642,10 @@ describe('Subscriber', () => { const enableTracing: s.SubscriberOptions = { enableOpenTelemetryTracing: true, }; - const disableTracing: s.SubscriberOptions = { - enableOpenTelemetryTracing: false, - }; - - beforeEach(() => { - // Pre-define _tracing to gain access to the private field after subscriber init - tracingSubscriber['_tracing'] = undefined; - }); - - it('should not instantiate a tracer when tracing is disabled', () => { - tracingSubscriber = new Subscriber(subscription); - assert.strictEqual(tracingSubscriber['_tracing'], undefined); - }); - - it('should instantiate a tracer when tracing is enabled through constructor', () => { - tracingSubscriber = new Subscriber(subscription, enableTracing); - assert.ok(tracingSubscriber['_tracing']); - }); - - it('should instantiate a tracer when tracing is enabled through setOptions', () => { - tracingSubscriber = new Subscriber(subscription); - tracingSubscriber.setOptions(enableTracing); - assert.ok(tracingSubscriber['_tracing']); - }); - - it('should disable tracing when tracing is disabled through setOptions', () => { - tracingSubscriber = new Subscriber(subscription, enableTracing); - tracingSubscriber.setOptions(disableTracing); - assert.strictEqual(tracingSubscriber['_tracing'], undefined); - }); it('exports a span once it is created', () => { tracingSubscriber = new Subscriber(subscription, enableTracing); + assert.ok(tracingSubscriber); // Setup trace exporting const provider: BasicTracerProvider = new BasicTracerProvider(); From c36c9f5d09a902d658c8d5091032af54f77aa7b8 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 18 Mar 2021 00:21:04 +0000 Subject: [PATCH 04/40] test: updated the span related tests --- test/publisher/index.ts | 13 ++++++++++--- test/subscriber.ts | 3 ++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/test/publisher/index.ts b/test/publisher/index.ts index 3d9860704..b2a206e60 100644 --- a/test/publisher/index.ts +++ b/test/publisher/index.ts @@ -26,7 +26,6 @@ import { SimpleSpanProcessor, } from '@opentelemetry/tracing'; import * as opentelemetry from '@opentelemetry/api'; - import {Topic} from '../../src'; import * as p from '../../src/publisher'; import * as q from '../../src/publisher/message-queues'; @@ -95,7 +94,7 @@ class FakeOrderedQueue extends FakeQueue { describe('Publisher', () => { const sandbox = sinon.createSandbox(); - const topic = {} as Topic; + const topic = {name: 'topic-name'} as Topic; // tslint:disable-next-line variable-name let Publisher: typeof p.Publisher; @@ -193,7 +192,15 @@ describe('Publisher', () => { opentelemetry.trace.setGlobalTracerProvider(provider); tracingPublisher.publish(buffer); - assert.ok(exporter.getFinishedSpans()); + const spans = exporter.getFinishedSpans(); + assert.equal(spans.length, 1, 'has span'); + const createdSpan = spans.shift()!; + assert.strictEqual( + createdSpan.status.code, + opentelemetry.SpanStatusCode.UNSET + ); + assert.strictEqual(createdSpan.name, 'topic-name publisher'); + assert.ok(spans); }); }); diff --git a/test/subscriber.ts b/test/subscriber.ts index e91085899..412ee4398 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -681,7 +681,8 @@ describe('Subscriber', () => { // Receive message and assert that it was exported const stream: FakeMessageStream = stubs.get('messageStream'); stream.emit('data', pullResponse); - assert.ok(exporter.getFinishedSpans()); + const spans = exporter.getFinishedSpans(); + assert.ok(spans); }); it('does not export a span when a span context is not present on message', () => { From e790c2317d134966b3aec5117b1ba3e7f1ccc43f Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 18 Mar 2021 01:12:31 +0000 Subject: [PATCH 05/40] test: updated the tests --- src/subscriber.ts | 7 ++++++- test/subscriber.ts | 12 +++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/subscriber.ts b/src/subscriber.ts index 97b863094..346b8b64a 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -239,6 +239,7 @@ export class Subscriber extends EventEmitter { private _histogram: Histogram; private _inventory!: LeaseManager; private _isUserSetDeadline: boolean; + private _useOpentelemetry: boolean; private _latencies: Histogram; private _modAcks!: ModAckQueue; private _name!: string; @@ -255,6 +256,7 @@ export class Subscriber extends EventEmitter { this.useLegacyFlowControl = false; this.isOpen = false; this._isUserSetDeadline = false; + this._useOpentelemetry = false; this._histogram = new Histogram({min: 10, max: 600}); this._latencies = new Histogram(); this._subscription = subscription; @@ -403,6 +405,8 @@ export class Subscriber extends EventEmitter { setOptions(options: SubscriberOptions): void { this._options = options; + this._useOpentelemetry = options.enableOpenTelemetryTracing || false; + if (options.ackDeadline) { this.ackDeadline = options.ackDeadline; this._isUserSetDeadline = true; @@ -447,7 +451,7 @@ export class Subscriber extends EventEmitter { private _constructSpan(message: Message): Span | undefined { // Handle cases where OpenTelemetry is disabled or no span context was sent through message if ( - !this._tracing || + !this._useOpentelemetry || !message.attributes || !message.attributes['googclient_OpenTelemetrySpanContext'] ) { @@ -491,6 +495,7 @@ export class Subscriber extends EventEmitter { const message = new Message(this, data); const span: Span | undefined = this._constructSpan(message); + if (this.isOpen) { message.modAck(this.ackDeadline); this._inventory.add(message); diff --git a/test/subscriber.ts b/test/subscriber.ts index 82064954f..36f501e5a 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -648,33 +648,35 @@ describe('Subscriber', () => { beforeEach(() => { // Pre-define _tracing to gain access to the private field after subscriber init - tracingSubscriber['_tracing'] = undefined; + tracingSubscriber['_useOpentelemetry'] = false; }); it('should not instantiate a tracer when tracing is disabled', () => { tracingSubscriber = new Subscriber(subscription); - assert.strictEqual(tracingSubscriber['_tracing'], undefined); + assert.strictEqual(tracingSubscriber['_useOpentelemetry'], false); }); it('should instantiate a tracer when tracing is enabled through constructor', () => { tracingSubscriber = new Subscriber(subscription, enableTracing); - assert.ok(tracingSubscriber['_tracing']); + assert.ok(tracingSubscriber['_useOpentelemetry']); }); it('should instantiate a tracer when tracing is enabled through setOptions', () => { tracingSubscriber = new Subscriber(subscription); tracingSubscriber.setOptions(enableTracing); - assert.ok(tracingSubscriber['_tracing']); + assert.ok(tracingSubscriber['_useOpentelemetry']); }); it('should disable tracing when tracing is disabled through setOptions', () => { tracingSubscriber = new Subscriber(subscription, enableTracing); tracingSubscriber.setOptions(disableTracing); - assert.strictEqual(tracingSubscriber['_tracing'], undefined); + assert.strictEqual(tracingSubscriber['_useOpentelemetry'], false); }); it('exports a span once it is created', () => { tracingSubscriber = new Subscriber(subscription, enableTracing); + tracingSubscriber.setOptions(enableTracing); + assert.strictEqual(tracingSubscriber['_useOpentelemetry'], true); // Setup trace exporting const provider: BasicTracerProvider = new BasicTracerProvider(); From d96d2d975343fe92475391de2fe8c68cea139f2a Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 18 Mar 2021 01:14:42 +0000 Subject: [PATCH 06/40] test: updated the tests --- src/subscriber.ts | 7 ++++++- test/subscriber.ts | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/subscriber.ts b/src/subscriber.ts index 41f6dc9e0..975effedb 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -239,6 +239,7 @@ export class Subscriber extends EventEmitter { private _histogram: Histogram; private _inventory!: LeaseManager; private _isUserSetDeadline: boolean; + private _useOpentelemetry: boolean; private _latencies: Histogram; private _modAcks!: ModAckQueue; private _name!: string; @@ -254,6 +255,7 @@ export class Subscriber extends EventEmitter { this.useLegacyFlowControl = false; this.isOpen = false; this._isUserSetDeadline = false; + this._useOpentelemetry = false; this._histogram = new Histogram({min: 10, max: 600}); this._latencies = new Histogram(); this._subscription = subscription; @@ -402,6 +404,8 @@ export class Subscriber extends EventEmitter { setOptions(options: SubscriberOptions): void { this._options = options; + this._useOpentelemetry = options.enableOpenTelemetryTracing || false; + if (options.ackDeadline) { this.ackDeadline = options.ackDeadline; this._isUserSetDeadline = true; @@ -443,7 +447,7 @@ export class Subscriber extends EventEmitter { private _constructSpan(message: Message): Span | undefined { // Handle cases where OpenTelemetry is disabled or no span context was sent through message if ( - !this._options.enableOpenTelemetryTracing || + !this._useOpentelemetry || !message.attributes || !message.attributes['googclient_OpenTelemetrySpanContext'] ) { @@ -487,6 +491,7 @@ export class Subscriber extends EventEmitter { const message = new Message(this, data); const span: Span | undefined = this._constructSpan(message); + if (this.isOpen) { message.modAck(this.ackDeadline); this._inventory.add(message); diff --git a/test/subscriber.ts b/test/subscriber.ts index 412ee4398..280e2d217 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -642,10 +642,41 @@ describe('Subscriber', () => { const enableTracing: s.SubscriberOptions = { enableOpenTelemetryTracing: true, }; + const disableTracing: s.SubscriberOptions = { + enableOpenTelemetryTracing: false, + }; + + beforeEach(() => { + // Pre-define _tracing to gain access to the private field after subscriber init + tracingSubscriber['_useOpentelemetry'] = false; + }); + + it('should not instantiate a tracer when tracing is disabled', () => { + tracingSubscriber = new Subscriber(subscription); + assert.strictEqual(tracingSubscriber['_useOpentelemetry'], false); + }); + + it('should instantiate a tracer when tracing is enabled through constructor', () => { + tracingSubscriber = new Subscriber(subscription, enableTracing); + assert.ok(tracingSubscriber['_useOpentelemetry']); + }); + + it('should instantiate a tracer when tracing is enabled through setOptions', () => { + tracingSubscriber = new Subscriber(subscription); + tracingSubscriber.setOptions(enableTracing); + assert.ok(tracingSubscriber['_useOpentelemetry']); + }); + + it('should disable tracing when tracing is disabled through setOptions', () => { + tracingSubscriber = new Subscriber(subscription, enableTracing); + tracingSubscriber.setOptions(disableTracing); + assert.strictEqual(tracingSubscriber['_useOpentelemetry'], false); + }); it('exports a span once it is created', () => { tracingSubscriber = new Subscriber(subscription, enableTracing); - assert.ok(tracingSubscriber); + tracingSubscriber.setOptions(enableTracing); + assert.strictEqual(tracingSubscriber['_useOpentelemetry'], true); // Setup trace exporting const provider: BasicTracerProvider = new BasicTracerProvider(); From 92b1a4c03bb417b02b78cb94f416551435513584 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 18 Mar 2021 17:38:27 +0000 Subject: [PATCH 07/40] refactor: move the tracer out of the `createSpan`-function Small refactor to ensure no new tracer gets created for each call to the `createSpan`-functio by initiating the `libraryTracer`-variable --- src/opentelemetry-tracing.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/opentelemetry-tracing.ts b/src/opentelemetry-tracing.ts index f0122d390..17e1414b1 100644 --- a/src/opentelemetry-tracing.ts +++ b/src/opentelemetry-tracing.ts @@ -23,6 +23,12 @@ import { setSpanContext, } from '@opentelemetry/api'; +/** + * @internal + * Instantiates a Opentelemetry tracer for the library + */ +const libraryTracer: Tracer = trace.getTracer('@google-cloud/pubsub'); + /** * Creates a new span with the given properties * @@ -35,9 +41,7 @@ export function createSpan( attributes?: SpanAttributes, parent?: SpanContext ): Span { - const tracerProvider: Tracer = trace.getTracer('default') as Tracer; - - return tracerProvider.startSpan( + return libraryTracer.startSpan( spanName, { attributes: attributes, From 1f6f7e2218bab4c54c34efe49f59d04b689bb2a3 Mon Sep 17 00:00:00 2001 From: Megan Potter Date: Wed, 24 Mar 2021 15:50:59 -0400 Subject: [PATCH 08/40] fix: get the unit test for publisher opentelemetry working again --- src/opentelemetry-tracing.ts | 9 +++------ test/publisher/index.ts | 3 +-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/opentelemetry-tracing.ts b/src/opentelemetry-tracing.ts index 17e1414b1..f03e6d72d 100644 --- a/src/opentelemetry-tracing.ts +++ b/src/opentelemetry-tracing.ts @@ -23,12 +23,6 @@ import { setSpanContext, } from '@opentelemetry/api'; -/** - * @internal - * Instantiates a Opentelemetry tracer for the library - */ -const libraryTracer: Tracer = trace.getTracer('@google-cloud/pubsub'); - /** * Creates a new span with the given properties * @@ -41,6 +35,9 @@ export function createSpan( attributes?: SpanAttributes, parent?: SpanContext ): Span { + // Should return the existing one, if we have one, or create a new one. + const libraryTracer: Tracer = trace.getTracer('@google-cloud/pubsub'); + return libraryTracer.startSpan( spanName, { diff --git a/test/publisher/index.ts b/test/publisher/index.ts index b2a206e60..2735ebb78 100644 --- a/test/publisher/index.ts +++ b/test/publisher/index.ts @@ -188,12 +188,11 @@ describe('Publisher', () => { const provider: BasicTracerProvider = new BasicTracerProvider(); const exporter: InMemorySpanExporter = new InMemorySpanExporter(); provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - provider.register(); opentelemetry.trace.setGlobalTracerProvider(provider); tracingPublisher.publish(buffer); const spans = exporter.getFinishedSpans(); - assert.equal(spans.length, 1, 'has span'); + assert.strictEqual(spans.length, 1, 'has span'); const createdSpan = spans.shift()!; assert.strictEqual( createdSpan.status.code, From 0035983291243338b89b4c6dff30ca2101be116c Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 30 Mar 2021 22:07:46 +0100 Subject: [PATCH 09/40] test: fix the subscriber unit tests for opentelemetry --- package.json | 2 +- protos/protos.d.ts | 249 +++++++++++++ protos/protos.js | 688 ++++++++++++++++++++++++++++++++++- protos/protos.json | 79 +++- src/opentelemetry-tracing.ts | 9 +- src/subscriber.ts | 4 +- test/subscriber.ts | 49 +-- 7 files changed, 1048 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 2c1e0f825..8c87e5960 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@google-cloud/precise-date": "^2.0.0", "@google-cloud/projectify": "^2.0.0", "@google-cloud/promisify": "^2.0.0", - "@opentelemetry/api": "^0.18.0", + "@opentelemetry/api": "^0.18.1", "@types/duplexify": "^3.6.0", "@types/long": "^4.0.0", "arrify": "^2.0.0", diff --git a/protos/protos.d.ts b/protos/protos.d.ts index 6ae2e2767..2bc15192a 100644 --- a/protos/protos.d.ts +++ b/protos/protos.d.ts @@ -6210,6 +6210,9 @@ export namespace google { /** Http rules */ rules?: (google.api.IHttpRule[]|null); + + /** Http fullyDecodeReservedExpansion */ + fullyDecodeReservedExpansion?: (boolean|null); } /** Represents a Http. */ @@ -6224,6 +6227,9 @@ export namespace google { /** Http rules. */ public rules: google.api.IHttpRule[]; + /** Http fullyDecodeReservedExpansion. */ + public fullyDecodeReservedExpansion: boolean; + /** * Creates a new Http instance using the specified properties. * @param [properties] Properties to set @@ -6322,6 +6328,9 @@ export namespace google { /** HttpRule body */ body?: (string|null); + /** HttpRule responseBody */ + responseBody?: (string|null); + /** HttpRule additionalBindings */ additionalBindings?: (google.api.IHttpRule[]|null); } @@ -6359,6 +6368,9 @@ export namespace google { /** HttpRule body. */ public body: string; + /** HttpRule responseBody. */ + public responseBody: string; + /** HttpRule additionalBindings. */ public additionalBindings: google.api.IHttpRule[]; @@ -7185,6 +7197,9 @@ export namespace google { /** ExtensionRange end */ end?: (number|null); + + /** ExtensionRange options */ + options?: (google.protobuf.IExtensionRangeOptions|null); } /** Represents an ExtensionRange. */ @@ -7202,6 +7217,9 @@ export namespace google { /** ExtensionRange end. */ public end: number; + /** ExtensionRange options. */ + public options?: (google.protobuf.IExtensionRangeOptions|null); + /** * Creates a new ExtensionRange instance using the specified properties. * @param [properties] Properties to set @@ -7370,6 +7388,96 @@ export namespace google { } } + /** Properties of an ExtensionRangeOptions. */ + interface IExtensionRangeOptions { + + /** ExtensionRangeOptions uninterpretedOption */ + uninterpretedOption?: (google.protobuf.IUninterpretedOption[]|null); + } + + /** Represents an ExtensionRangeOptions. */ + class ExtensionRangeOptions implements IExtensionRangeOptions { + + /** + * Constructs a new ExtensionRangeOptions. + * @param [properties] Properties to set + */ + constructor(properties?: google.protobuf.IExtensionRangeOptions); + + /** ExtensionRangeOptions uninterpretedOption. */ + public uninterpretedOption: google.protobuf.IUninterpretedOption[]; + + /** + * Creates a new ExtensionRangeOptions instance using the specified properties. + * @param [properties] Properties to set + * @returns ExtensionRangeOptions instance + */ + public static create(properties?: google.protobuf.IExtensionRangeOptions): google.protobuf.ExtensionRangeOptions; + + /** + * Encodes the specified ExtensionRangeOptions message. Does not implicitly {@link google.protobuf.ExtensionRangeOptions.verify|verify} messages. + * @param message ExtensionRangeOptions message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: google.protobuf.IExtensionRangeOptions, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified ExtensionRangeOptions message, length delimited. Does not implicitly {@link google.protobuf.ExtensionRangeOptions.verify|verify} messages. + * @param message ExtensionRangeOptions message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: google.protobuf.IExtensionRangeOptions, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an ExtensionRangeOptions message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns ExtensionRangeOptions + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.ExtensionRangeOptions; + + /** + * Decodes an ExtensionRangeOptions message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns ExtensionRangeOptions + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.ExtensionRangeOptions; + + /** + * Verifies an ExtensionRangeOptions message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates an ExtensionRangeOptions message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns ExtensionRangeOptions + */ + public static fromObject(object: { [k: string]: any }): google.protobuf.ExtensionRangeOptions; + + /** + * Creates a plain object from an ExtensionRangeOptions message. Also converts values to other types if specified. + * @param message ExtensionRangeOptions + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: google.protobuf.ExtensionRangeOptions, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this ExtensionRangeOptions to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; + } + /** Properties of a FieldDescriptorProto. */ interface IFieldDescriptorProto { @@ -7402,6 +7510,9 @@ export namespace google { /** FieldDescriptorProto options */ options?: (google.protobuf.IFieldOptions|null); + + /** FieldDescriptorProto proto3Optional */ + proto3Optional?: (boolean|null); } /** Represents a FieldDescriptorProto. */ @@ -7443,6 +7554,9 @@ export namespace google { /** FieldDescriptorProto options. */ public options?: (google.protobuf.IFieldOptions|null); + /** FieldDescriptorProto proto3Optional. */ + public proto3Optional: boolean; + /** * Creates a new FieldDescriptorProto instance using the specified properties. * @param [properties] Properties to set @@ -7653,6 +7767,12 @@ export namespace google { /** EnumDescriptorProto options */ options?: (google.protobuf.IEnumOptions|null); + + /** EnumDescriptorProto reservedRange */ + reservedRange?: (google.protobuf.EnumDescriptorProto.IEnumReservedRange[]|null); + + /** EnumDescriptorProto reservedName */ + reservedName?: (string[]|null); } /** Represents an EnumDescriptorProto. */ @@ -7673,6 +7793,12 @@ export namespace google { /** EnumDescriptorProto options. */ public options?: (google.protobuf.IEnumOptions|null); + /** EnumDescriptorProto reservedRange. */ + public reservedRange: google.protobuf.EnumDescriptorProto.IEnumReservedRange[]; + + /** EnumDescriptorProto reservedName. */ + public reservedName: string[]; + /** * Creates a new EnumDescriptorProto instance using the specified properties. * @param [properties] Properties to set @@ -7744,6 +7870,105 @@ export namespace google { public toJSON(): { [k: string]: any }; } + namespace EnumDescriptorProto { + + /** Properties of an EnumReservedRange. */ + interface IEnumReservedRange { + + /** EnumReservedRange start */ + start?: (number|null); + + /** EnumReservedRange end */ + end?: (number|null); + } + + /** Represents an EnumReservedRange. */ + class EnumReservedRange implements IEnumReservedRange { + + /** + * Constructs a new EnumReservedRange. + * @param [properties] Properties to set + */ + constructor(properties?: google.protobuf.EnumDescriptorProto.IEnumReservedRange); + + /** EnumReservedRange start. */ + public start: number; + + /** EnumReservedRange end. */ + public end: number; + + /** + * Creates a new EnumReservedRange instance using the specified properties. + * @param [properties] Properties to set + * @returns EnumReservedRange instance + */ + public static create(properties?: google.protobuf.EnumDescriptorProto.IEnumReservedRange): google.protobuf.EnumDescriptorProto.EnumReservedRange; + + /** + * Encodes the specified EnumReservedRange message. Does not implicitly {@link google.protobuf.EnumDescriptorProto.EnumReservedRange.verify|verify} messages. + * @param message EnumReservedRange message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: google.protobuf.EnumDescriptorProto.IEnumReservedRange, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified EnumReservedRange message, length delimited. Does not implicitly {@link google.protobuf.EnumDescriptorProto.EnumReservedRange.verify|verify} messages. + * @param message EnumReservedRange message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: google.protobuf.EnumDescriptorProto.IEnumReservedRange, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an EnumReservedRange message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns EnumReservedRange + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.EnumDescriptorProto.EnumReservedRange; + + /** + * Decodes an EnumReservedRange message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns EnumReservedRange + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.EnumDescriptorProto.EnumReservedRange; + + /** + * Verifies an EnumReservedRange message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates an EnumReservedRange message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns EnumReservedRange + */ + public static fromObject(object: { [k: string]: any }): google.protobuf.EnumDescriptorProto.EnumReservedRange; + + /** + * Creates a plain object from an EnumReservedRange message. Also converts values to other types if specified. + * @param message EnumReservedRange + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: google.protobuf.EnumDescriptorProto.EnumReservedRange, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this EnumReservedRange to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; + } + } + /** Properties of an EnumValueDescriptorProto. */ interface IEnumValueDescriptorProto { @@ -8101,6 +8326,9 @@ export namespace google { /** FileOptions pyGenericServices */ pyGenericServices?: (boolean|null); + /** FileOptions phpGenericServices */ + phpGenericServices?: (boolean|null); + /** FileOptions deprecated */ deprecated?: (boolean|null); @@ -8119,6 +8347,15 @@ export namespace google { /** FileOptions phpClassPrefix */ phpClassPrefix?: (string|null); + /** FileOptions phpNamespace */ + phpNamespace?: (string|null); + + /** FileOptions phpMetadataNamespace */ + phpMetadataNamespace?: (string|null); + + /** FileOptions rubyPackage */ + rubyPackage?: (string|null); + /** FileOptions uninterpretedOption */ uninterpretedOption?: (google.protobuf.IUninterpretedOption[]|null); @@ -8165,6 +8402,9 @@ export namespace google { /** FileOptions pyGenericServices. */ public pyGenericServices: boolean; + /** FileOptions phpGenericServices. */ + public phpGenericServices: boolean; + /** FileOptions deprecated. */ public deprecated: boolean; @@ -8183,6 +8423,15 @@ export namespace google { /** FileOptions phpClassPrefix. */ public phpClassPrefix: string; + /** FileOptions phpNamespace. */ + public phpNamespace: string; + + /** FileOptions phpMetadataNamespace. */ + public phpMetadataNamespace: string; + + /** FileOptions rubyPackage. */ + public rubyPackage: string; + /** FileOptions uninterpretedOption. */ public uninterpretedOption: google.protobuf.IUninterpretedOption[]; diff --git a/protos/protos.js b/protos/protos.js index 456396fe5..2d3c27e71 100644 --- a/protos/protos.js +++ b/protos/protos.js @@ -14123,6 +14123,7 @@ * @memberof google.api * @interface IHttp * @property {Array.|null} [rules] Http rules + * @property {boolean|null} [fullyDecodeReservedExpansion] Http fullyDecodeReservedExpansion */ /** @@ -14149,6 +14150,14 @@ */ Http.prototype.rules = $util.emptyArray; + /** + * Http fullyDecodeReservedExpansion. + * @member {boolean} fullyDecodeReservedExpansion + * @memberof google.api.Http + * @instance + */ + Http.prototype.fullyDecodeReservedExpansion = false; + /** * Creates a new Http instance using the specified properties. * @function create @@ -14176,6 +14185,8 @@ if (message.rules != null && message.rules.length) for (var i = 0; i < message.rules.length; ++i) $root.google.api.HttpRule.encode(message.rules[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.fullyDecodeReservedExpansion != null && Object.hasOwnProperty.call(message, "fullyDecodeReservedExpansion")) + writer.uint32(/* id 2, wireType 0 =*/16).bool(message.fullyDecodeReservedExpansion); return writer; }; @@ -14215,6 +14226,9 @@ message.rules = []; message.rules.push($root.google.api.HttpRule.decode(reader, reader.uint32())); break; + case 2: + message.fullyDecodeReservedExpansion = reader.bool(); + break; default: reader.skipType(tag & 7); break; @@ -14259,6 +14273,9 @@ return "rules." + error; } } + if (message.fullyDecodeReservedExpansion != null && message.hasOwnProperty("fullyDecodeReservedExpansion")) + if (typeof message.fullyDecodeReservedExpansion !== "boolean") + return "fullyDecodeReservedExpansion: boolean expected"; return null; }; @@ -14284,6 +14301,8 @@ message.rules[i] = $root.google.api.HttpRule.fromObject(object.rules[i]); } } + if (object.fullyDecodeReservedExpansion != null) + message.fullyDecodeReservedExpansion = Boolean(object.fullyDecodeReservedExpansion); return message; }; @@ -14302,11 +14321,15 @@ var object = {}; if (options.arrays || options.defaults) object.rules = []; + if (options.defaults) + object.fullyDecodeReservedExpansion = false; if (message.rules && message.rules.length) { object.rules = []; for (var j = 0; j < message.rules.length; ++j) object.rules[j] = $root.google.api.HttpRule.toObject(message.rules[j], options); } + if (message.fullyDecodeReservedExpansion != null && message.hasOwnProperty("fullyDecodeReservedExpansion")) + object.fullyDecodeReservedExpansion = message.fullyDecodeReservedExpansion; return object; }; @@ -14338,6 +14361,7 @@ * @property {string|null} [patch] HttpRule patch * @property {google.api.ICustomHttpPattern|null} [custom] HttpRule custom * @property {string|null} [body] HttpRule body + * @property {string|null} [responseBody] HttpRule responseBody * @property {Array.|null} [additionalBindings] HttpRule additionalBindings */ @@ -14421,6 +14445,14 @@ */ HttpRule.prototype.body = ""; + /** + * HttpRule responseBody. + * @member {string} responseBody + * @memberof google.api.HttpRule + * @instance + */ + HttpRule.prototype.responseBody = ""; + /** * HttpRule additionalBindings. * @member {Array.} additionalBindings @@ -14486,6 +14518,8 @@ if (message.additionalBindings != null && message.additionalBindings.length) for (var i = 0; i < message.additionalBindings.length; ++i) $root.google.api.HttpRule.encode(message.additionalBindings[i], writer.uint32(/* id 11, wireType 2 =*/90).fork()).ldelim(); + if (message.responseBody != null && Object.hasOwnProperty.call(message, "responseBody")) + writer.uint32(/* id 12, wireType 2 =*/98).string(message.responseBody); return writer; }; @@ -14544,6 +14578,9 @@ case 7: message.body = reader.string(); break; + case 12: + message.responseBody = reader.string(); + break; case 11: if (!(message.additionalBindings && message.additionalBindings.length)) message.additionalBindings = []; @@ -14634,6 +14671,9 @@ if (message.body != null && message.hasOwnProperty("body")) if (!$util.isString(message.body)) return "body: string expected"; + if (message.responseBody != null && message.hasOwnProperty("responseBody")) + if (!$util.isString(message.responseBody)) + return "responseBody: string expected"; if (message.additionalBindings != null && message.hasOwnProperty("additionalBindings")) { if (!Array.isArray(message.additionalBindings)) return "additionalBindings: array expected"; @@ -14677,6 +14717,8 @@ } if (object.body != null) message.body = String(object.body); + if (object.responseBody != null) + message.responseBody = String(object.responseBody); if (object.additionalBindings) { if (!Array.isArray(object.additionalBindings)) throw TypeError(".google.api.HttpRule.additionalBindings: array expected"); @@ -14708,6 +14750,7 @@ if (options.defaults) { object.selector = ""; object.body = ""; + object.responseBody = ""; } if (message.selector != null && message.hasOwnProperty("selector")) object.selector = message.selector; @@ -14748,6 +14791,8 @@ for (var j = 0; j < message.additionalBindings.length; ++j) object.additionalBindings[j] = $root.google.api.HttpRule.toObject(message.additionalBindings[j], options); } + if (message.responseBody != null && message.hasOwnProperty("responseBody")) + object.responseBody = message.responseBody; return object; }; @@ -16999,6 +17044,7 @@ * @interface IExtensionRange * @property {number|null} [start] ExtensionRange start * @property {number|null} [end] ExtensionRange end + * @property {google.protobuf.IExtensionRangeOptions|null} [options] ExtensionRange options */ /** @@ -17032,6 +17078,14 @@ */ ExtensionRange.prototype.end = 0; + /** + * ExtensionRange options. + * @member {google.protobuf.IExtensionRangeOptions|null|undefined} options + * @memberof google.protobuf.DescriptorProto.ExtensionRange + * @instance + */ + ExtensionRange.prototype.options = null; + /** * Creates a new ExtensionRange instance using the specified properties. * @function create @@ -17060,6 +17114,8 @@ writer.uint32(/* id 1, wireType 0 =*/8).int32(message.start); if (message.end != null && Object.hasOwnProperty.call(message, "end")) writer.uint32(/* id 2, wireType 0 =*/16).int32(message.end); + if (message.options != null && Object.hasOwnProperty.call(message, "options")) + $root.google.protobuf.ExtensionRangeOptions.encode(message.options, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); return writer; }; @@ -17100,6 +17156,9 @@ case 2: message.end = reader.int32(); break; + case 3: + message.options = $root.google.protobuf.ExtensionRangeOptions.decode(reader, reader.uint32()); + break; default: reader.skipType(tag & 7); break; @@ -17141,6 +17200,11 @@ if (message.end != null && message.hasOwnProperty("end")) if (!$util.isInteger(message.end)) return "end: integer expected"; + if (message.options != null && message.hasOwnProperty("options")) { + var error = $root.google.protobuf.ExtensionRangeOptions.verify(message.options); + if (error) + return "options." + error; + } return null; }; @@ -17160,6 +17224,11 @@ message.start = object.start | 0; if (object.end != null) message.end = object.end | 0; + if (object.options != null) { + if (typeof object.options !== "object") + throw TypeError(".google.protobuf.DescriptorProto.ExtensionRange.options: object expected"); + message.options = $root.google.protobuf.ExtensionRangeOptions.fromObject(object.options); + } return message; }; @@ -17179,11 +17248,14 @@ if (options.defaults) { object.start = 0; object.end = 0; + object.options = null; } if (message.start != null && message.hasOwnProperty("start")) object.start = message.start; if (message.end != null && message.hasOwnProperty("end")) object.end = message.end; + if (message.options != null && message.hasOwnProperty("options")) + object.options = $root.google.protobuf.ExtensionRangeOptions.toObject(message.options, options); return object; }; @@ -17414,6 +17486,214 @@ return DescriptorProto; })(); + protobuf.ExtensionRangeOptions = (function() { + + /** + * Properties of an ExtensionRangeOptions. + * @memberof google.protobuf + * @interface IExtensionRangeOptions + * @property {Array.|null} [uninterpretedOption] ExtensionRangeOptions uninterpretedOption + */ + + /** + * Constructs a new ExtensionRangeOptions. + * @memberof google.protobuf + * @classdesc Represents an ExtensionRangeOptions. + * @implements IExtensionRangeOptions + * @constructor + * @param {google.protobuf.IExtensionRangeOptions=} [properties] Properties to set + */ + function ExtensionRangeOptions(properties) { + this.uninterpretedOption = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * ExtensionRangeOptions uninterpretedOption. + * @member {Array.} uninterpretedOption + * @memberof google.protobuf.ExtensionRangeOptions + * @instance + */ + ExtensionRangeOptions.prototype.uninterpretedOption = $util.emptyArray; + + /** + * Creates a new ExtensionRangeOptions instance using the specified properties. + * @function create + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {google.protobuf.IExtensionRangeOptions=} [properties] Properties to set + * @returns {google.protobuf.ExtensionRangeOptions} ExtensionRangeOptions instance + */ + ExtensionRangeOptions.create = function create(properties) { + return new ExtensionRangeOptions(properties); + }; + + /** + * Encodes the specified ExtensionRangeOptions message. Does not implicitly {@link google.protobuf.ExtensionRangeOptions.verify|verify} messages. + * @function encode + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {google.protobuf.IExtensionRangeOptions} message ExtensionRangeOptions message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ExtensionRangeOptions.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.uninterpretedOption != null && message.uninterpretedOption.length) + for (var i = 0; i < message.uninterpretedOption.length; ++i) + $root.google.protobuf.UninterpretedOption.encode(message.uninterpretedOption[i], writer.uint32(/* id 999, wireType 2 =*/7994).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified ExtensionRangeOptions message, length delimited. Does not implicitly {@link google.protobuf.ExtensionRangeOptions.verify|verify} messages. + * @function encodeDelimited + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {google.protobuf.IExtensionRangeOptions} message ExtensionRangeOptions message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ExtensionRangeOptions.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an ExtensionRangeOptions message from the specified reader or buffer. + * @function decode + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {google.protobuf.ExtensionRangeOptions} ExtensionRangeOptions + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ExtensionRangeOptions.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.ExtensionRangeOptions(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 999: + if (!(message.uninterpretedOption && message.uninterpretedOption.length)) + message.uninterpretedOption = []; + message.uninterpretedOption.push($root.google.protobuf.UninterpretedOption.decode(reader, reader.uint32())); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an ExtensionRangeOptions message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {google.protobuf.ExtensionRangeOptions} ExtensionRangeOptions + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ExtensionRangeOptions.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an ExtensionRangeOptions message. + * @function verify + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + ExtensionRangeOptions.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.uninterpretedOption != null && message.hasOwnProperty("uninterpretedOption")) { + if (!Array.isArray(message.uninterpretedOption)) + return "uninterpretedOption: array expected"; + for (var i = 0; i < message.uninterpretedOption.length; ++i) { + var error = $root.google.protobuf.UninterpretedOption.verify(message.uninterpretedOption[i]); + if (error) + return "uninterpretedOption." + error; + } + } + return null; + }; + + /** + * Creates an ExtensionRangeOptions message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {Object.} object Plain object + * @returns {google.protobuf.ExtensionRangeOptions} ExtensionRangeOptions + */ + ExtensionRangeOptions.fromObject = function fromObject(object) { + if (object instanceof $root.google.protobuf.ExtensionRangeOptions) + return object; + var message = new $root.google.protobuf.ExtensionRangeOptions(); + if (object.uninterpretedOption) { + if (!Array.isArray(object.uninterpretedOption)) + throw TypeError(".google.protobuf.ExtensionRangeOptions.uninterpretedOption: array expected"); + message.uninterpretedOption = []; + for (var i = 0; i < object.uninterpretedOption.length; ++i) { + if (typeof object.uninterpretedOption[i] !== "object") + throw TypeError(".google.protobuf.ExtensionRangeOptions.uninterpretedOption: object expected"); + message.uninterpretedOption[i] = $root.google.protobuf.UninterpretedOption.fromObject(object.uninterpretedOption[i]); + } + } + return message; + }; + + /** + * Creates a plain object from an ExtensionRangeOptions message. Also converts values to other types if specified. + * @function toObject + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {google.protobuf.ExtensionRangeOptions} message ExtensionRangeOptions + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + ExtensionRangeOptions.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.uninterpretedOption = []; + if (message.uninterpretedOption && message.uninterpretedOption.length) { + object.uninterpretedOption = []; + for (var j = 0; j < message.uninterpretedOption.length; ++j) + object.uninterpretedOption[j] = $root.google.protobuf.UninterpretedOption.toObject(message.uninterpretedOption[j], options); + } + return object; + }; + + /** + * Converts this ExtensionRangeOptions to JSON. + * @function toJSON + * @memberof google.protobuf.ExtensionRangeOptions + * @instance + * @returns {Object.} JSON object + */ + ExtensionRangeOptions.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return ExtensionRangeOptions; + })(); + protobuf.FieldDescriptorProto = (function() { /** @@ -17430,6 +17710,7 @@ * @property {number|null} [oneofIndex] FieldDescriptorProto oneofIndex * @property {string|null} [jsonName] FieldDescriptorProto jsonName * @property {google.protobuf.IFieldOptions|null} [options] FieldDescriptorProto options + * @property {boolean|null} [proto3Optional] FieldDescriptorProto proto3Optional */ /** @@ -17527,6 +17808,14 @@ */ FieldDescriptorProto.prototype.options = null; + /** + * FieldDescriptorProto proto3Optional. + * @member {boolean} proto3Optional + * @memberof google.protobuf.FieldDescriptorProto + * @instance + */ + FieldDescriptorProto.prototype.proto3Optional = false; + /** * Creates a new FieldDescriptorProto instance using the specified properties. * @function create @@ -17571,6 +17860,8 @@ writer.uint32(/* id 9, wireType 0 =*/72).int32(message.oneofIndex); if (message.jsonName != null && Object.hasOwnProperty.call(message, "jsonName")) writer.uint32(/* id 10, wireType 2 =*/82).string(message.jsonName); + if (message.proto3Optional != null && Object.hasOwnProperty.call(message, "proto3Optional")) + writer.uint32(/* id 17, wireType 0 =*/136).bool(message.proto3Optional); return writer; }; @@ -17635,6 +17926,9 @@ case 8: message.options = $root.google.protobuf.FieldOptions.decode(reader, reader.uint32()); break; + case 17: + message.proto3Optional = reader.bool(); + break; default: reader.skipType(tag & 7); break; @@ -17729,6 +18023,9 @@ if (error) return "options." + error; } + if (message.proto3Optional != null && message.hasOwnProperty("proto3Optional")) + if (typeof message.proto3Optional !== "boolean") + return "proto3Optional: boolean expected"; return null; }; @@ -17851,6 +18148,8 @@ throw TypeError(".google.protobuf.FieldDescriptorProto.options: object expected"); message.options = $root.google.protobuf.FieldOptions.fromObject(object.options); } + if (object.proto3Optional != null) + message.proto3Optional = Boolean(object.proto3Optional); return message; }; @@ -17878,6 +18177,7 @@ object.options = null; object.oneofIndex = 0; object.jsonName = ""; + object.proto3Optional = false; } if (message.name != null && message.hasOwnProperty("name")) object.name = message.name; @@ -17899,6 +18199,8 @@ object.oneofIndex = message.oneofIndex; if (message.jsonName != null && message.hasOwnProperty("jsonName")) object.jsonName = message.jsonName; + if (message.proto3Optional != null && message.hasOwnProperty("proto3Optional")) + object.proto3Optional = message.proto3Optional; return object; }; @@ -18202,6 +18504,8 @@ * @property {string|null} [name] EnumDescriptorProto name * @property {Array.|null} [value] EnumDescriptorProto value * @property {google.protobuf.IEnumOptions|null} [options] EnumDescriptorProto options + * @property {Array.|null} [reservedRange] EnumDescriptorProto reservedRange + * @property {Array.|null} [reservedName] EnumDescriptorProto reservedName */ /** @@ -18214,6 +18518,8 @@ */ function EnumDescriptorProto(properties) { this.value = []; + this.reservedRange = []; + this.reservedName = []; if (properties) for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) if (properties[keys[i]] != null) @@ -18244,6 +18550,22 @@ */ EnumDescriptorProto.prototype.options = null; + /** + * EnumDescriptorProto reservedRange. + * @member {Array.} reservedRange + * @memberof google.protobuf.EnumDescriptorProto + * @instance + */ + EnumDescriptorProto.prototype.reservedRange = $util.emptyArray; + + /** + * EnumDescriptorProto reservedName. + * @member {Array.} reservedName + * @memberof google.protobuf.EnumDescriptorProto + * @instance + */ + EnumDescriptorProto.prototype.reservedName = $util.emptyArray; + /** * Creates a new EnumDescriptorProto instance using the specified properties. * @function create @@ -18275,6 +18597,12 @@ $root.google.protobuf.EnumValueDescriptorProto.encode(message.value[i], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); if (message.options != null && Object.hasOwnProperty.call(message, "options")) $root.google.protobuf.EnumOptions.encode(message.options, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + if (message.reservedRange != null && message.reservedRange.length) + for (var i = 0; i < message.reservedRange.length; ++i) + $root.google.protobuf.EnumDescriptorProto.EnumReservedRange.encode(message.reservedRange[i], writer.uint32(/* id 4, wireType 2 =*/34).fork()).ldelim(); + if (message.reservedName != null && message.reservedName.length) + for (var i = 0; i < message.reservedName.length; ++i) + writer.uint32(/* id 5, wireType 2 =*/42).string(message.reservedName[i]); return writer; }; @@ -18320,6 +18648,16 @@ case 3: message.options = $root.google.protobuf.EnumOptions.decode(reader, reader.uint32()); break; + case 4: + if (!(message.reservedRange && message.reservedRange.length)) + message.reservedRange = []; + message.reservedRange.push($root.google.protobuf.EnumDescriptorProto.EnumReservedRange.decode(reader, reader.uint32())); + break; + case 5: + if (!(message.reservedName && message.reservedName.length)) + message.reservedName = []; + message.reservedName.push(reader.string()); + break; default: reader.skipType(tag & 7); break; @@ -18372,6 +18710,22 @@ if (error) return "options." + error; } + if (message.reservedRange != null && message.hasOwnProperty("reservedRange")) { + if (!Array.isArray(message.reservedRange)) + return "reservedRange: array expected"; + for (var i = 0; i < message.reservedRange.length; ++i) { + var error = $root.google.protobuf.EnumDescriptorProto.EnumReservedRange.verify(message.reservedRange[i]); + if (error) + return "reservedRange." + error; + } + } + if (message.reservedName != null && message.hasOwnProperty("reservedName")) { + if (!Array.isArray(message.reservedName)) + return "reservedName: array expected"; + for (var i = 0; i < message.reservedName.length; ++i) + if (!$util.isString(message.reservedName[i])) + return "reservedName: string[] expected"; + } return null; }; @@ -18404,6 +18758,23 @@ throw TypeError(".google.protobuf.EnumDescriptorProto.options: object expected"); message.options = $root.google.protobuf.EnumOptions.fromObject(object.options); } + if (object.reservedRange) { + if (!Array.isArray(object.reservedRange)) + throw TypeError(".google.protobuf.EnumDescriptorProto.reservedRange: array expected"); + message.reservedRange = []; + for (var i = 0; i < object.reservedRange.length; ++i) { + if (typeof object.reservedRange[i] !== "object") + throw TypeError(".google.protobuf.EnumDescriptorProto.reservedRange: object expected"); + message.reservedRange[i] = $root.google.protobuf.EnumDescriptorProto.EnumReservedRange.fromObject(object.reservedRange[i]); + } + } + if (object.reservedName) { + if (!Array.isArray(object.reservedName)) + throw TypeError(".google.protobuf.EnumDescriptorProto.reservedName: array expected"); + message.reservedName = []; + for (var i = 0; i < object.reservedName.length; ++i) + message.reservedName[i] = String(object.reservedName[i]); + } return message; }; @@ -18420,8 +18791,11 @@ if (!options) options = {}; var object = {}; - if (options.arrays || options.defaults) + if (options.arrays || options.defaults) { object.value = []; + object.reservedRange = []; + object.reservedName = []; + } if (options.defaults) { object.name = ""; object.options = null; @@ -18435,6 +18809,16 @@ } if (message.options != null && message.hasOwnProperty("options")) object.options = $root.google.protobuf.EnumOptions.toObject(message.options, options); + if (message.reservedRange && message.reservedRange.length) { + object.reservedRange = []; + for (var j = 0; j < message.reservedRange.length; ++j) + object.reservedRange[j] = $root.google.protobuf.EnumDescriptorProto.EnumReservedRange.toObject(message.reservedRange[j], options); + } + if (message.reservedName && message.reservedName.length) { + object.reservedName = []; + for (var j = 0; j < message.reservedName.length; ++j) + object.reservedName[j] = message.reservedName[j]; + } return object; }; @@ -18449,6 +18833,216 @@ return this.constructor.toObject(this, $protobuf.util.toJSONOptions); }; + EnumDescriptorProto.EnumReservedRange = (function() { + + /** + * Properties of an EnumReservedRange. + * @memberof google.protobuf.EnumDescriptorProto + * @interface IEnumReservedRange + * @property {number|null} [start] EnumReservedRange start + * @property {number|null} [end] EnumReservedRange end + */ + + /** + * Constructs a new EnumReservedRange. + * @memberof google.protobuf.EnumDescriptorProto + * @classdesc Represents an EnumReservedRange. + * @implements IEnumReservedRange + * @constructor + * @param {google.protobuf.EnumDescriptorProto.IEnumReservedRange=} [properties] Properties to set + */ + function EnumReservedRange(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * EnumReservedRange start. + * @member {number} start + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @instance + */ + EnumReservedRange.prototype.start = 0; + + /** + * EnumReservedRange end. + * @member {number} end + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @instance + */ + EnumReservedRange.prototype.end = 0; + + /** + * Creates a new EnumReservedRange instance using the specified properties. + * @function create + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {google.protobuf.EnumDescriptorProto.IEnumReservedRange=} [properties] Properties to set + * @returns {google.protobuf.EnumDescriptorProto.EnumReservedRange} EnumReservedRange instance + */ + EnumReservedRange.create = function create(properties) { + return new EnumReservedRange(properties); + }; + + /** + * Encodes the specified EnumReservedRange message. Does not implicitly {@link google.protobuf.EnumDescriptorProto.EnumReservedRange.verify|verify} messages. + * @function encode + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {google.protobuf.EnumDescriptorProto.IEnumReservedRange} message EnumReservedRange message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + EnumReservedRange.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.start != null && Object.hasOwnProperty.call(message, "start")) + writer.uint32(/* id 1, wireType 0 =*/8).int32(message.start); + if (message.end != null && Object.hasOwnProperty.call(message, "end")) + writer.uint32(/* id 2, wireType 0 =*/16).int32(message.end); + return writer; + }; + + /** + * Encodes the specified EnumReservedRange message, length delimited. Does not implicitly {@link google.protobuf.EnumDescriptorProto.EnumReservedRange.verify|verify} messages. + * @function encodeDelimited + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {google.protobuf.EnumDescriptorProto.IEnumReservedRange} message EnumReservedRange message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + EnumReservedRange.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an EnumReservedRange message from the specified reader or buffer. + * @function decode + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {google.protobuf.EnumDescriptorProto.EnumReservedRange} EnumReservedRange + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + EnumReservedRange.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.EnumDescriptorProto.EnumReservedRange(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.start = reader.int32(); + break; + case 2: + message.end = reader.int32(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an EnumReservedRange message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {google.protobuf.EnumDescriptorProto.EnumReservedRange} EnumReservedRange + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + EnumReservedRange.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an EnumReservedRange message. + * @function verify + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + EnumReservedRange.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.start != null && message.hasOwnProperty("start")) + if (!$util.isInteger(message.start)) + return "start: integer expected"; + if (message.end != null && message.hasOwnProperty("end")) + if (!$util.isInteger(message.end)) + return "end: integer expected"; + return null; + }; + + /** + * Creates an EnumReservedRange message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {Object.} object Plain object + * @returns {google.protobuf.EnumDescriptorProto.EnumReservedRange} EnumReservedRange + */ + EnumReservedRange.fromObject = function fromObject(object) { + if (object instanceof $root.google.protobuf.EnumDescriptorProto.EnumReservedRange) + return object; + var message = new $root.google.protobuf.EnumDescriptorProto.EnumReservedRange(); + if (object.start != null) + message.start = object.start | 0; + if (object.end != null) + message.end = object.end | 0; + return message; + }; + + /** + * Creates a plain object from an EnumReservedRange message. Also converts values to other types if specified. + * @function toObject + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {google.protobuf.EnumDescriptorProto.EnumReservedRange} message EnumReservedRange + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + EnumReservedRange.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.start = 0; + object.end = 0; + } + if (message.start != null && message.hasOwnProperty("start")) + object.start = message.start; + if (message.end != null && message.hasOwnProperty("end")) + object.end = message.end; + return object; + }; + + /** + * Converts this EnumReservedRange to JSON. + * @function toJSON + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @instance + * @returns {Object.} JSON object + */ + EnumReservedRange.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return EnumReservedRange; + })(); + return EnumDescriptorProto; })(); @@ -19267,12 +19861,16 @@ * @property {boolean|null} [ccGenericServices] FileOptions ccGenericServices * @property {boolean|null} [javaGenericServices] FileOptions javaGenericServices * @property {boolean|null} [pyGenericServices] FileOptions pyGenericServices + * @property {boolean|null} [phpGenericServices] FileOptions phpGenericServices * @property {boolean|null} [deprecated] FileOptions deprecated * @property {boolean|null} [ccEnableArenas] FileOptions ccEnableArenas * @property {string|null} [objcClassPrefix] FileOptions objcClassPrefix * @property {string|null} [csharpNamespace] FileOptions csharpNamespace * @property {string|null} [swiftPrefix] FileOptions swiftPrefix * @property {string|null} [phpClassPrefix] FileOptions phpClassPrefix + * @property {string|null} [phpNamespace] FileOptions phpNamespace + * @property {string|null} [phpMetadataNamespace] FileOptions phpMetadataNamespace + * @property {string|null} [rubyPackage] FileOptions rubyPackage * @property {Array.|null} [uninterpretedOption] FileOptions uninterpretedOption * @property {Array.|null} [".google.api.resourceDefinition"] FileOptions .google.api.resourceDefinition */ @@ -19374,6 +19972,14 @@ */ FileOptions.prototype.pyGenericServices = false; + /** + * FileOptions phpGenericServices. + * @member {boolean} phpGenericServices + * @memberof google.protobuf.FileOptions + * @instance + */ + FileOptions.prototype.phpGenericServices = false; + /** * FileOptions deprecated. * @member {boolean} deprecated @@ -19388,7 +19994,7 @@ * @memberof google.protobuf.FileOptions * @instance */ - FileOptions.prototype.ccEnableArenas = false; + FileOptions.prototype.ccEnableArenas = true; /** * FileOptions objcClassPrefix. @@ -19422,6 +20028,30 @@ */ FileOptions.prototype.phpClassPrefix = ""; + /** + * FileOptions phpNamespace. + * @member {string} phpNamespace + * @memberof google.protobuf.FileOptions + * @instance + */ + FileOptions.prototype.phpNamespace = ""; + + /** + * FileOptions phpMetadataNamespace. + * @member {string} phpMetadataNamespace + * @memberof google.protobuf.FileOptions + * @instance + */ + FileOptions.prototype.phpMetadataNamespace = ""; + + /** + * FileOptions rubyPackage. + * @member {string} rubyPackage + * @memberof google.protobuf.FileOptions + * @instance + */ + FileOptions.prototype.rubyPackage = ""; + /** * FileOptions uninterpretedOption. * @member {Array.} uninterpretedOption @@ -19494,6 +20124,14 @@ writer.uint32(/* id 39, wireType 2 =*/314).string(message.swiftPrefix); if (message.phpClassPrefix != null && Object.hasOwnProperty.call(message, "phpClassPrefix")) writer.uint32(/* id 40, wireType 2 =*/322).string(message.phpClassPrefix); + if (message.phpNamespace != null && Object.hasOwnProperty.call(message, "phpNamespace")) + writer.uint32(/* id 41, wireType 2 =*/330).string(message.phpNamespace); + if (message.phpGenericServices != null && Object.hasOwnProperty.call(message, "phpGenericServices")) + writer.uint32(/* id 42, wireType 0 =*/336).bool(message.phpGenericServices); + if (message.phpMetadataNamespace != null && Object.hasOwnProperty.call(message, "phpMetadataNamespace")) + writer.uint32(/* id 44, wireType 2 =*/354).string(message.phpMetadataNamespace); + if (message.rubyPackage != null && Object.hasOwnProperty.call(message, "rubyPackage")) + writer.uint32(/* id 45, wireType 2 =*/362).string(message.rubyPackage); if (message.uninterpretedOption != null && message.uninterpretedOption.length) for (var i = 0; i < message.uninterpretedOption.length; ++i) $root.google.protobuf.UninterpretedOption.encode(message.uninterpretedOption[i], writer.uint32(/* id 999, wireType 2 =*/7994).fork()).ldelim(); @@ -19564,6 +20202,9 @@ case 18: message.pyGenericServices = reader.bool(); break; + case 42: + message.phpGenericServices = reader.bool(); + break; case 23: message.deprecated = reader.bool(); break; @@ -19582,6 +20223,15 @@ case 40: message.phpClassPrefix = reader.string(); break; + case 41: + message.phpNamespace = reader.string(); + break; + case 44: + message.phpMetadataNamespace = reader.string(); + break; + case 45: + message.rubyPackage = reader.string(); + break; case 999: if (!(message.uninterpretedOption && message.uninterpretedOption.length)) message.uninterpretedOption = []; @@ -19663,6 +20313,9 @@ if (message.pyGenericServices != null && message.hasOwnProperty("pyGenericServices")) if (typeof message.pyGenericServices !== "boolean") return "pyGenericServices: boolean expected"; + if (message.phpGenericServices != null && message.hasOwnProperty("phpGenericServices")) + if (typeof message.phpGenericServices !== "boolean") + return "phpGenericServices: boolean expected"; if (message.deprecated != null && message.hasOwnProperty("deprecated")) if (typeof message.deprecated !== "boolean") return "deprecated: boolean expected"; @@ -19681,6 +20334,15 @@ if (message.phpClassPrefix != null && message.hasOwnProperty("phpClassPrefix")) if (!$util.isString(message.phpClassPrefix)) return "phpClassPrefix: string expected"; + if (message.phpNamespace != null && message.hasOwnProperty("phpNamespace")) + if (!$util.isString(message.phpNamespace)) + return "phpNamespace: string expected"; + if (message.phpMetadataNamespace != null && message.hasOwnProperty("phpMetadataNamespace")) + if (!$util.isString(message.phpMetadataNamespace)) + return "phpMetadataNamespace: string expected"; + if (message.rubyPackage != null && message.hasOwnProperty("rubyPackage")) + if (!$util.isString(message.rubyPackage)) + return "rubyPackage: string expected"; if (message.uninterpretedOption != null && message.hasOwnProperty("uninterpretedOption")) { if (!Array.isArray(message.uninterpretedOption)) return "uninterpretedOption: array expected"; @@ -19746,6 +20408,8 @@ message.javaGenericServices = Boolean(object.javaGenericServices); if (object.pyGenericServices != null) message.pyGenericServices = Boolean(object.pyGenericServices); + if (object.phpGenericServices != null) + message.phpGenericServices = Boolean(object.phpGenericServices); if (object.deprecated != null) message.deprecated = Boolean(object.deprecated); if (object.ccEnableArenas != null) @@ -19758,6 +20422,12 @@ message.swiftPrefix = String(object.swiftPrefix); if (object.phpClassPrefix != null) message.phpClassPrefix = String(object.phpClassPrefix); + if (object.phpNamespace != null) + message.phpNamespace = String(object.phpNamespace); + if (object.phpMetadataNamespace != null) + message.phpMetadataNamespace = String(object.phpMetadataNamespace); + if (object.rubyPackage != null) + message.rubyPackage = String(object.rubyPackage); if (object.uninterpretedOption) { if (!Array.isArray(object.uninterpretedOption)) throw TypeError(".google.protobuf.FileOptions.uninterpretedOption: array expected"); @@ -19810,11 +20480,15 @@ object.javaGenerateEqualsAndHash = false; object.deprecated = false; object.javaStringCheckUtf8 = false; - object.ccEnableArenas = false; + object.ccEnableArenas = true; object.objcClassPrefix = ""; object.csharpNamespace = ""; object.swiftPrefix = ""; object.phpClassPrefix = ""; + object.phpNamespace = ""; + object.phpGenericServices = false; + object.phpMetadataNamespace = ""; + object.rubyPackage = ""; } if (message.javaPackage != null && message.hasOwnProperty("javaPackage")) object.javaPackage = message.javaPackage; @@ -19848,6 +20522,14 @@ object.swiftPrefix = message.swiftPrefix; if (message.phpClassPrefix != null && message.hasOwnProperty("phpClassPrefix")) object.phpClassPrefix = message.phpClassPrefix; + if (message.phpNamespace != null && message.hasOwnProperty("phpNamespace")) + object.phpNamespace = message.phpNamespace; + if (message.phpGenericServices != null && message.hasOwnProperty("phpGenericServices")) + object.phpGenericServices = message.phpGenericServices; + if (message.phpMetadataNamespace != null && message.hasOwnProperty("phpMetadataNamespace")) + object.phpMetadataNamespace = message.phpMetadataNamespace; + if (message.rubyPackage != null && message.hasOwnProperty("rubyPackage")) + object.rubyPackage = message.rubyPackage; if (message.uninterpretedOption && message.uninterpretedOption.length) { object.uninterpretedOption = []; for (var j = 0; j < message.uninterpretedOption.length; ++j) diff --git a/protos/protos.json b/protos/protos.json index ac1aae86d..f81292a93 100644 --- a/protos/protos.json +++ b/protos/protos.json @@ -1637,6 +1637,10 @@ "rule": "repeated", "type": "HttpRule", "id": 1 + }, + "fullyDecodeReservedExpansion": { + "type": "bool", + "id": 2 } } }, @@ -1686,6 +1690,10 @@ "type": "string", "id": 7 }, + "responseBody": { + "type": "string", + "id": 12 + }, "additionalBindings": { "rule": "repeated", "type": "HttpRule", @@ -1819,11 +1827,12 @@ }, "protobuf": { "options": { - "go_package": "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor", + "go_package": "google.golang.org/protobuf/types/descriptorpb", "java_package": "com.google.protobuf", "java_outer_classname": "DescriptorProtos", "csharp_namespace": "Google.Protobuf.Reflection", "objc_class_prefix": "GPB", + "cc_enable_arenas": true, "optimize_for": "SPEED" }, "nested": { @@ -1962,6 +1971,10 @@ "end": { "type": "int32", "id": 2 + }, + "options": { + "type": "ExtensionRangeOptions", + "id": 3 } } }, @@ -1979,6 +1992,21 @@ } } }, + "ExtensionRangeOptions": { + "fields": { + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ] + }, "FieldDescriptorProto": { "fields": { "name": { @@ -2020,6 +2048,10 @@ "options": { "type": "FieldOptions", "id": 8 + }, + "proto3Optional": { + "type": "bool", + "id": 17 } }, "nested": { @@ -2080,6 +2112,30 @@ "options": { "type": "EnumOptions", "id": 3 + }, + "reservedRange": { + "rule": "repeated", + "type": "EnumReservedRange", + "id": 4 + }, + "reservedName": { + "rule": "repeated", + "type": "string", + "id": 5 + } + }, + "nested": { + "EnumReservedRange": { + "fields": { + "start": { + "type": "int32", + "id": 1 + }, + "end": { + "type": "int32", + "id": 2 + } + } } } }, @@ -2213,6 +2269,13 @@ "default": false } }, + "phpGenericServices": { + "type": "bool", + "id": 42, + "options": { + "default": false + } + }, "deprecated": { "type": "bool", "id": 23, @@ -2224,7 +2287,7 @@ "type": "bool", "id": 31, "options": { - "default": false + "default": true } }, "objcClassPrefix": { @@ -2243,6 +2306,18 @@ "type": "string", "id": 40 }, + "phpNamespace": { + "type": "string", + "id": 41 + }, + "phpMetadataNamespace": { + "type": "string", + "id": 44 + }, + "rubyPackage": { + "type": "string", + "id": 45 + }, "uninterpretedOption": { "rule": "repeated", "type": "UninterpretedOption", diff --git a/src/opentelemetry-tracing.ts b/src/opentelemetry-tracing.ts index f03e6d72d..17e1414b1 100644 --- a/src/opentelemetry-tracing.ts +++ b/src/opentelemetry-tracing.ts @@ -23,6 +23,12 @@ import { setSpanContext, } from '@opentelemetry/api'; +/** + * @internal + * Instantiates a Opentelemetry tracer for the library + */ +const libraryTracer: Tracer = trace.getTracer('@google-cloud/pubsub'); + /** * Creates a new span with the given properties * @@ -35,9 +41,6 @@ export function createSpan( attributes?: SpanAttributes, parent?: SpanContext ): Span { - // Should return the existing one, if we have one, or create a new one. - const libraryTracer: Tracer = trace.getTracer('@google-cloud/pubsub'); - return libraryTracer.startSpan( spanName, { diff --git a/src/subscriber.ts b/src/subscriber.ts index 975effedb..df52a32f3 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -453,6 +453,7 @@ export class Subscriber extends EventEmitter { ) { return undefined; } + const spanValue = message.attributes['googclient_OpenTelemetrySpanContext']; const parentSpanContext: SpanContext | undefined = spanValue ? JSON.parse(spanValue) @@ -463,8 +464,9 @@ export class Subscriber extends EventEmitter { }; // Subscriber spans should always have a publisher span as a parent. // Return undefined if no parent is provided + const spanName = this.name ?? 'subscriber'; const span = parentSpanContext - ? createSpan(this._name, spanAttributes, parentSpanContext) + ? createSpan(spanName, spanAttributes, parentSpanContext) : undefined; return span; } diff --git a/test/subscriber.ts b/test/subscriber.ts index 280e2d217..6a4ad194e 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -637,8 +637,7 @@ describe('Subscriber', () => { }); }); - describe('OpenTelemetry tracing', () => { - let tracingSubscriber: s.Subscriber = {} as s.Subscriber; + describe.only('OpenTelemetry tracing', () => { const enableTracing: s.SubscriberOptions = { enableOpenTelemetryTracing: true, }; @@ -646,37 +645,38 @@ describe('Subscriber', () => { enableOpenTelemetryTracing: false, }; - beforeEach(() => { - // Pre-define _tracing to gain access to the private field after subscriber init - tracingSubscriber['_useOpentelemetry'] = false; + afterEach(() => { + subscriber.close(); }); it('should not instantiate a tracer when tracing is disabled', () => { - tracingSubscriber = new Subscriber(subscription); - assert.strictEqual(tracingSubscriber['_useOpentelemetry'], false); + subscriber = new Subscriber(subscription, {}); + assert.strictEqual(subscriber['_useOpentelemetry'], false); }); it('should instantiate a tracer when tracing is enabled through constructor', () => { - tracingSubscriber = new Subscriber(subscription, enableTracing); - assert.ok(tracingSubscriber['_useOpentelemetry']); + subscriber = new Subscriber(subscription, enableTracing); + assert.ok(subscriber['_useOpentelemetry']); }); it('should instantiate a tracer when tracing is enabled through setOptions', () => { - tracingSubscriber = new Subscriber(subscription); - tracingSubscriber.setOptions(enableTracing); - assert.ok(tracingSubscriber['_useOpentelemetry']); + subscriber = new Subscriber(subscription, {}); + subscriber.setOptions(enableTracing); + assert.ok(subscriber['_useOpentelemetry']); }); it('should disable tracing when tracing is disabled through setOptions', () => { - tracingSubscriber = new Subscriber(subscription, enableTracing); - tracingSubscriber.setOptions(disableTracing); - assert.strictEqual(tracingSubscriber['_useOpentelemetry'], false); + subscriber = new Subscriber(subscription, enableTracing); + subscriber.setOptions(disableTracing); + assert.strictEqual(subscriber['_useOpentelemetry'], false); }); it('exports a span once it is created', () => { - tracingSubscriber = new Subscriber(subscription, enableTracing); - tracingSubscriber.setOptions(enableTracing); - assert.strictEqual(tracingSubscriber['_useOpentelemetry'], true); + subscription = (new FakeSubscription() as {}) as Subscription; + subscriber = new Subscriber(subscription, enableTracing); + message = new Message(subscriber, RECEIVED_MESSAGE); + assert.strictEqual(subscriber['_useOpentelemetry'], true); + subscriber.open(); // Setup trace exporting const provider: BasicTracerProvider = new BasicTracerProvider(); @@ -710,14 +710,19 @@ describe('Subscriber', () => { }; // Receive message and assert that it was exported - const stream: FakeMessageStream = stubs.get('messageStream'); - stream.emit('data', pullResponse); + const msgStream = stubs.get('messageStream'); + msgStream.emit('data', pullResponse); const spans = exporter.getFinishedSpans(); - assert.ok(spans); + assert.strictEqual(exporter.getFinishedSpans().length, 1); + const firstSpan = spans.shift(); + assert.ok(firstSpan); + assert.strictEqual(firstSpan.parentSpanId, parentSpanContext.spanId); + // because the name of the subscriber is not set we check the fallback is set + assert.strictEqual(firstSpan.name, 'subscriber'); }); it('does not export a span when a span context is not present on message', () => { - tracingSubscriber = new Subscriber(subscription, enableTracing); + subscriber = new Subscriber(subscription, enableTracing); // Setup trace exporting const provider: BasicTracerProvider = new BasicTracerProvider(); From 3d3320877dcb9557d118e3d373826d7fb1c7b8ba Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 30 Mar 2021 22:09:09 +0100 Subject: [PATCH 10/40] chore: remove describe.only --- test/subscriber.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/subscriber.ts b/test/subscriber.ts index 6a4ad194e..7d8477618 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -637,7 +637,7 @@ describe('Subscriber', () => { }); }); - describe.only('OpenTelemetry tracing', () => { + describe('OpenTelemetry tracing', () => { const enableTracing: s.SubscriberOptions = { enableOpenTelemetryTracing: true, }; From 364de2842367e1372c816d923867db0b3eff2c92 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 30 Mar 2021 23:07:59 +0100 Subject: [PATCH 11/40] chore: latest changes --- src/publisher/index.ts | 3 +++ test/publisher/index.ts | 12 ++++++++++-- test/subscriber.ts | 16 +++++++++------- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/publisher/index.ts b/src/publisher/index.ts index 41095717d..d9e7c2a62 100644 --- a/src/publisher/index.ts +++ b/src/publisher/index.ts @@ -253,6 +253,7 @@ export class Publisher { * @param {PubsubMessage} message The message to create a span for */ constructSpan(message: PubsubMessage): Span | undefined { + console.log('Publisher.constructspan()'); const spanAttributes = { data: message.data, } as Attributes; @@ -275,6 +276,8 @@ export class Publisher { 'googclient_OpenTelemetrySpanContext' ] = JSON.stringify(span.context()); } + + console.log('Publisher.constructspan() span:', span); return span; } } diff --git a/test/publisher/index.ts b/test/publisher/index.ts index 2735ebb78..0ba553287 100644 --- a/test/publisher/index.ts +++ b/test/publisher/index.ts @@ -181,15 +181,23 @@ describe('Publisher', () => { }; const buffer = Buffer.from('Hello, world!'); - it('export created spans', () => { - tracingPublisher = new Publisher(topic, enableTracing); + beforeEach(() => { + opentelemetry.trace.disable(); + }); + + afterEach(() => { + opentelemetry.trace.disable(); + }); + it('export created spans', () => { // Setup trace exporting const provider: BasicTracerProvider = new BasicTracerProvider(); const exporter: InMemorySpanExporter = new InMemorySpanExporter(); provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); opentelemetry.trace.setGlobalTracerProvider(provider); + tracingPublisher = new Publisher(topic, enableTracing); + tracingPublisher.publish(buffer); const spans = exporter.getFinishedSpans(); assert.strictEqual(spans.length, 1, 'has span'); diff --git a/test/subscriber.ts b/test/subscriber.ts index 7d8477618..835fdbc39 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -637,7 +637,7 @@ describe('Subscriber', () => { }); }); - describe('OpenTelemetry tracing', () => { + describe.skip('OpenTelemetry tracing', () => { const enableTracing: s.SubscriberOptions = { enableOpenTelemetryTracing: true, }; @@ -647,6 +647,7 @@ describe('Subscriber', () => { afterEach(() => { subscriber.close(); + opentelemetry.trace.disable(); }); it('should not instantiate a tracer when tracing is disabled', () => { @@ -672,12 +673,6 @@ describe('Subscriber', () => { }); it('exports a span once it is created', () => { - subscription = (new FakeSubscription() as {}) as Subscription; - subscriber = new Subscriber(subscription, enableTracing); - message = new Message(subscriber, RECEIVED_MESSAGE); - assert.strictEqual(subscriber['_useOpentelemetry'], true); - subscriber.open(); - // Setup trace exporting const provider: BasicTracerProvider = new BasicTracerProvider(); const exporter: InMemorySpanExporter = new InMemorySpanExporter(); @@ -685,6 +680,13 @@ describe('Subscriber', () => { provider.register(); opentelemetry.trace.setGlobalTracerProvider(provider); + // + subscription = (new FakeSubscription() as {}) as Subscription; + subscriber = new Subscriber(subscription, enableTracing); + message = new Message(subscriber, RECEIVED_MESSAGE); + assert.strictEqual(subscriber['_useOpentelemetry'], true); + subscriber.open(); + // Construct mock of received message with span context const parentSpanContext: opentelemetry.SpanContext = { traceId: 'd4cda95b652f4a1592b449d5929fda1b', From 93eaaa1196927199dd499b8c442cb6b7b22baaa2 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Wed, 31 Mar 2021 01:46:15 +0100 Subject: [PATCH 12/40] test: updated the tests --- package.json | 2 ++ src/publisher/index.ts | 2 -- test/opentelemetry-tracing.ts | 27 ++++++++------------ test/publisher/index.ts | 38 ++++++++-------------------- test/subscriber.ts | 47 ++++++++++++----------------------- test/tracing.ts | 10 ++++++++ 6 files changed, 50 insertions(+), 76 deletions(-) create mode 100644 test/tracing.ts diff --git a/package.json b/package.json index 8c87e5960..69b64d901 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,8 @@ "system-test": "mocha build/system-test --timeout 600000", "samples-test": "cd samples/ && npm link ../ && npm install && npm test && cd ../", "test": "c8 mocha build/test --recursive", + "test:publisher": "npm run compile && mocha --file build/test/publisher/index.js", + "test:subscriber": "npm run compile && mocha --file build/test/subscriber.js", "lint": "gts check", "predocs": "npm run compile", "docs": "jsdoc -c .jsdoc.js", diff --git a/src/publisher/index.ts b/src/publisher/index.ts index d9e7c2a62..b51a366fb 100644 --- a/src/publisher/index.ts +++ b/src/publisher/index.ts @@ -253,7 +253,6 @@ export class Publisher { * @param {PubsubMessage} message The message to create a span for */ constructSpan(message: PubsubMessage): Span | undefined { - console.log('Publisher.constructspan()'); const spanAttributes = { data: message.data, } as Attributes; @@ -277,7 +276,6 @@ export class Publisher { ] = JSON.stringify(span.context()); } - console.log('Publisher.constructspan() span:', span); return span; } } diff --git a/test/opentelemetry-tracing.ts b/test/opentelemetry-tracing.ts index d39a543d8..d6fc0905a 100644 --- a/test/opentelemetry-tracing.ts +++ b/test/opentelemetry-tracing.ts @@ -15,12 +15,12 @@ */ import * as assert from 'assert'; -import {describe, it, before, afterEach} from 'mocha'; +import {describe, it, afterEach} from 'mocha'; import * as api from '@opentelemetry/api'; import * as trace from '@opentelemetry/tracing'; import {createSpan} from '../src/opentelemetry-tracing'; -import {SimpleSpanProcessor} from '@opentelemetry/tracing'; +import {exporter} from './tracing'; describe('OpenTelemetryTracer', () => { let span: trace.Span; @@ -34,21 +34,16 @@ describe('OpenTelemetryTracer', () => { foo: 'bar', }; - before(() => { - const provider = new trace.BasicTracerProvider(); - const exporter = new trace.InMemorySpanExporter(); - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - api.trace.setGlobalTracerProvider(provider); - }); - - afterEach(() => { - span.end(); - }); - it('creates a span', () => { span = createSpan(spanName, spanAttributes, spanContext) as trace.Span; - assert.strictEqual(span.name, spanName); - assert.deepStrictEqual(span.attributes, spanAttributes); - assert.strictEqual(span.parentSpanId, spanContext.spanId); + span.end(); + + const spans = exporter.getFinishedSpans(); + assert.notStrictEqual(spans.length, 0); + const exportedSpan = spans.concat().pop()!; + + assert.strictEqual(exportedSpan.name, spanName); + assert.deepStrictEqual(exportedSpan.attributes, spanAttributes); + assert.strictEqual(exportedSpan.parentSpanId, spanContext.spanId); }); }); diff --git a/test/publisher/index.ts b/test/publisher/index.ts index 0ba553287..63cba2092 100644 --- a/test/publisher/index.ts +++ b/test/publisher/index.ts @@ -16,15 +16,10 @@ import * as pfy from '@google-cloud/promisify'; import * as assert from 'assert'; -import {describe, it, before, beforeEach, afterEach} from 'mocha'; +import {describe, it, beforeEach, afterEach} from 'mocha'; import {EventEmitter} from 'events'; import * as proxyquire from 'proxyquire'; import * as sinon from 'sinon'; -import { - BasicTracerProvider, - InMemorySpanExporter, - SimpleSpanProcessor, -} from '@opentelemetry/tracing'; import * as opentelemetry from '@opentelemetry/api'; import {Topic} from '../../src'; import * as p from '../../src/publisher'; @@ -32,6 +27,7 @@ import * as q from '../../src/publisher/message-queues'; import {PublishError} from '../../src/publisher/publish-error'; import {defaultOptions} from '../../src/default-options'; +import {exporter} from '../tracing'; let promisified = false; const fakePromisify = Object.assign({}, pfy, { @@ -93,14 +89,18 @@ class FakeOrderedQueue extends FakeQueue { } describe('Publisher', () => { - const sandbox = sinon.createSandbox(); + let sandbox: sinon.SinonSandbox; + let spy: sinon.SinonSpyStatic; const topic = {name: 'topic-name'} as Topic; // tslint:disable-next-line variable-name let Publisher: typeof p.Publisher; let publisher: p.Publisher; - before(() => { + beforeEach(() => { + sandbox = sinon.createSandbox(); + spy = sandbox.spy(); + const mocked = proxyquire('../../src/publisher/index.js', { '@google-cloud/promisify': fakePromisify, './message-queues': { @@ -110,9 +110,7 @@ describe('Publisher', () => { }); Publisher = mocked.Publisher; - }); - beforeEach(() => { publisher = new Publisher(topic); }); @@ -150,7 +148,6 @@ describe('Publisher', () => { describe('publish', () => { const buffer = Buffer.from('Hello, world!'); - const spy = sandbox.spy(); it('should call through to publishMessage', () => { const stub = sandbox.stub(publisher, 'publishMessage'); @@ -181,27 +178,14 @@ describe('Publisher', () => { }; const buffer = Buffer.from('Hello, world!'); - beforeEach(() => { - opentelemetry.trace.disable(); - }); - - afterEach(() => { - opentelemetry.trace.disable(); - }); - it('export created spans', () => { // Setup trace exporting - const provider: BasicTracerProvider = new BasicTracerProvider(); - const exporter: InMemorySpanExporter = new InMemorySpanExporter(); - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - opentelemetry.trace.setGlobalTracerProvider(provider); - tracingPublisher = new Publisher(topic, enableTracing); tracingPublisher.publish(buffer); const spans = exporter.getFinishedSpans(); - assert.strictEqual(spans.length, 1, 'has span'); - const createdSpan = spans.shift()!; + assert.notStrictEqual(spans.length, 0, 'has span'); + const createdSpan = spans.concat().pop()!; assert.strictEqual( createdSpan.status.code, opentelemetry.SpanStatusCode.UNSET @@ -213,7 +197,7 @@ describe('Publisher', () => { describe('publishMessage', () => { const data = Buffer.from('hello, world!'); - const spy = sandbox.spy(); + // const spy = sandbox.spy(); it('should throw an error if data is not a Buffer', () => { const badData = {} as Buffer; diff --git a/test/subscriber.ts b/test/subscriber.ts index 835fdbc39..991a4d3f5 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -14,19 +14,15 @@ * limitations under the License. */ +import {exporter} from './tracing'; import * as assert from 'assert'; -import {describe, it, before, beforeEach, afterEach} from 'mocha'; +import {describe, it, beforeEach, afterEach} from 'mocha'; import {EventEmitter} from 'events'; import {common as protobuf} from 'protobufjs'; import * as proxyquire from 'proxyquire'; import * as sinon from 'sinon'; import {PassThrough} from 'stream'; import * as uuid from 'uuid'; -import { - SimpleSpanProcessor, - BasicTracerProvider, - InMemorySpanExporter, -} from '@opentelemetry/tracing'; import * as opentelemetry from '@opentelemetry/api'; import {HistogramOptions} from '../src/histogram'; @@ -150,10 +146,9 @@ const RECEIVED_MESSAGE = { }; describe('Subscriber', () => { - const sandbox = sinon.createSandbox(); - - const fakeProjectify = {replaceProjectIdToken: sandbox.stub()}; + let sandbox: sinon.SinonSandbox; + let fakeProjectify: any; let subscription: Subscription; // tslint:disable-next-line variable-name @@ -163,7 +158,12 @@ describe('Subscriber', () => { let Subscriber: typeof s.Subscriber; let subscriber: s.Subscriber; - before(() => { + beforeEach(() => { + sandbox = sinon.createSandbox(); + fakeProjectify = { + replaceProjectIdToken: sandbox.stub(), + }; + const s = proxyquire('../src/subscriber.js', { '@google-cloud/precise-date': {PreciseDate: FakePreciseDate}, '@google-cloud/projectify': fakeProjectify, @@ -178,9 +178,8 @@ describe('Subscriber', () => { Message = s.Message; Subscriber = s.Subscriber; - }); - beforeEach(() => { + // Create standard instance subscription = (new FakeSubscription() as {}) as Subscription; subscriber = new Subscriber(subscription); message = new Message(subscriber, RECEIVED_MESSAGE); @@ -637,7 +636,7 @@ describe('Subscriber', () => { }); }); - describe.skip('OpenTelemetry tracing', () => { + describe('OpenTelemetry tracing', () => { const enableTracing: s.SubscriberOptions = { enableOpenTelemetryTracing: true, }; @@ -646,8 +645,8 @@ describe('Subscriber', () => { }; afterEach(() => { + exporter.reset(); subscriber.close(); - opentelemetry.trace.disable(); }); it('should not instantiate a tracer when tracing is disabled', () => { @@ -673,14 +672,6 @@ describe('Subscriber', () => { }); it('exports a span once it is created', () => { - // Setup trace exporting - const provider: BasicTracerProvider = new BasicTracerProvider(); - const exporter: InMemorySpanExporter = new InMemorySpanExporter(); - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - provider.register(); - opentelemetry.trace.setGlobalTracerProvider(provider); - - // subscription = (new FakeSubscription() as {}) as Subscription; subscriber = new Subscriber(subscription, enableTracing); message = new Message(subscriber, RECEIVED_MESSAGE); @@ -714,9 +705,10 @@ describe('Subscriber', () => { // Receive message and assert that it was exported const msgStream = stubs.get('messageStream'); msgStream.emit('data', pullResponse); + const spans = exporter.getFinishedSpans(); - assert.strictEqual(exporter.getFinishedSpans().length, 1); - const firstSpan = spans.shift(); + assert.strictEqual(spans.length, 1); + const firstSpan = spans.concat().shift(); assert.ok(firstSpan); assert.strictEqual(firstSpan.parentSpanId, parentSpanContext.spanId); // because the name of the subscriber is not set we check the fallback is set @@ -726,13 +718,6 @@ describe('Subscriber', () => { it('does not export a span when a span context is not present on message', () => { subscriber = new Subscriber(subscription, enableTracing); - // Setup trace exporting - const provider: BasicTracerProvider = new BasicTracerProvider(); - const exporter: InMemorySpanExporter = new InMemorySpanExporter(); - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - provider.register(); - opentelemetry.trace.setGlobalTracerProvider(provider); - const pullResponse: s.PullResponse = { receivedMessages: [RECEIVED_MESSAGE], }; diff --git a/test/tracing.ts b/test/tracing.ts new file mode 100644 index 000000000..d5ff53636 --- /dev/null +++ b/test/tracing.ts @@ -0,0 +1,10 @@ +import { + BasicTracerProvider, + InMemorySpanExporter, + SimpleSpanProcessor, +} from '@opentelemetry/tracing'; + +export const exporter: InMemorySpanExporter = new InMemorySpanExporter(); +export const provider: BasicTracerProvider = new BasicTracerProvider(); +provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); +provider.register(); From 31b8371aee4d15cfec99a176d49a0aabf92cac2d Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Wed, 31 Mar 2021 01:53:25 +0100 Subject: [PATCH 13/40] test: improve the tests --- test/opentelemetry-tracing.ts | 6 +++++- test/publisher/index.ts | 4 ++++ test/subscriber.ts | 4 ++++ test/tracing.ts | 29 +++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/test/opentelemetry-tracing.ts b/test/opentelemetry-tracing.ts index d6fc0905a..3a85e5395 100644 --- a/test/opentelemetry-tracing.ts +++ b/test/opentelemetry-tracing.ts @@ -15,7 +15,7 @@ */ import * as assert from 'assert'; -import {describe, it, afterEach} from 'mocha'; +import {describe, it, beforeEach} from 'mocha'; import * as api from '@opentelemetry/api'; import * as trace from '@opentelemetry/tracing'; @@ -34,6 +34,10 @@ describe('OpenTelemetryTracer', () => { foo: 'bar', }; + beforeEach(() => { + exporter.reset(); + }); + it('creates a span', () => { span = createSpan(spanName, spanAttributes, spanContext) as trace.Span; span.end(); diff --git a/test/publisher/index.ts b/test/publisher/index.ts index 63cba2092..80ba5ae8b 100644 --- a/test/publisher/index.ts +++ b/test/publisher/index.ts @@ -178,6 +178,10 @@ describe('Publisher', () => { }; const buffer = Buffer.from('Hello, world!'); + beforeEach(() => { + exporter.reset(); + }); + it('export created spans', () => { // Setup trace exporting tracingPublisher = new Publisher(topic, enableTracing); diff --git a/test/subscriber.ts b/test/subscriber.ts index 991a4d3f5..eb0e654ea 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -644,6 +644,10 @@ describe('Subscriber', () => { enableOpenTelemetryTracing: false, }; + beforeEach(() => { + exporter.reset(); + }); + afterEach(() => { exporter.reset(); subscriber.close(); diff --git a/test/tracing.ts b/test/tracing.ts index d5ff53636..d71d9fc52 100644 --- a/test/tracing.ts +++ b/test/tracing.ts @@ -1,9 +1,38 @@ +/*! + * Copyright 2021 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor, } from '@opentelemetry/tracing'; +/** + * This file is used to initialise a global tracing provider and span exporter + * for our tests used in our project. This was the only way I was able to get + * the tracing tests to work. + * + * Now before each test related or touches Opentelemetry + * we are resetting the exporter defined below to ensure there are now spans + * from previous tests still in memory. + * + * The tracing provider is being registered as a global trace provider before + * we are importing our actual code which uses the Opentelemetry API to ensure + * its defined beforehand. + */ export const exporter: InMemorySpanExporter = new InMemorySpanExporter(); export const provider: BasicTracerProvider = new BasicTracerProvider(); provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); From 6159fb31a7cdd836e0c05fc92bebf27217254957 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Wed, 31 Mar 2021 01:58:02 +0100 Subject: [PATCH 14/40] chore: maybe its need to be Google LLC? --- test/tracing.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tracing.ts b/test/tracing.ts index d71d9fc52..fe5b907eb 100644 --- a/test/tracing.ts +++ b/test/tracing.ts @@ -1,5 +1,5 @@ /*! - * Copyright 2021 Google Inc. All Rights Reserved. + * Copyright 2021 Google LLC. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From f26d90ef44208ca7c7606a0a6aa1e74da0b854e7 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Wed, 31 Mar 2021 05:10:09 +0100 Subject: [PATCH 15/40] feat: add messaging attributes to otel spans --- package.json | 1 + src/opentelemetry-tracing.ts | 5 ++++ src/publisher/index.ts | 23 ++++++++++++++-- src/subscriber.ts | 35 ++++++++++++++++++++++--- test/opentelemetry-tracing.ts | 9 ++++++- test/publisher/index.ts | 37 ++++++++++++++++++++++++-- test/subscriber.ts | 49 ++++++++++++++++++++++++++++++++--- 7 files changed, 148 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 69b64d901..a41a229a5 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "@google-cloud/projectify": "^2.0.0", "@google-cloud/promisify": "^2.0.0", "@opentelemetry/api": "^0.18.1", + "@opentelemetry/semantic-conventions": "^0.18.2", "@types/duplexify": "^3.6.0", "@types/long": "^4.0.0", "arrify": "^2.0.0", diff --git a/src/opentelemetry-tracing.ts b/src/opentelemetry-tracing.ts index 17e1414b1..3d98cd97d 100644 --- a/src/opentelemetry-tracing.ts +++ b/src/opentelemetry-tracing.ts @@ -21,6 +21,7 @@ import { context, trace, setSpanContext, + SpanKind, } from '@opentelemetry/api'; /** @@ -38,12 +39,16 @@ const libraryTracer: Tracer = trace.getTracer('@google-cloud/pubsub'); */ export function createSpan( spanName: string, + kind: SpanKind, attributes?: SpanAttributes, parent?: SpanContext ): Span { return libraryTracer.startSpan( spanName, { + // set the kind of the span + kind, + // set the attributes of the span attributes: attributes, }, parent ? setSpanContext(context.active(), parent) : undefined diff --git a/src/publisher/index.ts b/src/publisher/index.ts index b51a366fb..186ec84f0 100644 --- a/src/publisher/index.ts +++ b/src/publisher/index.ts @@ -17,7 +17,11 @@ import {promisify, promisifyAll} from '@google-cloud/promisify'; import * as extend from 'extend'; import {CallOptions} from 'google-gax'; -import {Span} from '@opentelemetry/api'; +import { + GeneralAttribute, + MessagingAttribute, +} from '@opentelemetry/semantic-conventions'; +import {Span, SpanKind} from '@opentelemetry/api'; import {BatchPublishOptions} from './message-batch'; import {Queue, OrderedQueue} from './message-queues'; @@ -255,9 +259,24 @@ export class Publisher { constructSpan(message: PubsubMessage): Span | undefined { const spanAttributes = { data: message.data, + // Add Opentelemetry semantic convention attributes to the span + [GeneralAttribute.NET_PEER_NAME]: this.topic.pubsub.projectId, + [MessagingAttribute.MESSAGING_TEMP_DESTINATION]: false, + [MessagingAttribute.MESSAGING_SYSTEM]: 'pubsub', + [MessagingAttribute.MESSAGING_OPERATION]: '', // operation expected to be empty + [MessagingAttribute.MESSAGING_DESTINATION]: this.topic.name, + [MessagingAttribute.MESSAGING_DESTINATION_KIND]: 'topic', + [MessagingAttribute.MESSAGING_MESSAGE_ID]: message.messageId, + [MessagingAttribute.MESSAGING_PROTOCOL]: 'pubsub', + [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_COMPRESSED_SIZE_BYTES]: 0, + [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES]: + message.data?.length, + 'messaging.consumer.published_at': message.publishTime, + 'messaging.consumer.ordering_key': message.orderingKey, } as Attributes; + const span: Span | undefined = this.settings.enableOpenTelemetryTracing - ? createSpan(`${this.topic.name} publisher`, spanAttributes) + ? createSpan(`${this.topic.name} send`, SpanKind.PRODUCER, spanAttributes) : undefined; if (span) { if ( diff --git a/src/subscriber.ts b/src/subscriber.ts index df52a32f3..b125eeb6c 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -18,7 +18,11 @@ import {DateStruct, PreciseDate} from '@google-cloud/precise-date'; import {replaceProjectIdToken} from '@google-cloud/projectify'; import {promisify} from '@google-cloud/promisify'; import {EventEmitter} from 'events'; -import {SpanContext, Span} from '@opentelemetry/api'; +import {SpanContext, Span, SpanKind} from '@opentelemetry/api'; +import { + GeneralAttribute, + MessagingAttribute, +} from '@opentelemetry/semantic-conventions'; import {google} from '../protos/protos'; import {Histogram} from './histogram'; @@ -461,12 +465,37 @@ export class Subscriber extends EventEmitter { const spanAttributes = { ackId: message.ackId, deliveryAttempt: message.deliveryAttempt, + // + // based on https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/messaging.md#topic-with-multiple-consumers + [GeneralAttribute.NET_PEER_NAME]: this._subscription.projectId, + [MessagingAttribute.MESSAGING_SYSTEM]: 'pubsub', + [MessagingAttribute.MESSAGING_OPERATION]: 'process', + [MessagingAttribute.MESSAGING_DESTINATION]: this.name, + [MessagingAttribute.MESSAGING_DESTINATION_KIND]: 'topic', + [MessagingAttribute.MESSAGING_MESSAGE_ID]: message.id, + [MessagingAttribute.MESSAGING_PROTOCOL]: 'pubsub', + [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_COMPRESSED_SIZE_BYTES]: 0, + [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES]: message.length, + // Not in Opentelemetry semantic convention but mimics naming + 'messaging.consumer.published_at': + typeof message.publishTime.getTime !== 'undefined' + ? message.publishTime.getTime() + : undefined, + 'messaging.consumer.received_at': message.received, + 'messaging.consumer.acknowlege_id': message.ackId, + 'messaging.consumer.delivery_attempt': message.deliveryAttempt, }; + // Subscriber spans should always have a publisher span as a parent. // Return undefined if no parent is provided - const spanName = this.name ?? 'subscriber'; + const spanName = `${this.name} receive`; const span = parentSpanContext - ? createSpan(spanName, spanAttributes, parentSpanContext) + ? createSpan( + spanName.trim(), + SpanKind.CONSUMER, + spanAttributes, + parentSpanContext + ) : undefined; return span; } diff --git a/test/opentelemetry-tracing.ts b/test/opentelemetry-tracing.ts index 3a85e5395..dc6a1423e 100644 --- a/test/opentelemetry-tracing.ts +++ b/test/opentelemetry-tracing.ts @@ -21,6 +21,7 @@ import * as api from '@opentelemetry/api'; import * as trace from '@opentelemetry/tracing'; import {createSpan} from '../src/opentelemetry-tracing'; import {exporter} from './tracing'; +import {SpanKind} from '@opentelemetry/api'; describe('OpenTelemetryTracer', () => { let span: trace.Span; @@ -39,7 +40,12 @@ describe('OpenTelemetryTracer', () => { }); it('creates a span', () => { - span = createSpan(spanName, spanAttributes, spanContext) as trace.Span; + span = createSpan( + spanName, + SpanKind.PRODUCER, + spanAttributes, + spanContext + ) as trace.Span; span.end(); const spans = exporter.getFinishedSpans(); @@ -49,5 +55,6 @@ describe('OpenTelemetryTracer', () => { assert.strictEqual(exportedSpan.name, spanName); assert.deepStrictEqual(exportedSpan.attributes, spanAttributes); assert.strictEqual(exportedSpan.parentSpanId, spanContext.spanId); + assert.strictEqual(exportedSpan.kind, SpanKind.PRODUCER); }); }); diff --git a/test/publisher/index.ts b/test/publisher/index.ts index 80ba5ae8b..a9c3ef347 100644 --- a/test/publisher/index.ts +++ b/test/publisher/index.ts @@ -28,6 +28,11 @@ import {PublishError} from '../../src/publisher/publish-error'; import {defaultOptions} from '../../src/default-options'; import {exporter} from '../tracing'; +import {SpanKind} from '@opentelemetry/api'; +import { + GeneralAttribute, + MessagingAttribute, +} from '@opentelemetry/semantic-conventions'; let promisified = false; const fakePromisify = Object.assign({}, pfy, { @@ -91,7 +96,10 @@ class FakeOrderedQueue extends FakeQueue { describe('Publisher', () => { let sandbox: sinon.SinonSandbox; let spy: sinon.SinonSpyStatic; - const topic = {name: 'topic-name'} as Topic; + const topic = { + name: 'topic-name', + pubsub: {projectId: 'PROJECT_ID'}, + } as Topic; // tslint:disable-next-line variable-name let Publisher: typeof p.Publisher; @@ -194,7 +202,32 @@ describe('Publisher', () => { createdSpan.status.code, opentelemetry.SpanStatusCode.UNSET ); - assert.strictEqual(createdSpan.name, 'topic-name publisher'); + assert.strictEqual( + createdSpan.attributes[GeneralAttribute.NET_PEER_NAME], + 'PROJECT_ID' + ); + assert.strictEqual( + createdSpan.attributes[MessagingAttribute.MESSAGING_OPERATION], + '' + ); + assert.strictEqual( + createdSpan.attributes[MessagingAttribute.MESSAGING_SYSTEM], + 'pubsub' + ); + assert.strictEqual( + createdSpan.attributes[MessagingAttribute.MESSAGING_DESTINATION], + topic.name + ); + assert.strictEqual( + createdSpan.attributes[MessagingAttribute.MESSAGING_DESTINATION_KIND], + 'topic' + ); + assert.strictEqual(createdSpan.name, 'topic-name send'); + assert.strictEqual( + createdSpan.kind, + SpanKind.PRODUCER, + 'span kind should be PRODUCER' + ); assert.ok(spans); }); }); diff --git a/test/subscriber.ts b/test/subscriber.ts index eb0e654ea..14952ccc1 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -31,6 +31,11 @@ import {BatchOptions} from '../src/message-queues'; import {MessageStreamOptions} from '../src/message-stream'; import * as s from '../src/subscriber'; import {Subscription} from '../src/subscription'; +import {SpanKind} from '@opentelemetry/api'; +import { + GeneralAttribute, + MessagingAttribute, +} from '@opentelemetry/semantic-conventions'; const stubs = new Map(); @@ -161,7 +166,9 @@ describe('Subscriber', () => { beforeEach(() => { sandbox = sinon.createSandbox(); fakeProjectify = { - replaceProjectIdToken: sandbox.stub(), + replaceProjectIdToken: sandbox.stub().callsFake((name, projectId) => { + return `projects/${projectId}/name/${name}`; + }), }; const s = proxyquire('../src/subscriber.js', { @@ -715,8 +722,44 @@ describe('Subscriber', () => { const firstSpan = spans.concat().shift(); assert.ok(firstSpan); assert.strictEqual(firstSpan.parentSpanId, parentSpanContext.spanId); - // because the name of the subscriber is not set we check the fallback is set - assert.strictEqual(firstSpan.name, 'subscriber'); + assert.strictEqual( + firstSpan.name, + `${subscriber.name} receive`, + 'name of span should match' + ); + assert.strictEqual( + firstSpan.kind, + SpanKind.CONSUMER, + 'span kind should be CONSUMER' + ); + assert.strictEqual( + firstSpan.attributes[GeneralAttribute.NET_PEER_NAME], + subscription.projectId, + 'span net peer name should match' + ); + assert.strictEqual( + firstSpan.attributes[MessagingAttribute.MESSAGING_OPERATION], + 'process', + 'span messaging operation should match' + ); + assert.strictEqual( + firstSpan.attributes[MessagingAttribute.MESSAGING_SYSTEM], + 'pubsub' + ); + assert.strictEqual( + firstSpan.attributes[MessagingAttribute.MESSAGING_MESSAGE_ID], + messageWithSpanContext.message.messageId, + 'span messaging id should match' + ); + assert.strictEqual( + firstSpan.attributes[MessagingAttribute.MESSAGING_DESTINATION], + subscriber.name, + 'span messaging destination should match' + ); + assert.strictEqual( + firstSpan.attributes[MessagingAttribute.MESSAGING_DESTINATION_KIND], + 'topic' + ); }); it('does not export a span when a span context is not present on message', () => { From 2cbccb96d1280acf08753f1572f5760f838e5fea Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Wed, 31 Mar 2021 05:32:56 +0100 Subject: [PATCH 16/40] fix: include package.json version as instrumentation version --- src/opentelemetry-tracing.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/opentelemetry-tracing.ts b/src/opentelemetry-tracing.ts index 3d98cd97d..14727def2 100644 --- a/src/opentelemetry-tracing.ts +++ b/src/opentelemetry-tracing.ts @@ -24,11 +24,16 @@ import { SpanKind, } from '@opentelemetry/api'; +import PKG = require('../package.json'); + /** * @internal * Instantiates a Opentelemetry tracer for the library */ -const libraryTracer: Tracer = trace.getTracer('@google-cloud/pubsub'); +const libraryTracer: Tracer = trace.getTracer( + '@google-cloud/pubsub', + PKG.version +); /** * Creates a new span with the given properties From 93760c3903de34f9e199a7c6811d3546f3b7ccf4 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Wed, 31 Mar 2021 05:33:12 +0100 Subject: [PATCH 17/40] docs: update the opentelemetry example code --- samples/openTelemetryTracing.js | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/samples/openTelemetryTracing.js b/samples/openTelemetryTracing.js index 6c0190110..33fa7f2ec 100644 --- a/samples/openTelemetryTracing.js +++ b/samples/openTelemetryTracing.js @@ -62,6 +62,11 @@ function main( const provider = new BasicTracerProvider(); const exporter = new ConsoleSpanExporter(); provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); + // Enable the diagnostic logger for Opentelemetry + opentelemetry.diag.setLogger( + new opentelemetry.DiagConsoleLogger(), + opentelemetry.DiagLogLevel.INFO + ); provider.register(); opentelemetry.trace.setGlobalTracerProvider(provider); @@ -89,17 +94,32 @@ function main( const messageHandler = message => { console.log(`Message ${message.id} received.`); message.ack(); - process.exit(0); + + // Ensure that all spans got flushed by the exporter + console.log('Cleaning up Opentelemetry exporter...'); + exporter.shutdown().then(() => { + console.log('Cleaned up exporter.'); + process.exit(0); + }); }; const errorHandler = error => { console.log('Received error:', error); - process.exit(0); + + console.log('Cleaning up Opentelemetry exporter...'); + exporter.shutdown().then(() => { + console.log('Cleaned up exporter.'); + process.exit(0); + }); }; // Listens for new messages from the topic - pubSubClient.subscription(subscriptionName).on('message', messageHandler); - pubSubClient.subscription(subscriptionName).on('error', errorHandler); + pubSubClient + .subscription(subscriptionName, enableOpenTelemetryTracing) + .on('message', messageHandler); + pubSubClient + .subscription(subscriptionName, enableOpenTelemetryTracing) + .on('error', errorHandler); setTimeout(() => { pubSubClient From 54deb7cddd7a9d415ff21c86258b3c2704ff25d5 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 1 Apr 2021 21:01:35 +0100 Subject: [PATCH 18/40] style: remove unused code --- test/publisher/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/publisher/index.ts b/test/publisher/index.ts index a9c3ef347..fa0dc5cbc 100644 --- a/test/publisher/index.ts +++ b/test/publisher/index.ts @@ -234,7 +234,6 @@ describe('Publisher', () => { describe('publishMessage', () => { const data = Buffer.from('hello, world!'); - // const spy = sandbox.spy(); it('should throw an error if data is not a Buffer', () => { const badData = {} as Buffer; From 99adf228016d0a653404ba6557b30bfba617f6e8 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 1 Apr 2021 21:25:54 +0100 Subject: [PATCH 19/40] fix: remove peer name for now --- src/publisher/index.ts | 6 +----- src/subscriber.ts | 6 +----- test/publisher/index.ts | 4 ---- test/subscriber.ts | 5 ----- 4 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/publisher/index.ts b/src/publisher/index.ts index 186ec84f0..1e81e8949 100644 --- a/src/publisher/index.ts +++ b/src/publisher/index.ts @@ -17,10 +17,7 @@ import {promisify, promisifyAll} from '@google-cloud/promisify'; import * as extend from 'extend'; import {CallOptions} from 'google-gax'; -import { - GeneralAttribute, - MessagingAttribute, -} from '@opentelemetry/semantic-conventions'; +import {MessagingAttribute} from '@opentelemetry/semantic-conventions'; import {Span, SpanKind} from '@opentelemetry/api'; import {BatchPublishOptions} from './message-batch'; @@ -260,7 +257,6 @@ export class Publisher { const spanAttributes = { data: message.data, // Add Opentelemetry semantic convention attributes to the span - [GeneralAttribute.NET_PEER_NAME]: this.topic.pubsub.projectId, [MessagingAttribute.MESSAGING_TEMP_DESTINATION]: false, [MessagingAttribute.MESSAGING_SYSTEM]: 'pubsub', [MessagingAttribute.MESSAGING_OPERATION]: '', // operation expected to be empty diff --git a/src/subscriber.ts b/src/subscriber.ts index b125eeb6c..8ed109dc0 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -19,10 +19,7 @@ import {replaceProjectIdToken} from '@google-cloud/projectify'; import {promisify} from '@google-cloud/promisify'; import {EventEmitter} from 'events'; import {SpanContext, Span, SpanKind} from '@opentelemetry/api'; -import { - GeneralAttribute, - MessagingAttribute, -} from '@opentelemetry/semantic-conventions'; +import {MessagingAttribute} from '@opentelemetry/semantic-conventions'; import {google} from '../protos/protos'; import {Histogram} from './histogram'; @@ -467,7 +464,6 @@ export class Subscriber extends EventEmitter { deliveryAttempt: message.deliveryAttempt, // // based on https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/messaging.md#topic-with-multiple-consumers - [GeneralAttribute.NET_PEER_NAME]: this._subscription.projectId, [MessagingAttribute.MESSAGING_SYSTEM]: 'pubsub', [MessagingAttribute.MESSAGING_OPERATION]: 'process', [MessagingAttribute.MESSAGING_DESTINATION]: this.name, diff --git a/test/publisher/index.ts b/test/publisher/index.ts index fa0dc5cbc..9be9c4eb3 100644 --- a/test/publisher/index.ts +++ b/test/publisher/index.ts @@ -202,10 +202,6 @@ describe('Publisher', () => { createdSpan.status.code, opentelemetry.SpanStatusCode.UNSET ); - assert.strictEqual( - createdSpan.attributes[GeneralAttribute.NET_PEER_NAME], - 'PROJECT_ID' - ); assert.strictEqual( createdSpan.attributes[MessagingAttribute.MESSAGING_OPERATION], '' diff --git a/test/subscriber.ts b/test/subscriber.ts index 14952ccc1..dad5cc16c 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -732,11 +732,6 @@ describe('Subscriber', () => { SpanKind.CONSUMER, 'span kind should be CONSUMER' ); - assert.strictEqual( - firstSpan.attributes[GeneralAttribute.NET_PEER_NAME], - subscription.projectId, - 'span net peer name should match' - ); assert.strictEqual( firstSpan.attributes[MessagingAttribute.MESSAGING_OPERATION], 'process', From cff5314e6be62bd5964230d737c3c7306ae32640 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 1 Apr 2021 21:29:06 +0100 Subject: [PATCH 20/40] style: improve explanation regarding otel trace provider --- test/tracing.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/tracing.ts b/test/tracing.ts index fe5b907eb..8b1b31146 100644 --- a/test/tracing.ts +++ b/test/tracing.ts @@ -26,8 +26,10 @@ import { * the tracing tests to work. * * Now before each test related or touches Opentelemetry - * we are resetting the exporter defined below to ensure there are now spans - * from previous tests still in memory. + * we are resetting the exporter defined below to ensure there are no spans + * from previous tests still in memory. This is achived by calling `reset` + * on the exporter in the unit tests while keeping one instance of + * the trace provider and exporter. * * The tracing provider is being registered as a global trace provider before * we are importing our actual code which uses the Opentelemetry API to ensure From ae3e95911b1d3c30ef8509813e5daae9a4e51803 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 1 Apr 2021 23:19:28 +0100 Subject: [PATCH 21/40] chore: update the opentelemetry versios in the samples `package.json` --- samples/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/package.json b/samples/package.json index b008e7c01..4f7ea1ee8 100644 --- a/samples/package.json +++ b/samples/package.json @@ -15,8 +15,8 @@ }, "dependencies": { "@google-cloud/pubsub": "^2.10.0", - "@opentelemetry/api": "^0.11.0", - "@opentelemetry/tracing": "^0.11.0" + "@opentelemetry/api": "^0.18.1", + "@opentelemetry/tracing": "^0.18.2" }, "devDependencies": { "chai": "^4.2.0", From 2e0095b376b72c79df739fe5631bb25409b868bd Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Sat, 3 Apr 2021 15:42:06 +0100 Subject: [PATCH 22/40] test: remove extranous logging in the opentelemetry example app --- samples/openTelemetryTracing.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/samples/openTelemetryTracing.js b/samples/openTelemetryTracing.js index 33fa7f2ec..5d6c29569 100644 --- a/samples/openTelemetryTracing.js +++ b/samples/openTelemetryTracing.js @@ -69,7 +69,6 @@ function main( ); provider.register(); - opentelemetry.trace.setGlobalTracerProvider(provider); // OpenTelemetry tracing is an optional feature and can be enabled by setting // enableOpenTelemetryTraceing as a publisher or subscriber option @@ -98,7 +97,7 @@ function main( // Ensure that all spans got flushed by the exporter console.log('Cleaning up Opentelemetry exporter...'); exporter.shutdown().then(() => { - console.log('Cleaned up exporter.'); + // Cleaned up exporter. process.exit(0); }); }; @@ -108,7 +107,7 @@ function main( console.log('Cleaning up Opentelemetry exporter...'); exporter.shutdown().then(() => { - console.log('Cleaned up exporter.'); + // Cleaned up exporter. process.exit(0); }); }; From 78f31e4aa637a6ca755627ad3c54cbac59040e39 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Sat, 3 Apr 2021 15:45:40 +0100 Subject: [PATCH 23/40] test: remove the check for `traceId` that doesn't get outputted --- samples/system-test/openTelemetryTracing.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/system-test/openTelemetryTracing.test.js b/samples/system-test/openTelemetryTracing.test.js index bcc069084..c91f174e2 100644 --- a/samples/system-test/openTelemetryTracing.test.js +++ b/samples/system-test/openTelemetryTracing.test.js @@ -42,7 +42,6 @@ describe('openTelemetry', () => { const stdout = execSync( `node openTelemetryTracing ${topicName} ${subName}` ); - assert.match(stdout, /traceId/); assert.match(stdout, /Message .* published./); assert.match(stdout, /Message .* received/); assert.notMatch(stdout, /Received error/); From e42ac63ea3583f099ecd4a70450580f03d982bd3 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 6 Apr 2021 13:38:17 +0100 Subject: [PATCH 24/40] fix: remove unnecessary messaging span attribute and added comments --- src/publisher/index.ts | 4 ++-- src/subscriber.ts | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/publisher/index.ts b/src/publisher/index.ts index 1e81e8949..743bf8d4b 100644 --- a/src/publisher/index.ts +++ b/src/publisher/index.ts @@ -256,7 +256,8 @@ export class Publisher { constructSpan(message: PubsubMessage): Span | undefined { const spanAttributes = { data: message.data, - // Add Opentelemetry semantic convention attributes to the span + // Add Opentelemetry semantic convention attributes to the span, based on: + // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.1.0/specification/trace/semantic_conventions/messaging.md [MessagingAttribute.MESSAGING_TEMP_DESTINATION]: false, [MessagingAttribute.MESSAGING_SYSTEM]: 'pubsub', [MessagingAttribute.MESSAGING_OPERATION]: '', // operation expected to be empty @@ -264,7 +265,6 @@ export class Publisher { [MessagingAttribute.MESSAGING_DESTINATION_KIND]: 'topic', [MessagingAttribute.MESSAGING_MESSAGE_ID]: message.messageId, [MessagingAttribute.MESSAGING_PROTOCOL]: 'pubsub', - [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_COMPRESSED_SIZE_BYTES]: 0, [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES]: message.data?.length, 'messaging.consumer.published_at': message.publishTime, diff --git a/src/subscriber.ts b/src/subscriber.ts index 8ed109dc0..9ada6ba6e 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -470,7 +470,6 @@ export class Subscriber extends EventEmitter { [MessagingAttribute.MESSAGING_DESTINATION_KIND]: 'topic', [MessagingAttribute.MESSAGING_MESSAGE_ID]: message.id, [MessagingAttribute.MESSAGING_PROTOCOL]: 'pubsub', - [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_COMPRESSED_SIZE_BYTES]: 0, [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES]: message.length, // Not in Opentelemetry semantic convention but mimics naming 'messaging.consumer.published_at': From 0c542514c65c4e92aa0d3a56fd0e57c96d06f225 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 6 Apr 2021 13:47:57 +0100 Subject: [PATCH 25/40] style: use shiny new syntax for undefined check in `subscriber`-class --- src/subscriber.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/subscriber.ts b/src/subscriber.ts index 9ada6ba6e..ce3b39735 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -472,10 +472,7 @@ export class Subscriber extends EventEmitter { [MessagingAttribute.MESSAGING_PROTOCOL]: 'pubsub', [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES]: message.length, // Not in Opentelemetry semantic convention but mimics naming - 'messaging.consumer.published_at': - typeof message.publishTime.getTime !== 'undefined' - ? message.publishTime.getTime() - : undefined, + 'messaging.consumer.published_at': message.publishTime?.getTime?.(), 'messaging.consumer.received_at': message.received, 'messaging.consumer.acknowlege_id': message.ackId, 'messaging.consumer.delivery_attempt': message.deliveryAttempt, From d0f04981cef87c62c88e0e647396739aea7a8e74 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 6 Apr 2021 13:53:40 +0100 Subject: [PATCH 26/40] fix: match the span name with the operation kind in `subscriber`-class --- src/subscriber.ts | 2 +- test/subscriber.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/subscriber.ts b/src/subscriber.ts index ce3b39735..8454fd18b 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -480,7 +480,7 @@ export class Subscriber extends EventEmitter { // Subscriber spans should always have a publisher span as a parent. // Return undefined if no parent is provided - const spanName = `${this.name} receive`; + const spanName = `${this.name} process`; const span = parentSpanContext ? createSpan( spanName.trim(), diff --git a/test/subscriber.ts b/test/subscriber.ts index dad5cc16c..40e7d09be 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -724,7 +724,7 @@ describe('Subscriber', () => { assert.strictEqual(firstSpan.parentSpanId, parentSpanContext.spanId); assert.strictEqual( firstSpan.name, - `${subscriber.name} receive`, + `${subscriber.name} process`, 'name of span should match' ); assert.strictEqual( From 6c0ca40ba8c0daac166b2665fbea210c66afddc9 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 6 Apr 2021 21:42:39 +0100 Subject: [PATCH 27/40] chore: improved code based on PR feedback --- src/publisher/index.ts | 17 +++++++++++------ src/subscriber.ts | 11 ++++++----- test/publisher/index.ts | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/publisher/index.ts b/src/publisher/index.ts index 743bf8d4b..42fdfc62d 100644 --- a/src/publisher/index.ts +++ b/src/publisher/index.ts @@ -254,26 +254,31 @@ export class Publisher { * @param {PubsubMessage} message The message to create a span for */ constructSpan(message: PubsubMessage): Span | undefined { + if (!this.settings.enableOpenTelemetryTracing) { + return undefined; + } + const spanAttributes = { data: message.data, // Add Opentelemetry semantic convention attributes to the span, based on: // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.1.0/specification/trace/semantic_conventions/messaging.md [MessagingAttribute.MESSAGING_TEMP_DESTINATION]: false, [MessagingAttribute.MESSAGING_SYSTEM]: 'pubsub', - [MessagingAttribute.MESSAGING_OPERATION]: '', // operation expected to be empty + [MessagingAttribute.MESSAGING_OPERATION]: 'send', // operation expected to be empty [MessagingAttribute.MESSAGING_DESTINATION]: this.topic.name, [MessagingAttribute.MESSAGING_DESTINATION_KIND]: 'topic', [MessagingAttribute.MESSAGING_MESSAGE_ID]: message.messageId, [MessagingAttribute.MESSAGING_PROTOCOL]: 'pubsub', [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES]: message.data?.length, - 'messaging.consumer.published_at': message.publishTime, - 'messaging.consumer.ordering_key': message.orderingKey, + 'messaging.pubsub.ordering_key': message.orderingKey, } as Attributes; - const span: Span | undefined = this.settings.enableOpenTelemetryTracing - ? createSpan(`${this.topic.name} send`, SpanKind.PRODUCER, spanAttributes) - : undefined; + const span: Span | undefined = createSpan( + `${this.topic.name} send`, + SpanKind.PRODUCER, + spanAttributes + ); if (span) { if ( message.attributes && diff --git a/src/subscriber.ts b/src/subscriber.ts index 8454fd18b..bff1bb98d 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -460,6 +460,7 @@ export class Subscriber extends EventEmitter { ? JSON.parse(spanValue) : undefined; const spanAttributes = { + // Original span attributes ackId: message.ackId, deliveryAttempt: message.deliveryAttempt, // @@ -470,12 +471,12 @@ export class Subscriber extends EventEmitter { [MessagingAttribute.MESSAGING_DESTINATION_KIND]: 'topic', [MessagingAttribute.MESSAGING_MESSAGE_ID]: message.id, [MessagingAttribute.MESSAGING_PROTOCOL]: 'pubsub', - [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES]: message.length, + [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES]: (message.data as Buffer) + .length, // Not in Opentelemetry semantic convention but mimics naming - 'messaging.consumer.published_at': message.publishTime?.getTime?.(), - 'messaging.consumer.received_at': message.received, - 'messaging.consumer.acknowlege_id': message.ackId, - 'messaging.consumer.delivery_attempt': message.deliveryAttempt, + 'messaging.pubsub.received_at': message.received, + 'messaging.pubsub.acknowlege_id': message.ackId, + 'messaging.pubsub.delivery_attempt': message.deliveryAttempt, }; // Subscriber spans should always have a publisher span as a parent. diff --git a/test/publisher/index.ts b/test/publisher/index.ts index 9be9c4eb3..213625703 100644 --- a/test/publisher/index.ts +++ b/test/publisher/index.ts @@ -204,7 +204,7 @@ describe('Publisher', () => { ); assert.strictEqual( createdSpan.attributes[MessagingAttribute.MESSAGING_OPERATION], - '' + 'send' ); assert.strictEqual( createdSpan.attributes[MessagingAttribute.MESSAGING_SYSTEM], From 818013a6b701180c22759719981a5c30e615ae5c Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 6 Apr 2021 21:43:32 +0100 Subject: [PATCH 28/40] fix: BREAKING CHANGE: The Opentelemetry tracing span doesn't expose the `data`-attribute anymore to avoid accidentally exposing privacy/personal data --- src/publisher/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/publisher/index.ts b/src/publisher/index.ts index 42fdfc62d..9b02f3112 100644 --- a/src/publisher/index.ts +++ b/src/publisher/index.ts @@ -259,7 +259,6 @@ export class Publisher { } const spanAttributes = { - data: message.data, // Add Opentelemetry semantic convention attributes to the span, based on: // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.1.0/specification/trace/semantic_conventions/messaging.md [MessagingAttribute.MESSAGING_TEMP_DESTINATION]: false, From 2cbaa287242a5b56edd4cd80a530d8bb4d22d6e8 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 6 Apr 2021 21:50:18 +0100 Subject: [PATCH 29/40] fix: only include `googclient_OpenTelemetrySpanContext`-attribute when valid span context exists --- src/publisher/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/publisher/index.ts b/src/publisher/index.ts index 9b02f3112..91dfe459c 100644 --- a/src/publisher/index.ts +++ b/src/publisher/index.ts @@ -18,7 +18,7 @@ import {promisify, promisifyAll} from '@google-cloud/promisify'; import * as extend from 'extend'; import {CallOptions} from 'google-gax'; import {MessagingAttribute} from '@opentelemetry/semantic-conventions'; -import {Span, SpanKind} from '@opentelemetry/api'; +import {isSpanContextValid, Span, SpanKind} from '@opentelemetry/api'; import {BatchPublishOptions} from './message-batch'; import {Queue, OrderedQueue} from './message-queues'; @@ -278,7 +278,9 @@ export class Publisher { SpanKind.PRODUCER, spanAttributes ); - if (span) { + + // If the span's context is valid we should pass the span context special attribute + if (isSpanContextValid(span.context())) { if ( message.attributes && message.attributes['googclient_OpenTelemetrySpanContext'] @@ -290,6 +292,7 @@ export class Publisher { if (!message.attributes) { message.attributes = {}; } + message.attributes[ 'googclient_OpenTelemetrySpanContext' ] = JSON.stringify(span.context()); From 0c2c76f8efa66e5f66d97430964fd30ac7e19261 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 6 Apr 2021 21:53:22 +0100 Subject: [PATCH 30/40] fix: change the way `package.json` is being imported --- src/opentelemetry-tracing.ts | 3 +-- src/pubsub.ts | 4 ++-- test/pubsub.ts | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/opentelemetry-tracing.ts b/src/opentelemetry-tracing.ts index 42261a91a..94b45562d 100644 --- a/src/opentelemetry-tracing.ts +++ b/src/opentelemetry-tracing.ts @@ -24,8 +24,7 @@ import { SpanKind, } from '@opentelemetry/api'; -// eslint-disable-next-line @typescript-eslint/no-var-requires -const PKG = require('../../package.json'); +import * as PKG from '../package.json'; /** * @internal diff --git a/src/pubsub.ts b/src/pubsub.ts index 94f033911..f098e9a7a 100644 --- a/src/pubsub.ts +++ b/src/pubsub.ts @@ -21,8 +21,8 @@ import * as extend from 'extend'; import {GoogleAuth} from 'google-auth-library'; import * as gax from 'google-gax'; -// eslint-disable-next-line @typescript-eslint/no-var-requires -const PKG = require('../../package.json'); +import * as PKG from '../package.json'; + // eslint-disable-next-line @typescript-eslint/no-var-requires const v1 = require('./v1'); diff --git a/test/pubsub.ts b/test/pubsub.ts index 64e046627..7dfa5372e 100644 --- a/test/pubsub.ts +++ b/test/pubsub.ts @@ -28,8 +28,8 @@ import * as subby from '../src/subscription'; import {Topic} from '../src/topic'; import * as util from '../src/util'; -// eslint-disable-next-line @typescript-eslint/no-var-requires -const PKG = require('../../package.json'); +import * as PKG from '../package.json'; + const sandbox = sinon.createSandbox(); const fakeCreds = {} as gax.grpc.ChannelCredentials; From 4b93dd1c273f847b1d62f7df02e128ba7d8fe0b9 Mon Sep 17 00:00:00 2001 From: Megan Potter <57276408+feywind@users.noreply.github.com> Date: Wed, 7 Apr 2021 15:24:07 -0400 Subject: [PATCH 31/40] fix: revert bad merge that removed tracing on devDependencies At least I think that's what happened... --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 0e1171cad..50ce4078e 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "p-defer": "^3.0.0" }, "devDependencies": { + "@opentelemetry/tracing": "^0.18.0", "@grpc/proto-loader": "^0.6.0", "@types/execa": "^0.9.0", "@types/extend": "^3.0.0", From afe0529928a7836f506a012ea4f9fc9e9e2e9e50 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 8 Apr 2021 00:25:31 +0100 Subject: [PATCH 32/40] style: remove unnecessary comment --- src/publisher/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/publisher/index.ts b/src/publisher/index.ts index 91dfe459c..a7425fdbe 100644 --- a/src/publisher/index.ts +++ b/src/publisher/index.ts @@ -263,7 +263,7 @@ export class Publisher { // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.1.0/specification/trace/semantic_conventions/messaging.md [MessagingAttribute.MESSAGING_TEMP_DESTINATION]: false, [MessagingAttribute.MESSAGING_SYSTEM]: 'pubsub', - [MessagingAttribute.MESSAGING_OPERATION]: 'send', // operation expected to be empty + [MessagingAttribute.MESSAGING_OPERATION]: 'send', [MessagingAttribute.MESSAGING_DESTINATION]: this.topic.name, [MessagingAttribute.MESSAGING_DESTINATION_KIND]: 'topic', [MessagingAttribute.MESSAGING_MESSAGE_ID]: message.messageId, From fa66633e9f91dce0c07ab3076cccca6fbd13240d Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 8 Apr 2021 00:38:51 +0100 Subject: [PATCH 33/40] style: remove unused imports --- test/publisher/index.ts | 5 +---- test/subscriber.ts | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/test/publisher/index.ts b/test/publisher/index.ts index 213625703..7440bad66 100644 --- a/test/publisher/index.ts +++ b/test/publisher/index.ts @@ -29,10 +29,7 @@ import {PublishError} from '../../src/publisher/publish-error'; import {defaultOptions} from '../../src/default-options'; import {exporter} from '../tracing'; import {SpanKind} from '@opentelemetry/api'; -import { - GeneralAttribute, - MessagingAttribute, -} from '@opentelemetry/semantic-conventions'; +import {MessagingAttribute} from '@opentelemetry/semantic-conventions'; let promisified = false; const fakePromisify = Object.assign({}, pfy, { diff --git a/test/subscriber.ts b/test/subscriber.ts index 40e7d09be..031934e03 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -32,10 +32,7 @@ import {MessageStreamOptions} from '../src/message-stream'; import * as s from '../src/subscriber'; import {Subscription} from '../src/subscription'; import {SpanKind} from '@opentelemetry/api'; -import { - GeneralAttribute, - MessagingAttribute, -} from '@opentelemetry/semantic-conventions'; +import {MessagingAttribute} from '@opentelemetry/semantic-conventions'; const stubs = new Map(); From 7a628e9fda7a6589d309b4daefc9c58254fee4d8 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 8 Apr 2021 15:40:47 +0100 Subject: [PATCH 34/40] build: downgrade @sinonjs/fake-timers to v6 The v10 of sinonjs comes with v7 of fake-timers which comes with typescript type definitions that are generated by jsdoc comments which seems to cause trouble when compiling the app it. Downgrading to v6 to avoid needing to solve this problem now. --- package.json | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 50ce4078e..01fcc95e0 100644 --- a/package.json +++ b/package.json @@ -68,8 +68,11 @@ "p-defer": "^3.0.0" }, "devDependencies": { - "@opentelemetry/tracing": "^0.18.0", "@grpc/proto-loader": "^0.6.0", + "@microsoft/api-documenter": "^7.8.10", + "@microsoft/api-extractor": "^7.8.10", + "@opentelemetry/tracing": "^0.18.0", + "@sinonjs/fake-timers": "^6.0.1", "@types/execa": "^0.9.0", "@types/extend": "^3.0.0", "@types/lodash.snakecase": "^4.1.6", @@ -78,7 +81,7 @@ "@types/ncp": "^2.0.1", "@types/node": "^12.12.30", "@types/proxyquire": "^1.3.28", - "@types/sinon": "^9.0.0", + "@types/sinon": "^9.0.11", "@types/tmp": "^0.2.0", "@types/uuid": "^8.0.0", "c8": "^7.0.0", @@ -95,15 +98,13 @@ "null-loader": "^4.0.0", "protobufjs": "^6.10.1", "proxyquire": "^2.0.0", - "sinon": "^10.0.0", + "sinon": "^10.0.1", "tmp": "^0.2.0", "ts-loader": "^8.0.0", "typescript": "^3.8.3", "uuid": "^8.0.0", "webpack": "^5.0.0", "webpack-cli": "^4.0.0", - "yargs": "^16.0.0", - "@microsoft/api-documenter": "^7.8.10", - "@microsoft/api-extractor": "^7.8.10" + "yargs": "^16.0.0" } } From c1b66dd4eec7799727aa4b0929a4f31500413dd3 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 8 Apr 2021 15:44:30 +0100 Subject: [PATCH 35/40] style: cleanup type definition Removed the `| undefined` for the `span` in the `Publisher`-class Co-authored-by: Aaron Abbott --- src/publisher/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/publisher/index.ts b/src/publisher/index.ts index a7425fdbe..bcd8d9e33 100644 --- a/src/publisher/index.ts +++ b/src/publisher/index.ts @@ -273,7 +273,7 @@ export class Publisher { 'messaging.pubsub.ordering_key': message.orderingKey, } as Attributes; - const span: Span | undefined = createSpan( + const span: Span = createSpan( `${this.topic.name} send`, SpanKind.PRODUCER, spanAttributes From c081f6bbcb2034ffc2d40c70b30427379fed6265 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Fri, 9 Apr 2021 03:15:40 +0100 Subject: [PATCH 36/40] build: remove `package.json` after compilation step --- package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/package.json b/package.json index 01fcc95e0..addef3f2e 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,6 @@ "system-test": "mocha build/system-test --timeout 600000", "samples-test": "cd samples/ && npm link ../ && npm install && npm test && cd ../", "test": "c8 mocha build/test --recursive", - "test:publisher": "npm run compile && mocha --file build/test/publisher/index.js", - "test:subscriber": "npm run compile && mocha --file build/test/subscriber.js", "lint": "gts check", "predocs": "npm run compile", "docs": "jsdoc -c .jsdoc.js", @@ -40,7 +38,7 @@ "clean": "gts clean", "compile": "tsc -p . && cp -r protos build/", "compile-protos": "compileProtos src", - "prepare": "npm run compile-protos && npm run compile", + "prepare": "npm run compile-protos && npm run compile && rm ./build/package.json", "pretest": "npm run compile", "docs-test": "linkinator docs", "predocs-test": "npm run docs", From 9339bafb393782fd924c0d54b5c308f4208a375c Mon Sep 17 00:00:00 2001 From: Megan Potter Date: Fri, 9 Apr 2021 18:18:18 -0400 Subject: [PATCH 37/40] build: put back package.json in the build --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c87a20632..5c2a98526 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "clean": "gts clean", "compile": "tsc -p . && cp -r protos build/", "compile-protos": "compileProtos src", - "prepare": "npm run compile-protos && npm run compile && rm ./build/package.json", + "prepare": "npm run compile-protos && npm run compile", "pretest": "npm run compile", "docs-test": "linkinator docs", "predocs-test": "npm run docs", From 14de6257bf63acc6168c4b51c18088a5c74e673b Mon Sep 17 00:00:00 2001 From: Megan Potter Date: Tue, 13 Apr 2021 18:10:44 -0400 Subject: [PATCH 38/40] build: explicitly add package.json to the npm pack build --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 5c2a98526..66dfa636d 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "types": "./build/src/index.d.ts", "files": [ "build/protos", - "build/src" + "build/src", + "build/package.json" ], "keywords": [ "google apis client", From 253b56bf78b9f3a5dd7045f55165c8a1221fb096 Mon Sep 17 00:00:00 2001 From: Megan Potter Date: Wed, 14 Apr 2021 14:39:03 -0400 Subject: [PATCH 39/40] fix: revert "fix: change the way `package.json` is being imported" This reverts commit 0c2c76f8efa66e5f66d97430964fd30ac7e19261. --- src/opentelemetry-tracing.ts | 3 ++- src/pubsub.ts | 4 ++-- test/pubsub.ts | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/opentelemetry-tracing.ts b/src/opentelemetry-tracing.ts index 94b45562d..42261a91a 100644 --- a/src/opentelemetry-tracing.ts +++ b/src/opentelemetry-tracing.ts @@ -24,7 +24,8 @@ import { SpanKind, } from '@opentelemetry/api'; -import * as PKG from '../package.json'; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const PKG = require('../../package.json'); /** * @internal diff --git a/src/pubsub.ts b/src/pubsub.ts index f098e9a7a..94f033911 100644 --- a/src/pubsub.ts +++ b/src/pubsub.ts @@ -21,8 +21,8 @@ import * as extend from 'extend'; import {GoogleAuth} from 'google-auth-library'; import * as gax from 'google-gax'; -import * as PKG from '../package.json'; - +// eslint-disable-next-line @typescript-eslint/no-var-requires +const PKG = require('../../package.json'); // eslint-disable-next-line @typescript-eslint/no-var-requires const v1 = require('./v1'); diff --git a/test/pubsub.ts b/test/pubsub.ts index 7dfa5372e..64e046627 100644 --- a/test/pubsub.ts +++ b/test/pubsub.ts @@ -28,8 +28,8 @@ import * as subby from '../src/subscription'; import {Topic} from '../src/topic'; import * as util from '../src/util'; -import * as PKG from '../package.json'; - +// eslint-disable-next-line @typescript-eslint/no-var-requires +const PKG = require('../../package.json'); const sandbox = sinon.createSandbox(); const fakeCreds = {} as gax.grpc.ChannelCredentials; From 4db9ba57f8d05f7569fa6490f278d6a5d8fb1226 Mon Sep 17 00:00:00 2001 From: Megan Potter Date: Wed, 14 Apr 2021 14:42:31 -0400 Subject: [PATCH 40/40] fix: revert "build: explicitly add package.json to the npm pack build" This reverts commit 14de6257bf63acc6168c4b51c18088a5c74e673b. --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 66dfa636d..5c2a98526 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,7 @@ "types": "./build/src/index.d.ts", "files": [ "build/protos", - "build/src", - "build/package.json" + "build/src" ], "keywords": [ "google apis client",