Coming from Python I wanted to write something like this:
@trace('name', opts)
def business_logic(foo, bar):
return 0
To use opentelemetry in specific function and having goodies like putting relevant stuff in the context.
I am using Node.js 20
Careful with decorator or higher order functions
function example() {}
console.log(example.name); // "example"
const example2 = function() {}
console.log(example2.name); // "example2"
const example3 = () => 0
console.log(example3.name); // "example3"
const exampleFunc = function exampleFunction() {};
console.log(exampleFunc.name); // "exampleFunction"
function traceFn(fn) {
return function (...args) {
// Wrapper logic...
return fn(...args);
};
}
const tracedExample = traceFn(example);
console.log(tracedExample.name); // undefined
Preserving Function Names and Stack Traces
`trace-fn.js
function example() {}
console.log(example.name); // "example"
function traceFn(fn) {
const wrapped = function (...args) {
// Wrapper logic...
return fn(...args);
};
Object.defineProperty(wrapped, 'name', {value: `traced${fn.name}`, configurable: true});
return wrapped;
}
const tracedExample = traceFn(example);
console.log(tracedExample.name); // "tracedExample"
Error Handling and Stack Traces
etude-trace-fn.js
function traceFn(fn) {
const wrapped = function (...args) {
try {
// Simulate wrapper logic...
return fn(...args);
} catch (error) {
// Create a new error object for clean stack trace handling.
const tracedError = new Error(error.message);
// Omit this wrapped function from the stack trace to make it cleaner.
Error.captureStackTrace(tracedError, wrapped);
// Rethrow the new error with the modified stack trace.
throw tracedError;
}
};
Object.defineProperty(wrapped, 'name', {value: `traced${fn.name}`, configurable: true});
return wrapped;
}
// Adjust the example function to throw an error.
function example() {
throw new Error('Something went wrong!');
}
const tracedExample = traceFn(example);
// Execute the wrapped function to trigger the error.
try {
tracedExample();
} catch (e) {
console.log(e.stack);
}
Outputs:
Error: Something went wrong!
at Object.<anonymous> (/tmp/etude-trace-fn.js:30:3)
at Module._compile (node:internal/modules/cjs/loader:1376:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
at Module.load (node:internal/modules/cjs/loader:1207:32)
at Module._load (node:internal/modules/cjs/loader:1023:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
at node:internal/main/run_main_module:28:49
- Inside
traceFn
, thetry-catch
block is used to catch any errors thrown by thefn(...args)
call. - If an error occurs, a new
Error
object is created (tracedError
), inheriting the message from the caught error for clarity. Error.captureStackTrace(tracedError, wrapped);
is then called to modifytracedError
's stack trace. It removes thewrapped
function (and anything above it in the call stack) from the trace. This means when the error is thrown fromwrapped
, the stack trace will start from wherewrapped
was called, rather than including the internals ofwrapped
itself.- The modified error is then rethrown, and when caught and logged outside of
tracedExample()
, it will show a cleaner stack trace that excludes thewrapped
function, making it easier to identify the source of the erro