Skip to content
This repository has been archived by the owner on Jun 13, 2023. It is now read-only.

Commit

Permalink
feat(fs): add node fs support (#387)
Browse files Browse the repository at this point in the history
  • Loading branch information
idonava authored Nov 15, 2020
1 parent e7d9a2a commit bc9ac7f
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ Epsagon provides out-of-the-box instrumentation (tracing) for many popular frame
|https |Fully supported |
|http2 |Fully supported |
|dns |Fully supported |
|fs |Fully supported |
|aws-sdk |`>=2.2.0` |
|amazon-dax-client |`>=1.0.2` |
|@google-cloud |`>=2.0.0` |
Expand Down Expand Up @@ -700,6 +701,7 @@ Advanced options can be configured as a parameter to the init() method or as env
|- |EPSAGON_ADD_NODE_PATH |String |- |List of folders to looks for node_modules when patching libraries. Separated by `:`|
|- |EPSAGON_AUTO_ADD_NODE_PATHS|Boolean |`false` |Auto add node_modules sub folders to look when patching libraries. |
|- |EPSAGON_DNS_INSTRUMENTATION|Boolean|`false` |Whether to capture `dns` calls into the trace |
|- |EPSAGON_FS_INSTRUMENTATION |Boolean|`false` |Whether to capture node `file system` calls into the trace |
|- |EPSAGON_LOGGING_TRACING_ENABLED|Boolean|`true` |whether to add an Epsagon ID to the logs in order to correlate traces to logs in the dashboard|
|- |EPSAGON_STEPS_ID |String|- |The Epsagon step id from the ECS step functions state input |
|- |EPSAGON_STEPS_NUM |String|`0` |The step number of the ECS step functions state |
Expand Down
88 changes: 88 additions & 0 deletions src/events/fs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
const fs = require('fs');
const shimmer = require('shimmer');
const tracer = require('../tracer.js');
const eventInterface = require('../event.js');

/**
* Calling to the fs writeFileSync function without callback, And record the error if thrown.
* @param {Function} original The node fs function.
* @param {number} startTime Event start time.
* @param {serverlessEvent.Event} fsEvent FS event.
* @param {Array} args Array of function arguments.
* @returns {Object} original function response.
*/
function handleFunctionWithoutCallback(original, startTime, fsEvent, args) {
try {
tracer.addEvent(fsEvent);
return original.apply(this, args);
} catch (err) {
eventInterface.finalizeEvent(fsEvent, startTime, err);
throw err;
}
}

/**
* Wrap node fs requset.
* @param {Function} original The node fs function.
* @param {Function} originalName The node fs function name.
* @returns {Function} The wrapped function
*/
function wrapFsWriteFileFunction(original, originalName) {
return function internalWrapFsWriteFileFunction(file, data, options, callback) {
const fileName = typeof file === 'object' ? file.toString() : file;
const fsCallback = typeof (callback || options) === 'function' && (callback || options);
const { slsEvent: fsEvent, startTime } = eventInterface.initializeEvent('file_system', fileName, originalName, 'file_system');

eventInterface.addToMetadata(fsEvent, { 'fs.file': fileName });
if (!!options && typeof options === 'object') {
eventInterface.addToMetadata(fsEvent, { options });
}
if (!fsCallback) {
return handleFunctionWithoutCallback(original, startTime, fsEvent, [
fileName,
data,
options,
]);
}
let patchedCallback;
let clientRequest;
let clientRequestHasBeenCalled;
try {
const responsePromise = new Promise((resolve) => {
patchedCallback = (err) => {
eventInterface.finalizeEvent(fsEvent, startTime, err);
resolve();
fsCallback(err);
};
});
if (typeof callback === 'function') {
clientRequestHasBeenCalled = true;
clientRequest = original.apply(this, [file, data, options, patchedCallback]);
} else if (typeof options === 'function') {
clientRequestHasBeenCalled = true;
clientRequest = original.apply(this, [file, data, patchedCallback]);
}
tracer.addEvent(fsEvent, responsePromise);
} catch (err) {
tracer.addException(err);
}

return clientRequest || clientRequestHasBeenCalled ?
clientRequest :
original.apply(this, [file, data, options, callback]);
};
}


module.exports = {
/**
* Patch Node fs methods.
* process.env.EPSAGON_FS_INSTRUMENTATION=true is requird.
*/
init() {
if ((process.env.EPSAGON_FS_INSTRUMENTATION || '').toUpperCase() === 'TRUE') {
shimmer.wrap(fs, 'writeFile', () => wrapFsWriteFileFunction(fs.writeFile, 'writeFile'));
shimmer.wrap(fs, 'writeFileSync', () => wrapFsWriteFileFunction(fs.writeFileSync, 'writeFileSync'));
}
},
};

0 comments on commit bc9ac7f

Please sign in to comment.