@sentry/google-cloud-serverless
Version:
Official Sentry SDK for Google Cloud Functions
115 lines (103 loc) • 3.39 kB
JavaScript
var {
_optionalChain
} = require('@sentry/utils');
Object.defineProperty(exports, '__esModule', { value: true });
const core = require('@sentry/core');
const node = require('@sentry/node');
const utils = require('@sentry/utils');
const SERVICE_PATH_REGEX = /^(\w+)\.googleapis.com$/;
const INTEGRATION_NAME = 'GoogleCloudGrpc';
const SETUP_CLIENTS = new WeakMap();
const _googleCloudGrpcIntegration = ((options = {}) => {
const optional = options.optional || false;
return {
name: INTEGRATION_NAME,
setupOnce() {
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const gaxModule = require('google-gax');
utils.fill(
gaxModule.GrpcClient.prototype, // eslint-disable-line @typescript-eslint/no-unsafe-member-access
'createStub',
wrapCreateStub,
);
} catch (e) {
if (!optional) {
throw e;
}
}
},
setup(client) {
SETUP_CLIENTS.set(client, true);
},
};
}) ;
/**
* Google Cloud Platform service requests tracking for GRPC APIs.
*/
const googleCloudGrpcIntegration = core.defineIntegration(_googleCloudGrpcIntegration);
/** Returns a wrapped function that returns a stub with tracing enabled */
function wrapCreateStub(origCreate) {
return async function ( ...args) {
const servicePath = _optionalChain([args, 'access', _ => _[1], 'optionalAccess', _2 => _2.servicePath]);
if (servicePath == null || servicePath == undefined) {
return origCreate.apply(this, args);
}
const serviceIdentifier = identifyService(servicePath);
const stub = await origCreate.apply(this, args);
for (const methodName of Object.keys(Object.getPrototypeOf(stub))) {
fillGrpcFunction(stub, serviceIdentifier, methodName);
}
return stub;
};
}
/** Patches the function in grpc stub to enable tracing */
function fillGrpcFunction(stub, serviceIdentifier, methodName) {
const funcObj = stub[methodName];
if (typeof funcObj !== 'function') {
return;
}
const callType =
!funcObj.requestStream && !funcObj.responseStream
? 'unary call'
: funcObj.requestStream && !funcObj.responseStream
? 'client stream'
: !funcObj.requestStream && funcObj.responseStream
? 'server stream'
: 'bidi stream';
if (callType != 'unary call') {
return;
}
utils.fill(
stub,
methodName,
(orig) =>
(...args) => {
const ret = orig.apply(stub, args);
if (typeof _optionalChain([ret, 'optionalAccess', _3 => _3.on]) !== 'function' || !SETUP_CLIENTS.has(core.getClient() )) {
return ret;
}
const span = node.startInactiveSpan({
name: `${callType} ${methodName}`,
onlyIfParent: true,
op: `grpc.${serviceIdentifier}`,
attributes: {
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.grpc.serverless',
},
});
ret.on('status', () => {
if (span) {
span.end();
}
});
return ret;
},
);
}
/** Identifies service by its address */
function identifyService(servicePath) {
const match = servicePath.match(SERVICE_PATH_REGEX);
return match ? match[1] : servicePath;
}
exports.googleCloudGrpcIntegration = googleCloudGrpcIntegration;
//# sourceMappingURL=google-cloud-grpc.js.map