@sentry/node
Version:
Sentry Node SDK using OpenTelemetry for performance instrumentation
200 lines (196 loc) • 7.28 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const api = require('@opentelemetry/api');
const instrumentation = require('@opentelemetry/instrumentation');
function patchFunctions(tracer, functionsSupportedVersions, wrap, unwrap, config) {
let requestHook = () => {
};
let responseHook = () => {
};
const errorHook = config.functions?.errorHook;
const configRequestHook = config.functions?.requestHook;
const configResponseHook = config.functions?.responseHook;
if (typeof configResponseHook === "function") {
responseHook = (span, err) => {
instrumentation.safeExecuteInTheMiddle(
() => configResponseHook(span, err),
(error) => {
if (!error) {
return;
}
api.diag.error(error?.message);
},
true
);
};
}
if (typeof configRequestHook === "function") {
requestHook = (span) => {
instrumentation.safeExecuteInTheMiddle(
() => configRequestHook(span),
(error) => {
if (!error) {
return;
}
api.diag.error(error?.message);
},
true
);
};
}
const moduleFunctionsCJS = new instrumentation.InstrumentationNodeModuleDefinition("firebase-functions", functionsSupportedVersions);
const modulesToInstrument = [
{ name: "firebase-functions/lib/v2/providers/https.js", triggerType: "function" },
{ name: "firebase-functions/lib/v2/providers/firestore.js", triggerType: "firestore" },
{ name: "firebase-functions/lib/v2/providers/scheduler.js", triggerType: "scheduler" },
{ name: "firebase-functions/lib/v2/storage.js", triggerType: "storage" }
];
modulesToInstrument.forEach(({ name, triggerType }) => {
moduleFunctionsCJS.files.push(
new instrumentation.InstrumentationNodeModuleFile(
name,
functionsSupportedVersions,
(moduleExports) => wrapCommonFunctions(
moduleExports,
wrap,
unwrap,
tracer,
{ requestHook, responseHook, errorHook },
triggerType
),
(moduleExports) => unwrapCommonFunctions(moduleExports, unwrap)
)
);
});
return moduleFunctionsCJS;
}
function patchV2Functions(tracer, functionsConfig, triggerType) {
return function v2FunctionsWrapper(original) {
return function(...args) {
const handler = typeof args[0] === "function" ? args[0] : args[1];
const documentOrOptions = typeof args[0] === "function" ? void 0 : args[0];
if (!handler) {
return original.call(this, ...args);
}
const wrappedHandler = async function(...handlerArgs) {
const functionName = process.env.FUNCTION_TARGET || process.env.K_SERVICE || "unknown";
const span = tracer.startSpan(`firebase.function.${triggerType}`, {
kind: api.SpanKind.SERVER
});
const attributes = {
"faas.name": functionName,
"faas.trigger": triggerType,
"faas.provider": "firebase"
};
if (process.env.GCLOUD_PROJECT) {
attributes["cloud.project_id"] = process.env.GCLOUD_PROJECT;
}
if (process.env.EVENTARC_CLOUD_EVENT_SOURCE) {
attributes["cloud.event_source"] = process.env.EVENTARC_CLOUD_EVENT_SOURCE;
}
span.setAttributes(attributes);
functionsConfig?.requestHook?.(span);
return api.context.with(api.trace.setSpan(api.context.active(), span), async () => {
let error;
let result;
try {
result = await handler.apply(this, handlerArgs);
} catch (e) {
error = e;
}
functionsConfig?.responseHook?.(span, error);
if (error) {
span.recordException(error);
}
span.end();
if (error) {
await functionsConfig?.errorHook?.(span, error);
throw error;
}
return result;
});
};
if (documentOrOptions) {
return original.call(this, documentOrOptions, wrappedHandler);
} else {
return original.call(this, wrappedHandler);
}
};
};
}
function wrapCommonFunctions(moduleExports, wrap, unwrap, tracer, functionsConfig, triggerType) {
unwrapCommonFunctions(moduleExports, unwrap);
switch (triggerType) {
case "function":
wrap(moduleExports, "onRequest", patchV2Functions(tracer, functionsConfig, "http.request"));
wrap(moduleExports, "onCall", patchV2Functions(tracer, functionsConfig, "http.call"));
break;
case "firestore":
wrap(moduleExports, "onDocumentCreated", patchV2Functions(tracer, functionsConfig, "firestore.document.created"));
wrap(moduleExports, "onDocumentUpdated", patchV2Functions(tracer, functionsConfig, "firestore.document.updated"));
wrap(moduleExports, "onDocumentDeleted", patchV2Functions(tracer, functionsConfig, "firestore.document.deleted"));
wrap(moduleExports, "onDocumentWritten", patchV2Functions(tracer, functionsConfig, "firestore.document.written"));
wrap(
moduleExports,
"onDocumentCreatedWithAuthContext",
patchV2Functions(tracer, functionsConfig, "firestore.document.created")
);
wrap(
moduleExports,
"onDocumentUpdatedWithAuthContext",
patchV2Functions(tracer, functionsConfig, "firestore.document.updated")
);
wrap(
moduleExports,
"onDocumentDeletedWithAuthContext",
patchV2Functions(tracer, functionsConfig, "firestore.document.deleted")
);
wrap(
moduleExports,
"onDocumentWrittenWithAuthContext",
patchV2Functions(tracer, functionsConfig, "firestore.document.written")
);
break;
case "scheduler":
wrap(moduleExports, "onSchedule", patchV2Functions(tracer, functionsConfig, "scheduler.scheduled"));
break;
case "storage":
wrap(moduleExports, "onObjectFinalized", patchV2Functions(tracer, functionsConfig, "storage.object.finalized"));
wrap(moduleExports, "onObjectArchived", patchV2Functions(tracer, functionsConfig, "storage.object.archived"));
wrap(moduleExports, "onObjectDeleted", patchV2Functions(tracer, functionsConfig, "storage.object.deleted"));
wrap(
moduleExports,
"onObjectMetadataUpdated",
patchV2Functions(tracer, functionsConfig, "storage.object.metadataUpdated")
);
break;
}
return moduleExports;
}
function unwrapCommonFunctions(moduleExports, unwrap) {
const methods = [
"onSchedule",
"onRequest",
"onCall",
"onObjectFinalized",
"onObjectArchived",
"onObjectDeleted",
"onObjectMetadataUpdated",
"onDocumentCreated",
"onDocumentUpdated",
"onDocumentDeleted",
"onDocumentWritten",
"onDocumentCreatedWithAuthContext",
"onDocumentUpdatedWithAuthContext",
"onDocumentDeletedWithAuthContext",
"onDocumentWrittenWithAuthContext"
];
for (const method of methods) {
if (instrumentation.isWrapped(moduleExports[method])) {
unwrap(moduleExports, method);
}
}
return moduleExports;
}
exports.patchFunctions = patchFunctions;
exports.patchV2Functions = patchV2Functions;
//# sourceMappingURL=functions.js.map