Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions core/packages/gax/src/clientInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Comment thread
shivanee-p marked this conversation as resolved.

export interface ClientOptions
extends GrpcClientOptions,
GoogleAuthOptions,
ClientStubOptions {
extends GrpcClientOptions, GoogleAuthOptions, ClientStubOptions {
libName?: string;
libVersion?: string;
clientConfig?: gax.ClientConfig;
Expand All @@ -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;
Comment thread
shivanee-p marked this conversation as resolved.
/**
* The static trace context is information about the Google Cloud client library that is
* used to generate telemetry tracing information.
*/
internalTelemetryInfo?: StaticTraceContext;
Comment thread
shivanee-p marked this conversation as resolved.
}

export interface Descriptors {
Expand Down
24 changes: 21 additions & 3 deletions core/packages/gax/src/createApiCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -164,4 +181,5 @@ export function createApiCall(
// or to cancel the ongoing call.
return currentApiCaller.result(ongoingCall);
};
return invokeCall;
}
17 changes: 17 additions & 0 deletions core/packages/gax/src/gax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -170,6 +171,8 @@ export interface CallOptions {
longrunning?: BackoffSettings;
apiName?: string;
retryRequestOptions?: RetryRequestOptions;
enableTelemetryTracing?: boolean;
internalTelemetryInfo?: StaticTraceContext;
}

export class CallSettings {
Expand All @@ -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.
Expand Down Expand Up @@ -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;
}

/**
Expand All @@ -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.
Expand Down Expand Up @@ -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,
Expand All @@ -309,6 +324,8 @@ export class CallSettings {
isBundling,
apiName,
retryRequestOptions,
enableTelemetryTracing,
internalTelemetryInfo,
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/packages/gax/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
85 changes: 78 additions & 7 deletions core/packages/gax/test/unit/apiCallable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

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';
Expand Down Expand Up @@ -329,6 +330,75 @@
);
}
});

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');
});
});
Comment thread
shivanee-p marked this conversation as resolved.
});

describe('Promise', () => {
Expand All @@ -350,9 +420,9 @@
assert.ok(Array.isArray(response));
assert.strictEqual(response[0], 42);
assert.ok(deadlineArg);
done();
return done();

Check warning on line 423 in core/packages/gax/test/unit/apiCallable.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
})
.catch(done);

Check warning on line 425 in core/packages/gax/test/unit/apiCallable.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
});

it('emits error on rejected promise', async () => {
Expand Down Expand Up @@ -380,12 +450,12 @@
const promise = (apiCall as any)(null);
promise
.then(() => {
done(new Error('should not reach'));
return done(new Error('should not reach'));

Check warning on line 453 in core/packages/gax/test/unit/apiCallable.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
})
.catch((err: {code: number}) => {
assert(err instanceof GoogleError);
assert.strictEqual(err.code, status.CANCELLED);
done();

Check warning on line 458 in core/packages/gax/test/unit/apiCallable.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
});
promise.cancel();
});
Expand Down Expand Up @@ -420,13 +490,13 @@
const promise = (apiCall as any)(null);
promise
.then(() => {
done(new Error('should not reach'));
return done(new Error('should not reach'));

Check warning on line 493 in core/packages/gax/test/unit/apiCallable.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
})
.catch(() => {
assert(callCount < 4);
done();

Check warning on line 497 in core/packages/gax/test/unit/apiCallable.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
})
.catch(done);

Check warning on line 499 in core/packages/gax/test/unit/apiCallable.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
setTimeout(() => {
promise.cancel();
}, 15);
Expand Down Expand Up @@ -509,9 +579,9 @@
assert.strictEqual(resp[0], 1729);
assert.strictEqual(toAttempt, 0);
assert.ok(deadlineArg);
done();
return done();

Check warning on line 582 in core/packages/gax/test/unit/apiCallable.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
})
.catch(done);

Check warning on line 584 in core/packages/gax/test/unit/apiCallable.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
});

it('cancels in the middle of retries', done => {
Expand All @@ -534,7 +604,7 @@
const promise = apiCall({}, undefined);
promise
.then(() => {
done(new Error('should not reach'));
return done(new Error('should not reach'));

Check warning on line 607 in core/packages/gax/test/unit/apiCallable.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
})
.catch((err: Error) => {
assert(err instanceof Error);
Expand Down Expand Up @@ -795,6 +865,7 @@
})
.then(() => {
mockBuilder.verify();
return;
});
});

Expand All @@ -821,9 +892,9 @@
try {
assert.strictEqual(gotHeaders.h1, 'val1');
assert.strictEqual(gotHeaders.h2, 'val2');
done();
return done();
} catch (err) {
done(err);
return done(err);
}
});
});
Expand Down
71 changes: 71 additions & 0 deletions core/packages/gax/test/unit/gax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
);
});
});
});
Loading