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)