traceperf
Version:
High-performance function execution tracking and monitoring for Node.js
131 lines • 4.42 kB
JavaScript
;
/**
* Proxy-based function tracking utility
*
* This module provides utilities for automatically tracking nested function calls
* using JavaScript Proxies without modifying the original code structure.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProxyTracker = void 0;
/**
* A tracking context that manages function tracking using proxies
*/
class ProxyTracker {
/**
* Create a new ProxyTracker
*
* @param trackFn - The function to use for tracking
*/
constructor(trackFn) {
this._originalFunctions = new Map();
this._trackedFunctions = new Map();
this._isEnabled = true;
this._trackFn = trackFn;
}
/**
* Enable or disable tracking
*
* @param enabled - Whether tracking is enabled
*/
setEnabled(enabled) {
this._isEnabled = enabled;
}
/**
* Check if tracking is enabled
*
* @returns Whether tracking is enabled
*/
isEnabled() {
return this._isEnabled;
}
/**
* Make a function trackable
*
* @param fn - The function to make trackable
* @param name - The name to use for tracking
* @returns A tracked version of the function
*/
makeTrackable(fn, name) {
// If tracking is disabled, return the original function
if (!this._isEnabled) {
return fn;
}
// If we've already tracked this function, return the tracked version
if (this._trackedFunctions.has(fn)) {
return this._trackedFunctions.get(fn);
}
// Create a tracked version of the function
const self = this;
const trackedFn = function (...args) {
return self._trackFn(() => fn.apply(this, args), {
label: name || fn.name || 'anonymous'
});
};
// Store the tracked version
this._trackedFunctions.set(fn, trackedFn);
return trackedFn;
}
/**
* Create a proxy for an object to track all its methods
*
* @param obj - The object to proxy
* @param namespace - The namespace to use for tracking
* @returns A proxied version of the object
*/
createProxy(obj, namespace = '') {
// If tracking is disabled, return the original object
if (!this._isEnabled) {
return obj;
}
const self = this;
return new Proxy(obj, {
get(target, prop, receiver) {
const value = Reflect.get(target, prop, receiver);
// If the property is a function, make it trackable
if (typeof value === 'function' && prop !== 'constructor') {
const name = namespace
? `${namespace}.${String(prop)}`
: String(prop);
return self.makeTrackable(value, name);
}
// If the property is an object (but not a built-in), proxy it too
if (value &&
typeof value === 'object' &&
!Array.isArray(value) &&
Object.getPrototypeOf(value) === Object.prototype) {
const nestedNamespace = namespace
? `${namespace}.${String(prop)}`
: String(prop);
return self.createProxy(value, nestedNamespace);
}
return value;
},
apply(target, thisArg, args) {
// This handles the case when the proxy itself is called as a function
const name = namespace || target.name || 'anonymous';
return self._trackFn(() => Reflect.apply(target, thisArg, args), {
label: name
});
}
});
}
/**
* Track a module's exports
*
* @param moduleExports - The module's exports
* @param namespace - The namespace to use for tracking
* @returns A proxied version of the module's exports
*/
trackModule(moduleExports, namespace) {
return this.createProxy(moduleExports, namespace);
}
/**
* Clear all tracked functions
*/
clear() {
this._trackedFunctions.clear();
this._originalFunctions.clear();
}
}
exports.ProxyTracker = ProxyTracker;
//# sourceMappingURL=proxy-tracker.js.map