Performance Monitoring Guide
@mcabreradev/filter includes built-in performance monitoring to help you track and optimize filter operations.
Quick Start
typescript
import { filter, getPerformanceMonitor } from '@mcabreradev/filter';
// Enable performance monitoring
const result = filter(users, { age: { $gte: 18 } }, {
enablePerformanceMonitoring: true
});
// Get performance metrics
const monitor = getPerformanceMonitor();
const metrics = monitor.getMetrics('filter:total');
console.log(`Average: ${metrics?.avg}ms`);
console.log(`Min: ${metrics?.min}ms`);
console.log(`Max: ${metrics?.max}ms`);
console.log(`P95: ${metrics?.p95}ms`);PerformanceMonitor Class
Creating a Monitor
typescript
import { PerformanceMonitor } from '@mcabreradev/filter';
const monitor = new PerformanceMonitor({
enabled: true,
maxSamples: 1000,
verbose: false,
onMetric: (operation, duration) => {
console.log(`${operation}: ${duration}ms`);
}
});Options:
enabled(boolean): Enable/disable monitoring (default:true)maxSamples(number): Maximum samples per operation (default:1000)verbose(boolean): Enable detailed logging (default:false)onMetric(function): Callback when metrics are recorded
Tracking Operations
Manual Tracking
typescript
monitor.track('my-operation', 150); // Track 150ms durationAutomatic Tracking
typescript
const end = monitor.start('my-operation');
// Do some work
performWork();
end(); // Automatically records durationAsync Operations
typescript
async function asyncOperation() {
const end = monitor.start('async-op');
try {
await doAsyncWork();
} finally {
end();
}
}Getting Metrics
Single Operation
typescript
const metrics = monitor.getMetrics('filter:total');
if (metrics) {
console.log({
count: metrics.count, // Number of samples
avg: metrics.avg, // Average duration (ms)
min: metrics.min, // Minimum duration (ms)
max: metrics.max, // Maximum duration (ms)
p95: metrics.p95, // 95th percentile (ms)
p99: metrics.p99, // 99th percentile (ms)
total: metrics.total // Total duration (ms)
});
}All Operations
typescript
const allMetrics = monitor.getAllMetrics();
for (const [operation, metrics] of allMetrics) {
console.log(`${operation}: ${metrics.avg}ms avg`);
}Summary
typescript
const summary = monitor.getSummary();
console.log({
operations: summary.operations, // Number of tracked operations
totalTracked: summary.totalTracked, // Total samples
slowest: summary.slowest, // Slowest operation
fastest: summary.fastest // Fastest operation
});Managing Metrics
Clear Specific Operation
typescript
monitor.clear('filter:total');Clear All Operations
typescript
monitor.clearAll();Enable/Disable
typescript
monitor.setEnabled(false); // Disable
monitor.setEnabled(true); // Enable
console.log(monitor.isEnabled()); // Check statusExporting Metrics
JSON Export
typescript
const json = monitor.toJSON();
// Send to analytics service
fetch('/api/metrics', {
method: 'POST',
body: JSON.stringify(json)
});String Format
typescript
console.log(monitor.toString());
// Output:
// Performance Metrics:
// Total Operations: 3
// Total Tracked: 150
// Slowest: filter:filtering (25.32ms)
// Fastest: filter:validation (0.15ms)
//
// Detailed Metrics:
// filter:total:
// Count: 50
// Avg: 15.23ms
// Min: 10.12ms
// Max: 25.32ms
// P95: 22.15ms
// P99: 24.87msGlobal Monitor
Use the global monitor instance for convenience:
typescript
import { getPerformanceMonitor, resetPerformanceMonitor } from '@mcabreradev/filter';
// Get or create global monitor
const monitor = getPerformanceMonitor({ enabled: true });
// Use the monitor
monitor.track('operation', 100);
// Reset global monitor (creates new instance)
resetPerformanceMonitor();Filter Integration
Performance monitoring is automatically integrated into the filter function:
typescript
import { filter, getPerformanceMonitor } from '@mcabreradev/filter';
// Enable monitoring
filter(users, expression, { enablePerformanceMonitoring: true });
// Get metrics
const monitor = getPerformanceMonitor();
// View all operation timings
console.log(monitor.toJSON());Tracked Operations:
filter:total- Total filter operation timefilter:validation- Expression validation timefilter:cache-lookup- Cache lookup timefilter:cache-set- Cache set timefilter:predicate-creation- Predicate creation timefilter:filtering- Actual filtering time
Decorator (TypeScript)
Use the @trackPerformance decorator for class methods:
typescript
import { trackPerformance } from '@mcabreradev/filter';
class DataService {
@trackPerformance('DataService.processUsers')
async processUsers(users: User[]) {
// Method will be automatically tracked
return users.filter(u => u.active);
}
}Real-World Examples
1. Performance Dashboard
typescript
import { filter, getPerformanceMonitor } from '@mcabreradev/filter';
class FilterDashboard {
private monitor = getPerformanceMonitor({ enabled: true });
filterUsers(users: User[], expression: unknown) {
return filter(users, expression, {
enablePerformanceMonitoring: true
});
}
getPerformanceReport() {
const summary = this.monitor.getSummary();
const allMetrics = this.monitor.getAllMetrics();
return {
summary,
operations: Array.from(allMetrics.entries()).map(([op, metrics]) => ({
operation: op,
count: metrics.count,
avg: metrics.avg,
p95: metrics.p95
}))
};
}
}2. Performance Alerts
typescript
import { PerformanceMonitor } from '@mcabreradev/filter';
const monitor = new PerformanceMonitor({
enabled: true,
onMetric: (operation, duration) => {
// Alert if operation is too slow
if (duration > 1000) {
console.warn(`Slow operation detected: ${operation} took ${duration}ms`);
// Send to monitoring service
sendAlert({
type: 'performance',
operation,
duration,
threshold: 1000
});
}
}
});3. A/B Testing
typescript
import { filter, getPerformanceMonitor } from '@mcabreradev/filter';
// Test with cache enabled
const monitorA = new PerformanceMonitor({ enabled: true });
const resultA = filter(largeDataset, expression, {
enableCache: true,
enablePerformanceMonitoring: true
});
const metricsA = monitorA.getMetrics('filter:total');
// Test with cache disabled
const monitorB = new PerformanceMonitor({ enabled: true });
const resultB = filter(largeDataset, expression, {
enableCache: false,
enablePerformanceMonitoring: true
});
const metricsB = monitorB.getMetrics('filter:total');
console.log('Cache enabled:', metricsA?.avg, 'ms');
console.log('Cache disabled:', metricsB?.avg, 'ms');
console.log('Speedup:', (metricsB?.avg / metricsA?.avg).toFixed(2), 'x');4. Regression Detection
typescript
import { PerformanceMonitor } from '@mcabreradev/filter';
const monitor = new PerformanceMonitor({ enabled: true });
const baseline = { avg: 10, p95: 15 }; // Known good performance
// After changes
runFilterOperations();
const current = monitor.getMetrics('filter:total');
if (current && current.avg > baseline.avg * 1.2) {
console.error('Performance regression detected!');
console.error(`Current avg: ${current.avg}ms`);
console.error(`Baseline avg: ${baseline.avg}ms`);
console.error(`Regression: ${((current.avg / baseline.avg - 1) * 100).toFixed(1)}%`);
}5. Production Monitoring
typescript
import { filter, getPerformanceMonitor } from '@mcabreradev/filter';
// Enable monitoring in production
const monitor = getPerformanceMonitor({
enabled: process.env.NODE_ENV === 'production',
maxSamples: 5000
});
// Filter with monitoring
app.post('/api/filter', (req, res) => {
const result = filter(data, req.body.expression, {
enablePerformanceMonitoring: true
});
res.json({ data: result });
});
// Periodic reporting
setInterval(() => {
const summary = monitor.getSummary();
// Send to analytics
analytics.track('filter_performance', {
operations: summary.operations,
totalTracked: summary.totalTracked,
slowest: summary.slowest,
fastest: summary.fastest
});
}, 60000); // Every minute6. Memory-Efficient Monitoring
typescript
import { PerformanceMonitor } from '@mcabreradev/filter';
// Limit samples to prevent memory issues
const monitor = new PerformanceMonitor({
enabled: true,
maxSamples: 100 // Keep only last 100 samples
});
// For long-running applications
setInterval(() => {
// Export and clear old data
const metrics = monitor.toJSON();
saveMetrics(metrics);
monitor.clearAll();
}, 3600000); // Every hourBest Practices
✅ Do
- Enable monitoring in development for optimization
- Use global monitor for consistency
- Set appropriate
maxSamplesfor your use case - Clear metrics periodically in long-running apps
- Export metrics to analytics services
- Use
onMetriccallback for real-time alerts
❌ Don't
- Enable verbose mode in production
- Keep unlimited samples in memory
- Track every single operation in production
- Forget to disable monitoring when not needed
- Ignore performance metrics from monitoring
Integration with Monitoring Services
Datadog
typescript
import { StatsD } from 'hot-shots';
import { PerformanceMonitor } from '@mcabreradev/filter';
const dogstatsd = new StatsD();
const monitor = new PerformanceMonitor({
enabled: true,
onMetric: (operation, duration) => {
dogstatsd.timing(operation, duration);
}
});Prometheus
typescript
import { Histogram } from 'prom-client';
import { PerformanceMonitor } from '@mcabreradev/filter';
const histogram = new Histogram({
name: 'filter_duration_ms',
help: 'Filter operation duration',
labelNames: ['operation']
});
const monitor = new PerformanceMonitor({
enabled: true,
onMetric: (operation, duration) => {
histogram.observe({ operation }, duration);
}
});New Relic
typescript
import newrelic from 'newrelic';
import { PerformanceMonitor } from '@mcabreradev/filter';
const monitor = new PerformanceMonitor({
enabled: true,
onMetric: (operation, duration) => {
newrelic.recordMetric(`Custom/Filter/${operation}`, duration);
}
});TypeScript Types
typescript
import type {
PerformanceMetrics,
PerformanceMonitorOptions
} from '@mcabreradev/filter';
const options: PerformanceMonitorOptions = {
enabled: true,
maxSamples: 1000,
verbose: false,
onMetric: (operation: string, duration: number) => {
console.log(`${operation}: ${duration}ms`);
}
};
const metrics: PerformanceMetrics = {
count: 100,
avg: 15.5,
min: 10.2,
max: 25.8,
p95: 22.1,
p99: 24.5,
total: 1550
};See Also: