lag-monitor
Version:
A lightweight utility for monitoring JavaScript event loop lag in real-time
283 lines (208 loc) โข 8.16 kB
Markdown
A lightweight, TypeScript-first utility for monitoring JavaScript event loop lag in real-time. Perfect for performance monitoring, debugging, and alerting on event loop blocking in both browser and Node.js environments.
[](https://badge.fury.io/js/lag-monitor)
[](http://www.typescriptlang.org/)
[](https://opensource.org/licenses/MIT)
- ๐ **Lightweight**: Minimal overhead with efficient circular buffer implementation
- ๐ **Real-time Monitoring**: Track event loop lag as it happens
- ๐ฏ **Multiple Metrics**: Built-in support for latest, average, min, max, and custom metrics
- ๐ง **Flexible Configuration**: Customizable sample rates, buffer sizes, and measurement methods
- ๐ **Universal**: Works in browsers and Node.js environments
- ๐ **TypeScript First**: Full type safety with comprehensive TypeScript definitions
- ๐งช **Well Tested**: Comprehensive test suite with high coverage
- ๐ **Custom Metrics**: Define your own metrics for specialized monitoring needs
```bash
npm install lag-monitor
```
```typescript
import LagMonitor from 'lag-monitor';
// Basic usage with default settings
const monitor = new LagMonitor();
// Get current lag metrics
console.log(monitor.snapshot());
// Output: { latest: 2.1, average: 1.8, min: 0.5, max: 5.2, samples: 10 }
// Stop monitoring when done
monitor.stop();
```
```typescript
new LagMonitor(options?: LagMonitorOptions)
```
#### Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `lagType` | `'setTimeout' \| 'setInterval' \| 'requestAnimationFrame'` | `'setTimeout'` | Method used for scheduling measurements |
| `sampleRate` | `number` | `100` | Interval between measurements in milliseconds |
| `sampleCount` | `number` | `10` | Number of samples to keep for calculations |
| `callback` | `LagCallback` | `undefined` | Optional callback invoked on each measurement |
| `autoStart` | `boolean` | `true` | Whether to start monitoring immediately |
| `userMetrics` | `Record<string, (samples: number[]) => number>` | `{}` | Custom metrics to compute |
Start lag monitoring.
Stop lag monitoring.
Reset and restart monitoring.
Clear all collected samples and stop monitoring.
Check if monitoring is currently active.
Get current lag statistics. If `metric` is specified, returns only that metric.
Get list of all available metrics (built-in + user-defined).
### Properties
#### `latest: number`
Most recent lag measurement in milliseconds.
#### `average: number`
Average lag over the current sample window.
#### `min: number`
Minimum lag in the current sample window.
#### `max: number`
Maximum lag in the current sample window.
## Usage Examples
### Basic Monitoring
```typescript
import LagMonitor from 'lag-monitor';
const monitor = new LagMonitor({
sampleRate: 50, // Check every 50ms
sampleCount: 20 // Keep last 20 samples
});
// Check lag periodically
setInterval(() => {
const lag = monitor.latest;
if (lag > 16) {
console.warn(`High lag detected: ${lag.toFixed(2)}ms`);
}
}, 1000);
```
```typescript
const monitor = new LagMonitor({
callback: (currentLag, lagData) => {
if (currentLag > 16) {
console.warn(`Frame drop detected: ${currentLag.toFixed(2)}ms`);
console.log('Current stats:', lagData);
}
}
});
```
```typescript
const monitor = new LagMonitor({
userMetrics: {
median: (samples) => {
const sorted = [...samples].sort((a, b) => a - b);
const mid = Math.floor(sorted.length / 2);
return sorted.length % 2 === 0
? (sorted[mid - 1] + sorted[mid]) / 2
: sorted[mid];
},
p95: (samples) => {
const sorted = [...samples].sort((a, b) => a - b);
const index = Math.ceil(sorted.length * 0.95) - 1;
return sorted[index];
}
}
});
console.log(monitor.snapshot());
// Output includes: { latest: 2.1, average: 1.8, median: 1.9, p95: 4.2, ... }
```
```typescript
const monitor = new LagMonitor({ autoStart: false });
// Start monitoring when needed
monitor.start();
// Get specific metrics
console.log('Current lag:', monitor.latest);
console.log('Average lag:', monitor.average);
// Get all metrics at once (atomic snapshot)
const stats = monitor.snapshot();
console.log('All metrics:', stats);
// Stop when done
monitor.stop();
```
```typescript
class PerformanceDashboard {
private monitor: LagMonitor;
private alertThreshold = 16; // 60fps threshold
constructor() {
this.monitor = new LagMonitor({
sampleRate: 16, // Check every frame at 60fps
callback: this.onLagMeasurement.bind(this)
});
}
private onLagMeasurement(lag: number, data: any) {
this.updateUI(data);
if (lag > this.alertThreshold) {
this.triggerAlert(lag);
}
}
private updateUI(data: any) {
// Update your dashboard UI
document.getElementById('current-lag').textContent = `${data.latest.toFixed(1)}ms`;
document.getElementById('avg-lag').textContent = `${data.average.toFixed(1)}ms`;
document.getElementById('max-lag').textContent = `${data.max.toFixed(1)}ms`;
}
private triggerAlert(lag: number) {
console.warn(`Performance alert: ${lag.toFixed(2)}ms lag detected`);
// Send to monitoring service, show notification, etc.
}
}
```
The library works in both environments with some considerations:
- All lag types supported: `setTimeout`, `setInterval`, `requestAnimationFrame`
- Uses `performance.now()` for high-precision timing
- Ideal for monitoring UI responsiveness
- Supports `setTimeout` and `setInterval`
- `requestAnimationFrame` will throw an error (not available)
- Uses `performance.now()` for timing
- Great for monitoring server-side event loop health
```typescript
// Node.js specific configuration
const monitor = new LagMonitor({
lagType: 'setTimeout', // Avoid requestAnimationFrame
sampleRate: 100
});
```
- **Minimal Overhead**: The monitor itself adds minimal overhead (~0.1ms per measurement)
- **Efficient Storage**: Uses circular buffer to maintain constant memory usage
- **Configurable Impact**: Adjust `sampleRate` to balance accuracy vs. performance
- **Smart Scheduling**: Different lag types for different use cases:
- `setTimeout`: General purpose, works everywhere
- `setInterval`: More consistent timing, good for steady monitoring
- `requestAnimationFrame`: Browser only, synced with display refresh
## TypeScript Support
Full TypeScript support with comprehensive type definitions:
```typescript
import LagMonitor, { LagMonitorOptions, LagData, LagCallback } from 'lag-monitor';
const options: LagMonitorOptions = {
sampleRate: 100,
callback: (lag: number, data: LagData) => {
console.log(`Lag: ${lag}ms`, data);
}
};
const monitor = new LagMonitor(options);
```
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
See [CHANGELOG.md](CHANGELOG.md) for a detailed history of changes.
- ๐ [Documentation](https://github.com/yourusername/lag-monitor#readme)
- ๐ [Issue Tracker](https://github.com/yourusername/lag-monitor/issues)
- ๐ฌ [Discussions](https://github.com/yourusername/lag-monitor/discussions)
---
Made with โค๏ธ for the JavaScript performance monitoring community.