From 6683e634e2d1d6a257ae2da861a3ce1f301f98af Mon Sep 17 00:00:00 2001 From: Shivanee Persaud Date: Wed, 26 Aug 2026 13:58:17 -0700 Subject: [PATCH 1/2] feat(generator): add internalTelemetryInfo configuration when enableTelemetryTracing is enabled --- .../src/$version/$service_client.ts.njk | 17 ++ .../esm/src/$version/$service_client.ts.njk | 17 ++ .../typescript/test/unit/generator.ts | 208 +++++++++++++++++- 3 files changed, 239 insertions(+), 3 deletions(-) diff --git a/core/generator/gapic-generator-typescript/templates/cjs/typescript_gapic/src/$version/$service_client.ts.njk b/core/generator/gapic-generator-typescript/templates/cjs/typescript_gapic/src/$version/$service_client.ts.njk index 90553e89770f..182dae751d01 100644 --- a/core/generator/gapic-generator-typescript/templates/cjs/typescript_gapic/src/$version/$service_client.ts.njk +++ b/core/generator/gapic-generator-typescript/templates/cjs/typescript_gapic/src/$version/$service_client.ts.njk @@ -398,6 +398,23 @@ export class {{ service.name }}Client { , 'x-goog-api-version': '{{ service.apiVersion }}' {%- endif -%}}); + {%- if api.enableTelemetryTracing %} + if (opts.enableTelemetryTracing) { + // set the internal telemetry info using `otherArgs` attribute of `CallSettings` + const internalTelemetryInfo = { + gcpClientService: '{{ api.loggingName }}', + gcpVersion: '{{ api.naming.version }}', + gcpRepo: 'googleapis/google-cloud-node', + gcpArtifact: '{{ api.publishName }}', + }; + for (const methodName of Object.keys(this._defaults)) { + this._defaults[methodName].enableTelemetryTracing = opts.enableTelemetryTracing; + this._defaults[methodName].otherArgs = this._defaults[methodName].otherArgs || {}; + this._defaults[methodName].otherArgs.internalTelemetryInfo = internalTelemetryInfo; + } + } + {%- endif %} + // Set up a dictionary of "inner API calls"; the core implementation // of calling the API is handled in `google-gax`, with this code // merely providing the destination and request information. diff --git a/core/generator/gapic-generator-typescript/templates/esm/typescript_gapic/esm/src/$version/$service_client.ts.njk b/core/generator/gapic-generator-typescript/templates/esm/typescript_gapic/esm/src/$version/$service_client.ts.njk index e505db0eef11..fc0ca68f067d 100644 --- a/core/generator/gapic-generator-typescript/templates/esm/typescript_gapic/esm/src/$version/$service_client.ts.njk +++ b/core/generator/gapic-generator-typescript/templates/esm/typescript_gapic/esm/src/$version/$service_client.ts.njk @@ -409,6 +409,23 @@ export class {{ service.name }}Client { , 'x-goog-api-version': '{{ service.apiVersion }}' {%- endif %}}); + {%- if api.enableTelemetryTracing %} + if (opts.enableTelemetryTracing) { + // set the internal telemetry info using `otherArgs` attribute of `CallSettings` + const internalTelemetryInfo = { + gcpClientService: '{{ api.loggingName }}', + gcpVersion: '{{ api.naming.version }}', + gcpRepo: 'googleapis/google-cloud-node', + gcpArtifact: '{{ api.publishName }}', + }; + for (const methodName of Object.keys(this._defaults)) { + this._defaults[methodName].enableTelemetryTracing = opts.enableTelemetryTracing; + this._defaults[methodName].otherArgs = this._defaults[methodName].otherArgs || {}; + this._defaults[methodName].otherArgs.internalTelemetryInfo = internalTelemetryInfo; + } + } + {%- endif %} + // Set up a dictionary of "inner API calls"; the core implementation // of calling the API is handled in `google-gax`, with this code // merely providing the destination and request information. diff --git a/core/generator/gapic-generator-typescript/typescript/test/unit/generator.ts b/core/generator/gapic-generator-typescript/typescript/test/unit/generator.ts index 5ec3b3e1b8a1..4500b7be6ed4 100644 --- a/core/generator/gapic-generator-typescript/typescript/test/unit/generator.ts +++ b/core/generator/gapic-generator-typescript/typescript/test/unit/generator.ts @@ -300,10 +300,10 @@ apis: {name: 'google/cloud/test/v1/test.proto'}, {name: 'google/cloud/test/v1/other.proto'}, ], - } as unknown as protos.google.protobuf.compiler.CodeGeneratorRequest; + } as protos.google.protobuf.compiler.CodeGeneratorRequest; generator.response = { file: [], - } as unknown as protos.google.protobuf.compiler.CodeGeneratorResponse; + } as protos.google.protobuf.compiler.CodeGeneratorResponse; getTestGenerator(generator).addProtosToResponse(); @@ -367,6 +367,208 @@ apis: await generator.processTemplates(api); }, /Template directory .* does not exist\./); }); + + it('should generate telemetry tracing configuration in service client when enableTelemetryTracing is true (CJS)', async () => { + generator.request = { + protoFile: [ + { + name: 'google/cloud/test/v1/test.proto', + package: 'google.cloud.test.v1', + messageType: [{name: 'TestRequest'}, {name: 'TestResponse'}], + service: [ + { + name: 'TestService', + options: { + '.google.api.defaultHost': 'test.googleapis.com', + }, + method: [ + { + name: 'TestMethod', + inputType: '.google.cloud.test.v1.TestRequest', + outputType: '.google.cloud.test.v1.TestResponse', + }, + ], + }, + ], + }, + ], + fileToGenerate: ['google/cloud/test/v1/test.proto'], + } as protos.google.protobuf.compiler.CodeGeneratorRequest; + generator.templates = ['typescript_gapic']; + generator.enableTelemetryTracing = true; + generator.publishName = '@google-cloud/test'; + generator.response = { + file: [], + } as protos.google.protobuf.compiler.CodeGeneratorResponse; + + const api = getTestGenerator(generator).buildAPIObject(); + await generator.processTemplates(api); + + const clientFile = generator.response.file.find(f => + f.name?.includes('test_service_client.ts'), + ); + assert.ok(clientFile); + assert.ok( + clientFile.content?.includes('if (opts.enableTelemetryTracing) {'), + ); + assert.ok(clientFile.content?.includes('internalTelemetryInfo')); + assert.ok(clientFile.content?.includes("gcpClientService: 'test',")); + assert.ok(clientFile.content?.includes("gcpVersion: 'v1',")); + assert.ok( + clientFile.content?.includes( + "gcpRepo: 'googleapis/google-cloud-node',", + ), + ); + assert.ok( + clientFile.content?.includes("gcpArtifact: '@google-cloud/test',"), + ); + assert.ok( + clientFile.content?.includes( + 'this._defaults[methodName].enableTelemetryTracing =', + ), + ); + assert.ok(clientFile.content?.includes('opts.enableTelemetryTracing;')); + assert.ok( + clientFile.content?.includes('this._defaults[methodName].otherArgs ='), + ); + assert.ok( + clientFile.content?.includes( + 'this._defaults[methodName].otherArgs || {};', + ), + ); + assert.ok( + clientFile.content?.includes( + 'this._defaults[methodName].otherArgs.internalTelemetryInfo =', + ), + ); + assert.ok(clientFile.content?.includes('internalTelemetryInfo;')); + }); + + it('should generate telemetry tracing configuration in service client when enableTelemetryTracing is true (ESM)', async () => { + generator.request = { + protoFile: [ + { + name: 'google/cloud/test/v1/test.proto', + package: 'google.cloud.test.v1', + messageType: [{name: 'TestRequest'}, {name: 'TestResponse'}], + service: [ + { + name: 'TestService', + options: { + '.google.api.defaultHost': 'test.googleapis.com', + }, + method: [ + { + name: 'TestMethod', + inputType: '.google.cloud.test.v1.TestRequest', + outputType: '.google.cloud.test.v1.TestResponse', + }, + ], + }, + ], + }, + ], + fileToGenerate: ['google/cloud/test/v1/test.proto'], + } as protos.google.protobuf.compiler.CodeGeneratorRequest; + generator.templates = ['typescript_gapic']; + generator.format = ['esm']; + generator.enableTelemetryTracing = true; + generator.publishName = '@google-cloud/test'; + generator.response = { + file: [], + } as protos.google.protobuf.compiler.CodeGeneratorResponse; + + const api = getTestGenerator(generator).buildAPIObject(); + await generator.processTemplates(api); + + const clientFile = generator.response.file.find(f => + f.name?.includes('test_service_client.ts'), + ); + assert.ok(clientFile); + assert.ok( + clientFile.content?.includes('if (opts.enableTelemetryTracing) {'), + ); + assert.ok(clientFile.content?.includes('internalTelemetryInfo')); + assert.ok(clientFile.content?.includes("gcpClientService: 'test',")); + assert.ok(clientFile.content?.includes("gcpVersion: 'v1',")); + assert.ok( + clientFile.content?.includes( + "gcpRepo: 'googleapis/google-cloud-node',", + ), + ); + assert.ok( + clientFile.content?.includes("gcpArtifact: '@google-cloud/test',"), + ); + assert.ok( + clientFile.content?.includes( + 'this._defaults[methodName].enableTelemetryTracing =', + ), + ); + assert.ok(clientFile.content?.includes('opts.enableTelemetryTracing;')); + assert.ok( + clientFile.content?.includes('this._defaults[methodName].otherArgs ='), + ); + assert.ok( + clientFile.content?.includes( + 'this._defaults[methodName].otherArgs || {};', + ), + ); + assert.ok( + clientFile.content?.includes( + 'this._defaults[methodName].otherArgs.internalTelemetryInfo =', + ), + ); + assert.ok(clientFile.content?.includes('internalTelemetryInfo;')); + }); + + it('should not generate telemetry tracing configuration when enableTelemetryTracing is false', async () => { + generator.request = { + protoFile: [ + { + name: 'google/cloud/test/v1/test.proto', + package: 'google.cloud.test.v1', + messageType: [{name: 'TestRequest'}, {name: 'TestResponse'}], + service: [ + { + name: 'TestService', + options: { + '.google.api.defaultHost': 'test.googleapis.com', + }, + method: [ + { + name: 'TestMethod', + inputType: '.google.cloud.test.v1.TestRequest', + outputType: '.google.cloud.test.v1.TestResponse', + }, + ], + }, + ], + }, + ], + fileToGenerate: ['google/cloud/test/v1/test.proto'], + } as protos.google.protobuf.compiler.CodeGeneratorRequest; + generator.templates = ['typescript_gapic']; + generator.enableTelemetryTracing = false; + generator.response = { + file: [], + } as protos.google.protobuf.compiler.CodeGeneratorResponse; + + const api = getTestGenerator(generator).buildAPIObject(); + await generator.processTemplates(api); + + const clientFile = generator.response.file.find(f => + f.name?.includes('test_service_client.ts'), + ); + assert.ok(clientFile); + assert.strictEqual( + clientFile.content?.includes('if (opts.enableTelemetryTracing) {'), + false, + ); + assert.strictEqual( + clientFile.content?.includes('internalTelemetryInfo'), + false, + ); + }); }); describe('generate', () => { @@ -382,7 +584,7 @@ apis: try { generator.request = { protoFile: [], - } as unknown as protos.google.protobuf.compiler.CodeGeneratorRequest; + } as protos.google.protobuf.compiler.CodeGeneratorRequest; await generator.generate(); From d09833b104f844ec5b4848d5f0cb2798220428ee Mon Sep 17 00:00:00 2001 From: Shivanee Persaud Date: Tue, 1 Sep 2026 20:58:43 -0700 Subject: [PATCH 2/2] feat: add enableTelemetryTracing and internalTelemetryInfo to constructSettings Pass enableTelemetryTracing and internalTelemetryInfo directly into constructSettings in google-gax (gax, grpc, fallback) and generator templates, avoiding post-construction mutation of the defaults object. --- .../src/$version/$service_client.ts.njk | 28 +++---- .../esm/src/$version/$service_client.ts.njk | 28 +++---- .../typescript/test/unit/generator.ts | 52 +++++-------- core/packages/gax/src/fallback.ts | 12 ++- core/packages/gax/src/gax.ts | 13 +++- core/packages/gax/src/grpc.ts | 9 ++- core/packages/gax/test/unit/gax.ts | 75 +++++++++++++++++++ core/packages/gax/test/unit/grpc-fallback.ts | 35 +++++++++ core/packages/gax/test/unit/grpc.ts | 54 +++++++++++++ 9 files changed, 229 insertions(+), 77 deletions(-) diff --git a/core/generator/gapic-generator-typescript/templates/cjs/typescript_gapic/src/$version/$service_client.ts.njk b/core/generator/gapic-generator-typescript/templates/cjs/typescript_gapic/src/$version/$service_client.ts.njk index 182dae751d01..82dded752187 100644 --- a/core/generator/gapic-generator-typescript/templates/cjs/typescript_gapic/src/$version/$service_client.ts.njk +++ b/core/generator/gapic-generator-typescript/templates/cjs/typescript_gapic/src/$version/$service_client.ts.njk @@ -388,6 +388,15 @@ export class {{ service.name }}Client { ), }; {%- endfor %} +{%- endif %} +{%- if api.enableTelemetryTracing %} + + const internalTelemetryInfo = { + gcpClientService: '{{ api.loggingName }}', + gcpVersion: '{{ api.naming.version }}', + gcpRepo: 'googleapis/google-cloud-node', + gcpArtifact: '{{ api.publishName }}', + }; {%- endif %} // Put together the default options sent with requests. @@ -396,24 +405,7 @@ export class {{ service.name }}Client { opts.clientConfig || {}, {'x-goog-api-client': clientHeader.join(' ') {%- if service.apiVersion -%} , 'x-goog-api-version': '{{ service.apiVersion }}' -{%- endif -%}}); - - {%- if api.enableTelemetryTracing %} - if (opts.enableTelemetryTracing) { - // set the internal telemetry info using `otherArgs` attribute of `CallSettings` - const internalTelemetryInfo = { - gcpClientService: '{{ api.loggingName }}', - gcpVersion: '{{ api.naming.version }}', - gcpRepo: 'googleapis/google-cloud-node', - gcpArtifact: '{{ api.publishName }}', - }; - for (const methodName of Object.keys(this._defaults)) { - this._defaults[methodName].enableTelemetryTracing = opts.enableTelemetryTracing; - this._defaults[methodName].otherArgs = this._defaults[methodName].otherArgs || {}; - this._defaults[methodName].otherArgs.internalTelemetryInfo = internalTelemetryInfo; - } - } - {%- endif %} +{%- endif -%}}{% if api.enableTelemetryTracing %}, opts.enableTelemetryTracing, internalTelemetryInfo{% endif %}); // Set up a dictionary of "inner API calls"; the core implementation // of calling the API is handled in `google-gax`, with this code diff --git a/core/generator/gapic-generator-typescript/templates/esm/typescript_gapic/esm/src/$version/$service_client.ts.njk b/core/generator/gapic-generator-typescript/templates/esm/typescript_gapic/esm/src/$version/$service_client.ts.njk index fc0ca68f067d..e61b45594482 100644 --- a/core/generator/gapic-generator-typescript/templates/esm/typescript_gapic/esm/src/$version/$service_client.ts.njk +++ b/core/generator/gapic-generator-typescript/templates/esm/typescript_gapic/esm/src/$version/$service_client.ts.njk @@ -399,6 +399,15 @@ export class {{ service.name }}Client { ), }; {%- endfor %} +{%- endif %} +{%- if api.enableTelemetryTracing %} + + const internalTelemetryInfo = { + gcpClientService: '{{ api.loggingName }}', + gcpVersion: '{{ api.naming.version }}', + gcpRepo: 'googleapis/google-cloud-node', + gcpArtifact: '{{ api.publishName }}', + }; {%- endif %} // Put together the default options sent with requests. @@ -407,24 +416,7 @@ export class {{ service.name }}Client { opts.clientConfig || {}, {'x-goog-api-client': clientHeader.join(' ') {%- if service.apiVersion -%} , 'x-goog-api-version': '{{ service.apiVersion }}' -{%- endif %}}); - - {%- if api.enableTelemetryTracing %} - if (opts.enableTelemetryTracing) { - // set the internal telemetry info using `otherArgs` attribute of `CallSettings` - const internalTelemetryInfo = { - gcpClientService: '{{ api.loggingName }}', - gcpVersion: '{{ api.naming.version }}', - gcpRepo: 'googleapis/google-cloud-node', - gcpArtifact: '{{ api.publishName }}', - }; - for (const methodName of Object.keys(this._defaults)) { - this._defaults[methodName].enableTelemetryTracing = opts.enableTelemetryTracing; - this._defaults[methodName].otherArgs = this._defaults[methodName].otherArgs || {}; - this._defaults[methodName].otherArgs.internalTelemetryInfo = internalTelemetryInfo; - } - } - {%- endif %} +{%- endif %}}{% if api.enableTelemetryTracing %}, opts.enableTelemetryTracing, internalTelemetryInfo{% endif %}); // Set up a dictionary of "inner API calls"; the core implementation // of calling the API is handled in `google-gax`, with this code diff --git a/core/generator/gapic-generator-typescript/typescript/test/unit/generator.ts b/core/generator/gapic-generator-typescript/typescript/test/unit/generator.ts index 4500b7be6ed4..1048ab2f7d65 100644 --- a/core/generator/gapic-generator-typescript/typescript/test/unit/generator.ts +++ b/core/generator/gapic-generator-typescript/typescript/test/unit/generator.ts @@ -408,9 +408,6 @@ apis: f.name?.includes('test_service_client.ts'), ); assert.ok(clientFile); - assert.ok( - clientFile.content?.includes('if (opts.enableTelemetryTracing) {'), - ); assert.ok(clientFile.content?.includes('internalTelemetryInfo')); assert.ok(clientFile.content?.includes("gcpClientService: 'test',")); assert.ok(clientFile.content?.includes("gcpVersion: 'v1',")); @@ -423,25 +420,20 @@ apis: clientFile.content?.includes("gcpArtifact: '@google-cloud/test',"), ); assert.ok( - clientFile.content?.includes( - 'this._defaults[methodName].enableTelemetryTracing =', + /constructSettings\([\s\S]*opts\.enableTelemetryTracing[\s\S]*internalTelemetryInfo[\s\S]*\)/.test( + clientFile.content || '', ), ); - assert.ok(clientFile.content?.includes('opts.enableTelemetryTracing;')); - assert.ok( - clientFile.content?.includes('this._defaults[methodName].otherArgs ='), - ); - assert.ok( + assert.strictEqual( clientFile.content?.includes( - 'this._defaults[methodName].otherArgs || {};', + 'this._defaults[methodName].enableTelemetryTracing', ), + false, ); - assert.ok( - clientFile.content?.includes( - 'this._defaults[methodName].otherArgs.internalTelemetryInfo =', - ), + assert.strictEqual( + clientFile.content?.includes('this._defaults[methodName].otherArgs'), + false, ); - assert.ok(clientFile.content?.includes('internalTelemetryInfo;')); }); it('should generate telemetry tracing configuration in service client when enableTelemetryTracing is true (ESM)', async () => { @@ -485,9 +477,6 @@ apis: f.name?.includes('test_service_client.ts'), ); assert.ok(clientFile); - assert.ok( - clientFile.content?.includes('if (opts.enableTelemetryTracing) {'), - ); assert.ok(clientFile.content?.includes('internalTelemetryInfo')); assert.ok(clientFile.content?.includes("gcpClientService: 'test',")); assert.ok(clientFile.content?.includes("gcpVersion: 'v1',")); @@ -500,25 +489,20 @@ apis: clientFile.content?.includes("gcpArtifact: '@google-cloud/test',"), ); assert.ok( - clientFile.content?.includes( - 'this._defaults[methodName].enableTelemetryTracing =', + /constructSettings\([\s\S]*opts\.enableTelemetryTracing[\s\S]*internalTelemetryInfo[\s\S]*\)/.test( + clientFile.content || '', ), ); - assert.ok(clientFile.content?.includes('opts.enableTelemetryTracing;')); - assert.ok( - clientFile.content?.includes('this._defaults[methodName].otherArgs ='), - ); - assert.ok( + assert.strictEqual( clientFile.content?.includes( - 'this._defaults[methodName].otherArgs || {};', + 'this._defaults[methodName].enableTelemetryTracing', ), + false, ); - assert.ok( - clientFile.content?.includes( - 'this._defaults[methodName].otherArgs.internalTelemetryInfo =', - ), + assert.strictEqual( + clientFile.content?.includes('this._defaults[methodName].otherArgs'), + false, ); - assert.ok(clientFile.content?.includes('internalTelemetryInfo;')); }); it('should not generate telemetry tracing configuration when enableTelemetryTracing is false', async () => { @@ -561,11 +545,11 @@ apis: ); assert.ok(clientFile); assert.strictEqual( - clientFile.content?.includes('if (opts.enableTelemetryTracing) {'), + clientFile.content?.includes('internalTelemetryInfo'), false, ); assert.strictEqual( - clientFile.content?.includes('internalTelemetryInfo'), + clientFile.content?.includes('opts.enableTelemetryTracing'), false, ); }); diff --git a/core/packages/gax/src/fallback.ts b/core/packages/gax/src/fallback.ts index 9042340a11f2..d6c9f125432d 100644 --- a/core/packages/gax/src/fallback.ts +++ b/core/packages/gax/src/fallback.ts @@ -31,7 +31,7 @@ import * as fallbackRest from './fallbackRest'; import {isNodeJS} from './featureDetection'; import {generateServiceStub} from './fallbackServiceStub'; import {StreamType} from './streamingCalls/streaming'; -import {toLowerCamelCase} from './util'; +import {toLowerCamelCase, StaticTraceContext} from './util'; import {google} from '../protos/http'; import * as IamProtos from '../protos/iam_service'; import * as LocationProtos from '../protos/locations'; @@ -188,14 +188,16 @@ export class GrpcClient { /** * gRPC-fallback version of constructSettings - * A wrapper of {@link constructSettings} function under the gRPC context. + * A wrapper of {@link constructSettings} function under the gRPC-fallback context. * * Most of parameters are common among constructSettings, please take a look. - * @param {string} serviceName - The fullly-qualified name of the service. + * @param {string} serviceName - The fully-qualified name of the service. * @param {Object} clientConfig - A dictionary of the client config. * @param {Object} configOverrides - A dictionary of overriding configs. * @param {Object} headers - A dictionary of additional HTTP header name to * its value. + * @param {boolean} [enableTelemetryTracing] - Flag to enable telemetry tracing. + * @param {StaticTraceContext} [internalTelemetryInfo] - Static trace context for telemetry. * @return {Object} A mapping of method names to CallSettings. */ constructSettings( @@ -203,6 +205,8 @@ export class GrpcClient { clientConfig: gax.ClientConfig, configOverrides: gax.ClientConfig, headers: OutgoingHttpHeaders, + enableTelemetryTracing?: boolean, + internalTelemetryInfo?: StaticTraceContext, ) { function buildMetadata(abTests: {}, moreHeaders: OutgoingHttpHeaders) { const metadata: OutgoingHttpHeaders = {}; @@ -267,6 +271,8 @@ export class GrpcClient { configOverrides, Status, {metadataBuilder: buildMetadata}, + enableTelemetryTracing, + internalTelemetryInfo, ); } diff --git a/core/packages/gax/src/gax.ts b/core/packages/gax/src/gax.ts index 33f8d1672d3b..d106516b48ef 100644 --- a/core/packages/gax/src/gax.ts +++ b/core/packages/gax/src/gax.ts @@ -22,7 +22,7 @@ import type {Message} from 'protobufjs'; import {warn} from './warnings'; import {GoogleError} from './googleError'; import {BundleOptions} from './bundlingCalls/bundleExecutor'; -import {toLowerCamelCase} from './util'; +import {toLowerCamelCase, StaticTraceContext} from './util'; import {Status} from './status'; import {RequestType} from './apitypes'; @@ -788,8 +788,10 @@ export interface ClientConfig { * @param {Object.} retryNames - A dictionary mapping the strings * referring to response status codes to objects representing * those codes. - * @param {Object} otherArgs - the non-request arguments to be passed to the API + * @param {Object} [otherArgs] - the non-request arguments to be passed to the API * calls. + * @param {boolean} [enableTelemetryTracing] - Flag to enable telemetry tracing. + * @param {StaticTraceContext} [internalTelemetryInfo] - Static trace context for telemetry. * @return {Object} A mapping from method name to CallSettings, or null if the * service is not found in the config. */ @@ -799,8 +801,12 @@ export function constructSettings( configOverrides: ClientConfig, retryNames: {}, otherArgs?: {}, + enableTelemetryTracing?: boolean, + internalTelemetryInfo?: StaticTraceContext, ) { - otherArgs = otherArgs || {}; + otherArgs = internalTelemetryInfo + ? {...otherArgs, internalTelemetryInfo} + : otherArgs || {}; // eslint-disable-next-line @typescript-eslint/no-explicit-any const defaults: any = {}; @@ -859,6 +865,7 @@ export function constructSettings( : null, otherArgs, apiName, + enableTelemetryTracing, }); } diff --git a/core/packages/gax/src/grpc.ts b/core/packages/gax/src/grpc.ts index 3d39c628ef3f..05f31d5682a3 100644 --- a/core/packages/gax/src/grpc.ts +++ b/core/packages/gax/src/grpc.ts @@ -27,6 +27,7 @@ import * as protobuf from 'protobufjs'; import objectHash from 'object-hash'; import * as gax from './gax'; +import {StaticTraceContext} from './util'; import {ClientOptions} from '@grpc/grpc-js/build/src/client'; const googleProtoFilesDir = path.join(__dirname, '..', '..', 'build', 'protos'); @@ -370,11 +371,13 @@ export class GrpcClient { * A wrapper of {@link constructSettings} function under the gRPC context. * * Most of parameters are common among constructSettings, please take a look. - * @param {string} serviceName - The fullly-qualified name of the service. + * @param {string} serviceName - The fully-qualified name of the service. * @param {Object} clientConfig - A dictionary of the client config. * @param {Object} configOverrides - A dictionary of overriding configs. * @param {Object} headers - A dictionary of additional HTTP header name to * its value. + * @param {boolean} [enableTelemetryTracing] - Flag to enable telemetry tracing. + * @param {StaticTraceContext} [internalTelemetryInfo] - Static trace context for telemetry. * @return {Object} A mapping of method names to CallSettings. */ constructSettings( @@ -382,6 +385,8 @@ export class GrpcClient { clientConfig: gax.ClientConfig, configOverrides: gax.ClientConfig, headers: OutgoingHttpHeaders, + enableTelemetryTracing?: boolean, + internalTelemetryInfo?: StaticTraceContext, ) { return gax.constructSettings( serviceName, @@ -389,6 +394,8 @@ export class GrpcClient { configOverrides, this.grpc.status, {metadataBuilder: this.metadataBuilder(headers)}, + enableTelemetryTracing, + internalTelemetryInfo, ); } diff --git a/core/packages/gax/test/unit/gax.ts b/core/packages/gax/test/unit/gax.ts index d166ef98c03c..510278281207 100644 --- a/core/packages/gax/test/unit/gax.ts +++ b/core/packages/gax/test/unit/gax.ts @@ -114,12 +114,16 @@ describe('gax construct settings', () => { expectRetryOptions(settings.retry); assert.deepStrictEqual(settings.retry.retryCodes, [1, 2]); assert.strictEqual(settings.otherArgs, otherArgs); + assert.strictEqual(settings.enableTelemetryTracing, undefined); + assert.strictEqual(settings.otherArgs.internalTelemetryInfo, undefined); settings = defaults.pageStreamingMethod; assert.strictEqual(settings.timeout, 30000); expectRetryOptions(settings.retry); assert.deepStrictEqual(settings.retry.retryCodes, [3]); assert.strictEqual(settings.otherArgs, otherArgs); + assert.strictEqual(settings.enableTelemetryTracing, undefined); + assert.strictEqual(settings.otherArgs.internalTelemetryInfo, undefined); }); it('overrides settings', () => { @@ -199,6 +203,77 @@ describe('gax construct settings', () => { assert.deepStrictEqual(settings.retry.retryCodes, [RETRY_DICT.code_c]); }); + it('creates settings with enableTelemetryTracing and internalTelemetryInfo', () => { + const otherArgs = {key: 'value'}; + const telemetryInfo = { + gcpClientService: 'test.googleapis.com', + gcpVersion: '1.0.0', + gcpRepo: 'googleapis/google-cloud-node', + gcpArtifact: 'google-cloud-test', + }; + const defaults = gax.constructSettings( + SERVICE_NAME, + A_CONFIG, + {}, + RETRY_DICT, + otherArgs, + true, + telemetryInfo, + ); + const settings = defaults.bundlingMethod; + assert.strictEqual(settings.enableTelemetryTracing, true); + assert.strictEqual(settings.otherArgs.key, 'value'); + assert.deepStrictEqual( + settings.otherArgs.internalTelemetryInfo, + telemetryInfo, + ); + + const pageSettings = defaults.pageStreamingMethod; + assert.strictEqual(pageSettings.enableTelemetryTracing, true); + assert.deepStrictEqual( + pageSettings.otherArgs.internalTelemetryInfo, + telemetryInfo, + ); + }); + + it('creates settings with internalTelemetryInfo when otherArgs is undefined', () => { + const telemetryInfo = { + gcpClientService: 'test.googleapis.com', + gcpVersion: '1.0.0', + gcpRepo: 'googleapis/google-cloud-node', + gcpArtifact: 'google-cloud-test', + }; + const defaults = gax.constructSettings( + SERVICE_NAME, + A_CONFIG, + {}, + RETRY_DICT, + undefined, + true, + telemetryInfo, + ); + const settings = defaults.bundlingMethod; + assert.strictEqual(settings.enableTelemetryTracing, true); + assert.deepStrictEqual( + settings.otherArgs.internalTelemetryInfo, + telemetryInfo, + ); + }); + + it('creates settings with enableTelemetryTracing set to false', () => { + const defaults = gax.constructSettings( + SERVICE_NAME, + A_CONFIG, + {}, + RETRY_DICT, + {}, + false, + ); + const settings = defaults.bundlingMethod; + assert.strictEqual(settings.enableTelemetryTracing, false); + assert.strictEqual(settings.otherArgs.internalTelemetryInfo, undefined); + }); + describe('CallSettings telemetry fields', () => { it('defaults enableTelemetryTracing to undefined', () => { const settings = new gax.CallSettings(); diff --git a/core/packages/gax/test/unit/grpc-fallback.ts b/core/packages/gax/test/unit/grpc-fallback.ts index 3ea2a5511292..456bca7e1902 100644 --- a/core/packages/gax/test/unit/grpc-fallback.ts +++ b/core/packages/gax/test/unit/grpc-fallback.ts @@ -255,6 +255,41 @@ describe('grpc-fallback', () => { assert(headers['x-goog-api-client'][0].match('grpc-web/')); }); + it('constructSettings should accept enableTelemetryTracing and internalTelemetryInfo', () => { + const gapicConfig = { + interfaces: { + 'google.showcase.v1beta1.Echo': { + retry_codes: {}, + retry_params: {}, + methods: { + Echo: { + timeout_millis: 60000, + }, + }, + }, + }, + }; + const telemetryInfo = { + gcpClientService: 'fake', + gcpVersion: 'v1', + gcpRepo: 'googleapis/google-cloud-node', + gcpArtifact: '@google-cloud/fake', + }; + const settings = gaxGrpc.constructSettings( + 'google.showcase.v1beta1.Echo', + gapicConfig, + {}, + {}, + true, + telemetryInfo, + ); + assert.strictEqual(settings.echo.enableTelemetryTracing, true); + assert.deepStrictEqual( + settings.echo.otherArgs.internalTelemetryInfo, + telemetryInfo, + ); + }); + it('should make a request', done => { const requestObject = {content: 'test-content'}; const responseType = protos.lookupType('EchoResponse'); diff --git a/core/packages/gax/test/unit/grpc.ts b/core/packages/gax/test/unit/grpc.ts index 7b82cb80e17b..986f57c52535 100644 --- a/core/packages/gax/test/unit/grpc.ts +++ b/core/packages/gax/test/unit/grpc.ts @@ -33,6 +33,7 @@ import { GrpcClientOptions, GrpcModule, } from '../../src/grpc'; +import {ClientConfig} from '../../src/gax'; import {PassThroughClient} from 'google-auth-library'; function gaxGrpc(options?: GrpcClientOptions) { @@ -127,6 +128,59 @@ describe('grpc', () => { ) {} } + describe('constructSettings', () => { + const grpcClient = gaxGrpc(); + const serviceConfig = { + interfaces: { + 'google.fake.service': { + methods: { + method: { + timeout_millis: 10, + }, + }, + }, + }, + }; + + it('constructs settings without telemetry options', () => { + const settings = grpcClient.constructSettings( + 'google.fake.service', + serviceConfig as unknown as ClientConfig, + {} as unknown as ClientConfig, + {}, + ); + assert.strictEqual(settings.method.timeout, 10); + assert.strictEqual(settings.method.enableTelemetryTracing, undefined); + assert.strictEqual( + settings.method.otherArgs.internalTelemetryInfo, + undefined, + ); + }); + + it('constructs settings with enableTelemetryTracing and internalTelemetryInfo', () => { + const telemetryInfo = { + gcpClientService: 'fake', + gcpVersion: 'v1', + gcpRepo: 'googleapis/google-cloud-node', + gcpArtifact: '@google-cloud/fake', + }; + const settings = grpcClient.constructSettings( + 'google.fake.service', + serviceConfig as unknown as ClientConfig, + {} as unknown as ClientConfig, + {}, + true, + telemetryInfo, + ); + assert.strictEqual(settings.method.timeout, 10); + assert.strictEqual(settings.method.enableTelemetryTracing, true); + assert.deepStrictEqual( + settings.method.otherArgs.internalTelemetryInfo, + telemetryInfo, + ); + }); + }); + describe('createStub', () => { let grpcClient: GrpcClient; const dummyChannelCreds = {channelCreds: 'dummyChannelCreds'};