Skip to content
Merged
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
8 changes: 5 additions & 3 deletions core/packages/gax/src/clientInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ import * as longrunning from './longRunningCalls/longrunning';
import * as operationProtos from '../protos/operations';

export interface ClientOptions
extends GrpcClientOptions,
GoogleAuthOptions,
ClientStubOptions {
extends GrpcClientOptions, GoogleAuthOptions, ClientStubOptions {
libName?: string;
libVersion?: string;
clientConfig?: gax.ClientConfig;
Expand All @@ -42,6 +40,10 @@ 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.
Comment thread
danieljbruce marked this conversation as resolved.
}

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

export class CallSettings {
Expand All @@ -186,6 +187,7 @@ export class CallSettings {
longrunning?: BackoffSettings;
apiName?: string;
retryRequestOptions?: RetryRequestOptions;
enableTelemetryTracing?: boolean;

/**
* @param {Object} settings - An object containing parameters of this settings.
Expand Down Expand Up @@ -219,6 +221,7 @@ export class CallSettings {
'longrunning' in settings ? settings.longrunning : undefined;
this.apiName = settings.apiName ?? undefined;
this.retryRequestOptions = settings.retryRequestOptions;
this.enableTelemetryTracing = settings.enableTelemetryTracing;
}

/**
Expand All @@ -242,6 +245,7 @@ export class CallSettings {
let longrunning = this.longrunning;
let apiName = this.apiName;
let retryRequestOptions = this.retryRequestOptions;
let enableTelemetryTracing = this.enableTelemetryTracing;

// 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 +301,9 @@ export class CallSettings {
if ('retryRequestOptions' in options) {
retryRequestOptions = options.retryRequestOptions;
}
if ('enableTelemetryTracing' in options) {
enableTelemetryTracing = options.enableTelemetryTracing;
}

return new CallSettings({
timeout,
Expand All @@ -309,6 +316,7 @@ export class CallSettings {
isBundling,
apiName,
retryRequestOptions,
enableTelemetryTracing,
});
}
}
Expand Down
8 changes: 7 additions & 1 deletion core/packages/gax/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,13 @@ export {
PaginationResponse,
} from './clientInterface';

export {makeUUID, decodeAnyProtosInArray, decodeProtobufAny} from './util';
export {
makeUUID,
decodeAnyProtosInArray,
decodeProtobufAny,
checkTelemetryEnabled,
StaticTraceContext,
} from './util';

export {ServiceError, ChannelCredentials} from '@grpc/grpc-js';
export {warn} from './warnings';
Expand Down
26 changes: 26 additions & 0 deletions core/packages/gax/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,38 @@
* 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();

/**
* 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
* @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?.otherArgs?.internalTelemetryInfo !== undefined;
return Boolean(tracingEnabled);
}

function words(str: string, normalize = false) {
if (normalize) {
// strings like somethingABCSomething are special case for protobuf.js,
Expand Down Expand Up @@ -129,7 +155,7 @@

// Given a proto Any and a set of protos, decode using the set of protos.
export const decodeProtobufAny = (
anyValue: any,

Check warning on line 158 in core/packages/gax/src/util.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
protobuf: protobuf.Type,
): protobuf.Message<{}> => {
if (anyValue.type_url === '') {
Expand All @@ -152,7 +178,7 @@
// Proto is Any we try to decode with protos in protobuf.
const decodedAnyProto = decodeProtobufAny(proto, protobuf);
protoListDecoded.push(decodedAnyProto);
} catch (e: any) {

Check warning on line 181 in core/packages/gax/src/util.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
// Skip we can't process it.
}
continue;
Expand Down
40 changes: 33 additions & 7 deletions core/packages/gax/test/unit/apiCallable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,31 @@
);
}
});

describe('in regards to OpenTelemetry Tracing', () => {
afterEach(() => {
delete process.env.GOOGLE_SDK_NODE_EXPERIMENTAL_O11Y_ENABLED;
});

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 mockCallOptions: gax.CallOptions = {
enableTelemetryTracing: true,
otherArgs: {
internalTelemetryInfo: {
gcpClientService: 'test.googleapis.com',
},
},
};
const apiCall = createApiCall(() => {}, {settings: mockCallOptions});
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 +375,9 @@
assert.ok(Array.isArray(response));
assert.strictEqual(response[0], 42);
assert.ok(deadlineArg);
done();
return done();

Check warning on line 378 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 380 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 +405,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 408 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 413 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 +445,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 448 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 452 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 454 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,7 +534,7 @@
assert.strictEqual(resp[0], 1729);
assert.strictEqual(toAttempt, 0);
assert.ok(deadlineArg);
done();
return done();

Check warning on line 537 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);
});
Expand All @@ -534,7 +559,7 @@
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);
Expand Down Expand Up @@ -795,6 +820,7 @@
})
.then(() => {
mockBuilder.verify();
return;
});
});

Expand All @@ -821,9 +847,9 @@
try {
assert.strictEqual(gotHeaders.h1, 'val1');
assert.strictEqual(gotHeaders.h2, 'val2');
done();
return done();
} catch (err) {
done(err);
return done(err);
}
});
});
Expand Down
3 changes: 3 additions & 0 deletions core/packages/gax/test/unit/exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ describe('exports', () => {
it('exports protobufMinimal', () => {
assert(typeof index.protobufMinimal === 'object');
});
it('exports checkTelemetryEnabled', () => {
assert(typeof index.checkTelemetryEnabled === 'function');
});
});

describe('fallback', () => {
Expand Down
35 changes: 35 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,39 @@ describe('gax construct settings', () => {
assert.strictEqual(backoff.maxRetryDelayMillis, 1000);
assert.deepStrictEqual(settings.retry.retryCodes, [RETRY_DICT.code_c]);
});

describe('CallSettings telemetry fields', () => {
it('defaults enableTelemetryTracing to undefined', () => {
const settings = new gax.CallSettings();
assert.strictEqual(settings.enableTelemetryTracing, undefined);
});

it('initializes enableTelemetryTracing', () => {
const settings = new gax.CallSettings({
enableTelemetryTracing: true,
});
assert.strictEqual(settings.enableTelemetryTracing, true);
});

it('merges enableTelemetryTracing', () => {
const settings = new gax.CallSettings({
enableTelemetryTracing: true,
});
const merged = settings.merge({
enableTelemetryTracing: false,
});
assert.strictEqual(merged.enableTelemetryTracing, false);
});

it('copies enableTelemetryTracing when merging with null/empty options', () => {
const settings = new gax.CallSettings({
enableTelemetryTracing: true,
});
const mergedNull = settings.merge(null);
assert.strictEqual(mergedNull.enableTelemetryTracing, true);

const mergedEmpty = settings.merge({});
assert.strictEqual(mergedEmpty.enableTelemetryTracing, true);
});
});
});
64 changes: 63 additions & 1 deletion core/packages/gax/test/unit/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import assert from 'assert';
import {describe, it} from 'mocha';
import {afterEach, describe, it} from 'mocha';
import {
toCamelCase as snakeToCamelCase,
camelToSnakeCase,
Expand All @@ -24,7 +24,10 @@ import {
getProtoNameFromFullName,
decodeProtobufAny,
decodeAnyProtosInArray,
checkTelemetryEnabled,
StaticTraceContext,
} from '../../src/util';
import {CallSettings} from '../../src/gax';
import * as protobuf from 'protobufjs';
import protosJson from '../../protos/status.json';

Expand Down Expand Up @@ -196,4 +199,63 @@ describe('util.ts', () => {
JSON.stringify([{reason: 'SERVICE_DISABLED'}]),
);
});

describe('checkTelemetryEnabled', () => {
afterEach(() => {
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: mockTelemetryInfo,
},
});

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({
otherArgs: {
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);
});
});
});
Loading