From abb49c65dd0dc5759ece36cf8df1d9d2d8adce5f Mon Sep 17 00:00:00 2001 From: Shivanee Persaud Date: Fri, 21 Aug 2026 13:43:15 -0700 Subject: [PATCH 1/5] feat(gax): support telemetry options in CallSettings for tracing --- core/packages/gax/src/clientInterface.ts | 24 +++++- core/packages/gax/src/createApiCall.ts | 24 +++++- core/packages/gax/src/gax.ts | 17 +++++ core/packages/gax/src/index.ts | 2 +- core/packages/gax/test/unit/apiCallable.ts | 85 ++++++++++++++++++++-- core/packages/gax/test/unit/gax.ts | 71 ++++++++++++++++++ 6 files changed, 209 insertions(+), 14 deletions(-) diff --git a/core/packages/gax/src/clientInterface.ts b/core/packages/gax/src/clientInterface.ts index b9f3bd8b8e9c..b872b795c33c 100644 --- a/core/packages/gax/src/clientInterface.ts +++ b/core/packages/gax/src/clientInterface.ts @@ -28,10 +28,19 @@ import { import * as longrunning from './longRunningCalls/longrunning'; import * as operationProtos from '../protos/operations'; +/** + * The static trace context is information about the Google Cloud client library that is + * used to generate telemetry tracing information. + */ +export interface StaticTraceContext { + gcpClientService?: string; + gcpVersion?: string; + gcpRepo?: string; + gcpArtifact?: string; +} + export interface ClientOptions - extends GrpcClientOptions, - GoogleAuthOptions, - ClientStubOptions { + extends GrpcClientOptions, GoogleAuthOptions, ClientStubOptions { libName?: string; libVersion?: string; clientConfig?: gax.ClientConfig; @@ -42,6 +51,15 @@ export interface ClientOptions // No preference; exception will be thrown if both are set to different values. universeDomain?: string; universe_domain?: string; + /** + * Whether to enable telemetry tracing for the client. + */ + enableTelemetryTracing?: boolean; + /** + * The static trace context is information about the Google Cloud client library that is + * used to generate telemetry tracing information. + */ + internalTelemetryInfo?: StaticTraceContext; } export interface Descriptors { diff --git a/core/packages/gax/src/createApiCall.ts b/core/packages/gax/src/createApiCall.ts index b3fdee987a6d..ca0e66a9aa1b 100644 --- a/core/packages/gax/src/createApiCall.ts +++ b/core/packages/gax/src/createApiCall.ts @@ -34,6 +34,19 @@ import {addTimeoutArg} from './normalCalls/timeout'; import {StreamingApiCaller} from './streamingCalls/streamingApiCaller'; import {warn} from './warnings'; +/** + * Checks if telemetry tracing is enabled + * @param settings + * @returns true if telemetry tracing is enabled, false otherwise + */ +export function checkTelemetryEnabled(settings?: CallSettings): boolean { + const tracingEnabled = + Boolean(settings?.enableTelemetryTracing) && + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED === 'true' && + settings?.internalTelemetryInfo !== undefined; + return Boolean(tracingEnabled); +} + /** * Converts an rpc call into an API call governed by the settings. * @@ -66,8 +79,7 @@ export function createApiCall( const funcPromise = typeof func === 'function' ? Promise.resolve(func) : func; // the following apiCaller will be used for all calls of this function... const apiCaller = createAPICaller(settings, descriptor); - - return ( + const invokeCall = ( request: RequestType, callOptions?: CallOptions, callback?: APICallback, @@ -154,7 +166,12 @@ export function createApiCall( .then((apiCall: SimpleCallbackFunction) => { // After adding retries / timeouts, the call function becomes simpler: // it only accepts request and callback. - currentApiCaller.call(apiCall, request, thisSettings, ongoingCall); + return currentApiCaller.call( + apiCall, + request, + thisSettings, + ongoingCall, + ); }) .catch(err => { currentApiCaller.fail(ongoingCall, err); @@ -164,4 +181,5 @@ export function createApiCall( // or to cancel the ongoing call. return currentApiCaller.result(ongoingCall); }; + return invokeCall; } diff --git a/core/packages/gax/src/gax.ts b/core/packages/gax/src/gax.ts index a38152c24290..8b70f5d9b052 100644 --- a/core/packages/gax/src/gax.ts +++ b/core/packages/gax/src/gax.ts @@ -25,6 +25,7 @@ import {BundleOptions} from './bundlingCalls/bundleExecutor'; import {toLowerCamelCase} from './util'; import {Status} from './status'; import {RequestType} from './apitypes'; +import type {StaticTraceContext} from './clientInterface'; /** * Encapsulates the overridable settings for a particular API call. @@ -170,6 +171,8 @@ export interface CallOptions { longrunning?: BackoffSettings; apiName?: string; retryRequestOptions?: RetryRequestOptions; + enableTelemetryTracing?: boolean; + internalTelemetryInfo?: StaticTraceContext; } export class CallSettings { @@ -186,6 +189,8 @@ export class CallSettings { longrunning?: BackoffSettings; apiName?: string; retryRequestOptions?: RetryRequestOptions; + enableTelemetryTracing?: boolean; + internalTelemetryInfo?: StaticTraceContext; /** * @param {Object} settings - An object containing parameters of this settings. @@ -219,6 +224,8 @@ export class CallSettings { 'longrunning' in settings ? settings.longrunning : undefined; this.apiName = settings.apiName ?? undefined; this.retryRequestOptions = settings.retryRequestOptions; + this.enableTelemetryTracing = settings.enableTelemetryTracing; + this.internalTelemetryInfo = settings.internalTelemetryInfo; } /** @@ -242,6 +249,8 @@ export class CallSettings { let longrunning = this.longrunning; let apiName = this.apiName; let retryRequestOptions = this.retryRequestOptions; + let enableTelemetryTracing = this.enableTelemetryTracing; + let internalTelemetryInfo = this.internalTelemetryInfo; // If the user provides a timeout to the method, that timeout value will be used // to override the backoff settings. @@ -297,6 +306,12 @@ export class CallSettings { if ('retryRequestOptions' in options) { retryRequestOptions = options.retryRequestOptions; } + if ('enableTelemetryTracing' in options) { + enableTelemetryTracing = options.enableTelemetryTracing; + } + if ('internalTelemetryInfo' in options) { + internalTelemetryInfo = options.internalTelemetryInfo; + } return new CallSettings({ timeout, @@ -309,6 +324,8 @@ export class CallSettings { isBundling, apiName, retryRequestOptions, + enableTelemetryTracing, + internalTelemetryInfo, }); } } diff --git a/core/packages/gax/src/index.ts b/core/packages/gax/src/index.ts index d9c82f34530e..710d90e42a71 100644 --- a/core/packages/gax/src/index.ts +++ b/core/packages/gax/src/index.ts @@ -29,7 +29,7 @@ export * as loggingUtils from 'google-logging-utils'; export {grpc}; export {CancellablePromise, OngoingCall} from './call'; -export {createApiCall} from './createApiCall'; +export {createApiCall, checkTelemetryEnabled} from './createApiCall'; export { BundleDescriptor, LongrunningDescriptor, diff --git a/core/packages/gax/test/unit/apiCallable.ts b/core/packages/gax/test/unit/apiCallable.ts index f341ec12f01f..59bed189bad6 100644 --- a/core/packages/gax/test/unit/apiCallable.ts +++ b/core/packages/gax/test/unit/apiCallable.ts @@ -21,6 +21,7 @@ import * as sinon from 'sinon'; import {RequestType} from '../../src/apitypes'; import * as gax from '../../src/gax'; +import {checkTelemetryEnabled} from '../../src/createApiCall'; import {GoogleError} from '../../src/googleError'; import * as utils from './utils'; import * as retries from '../../src/normalCalls/retries'; @@ -329,6 +330,75 @@ describe('createApiCall', () => { ); } }); + + describe('in regards to OpenTelemetry Tracing', () => { + afterEach(() => { + delete process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED; + }); + + describe('checkTelemetryEnabled', () => { + const mockSettings = new gax.CallSettings({ + enableTelemetryTracing: true, + internalTelemetryInfo: { + gcpClientService: 'test.googleapis.com', + }, + }); + + it('returns true when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED=true and settings are configured', () => { + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; + assert.strictEqual(checkTelemetryEnabled(mockSettings), true); + }); + + it('returns false when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED is not set', () => { + assert.strictEqual(checkTelemetryEnabled(mockSettings), false); + }); + + it('returns false when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED is not "true"', () => { + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'false'; + assert.strictEqual(checkTelemetryEnabled(mockSettings), false); + }); + + it('returns false when enableTelemetryTracing is not set on settings', () => { + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; + const noTracingSettings = new gax.CallSettings({ + internalTelemetryInfo: { + gcpClientService: 'test.googleapis.com', + }, + }); + assert.strictEqual(checkTelemetryEnabled(noTracingSettings), false); + }); + + it('returns false when internalTelemetryInfo is not set on settings', () => { + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; + const noInfoSettings = new gax.CallSettings({ + enableTelemetryTracing: true, + }); + assert.strictEqual(checkTelemetryEnabled(noInfoSettings), false); + }); + + it('returns false when settings is undefined', () => { + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; + assert.strictEqual(checkTelemetryEnabled(undefined), false); + }); + }); + + it('creates an api call when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED and CallSettings field is set', () => { + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; + const mockCallSettings = { + enableTelemetryTracing: true, + internalTelemetryInfo: { + gcpClientService: 'test.googleapis.com', + }, + }; + const apiCall = createApiCall(() => {}, {settings: mockCallSettings}); + assert.strictEqual(typeof apiCall, 'function'); + }); + + it('creates an api call when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED is not set', () => { + const apiCall = createApiCall(() => {}); + assert.strictEqual(typeof apiCall, 'function'); + }); + }); }); describe('Promise', () => { @@ -350,7 +420,7 @@ describe('Promise', () => { assert.ok(Array.isArray(response)); assert.strictEqual(response[0], 42); assert.ok(deadlineArg); - done(); + return done(); }) .catch(done); }); @@ -380,7 +450,7 @@ describe('Promise', () => { const promise = (apiCall as any)(null); promise .then(() => { - done(new Error('should not reach')); + return done(new Error('should not reach')); }) .catch((err: {code: number}) => { assert(err instanceof GoogleError); @@ -420,7 +490,7 @@ describe('Promise', () => { const promise = (apiCall as any)(null); promise .then(() => { - done(new Error('should not reach')); + return done(new Error('should not reach')); }) .catch(() => { assert(callCount < 4); @@ -509,7 +579,7 @@ describe('retryable', () => { assert.strictEqual(resp[0], 1729); assert.strictEqual(toAttempt, 0); assert.ok(deadlineArg); - done(); + return done(); }) .catch(done); }); @@ -534,7 +604,7 @@ describe('retryable', () => { const promise = apiCall({}, undefined); promise .then(() => { - done(new Error('should not reach')); + return done(new Error('should not reach')); }) .catch((err: Error) => { assert(err instanceof Error); @@ -795,6 +865,7 @@ describe('retryable', () => { }) .then(() => { mockBuilder.verify(); + return; }); }); @@ -821,9 +892,9 @@ describe('retryable', () => { try { assert.strictEqual(gotHeaders.h1, 'val1'); assert.strictEqual(gotHeaders.h2, 'val2'); - done(); + return done(); } catch (err) { - done(err); + return done(err); } }); }); diff --git a/core/packages/gax/test/unit/gax.ts b/core/packages/gax/test/unit/gax.ts index 214b3d07d46f..74271d8df16a 100644 --- a/core/packages/gax/test/unit/gax.ts +++ b/core/packages/gax/test/unit/gax.ts @@ -198,4 +198,75 @@ describe('gax construct settings', () => { assert.strictEqual(backoff.maxRetryDelayMillis, 1000); assert.deepStrictEqual(settings.retry.retryCodes, [RETRY_DICT.code_c]); }); + + describe('CallSettings telemetry fields', () => { + const mockTelemetryInfo = { + gcpClientService: 'test.googleapis.com', + gcpVersion: '1.0.0', + gcpRepo: 'googleapis/google-cloud-node', + gcpArtifact: 'google-cloud-test', + }; + + it('defaults enableTelemetryTracing and internalTelemetryInfo to undefined', () => { + const settings = new gax.CallSettings(); + assert.strictEqual(settings.enableTelemetryTracing, undefined); + assert.strictEqual(settings.internalTelemetryInfo, undefined); + }); + + it('initializes enableTelemetryTracing and internalTelemetryInfo', () => { + const settings = new gax.CallSettings({ + enableTelemetryTracing: true, + internalTelemetryInfo: mockTelemetryInfo, + }); + assert.strictEqual(settings.enableTelemetryTracing, true); + assert.deepStrictEqual(settings.internalTelemetryInfo, mockTelemetryInfo); + }); + + it('merges enableTelemetryTracing and internalTelemetryInfo', () => { + const settings = new gax.CallSettings({ + enableTelemetryTracing: true, + internalTelemetryInfo: mockTelemetryInfo, + }); + const merged = settings.merge({ + enableTelemetryTracing: false, + }); + assert.strictEqual(merged.enableTelemetryTracing, false); + assert.deepStrictEqual(merged.internalTelemetryInfo, mockTelemetryInfo); + }); + + it('merges with new internalTelemetryInfo', () => { + const settings = new gax.CallSettings({ + enableTelemetryTracing: true, + internalTelemetryInfo: mockTelemetryInfo, + }); + const newTelemetryInfo = { + gcpClientService: 'updated.googleapis.com', + }; + const merged = settings.merge({ + internalTelemetryInfo: newTelemetryInfo, + }); + assert.strictEqual(merged.enableTelemetryTracing, true); + assert.deepStrictEqual(merged.internalTelemetryInfo, newTelemetryInfo); + }); + + it('copies telemetry fields when merging with null/empty options', () => { + const settings = new gax.CallSettings({ + enableTelemetryTracing: true, + internalTelemetryInfo: mockTelemetryInfo, + }); + const mergedNull = settings.merge(null); + assert.strictEqual(mergedNull.enableTelemetryTracing, true); + assert.deepStrictEqual( + mergedNull.internalTelemetryInfo, + mockTelemetryInfo, + ); + + const mergedEmpty = settings.merge({}); + assert.strictEqual(mergedEmpty.enableTelemetryTracing, true); + assert.deepStrictEqual( + mergedEmpty.internalTelemetryInfo, + mockTelemetryInfo, + ); + }); + }); }); From f6932dc93915679b481be92a93887d0af66580ab Mon Sep 17 00:00:00 2001 From: Shivanee Persaud Date: Tue, 25 Aug 2026 12:58:29 -0700 Subject: [PATCH 2/5] refactor(gax): remove internalTelemetryInfo from ClientOptions --- core/packages/gax/src/clientInterface.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/packages/gax/src/clientInterface.ts b/core/packages/gax/src/clientInterface.ts index b872b795c33c..69517812f25c 100644 --- a/core/packages/gax/src/clientInterface.ts +++ b/core/packages/gax/src/clientInterface.ts @@ -55,11 +55,6 @@ export interface ClientOptions * Whether to enable telemetry tracing for the client. */ enableTelemetryTracing?: boolean; - /** - * The static trace context is information about the Google Cloud client library that is - * used to generate telemetry tracing information. - */ - internalTelemetryInfo?: StaticTraceContext; } export interface Descriptors { From 01dca2b62d9593392f6d79a6eaa83135f583bcc7 Mon Sep 17 00:00:00 2001 From: Shivanee Persaud Date: Tue, 25 Aug 2026 13:13:07 -0700 Subject: [PATCH 3/5] refactor(gax): move checkTelemetryEnabled to util.ts and export it --- core/packages/gax/src/createApiCall.ts | 13 ------ core/packages/gax/src/index.ts | 9 +++- core/packages/gax/src/util.ts | 15 ++++++ core/packages/gax/test/unit/apiCallable.ts | 47 ------------------- core/packages/gax/test/unit/util.ts | 54 +++++++++++++++++++++- 5 files changed, 75 insertions(+), 63 deletions(-) diff --git a/core/packages/gax/src/createApiCall.ts b/core/packages/gax/src/createApiCall.ts index ca0e66a9aa1b..e161879d5c93 100644 --- a/core/packages/gax/src/createApiCall.ts +++ b/core/packages/gax/src/createApiCall.ts @@ -34,19 +34,6 @@ import {addTimeoutArg} from './normalCalls/timeout'; import {StreamingApiCaller} from './streamingCalls/streamingApiCaller'; import {warn} from './warnings'; -/** - * Checks if telemetry tracing is enabled - * @param settings - * @returns true if telemetry tracing is enabled, false otherwise - */ -export function checkTelemetryEnabled(settings?: CallSettings): boolean { - const tracingEnabled = - Boolean(settings?.enableTelemetryTracing) && - process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED === 'true' && - settings?.internalTelemetryInfo !== undefined; - return Boolean(tracingEnabled); -} - /** * Converts an rpc call into an API call governed by the settings. * diff --git a/core/packages/gax/src/index.ts b/core/packages/gax/src/index.ts index 710d90e42a71..cb86a17ba3ae 100644 --- a/core/packages/gax/src/index.ts +++ b/core/packages/gax/src/index.ts @@ -29,7 +29,7 @@ export * as loggingUtils from 'google-logging-utils'; export {grpc}; export {CancellablePromise, OngoingCall} from './call'; -export {createApiCall, checkTelemetryEnabled} from './createApiCall'; +export {createApiCall} from './createApiCall'; export { BundleDescriptor, LongrunningDescriptor, @@ -113,7 +113,12 @@ export { PaginationResponse, } from './clientInterface'; -export {makeUUID, decodeAnyProtosInArray, decodeProtobufAny} from './util'; +export { + makeUUID, + decodeAnyProtosInArray, + decodeProtobufAny, + checkTelemetryEnabled, +} from './util'; export {ServiceError, ChannelCredentials} from '@grpc/grpc-js'; export {warn} from './warnings'; diff --git a/core/packages/gax/src/util.ts b/core/packages/gax/src/util.ts index 16f32f56eb75..180209a8e988 100644 --- a/core/packages/gax/src/util.ts +++ b/core/packages/gax/src/util.ts @@ -14,12 +14,27 @@ * limitations under the License. */ +import {CallSettings} from './gax'; + const PROTO_TYPE_PREFIX = 'type.googleapis.com/'; const NUM_OF_PARTS_IN_PROTO_TYPE_NAME = 2; const randomUUID = () => globalThis.crypto?.randomUUID() || require('crypto').randomUUID(); +/** + * Checks if telemetry tracing is enabled + * @param settings + * @returns true if telemetry tracing is enabled, false otherwise + */ +export function checkTelemetryEnabled(settings?: CallSettings): boolean { + const tracingEnabled = + Boolean(settings?.enableTelemetryTracing) && + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED === 'true' && + settings?.internalTelemetryInfo !== undefined; + return Boolean(tracingEnabled); +} + function words(str: string, normalize = false) { if (normalize) { // strings like somethingABCSomething are special case for protobuf.js, diff --git a/core/packages/gax/test/unit/apiCallable.ts b/core/packages/gax/test/unit/apiCallable.ts index 59bed189bad6..db2c60abe442 100644 --- a/core/packages/gax/test/unit/apiCallable.ts +++ b/core/packages/gax/test/unit/apiCallable.ts @@ -21,7 +21,6 @@ import * as sinon from 'sinon'; import {RequestType} from '../../src/apitypes'; import * as gax from '../../src/gax'; -import {checkTelemetryEnabled} from '../../src/createApiCall'; import {GoogleError} from '../../src/googleError'; import * as utils from './utils'; import * as retries from '../../src/normalCalls/retries'; @@ -336,52 +335,6 @@ describe('createApiCall', () => { delete process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED; }); - describe('checkTelemetryEnabled', () => { - const mockSettings = new gax.CallSettings({ - enableTelemetryTracing: true, - internalTelemetryInfo: { - gcpClientService: 'test.googleapis.com', - }, - }); - - it('returns true when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED=true and settings are configured', () => { - process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; - assert.strictEqual(checkTelemetryEnabled(mockSettings), true); - }); - - it('returns false when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED is not set', () => { - assert.strictEqual(checkTelemetryEnabled(mockSettings), false); - }); - - it('returns false when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED is not "true"', () => { - process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'false'; - assert.strictEqual(checkTelemetryEnabled(mockSettings), false); - }); - - it('returns false when enableTelemetryTracing is not set on settings', () => { - process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; - const noTracingSettings = new gax.CallSettings({ - internalTelemetryInfo: { - gcpClientService: 'test.googleapis.com', - }, - }); - assert.strictEqual(checkTelemetryEnabled(noTracingSettings), false); - }); - - it('returns false when internalTelemetryInfo is not set on settings', () => { - process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; - const noInfoSettings = new gax.CallSettings({ - enableTelemetryTracing: true, - }); - assert.strictEqual(checkTelemetryEnabled(noInfoSettings), false); - }); - - it('returns false when settings is undefined', () => { - process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; - assert.strictEqual(checkTelemetryEnabled(undefined), false); - }); - }); - it('creates an api call when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED and CallSettings field is set', () => { process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; const mockCallSettings = { diff --git a/core/packages/gax/test/unit/util.ts b/core/packages/gax/test/unit/util.ts index 2a716fa27113..fffaf7b69509 100644 --- a/core/packages/gax/test/unit/util.ts +++ b/core/packages/gax/test/unit/util.ts @@ -15,7 +15,7 @@ */ import assert from 'assert'; -import {describe, it} from 'mocha'; +import {afterEach, describe, it} from 'mocha'; import { toCamelCase as snakeToCamelCase, camelToSnakeCase, @@ -24,7 +24,9 @@ import { getProtoNameFromFullName, decodeProtobufAny, decodeAnyProtosInArray, + checkTelemetryEnabled, } from '../../src/util'; +import {CallSettings} from '../../src/gax'; import * as protobuf from 'protobufjs'; import protosJson from '../../protos/status.json'; @@ -196,4 +198,54 @@ describe('util.ts', () => { JSON.stringify([{reason: 'SERVICE_DISABLED'}]), ); }); + + describe('checkTelemetryEnabled', () => { + afterEach(() => { + delete process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED; + }); + + const mockSettings = new CallSettings({ + enableTelemetryTracing: true, + internalTelemetryInfo: { + gcpClientService: 'test.googleapis.com', + }, + }); + + it('returns true when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED=true and settings are configured', () => { + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; + assert.strictEqual(checkTelemetryEnabled(mockSettings), true); + }); + + it('returns false when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED is not set', () => { + assert.strictEqual(checkTelemetryEnabled(mockSettings), false); + }); + + it('returns false when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED is not "true"', () => { + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'false'; + assert.strictEqual(checkTelemetryEnabled(mockSettings), false); + }); + + it('returns false when enableTelemetryTracing is not set on settings', () => { + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; + const noTracingSettings = new CallSettings({ + internalTelemetryInfo: { + gcpClientService: 'test.googleapis.com', + }, + }); + assert.strictEqual(checkTelemetryEnabled(noTracingSettings), false); + }); + + it('returns false when internalTelemetryInfo is not set on settings', () => { + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; + const noInfoSettings = new CallSettings({ + enableTelemetryTracing: true, + }); + assert.strictEqual(checkTelemetryEnabled(noInfoSettings), false); + }); + + it('returns false when settings is undefined', () => { + process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; + assert.strictEqual(checkTelemetryEnabled(undefined), false); + }); + }); }); From cdd934ff099301e12df4ed24624a439c39b9cb91 Mon Sep 17 00:00:00 2001 From: Shivanee Persaud Date: Tue, 25 Aug 2026 15:36:37 -0700 Subject: [PATCH 4/5] refactor(gax): remove internalTelemetryInfo from CallSettings and CallOptions --- core/packages/gax/src/gax.ts | 9 ----- core/packages/gax/src/util.ts | 2 +- core/packages/gax/test/unit/apiCallable.ts | 10 +++-- core/packages/gax/test/unit/gax.ts | 44 ++-------------------- core/packages/gax/test/unit/util.ts | 12 ++++-- 5 files changed, 19 insertions(+), 58 deletions(-) diff --git a/core/packages/gax/src/gax.ts b/core/packages/gax/src/gax.ts index 8b70f5d9b052..33f8d1672d3b 100644 --- a/core/packages/gax/src/gax.ts +++ b/core/packages/gax/src/gax.ts @@ -25,7 +25,6 @@ import {BundleOptions} from './bundlingCalls/bundleExecutor'; import {toLowerCamelCase} from './util'; import {Status} from './status'; import {RequestType} from './apitypes'; -import type {StaticTraceContext} from './clientInterface'; /** * Encapsulates the overridable settings for a particular API call. @@ -172,7 +171,6 @@ export interface CallOptions { apiName?: string; retryRequestOptions?: RetryRequestOptions; enableTelemetryTracing?: boolean; - internalTelemetryInfo?: StaticTraceContext; } export class CallSettings { @@ -190,7 +188,6 @@ export class CallSettings { apiName?: string; retryRequestOptions?: RetryRequestOptions; enableTelemetryTracing?: boolean; - internalTelemetryInfo?: StaticTraceContext; /** * @param {Object} settings - An object containing parameters of this settings. @@ -225,7 +222,6 @@ export class CallSettings { this.apiName = settings.apiName ?? undefined; this.retryRequestOptions = settings.retryRequestOptions; this.enableTelemetryTracing = settings.enableTelemetryTracing; - this.internalTelemetryInfo = settings.internalTelemetryInfo; } /** @@ -250,7 +246,6 @@ export class CallSettings { let apiName = this.apiName; let retryRequestOptions = this.retryRequestOptions; let enableTelemetryTracing = this.enableTelemetryTracing; - let internalTelemetryInfo = this.internalTelemetryInfo; // If the user provides a timeout to the method, that timeout value will be used // to override the backoff settings. @@ -309,9 +304,6 @@ export class CallSettings { if ('enableTelemetryTracing' in options) { enableTelemetryTracing = options.enableTelemetryTracing; } - if ('internalTelemetryInfo' in options) { - internalTelemetryInfo = options.internalTelemetryInfo; - } return new CallSettings({ timeout, @@ -325,7 +317,6 @@ export class CallSettings { apiName, retryRequestOptions, enableTelemetryTracing, - internalTelemetryInfo, }); } } diff --git a/core/packages/gax/src/util.ts b/core/packages/gax/src/util.ts index 180209a8e988..de388fe4c834 100644 --- a/core/packages/gax/src/util.ts +++ b/core/packages/gax/src/util.ts @@ -31,7 +31,7 @@ export function checkTelemetryEnabled(settings?: CallSettings): boolean { const tracingEnabled = Boolean(settings?.enableTelemetryTracing) && process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED === 'true' && - settings?.internalTelemetryInfo !== undefined; + settings?.otherArgs?.internalTelemetryInfo !== undefined; return Boolean(tracingEnabled); } diff --git a/core/packages/gax/test/unit/apiCallable.ts b/core/packages/gax/test/unit/apiCallable.ts index db2c60abe442..f7cfaed41485 100644 --- a/core/packages/gax/test/unit/apiCallable.ts +++ b/core/packages/gax/test/unit/apiCallable.ts @@ -337,13 +337,15 @@ describe('createApiCall', () => { it('creates an api call when GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED and CallSettings field is set', () => { process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; - const mockCallSettings = { + const mockCallOptions: gax.CallOptions = { enableTelemetryTracing: true, - internalTelemetryInfo: { - gcpClientService: 'test.googleapis.com', + otherArgs: { + internalTelemetryInfo: { + gcpClientService: 'test.googleapis.com', + }, }, }; - const apiCall = createApiCall(() => {}, {settings: mockCallSettings}); + const apiCall = createApiCall(() => {}, {settings: mockCallOptions}); assert.strictEqual(typeof apiCall, 'function'); }); diff --git a/core/packages/gax/test/unit/gax.ts b/core/packages/gax/test/unit/gax.ts index 74271d8df16a..d166ef98c03c 100644 --- a/core/packages/gax/test/unit/gax.ts +++ b/core/packages/gax/test/unit/gax.ts @@ -200,73 +200,37 @@ describe('gax construct settings', () => { }); describe('CallSettings telemetry fields', () => { - const mockTelemetryInfo = { - gcpClientService: 'test.googleapis.com', - gcpVersion: '1.0.0', - gcpRepo: 'googleapis/google-cloud-node', - gcpArtifact: 'google-cloud-test', - }; - - it('defaults enableTelemetryTracing and internalTelemetryInfo to undefined', () => { + it('defaults enableTelemetryTracing to undefined', () => { const settings = new gax.CallSettings(); assert.strictEqual(settings.enableTelemetryTracing, undefined); - assert.strictEqual(settings.internalTelemetryInfo, undefined); }); - it('initializes enableTelemetryTracing and internalTelemetryInfo', () => { + it('initializes enableTelemetryTracing', () => { const settings = new gax.CallSettings({ enableTelemetryTracing: true, - internalTelemetryInfo: mockTelemetryInfo, }); assert.strictEqual(settings.enableTelemetryTracing, true); - assert.deepStrictEqual(settings.internalTelemetryInfo, mockTelemetryInfo); }); - it('merges enableTelemetryTracing and internalTelemetryInfo', () => { + it('merges enableTelemetryTracing', () => { const settings = new gax.CallSettings({ enableTelemetryTracing: true, - internalTelemetryInfo: mockTelemetryInfo, }); const merged = settings.merge({ enableTelemetryTracing: false, }); assert.strictEqual(merged.enableTelemetryTracing, false); - assert.deepStrictEqual(merged.internalTelemetryInfo, mockTelemetryInfo); - }); - - it('merges with new internalTelemetryInfo', () => { - const settings = new gax.CallSettings({ - enableTelemetryTracing: true, - internalTelemetryInfo: mockTelemetryInfo, - }); - const newTelemetryInfo = { - gcpClientService: 'updated.googleapis.com', - }; - const merged = settings.merge({ - internalTelemetryInfo: newTelemetryInfo, - }); - assert.strictEqual(merged.enableTelemetryTracing, true); - assert.deepStrictEqual(merged.internalTelemetryInfo, newTelemetryInfo); }); - it('copies telemetry fields when merging with null/empty options', () => { + it('copies enableTelemetryTracing when merging with null/empty options', () => { const settings = new gax.CallSettings({ enableTelemetryTracing: true, - internalTelemetryInfo: mockTelemetryInfo, }); const mergedNull = settings.merge(null); assert.strictEqual(mergedNull.enableTelemetryTracing, true); - assert.deepStrictEqual( - mergedNull.internalTelemetryInfo, - mockTelemetryInfo, - ); const mergedEmpty = settings.merge({}); assert.strictEqual(mergedEmpty.enableTelemetryTracing, true); - assert.deepStrictEqual( - mergedEmpty.internalTelemetryInfo, - mockTelemetryInfo, - ); }); }); }); diff --git a/core/packages/gax/test/unit/util.ts b/core/packages/gax/test/unit/util.ts index fffaf7b69509..1eaeb76c7763 100644 --- a/core/packages/gax/test/unit/util.ts +++ b/core/packages/gax/test/unit/util.ts @@ -206,8 +206,10 @@ describe('util.ts', () => { const mockSettings = new CallSettings({ enableTelemetryTracing: true, - internalTelemetryInfo: { - gcpClientService: 'test.googleapis.com', + otherArgs: { + internalTelemetryInfo: { + gcpClientService: 'test.googleapis.com', + }, }, }); @@ -228,8 +230,10 @@ describe('util.ts', () => { it('returns false when enableTelemetryTracing is not set on settings', () => { process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED = 'true'; const noTracingSettings = new CallSettings({ - internalTelemetryInfo: { - gcpClientService: 'test.googleapis.com', + otherArgs: { + internalTelemetryInfo: { + gcpClientService: 'test.googleapis.com', + }, }, }); assert.strictEqual(checkTelemetryEnabled(noTracingSettings), false); From bac525043eb131355ac46486dcae57d08c728898 Mon Sep 17 00:00:00 2001 From: Shivanee Persaud Date: Tue, 25 Aug 2026 15:53:52 -0700 Subject: [PATCH 5/5] refactor(gax): move StaticTraceContext to util.ts --- core/packages/gax/src/clientInterface.ts | 11 ----------- core/packages/gax/src/index.ts | 1 + core/packages/gax/src/util.ts | 11 +++++++++++ core/packages/gax/test/unit/exports.ts | 3 +++ core/packages/gax/test/unit/util.ts | 12 +++++++++--- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/core/packages/gax/src/clientInterface.ts b/core/packages/gax/src/clientInterface.ts index 69517812f25c..bf4571d62689 100644 --- a/core/packages/gax/src/clientInterface.ts +++ b/core/packages/gax/src/clientInterface.ts @@ -28,17 +28,6 @@ import { import * as longrunning from './longRunningCalls/longrunning'; import * as operationProtos from '../protos/operations'; -/** - * The static trace context is information about the Google Cloud client library that is - * used to generate telemetry tracing information. - */ -export interface StaticTraceContext { - gcpClientService?: string; - gcpVersion?: string; - gcpRepo?: string; - gcpArtifact?: string; -} - export interface ClientOptions extends GrpcClientOptions, GoogleAuthOptions, ClientStubOptions { libName?: string; diff --git a/core/packages/gax/src/index.ts b/core/packages/gax/src/index.ts index cb86a17ba3ae..55c133933787 100644 --- a/core/packages/gax/src/index.ts +++ b/core/packages/gax/src/index.ts @@ -118,6 +118,7 @@ export { decodeAnyProtosInArray, decodeProtobufAny, checkTelemetryEnabled, + StaticTraceContext, } from './util'; export {ServiceError, ChannelCredentials} from '@grpc/grpc-js'; diff --git a/core/packages/gax/src/util.ts b/core/packages/gax/src/util.ts index de388fe4c834..0492a4321c24 100644 --- a/core/packages/gax/src/util.ts +++ b/core/packages/gax/src/util.ts @@ -22,6 +22,17 @@ const NUM_OF_PARTS_IN_PROTO_TYPE_NAME = 2; const randomUUID = () => globalThis.crypto?.randomUUID() || require('crypto').randomUUID(); +/** + * The static trace context is information about the Google Cloud client library that is + * used to generate telemetry tracing information. + */ +export interface StaticTraceContext { + gcpClientService?: string; + gcpVersion?: string; + gcpRepo?: string; + gcpArtifact?: string; +} + /** * Checks if telemetry tracing is enabled * @param settings diff --git a/core/packages/gax/test/unit/exports.ts b/core/packages/gax/test/unit/exports.ts index 8132209b46d8..fefa004f9fd4 100644 --- a/core/packages/gax/test/unit/exports.ts +++ b/core/packages/gax/test/unit/exports.ts @@ -62,6 +62,9 @@ describe('exports', () => { it('exports protobufMinimal', () => { assert(typeof index.protobufMinimal === 'object'); }); + it('exports checkTelemetryEnabled', () => { + assert(typeof index.checkTelemetryEnabled === 'function'); + }); }); describe('fallback', () => { diff --git a/core/packages/gax/test/unit/util.ts b/core/packages/gax/test/unit/util.ts index 1eaeb76c7763..85be595496b6 100644 --- a/core/packages/gax/test/unit/util.ts +++ b/core/packages/gax/test/unit/util.ts @@ -25,6 +25,7 @@ import { decodeProtobufAny, decodeAnyProtosInArray, checkTelemetryEnabled, + StaticTraceContext, } from '../../src/util'; import {CallSettings} from '../../src/gax'; import * as protobuf from 'protobufjs'; @@ -204,12 +205,17 @@ describe('util.ts', () => { delete process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED; }); + const mockTelemetryInfo: StaticTraceContext = { + gcpClientService: 'test.googleapis.com', + gcpVersion: '1.0.0', + gcpRepo: 'googleapis/google-cloud-node', + gcpArtifact: 'google-cloud-test', + }; + const mockSettings = new CallSettings({ enableTelemetryTracing: true, otherArgs: { - internalTelemetryInfo: { - gcpClientService: 'test.googleapis.com', - }, + internalTelemetryInfo: mockTelemetryInfo, }, });