TracePerf is a Node.js library for advanced console logging and performance tracking. It provides structured logs, execution flow tracing, and performance bottleneck detection to help developers debug and optimize their applications.
The central component of TracePerf is the Logger core, which handles basic logging functionality and coordinates between different modules.
┌─────────────────────────────────────────┐
│ Logger Core │
├─────────────────────────────────────────┤
│ - Basic logging (info, warn, error) │
│ - Configuration management │
│ - Log filtering and formatting │
│ - Transport management │
└───────────────┬─────────────────────────┘
│
┌───────────┴───────────┐
│ │
┌───▼───────────┐ ┌───────▼─────────┐
│ Execution │ │ Performance │
│ Tracker │ │ Monitor │
└───────────────┘ └─────────────────┘
The Execution Tracker is responsible for tracing function calls and generating visual representations of the execution flow.
┌─────────────────────────────────────────┐
│ Execution Tracker │
├─────────────────────────────────────────┤
│ - Function call tracking │
│ - Call stack management │
│ - Execution time measurement │
│ - ASCII flow chart generation │
└─────────────────────────────────────────┘
The Performance Monitor tracks execution time and memory usage, identifying potential bottlenecks in the application.
┌─────────────────────────────────────────┐
│ Performance Monitor │
├─────────────────────────────────────────┤
│ - High-resolution timing │
│ - Bottleneck detection │
│ - Memory usage tracking │
│ - Performance statistics │
└─────────────────────────────────────────┘
Formatters are responsible for converting log data into different output formats.
┌─────────────────────────────────────────┐
│ Formatters │
├─────────────────────────────────────────┤
│ - CLI formatter (colored text) │
│ - JSON formatter │
│ - ASCII art generator │
│ - Custom formatters │
└─────────────────────────────────────────┘
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Logger │───►│ Filter │───►│ Formatter│───►│ Transport│
│ API │ │ │ │ │ │ │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
- User calls a logging method (
info,warn,error,debug) - Log entry is filtered based on current logging mode
- Log entry is formatted according to the selected formatter
- Formatted log is sent to the appropriate transport (console, file, etc.)
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Function │───►│ Execution│───►│Performance│───►│ Logger │
│ Wrapper │ │ Tracker │ │ Monitor │ │ │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
- User wraps a function with
tracePerf.track() - Execution Tracker intercepts function call and starts timing
- Original function is executed
- Execution Tracker records function completion and calculates metrics
- Performance Monitor analyzes metrics for bottlenecks
- Results are logged through the Logger core
interface ILogger {
info(message: string | object, ...args: any[]): void;
warn(message: string | object, ...args: any[]): void;
error(message: string | object, ...args: any[]): void;
debug(message: string | object, ...args: any[]): void;
group(label: string): void;
groupEnd(): void;
setMode(mode: 'dev' | 'staging' | 'prod' | string): void;
getMode(): string;
track<T>(fn: () => T, options?: TrackOptions): T;
}interface ILoggerConfig {
mode?: 'dev' | 'staging' | 'prod' | string;
level?: 'debug' | 'info' | 'warn' | 'error';
colorize?: boolean;
timestamp?: boolean;
performanceThreshold?: number; // ms
indentSize?: number;
transports?: Transport[];
formatters?: Formatter[];
}interface ITrackOptions {
label?: string;
threshold?: number; // ms
includeMemory?: boolean;
silent?: boolean;
}TracePerf will use function wrappers to track execution:
function track<T>(fn: () => T, options?: TrackOptions): T {
const start = process.hrtime();
const startMemory = process.memoryUsage().heapUsed;
try {
// Get function name through reflection
const fnName = getFunctionName(fn);
// Add to call stack
callStack.push(fnName);
// Execute the function
const result = fn();
// Calculate execution time
const [seconds, nanoseconds] = process.hrtime(start);
const duration = seconds * 1000 + nanoseconds / 1000000;
// Calculate memory usage
const endMemory = process.memoryUsage().heapUsed;
const memoryDiff = endMemory - startMemory;
// Check for bottlenecks
if (duration > (options?.threshold || defaultThreshold)) {
logBottleneck(fnName, duration, memoryDiff);
}
// Log execution
logExecution(fnName, duration, memoryDiff, callStack.length - 1);
return result;
} finally {
// Remove from call stack
callStack.pop();
}
}TracePerf will generate ASCII flow charts using a combination of box-drawing characters:
function generateFlowChart(executions: Execution[]): string {
let chart = '';
for (let i = 0; i < executions.length; i++) {
const execution = executions[i];
// Generate box for function
chart += '┌─────────────────┐\n';
chart += `│ ${execution.name.padEnd(15)} │ ⏱ ${execution.duration}ms`;
if (execution.isSlow) {
chart += ' ⚠️ SLOW';
}
chart += '\n';
chart += '└─────────────────┘\n';
// Add arrow to next function if not the last one
if (i < executions.length - 1) {
chart += ' │ \n';
chart += ' ▼ \n';
}
}
return chart;
}TracePerf will implement conditional logging based on the current mode:
function shouldLog(level: LogLevel, mode: LogMode): boolean {
const levelPriority = {
debug: 0,
info: 1,
warn: 2,
error: 3
};
const modeLevels = {
dev: 'debug', // In dev mode, show all logs
staging: 'warn', // In staging, show only warnings and errors
prod: 'error' // In prod, show only errors
};
const modeMinLevel = modeLevels[mode] || 'info';
return levelPriority[level] >= levelPriority[modeMinLevel];
}To minimize the performance impact of TracePerf, especially in production environments:
- Conditional Compilation: Use build-time flags to remove debug code in production
- Sampling: Implement sampling for high-frequency function calls
- Buffering: Buffer logs and flush periodically to reduce I/O overhead
- Async Logging: Use non-blocking operations for I/O-bound operations
- Lazy Evaluation: Evaluate log messages only if they will be output
To minimize memory usage:
- Object Pooling: Reuse log objects to reduce garbage collection
- Stream Processing: Process logs as streams to avoid storing large amounts of data
- Circular Buffers: Use circular buffers for storing recent logs
- Weak References: Use weak references for tracking objects
TracePerf is designed to be extensible through several mechanisms:
- Custom Formatters: Users can create custom formatters for specialized output
- Custom Transports: Support for sending logs to different destinations
- Plugins: Plugin system for adding new functionality
- Middleware: Middleware for processing logs before output
TracePerf will support:
- Node.js 14.x and above (LTS versions)
- Both CommonJS and ES Modules
To minimize the dependency footprint:
- Use only essential dependencies
- Prefer small, focused packages over large frameworks
- Make heavy use of Node.js built-in modules
While primarily designed for Node.js, TracePerf will provide:
- A browser-compatible build with reduced functionality
- Polyfills for Node.js-specific APIs
Potential future enhancements include:
- Distributed Tracing: Support for tracing across multiple services
- Visualization Tools: Web-based visualization of execution flows
- Machine Learning: Anomaly detection for performance issues
- Integration with APM Tools: Integration with Application Performance Monitoring tools
- Remote Logging: Support for sending logs to remote servers