memory-watch
Version:
Advanced Node.js memory monitoring with stack trace analysis, user code detection, and memory leak identification
178 lines (157 loc) ⢠5.24 kB
JavaScript
const { MemoryWatch, generateDiagnosticReport } = require("../dist/index");
// Simulate a real application scenario
class UserService {
constructor() {
this.users = [];
this.cache = new Map();
}
async loadUsers() {
console.log("š„ Loading users...");
// Simulate loading lots of users (this will show in stack trace)
for (let i = 0; i < 1000; i++) {
const user = {
id: i,
name: `User ${i}`,
email: `user${i}@example.com`,
profile: {
bio: `This is a long biography for user ${i}`.repeat(10),
preferences: new Array(50).fill(`pref-${i}`),
history: new Array(100).fill({
action: `action-${i}`,
timestamp: new Date(),
data: new Array(20).fill(`data-${i}`),
}),
},
};
this.users.push(user);
// Also cache the user (double memory usage!)
this.cache.set(user.id, JSON.parse(JSON.stringify(user)));
}
console.log(`ā
Loaded ${this.users.length} users`);
return this.users;
}
processUserData() {
console.log("āļø Processing user data...");
// This function will appear in stack trace when memory spikes
const processedData = this.users.map((user) => {
return {
...user,
processedProfile: {
...user.profile,
extraData: new Array(100).fill(`processed-${user.id}`),
analytics: {
score: Math.random(),
details: new Array(50).fill(`analytics-${user.id}`),
},
},
};
});
console.log("š User data processed");
return processedData;
}
}
class APIController {
constructor() {
this.userService = new UserService();
}
async handleUserRequest() {
console.log("š API: Handling user request...");
// This will show up as the source of memory usage
await this.userService.loadUsers();
const processed = this.userService.processUserData();
console.log("ā
API: Request completed");
return processed;
}
}
// Setup memory monitoring with low threshold
const watch = new MemoryWatch({
threshold: 0.4, // 40% threshold
interval: 2000, // Check every 2 seconds
actions: [
(data) => {
console.log("\n" + "šØ".repeat(20));
console.log("MEMORY ALERT - Real Application Scenario");
console.log("šØ".repeat(20));
console.log(
`š Memory: ${(data.percentage * 100).toFixed(1)}% (${Math.round(
data.usedBytes / 1024 / 1024
)}MB)`
);
// Show user code in stack trace
if (data.context?.stackTrace) {
console.log("\nš STACK TRACE (Your Code):");
data.context.stackTrace.forEach((trace, index) => {
// Highlight user code vs system code
if (
trace.fileName &&
!trace.fileName.includes("node:") &&
!trace.fileName.includes("internal")
) {
console.log(
` ${index + 1}. šÆ ${trace.functionName} ā ${trace.fileName}:${
trace.lineNumber
} ā`
);
} else if (!trace.fileName?.includes("node:")) {
console.log(` ${index + 1}. ${trace.functionName}`);
}
});
}
console.log("\nš” ANALYSIS:");
if (
data.context?.stackTrace?.some((t) =>
t.functionName?.includes("loadUsers")
)
) {
console.log(" ⢠Memory spike detected in loadUsers function");
console.log(" ⢠Possible cause: Loading too many users at once");
}
if (
data.context?.stackTrace?.some((t) =>
t.functionName?.includes("processUserData")
)
) {
console.log(" ⢠Memory spike in processUserData function");
console.log(" ⢠Possible cause: Creating too many processed objects");
}
if (
data.context?.stackTrace?.some((t) =>
t.functionName?.includes("handleUserRequest")
)
) {
console.log(" ⢠Memory spike in API handler");
console.log(" ⢠Possible cause: API processing large datasets");
}
console.log("\nš RECOMMENDATIONS:");
console.log(" ⢠Implement pagination for user loading");
console.log(" ⢠Use streaming for large datasets");
console.log(" ⢠Clear cache periodically");
console.log(" ⢠Consider database connection pooling");
console.log("šØ".repeat(20) + "\n");
},
],
});
async function runTest() {
console.log("š Starting Real Application Memory Test...");
console.log(" Simulating: User Service + API Controller");
console.log(" Threshold: 40%");
console.log("");
watch.start();
// Simulate real application flow
const controller = new APIController();
// Start the memory-intensive operation
setTimeout(async () => {
try {
await controller.handleUserRequest();
} catch (error) {
console.error("Error in API:", error);
}
}, 1000);
// Stop monitoring after 15 seconds
setTimeout(() => {
watch.stop();
console.log("ā
Test completed - Memory monitoring stopped");
process.exit(0);
}, 15000);
}
runTest();