Have you ever wondered:
- "Why is this function so slow?"
- "How many times is this being called?"
- "Where exactly is my code failing?"
I was asking myself these questions every single day. So I built a tool to answer them.
Introducing function-trace β a tiny, zero-dependency function profiler for JavaScript and TypeScript.
π€― The Problem
Last month, I was debugging a production issue. An API endpoint was randomly slow, but I couldn't figure out which function was the culprit.
My debugging process looked like this:
const start = performance.now();
const result = await someFunction();
const end = performance.now();
console.log(`someFunction took ${end - start}ms`);
I was copy-pasting this everywhere. It was:
- β Ugly
- β Time-consuming
- β Easy to forget to remove
- β No historical data
There had to be a better way.
π‘ The Solution
I built function-trace β a wrapper that does all of this automatically:
import { trace } from 'function-trace';
const fetchUser = trace(
async (id) => {
const res = await fetch(`/api/users/${id}`);
return res.json();
},
{ log: true }
);
await fetchUser(1);
// [function-trace] fetchUser executed in 142.35ms
One line. That's it. No setup. No configuration. Just wrap and go.
β¨ Features That Make It Special
1. Works with Everything
Sync functions? β
Async functions? β
Arrow functions? β
Class methods? β
// Sync
const add = trace((a, b) => a + b, { log: true });
// Async
const fetchData = trace(async () => {
return await fetch('/api/data');
}, { log: true });
2. Built-in Statistics
Every traced function comes with a .stats property:
const myFunction = trace(someFunction, { log: true });
// Call it a few times
myFunction();
myFunction();
myFunction();
console.log(myFunction.stats);
// {
// calls: 3,
// errors: 0,
// lastTime: 0.02,
// history: [0.02, 0.01, 0.02]
// }
You get:
- calls β Total number of invocations
- errors β How many times it threw an error
- lastTime β Most recent execution time
- history β Array of past execution times
3. Performance Alerts
Build your own monitoring with the stats:
const criticalOperation = trace(async () => {
// Some critical operation
}, { log: true, maxHistory: 100 });
async function executeWithMonitoring() {
await criticalOperation();
const avgTime =
criticalOperation.stats.history.reduce((a, b) => a + b, 0) /
criticalOperation.stats.history.length;
if (avgTime > 1000) {
console.error('β οΈ SLA threshold exceeded!');
// Send alert to your monitoring service
}
}
4. Zero Dependencies
The entire package is pure TypeScript. No lodash. No moment. No bloat.
Just clean, efficient code.
5. Type-Safe
Full TypeScript support with proper type inference:
const multiply = trace(
(a: number, b: number): number => a * b,
{ log: true }
);
const result = multiply(3, 4); // result is typed as number
π Real-World Use Cases
Database Query Monitoring
import { trace } from 'function-trace';
const getUserById = trace(
async (userId) => {
return await db.users.findById(userId);
},
{ log: true, maxHistory: 100 }
);
// Later, check if queries are getting slow
const avgQueryTime =
getUserById.stats.history.reduce((a, b) => a + b, 0) /
getUserById.stats.history.length;
if (avgQueryTime > 100) {
console.warn('β οΈ Database queries are slow. Consider adding an index.');
}
API Endpoint Profiling
const apiCall = trace(
async (endpoint) => {
const response = await fetch(endpoint);
return response.json();
},
{ log: true }
);
// After some usage
console.log(`Total API calls: ${apiCall.stats.calls}`);
console.log(`Failed calls: ${apiCall.stats.errors}`);
console.log(`Last response time: ${apiCall.stats.lastTime}ms`);
Finding Performance Bottlenecks
const step1 = trace(processData, { log: true });
const step2 = trace(transformData, { log: true });
const step3 = trace(saveData, { log: true });
await step1(data);
await step2(data);
await step3(data);
// Console output shows exactly where time is spent:
// [function-trace] processData executed in 5.23ms
// [function-trace] transformData executed in 234.56ms <-- Found it!
// [function-trace] saveData executed in 12.34ms
π¦ Installation
npm install function-trace
or
yarn add function-trace
or
pnpm add function-trace
π― API Reference
trace<F>(fn: F, options?: TraceOptions): F & { stats: TraceStats }
Options
| Option | Type | Default | Description |
|---|---|---|---|
log |
boolean |
false |
Enable console logging |
maxHistory |
number |
50 |
Number of execution times to keep |
color |
boolean |
true |
Enable colored output |
Stats Object
| Property | Type | Description |
|---|---|---|
calls |
number |
Total number of calls |
errors |
number |
Total number of errors |
lastTime |
number |
Last execution time (ms) |
history |
number[] |
Array of past execution times |
β‘ Performance
I know what you're thinking: "Won't this slow down my code?"
The overhead is approximately ~0.05ms per call. Unless you're calling a function millions of times per second, you won't notice it.
For production:
- Use
log: falseto disable console output - Adjust
maxHistorybased on your memory constraints - The history array is automatically bounded β no memory leaks
π Why Not Just Use Chrome DevTools?
Great question! Chrome DevTools is amazing, but:
| Feature | Chrome DevTools | function-trace |
|---|---|---|
| Works in Node.js | β | β |
| Programmatic access to data | β | β |
| Custom alerting | β | β |
| Production monitoring | β | β |
| Zero setup | β | β |
| Historical data | Limited | β |
They're complementary tools. Use DevTools for deep profiling, use function-trace for quick debugging and production monitoring.
π οΈ Best Practices
-
Development: Enable logging with
{ log: true } -
Production: Disable logging with
{ log: false }but keep stats -
High-frequency functions: Lower
maxHistoryto save memory -
Critical paths: Build alerts based on
stats.history - Debugging: Wrap suspect functions to find bottlenecks
π€ Contributing
This is open source under the MIT license. Contributions are welcome!
- Found a bug? Open an issue
- Have an idea? Submit a PR
- Like it? Give it a β on GitHub
π Links
π Final Thoughts
I built function-trace to solve my own problems, but I hope it helps you too.
If you try it out, let me know in the comments! I'd love to hear:
- How are you using it?
- What features would you like to see?
- Did it help you find a performance issue?
Happy debugging! ππ
If this helped you, consider following me for more JavaScript/TypeScript content. I write about web development, open source, and developer tools.
What's your go-to debugging technique? Drop it in the comments! π
Top comments (0)