mirror of
https://github.com/betaflight/betaflight-configurator.git
synced 2025-07-26 01:35:28 +03:00
Suggestions per Coderabbit
This commit is contained in:
parent
07ca99ad0d
commit
12d3ddfcaa
8 changed files with 258 additions and 184 deletions
|
@ -132,7 +132,8 @@ function startProcess() {
|
||||||
console.log(`Libraries: jQuery - ${$.fn.jquery}, three.js - ${THREE.REVISION}`);
|
console.log(`Libraries: jQuery - ${$.fn.jquery}, three.js - ${THREE.REVISION}`);
|
||||||
|
|
||||||
// Check if this is the first visit
|
// Check if this is the first visit
|
||||||
if (getConfig("firstRun").firstRun === undefined) {
|
const firstRunCfg = getConfig("firstRun") ?? {};
|
||||||
|
if (firstRunCfg.firstRun === undefined) {
|
||||||
setConfig({ firstRun: true });
|
setConfig({ firstRun: true });
|
||||||
import("./tabs/static_tab.js").then(({ staticTab }) => {
|
import("./tabs/static_tab.js").then(({ staticTab }) => {
|
||||||
staticTab.initialize("options", () => {
|
staticTab.initialize("options", () => {
|
||||||
|
|
|
@ -51,11 +51,14 @@ const MSP = {
|
||||||
message_buffer: null,
|
message_buffer: null,
|
||||||
message_buffer_uint8_view: null,
|
message_buffer_uint8_view: null,
|
||||||
message_checksum: 0,
|
message_checksum: 0,
|
||||||
|
crcError: false,
|
||||||
|
|
||||||
callbacks: [],
|
callbacks: [],
|
||||||
packet_error: 0,
|
packet_error: 0,
|
||||||
unsupported: 0,
|
unsupported: 0,
|
||||||
|
|
||||||
|
TIMEOUT: 1000,
|
||||||
|
|
||||||
last_received_timestamp: null,
|
last_received_timestamp: null,
|
||||||
listeners: [],
|
listeners: [],
|
||||||
|
|
||||||
|
@ -65,8 +68,6 @@ const MSP = {
|
||||||
cli_output: [],
|
cli_output: [],
|
||||||
cli_callback: null,
|
cli_callback: null,
|
||||||
|
|
||||||
TIMEOUT: 1000,
|
|
||||||
|
|
||||||
read(readInfo) {
|
read(readInfo) {
|
||||||
if (CONFIGURATOR.virtualMode) {
|
if (CONFIGURATOR.virtualMode) {
|
||||||
return;
|
return;
|
||||||
|
@ -377,7 +378,6 @@ const MSP = {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create unique key combining code and data
|
|
||||||
const requestExists = this.callbacks.some((instance) => instance.code === code);
|
const requestExists = this.callbacks.some((instance) => instance.code === code);
|
||||||
|
|
||||||
const bufferOut = code <= 254 ? this.encode_message_v1(code, data) : this.encode_message_v2(code, data);
|
const bufferOut = code <= 254 ? this.encode_message_v1(code, data) : this.encode_message_v2(code, data);
|
||||||
|
@ -390,7 +390,6 @@ const MSP = {
|
||||||
start: performance.now(),
|
start: performance.now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Track only the first outstanding request for a given key
|
|
||||||
if (!requestExists) {
|
if (!requestExists) {
|
||||||
obj.timer = setTimeout(() => {
|
obj.timer = setTimeout(() => {
|
||||||
console.warn(
|
console.warn(
|
||||||
|
@ -404,9 +403,7 @@ const MSP = {
|
||||||
// We should probably give up connection if the request takes too long ?
|
// We should probably give up connection if the request takes too long ?
|
||||||
if (executionTime > 5000) {
|
if (executionTime > 5000) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`MSP: data request took too long: ${code} ID: ${serial.connectionId} TAB: ${GUI.active_tab} TIMEOUT: ${
|
`MSP: data request took too long: ${code} ID: ${serial.connectionId} TAB: ${GUI.active_tab} EXECUTION TIME: ${executionTime}ms`,
|
||||||
this.timeout
|
|
||||||
} EXECUTION TIME: ${executionTime}ms`,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,62 +48,82 @@ import('./src/js/msp_debug_tools.js');
|
||||||
|
|
||||||
**Start monitoring:**
|
**Start monitoring:**
|
||||||
```javascript
|
```javascript
|
||||||
MSPTestRunner.startQuickMonitor();
|
MSPDebug.startMonitoring();
|
||||||
```
|
```
|
||||||
|
|
||||||
**Show visual dashboard:**
|
**Show visual dashboard:**
|
||||||
```javascript
|
```javascript
|
||||||
MSPTestRunner.showDashboard();
|
MSPDebug.show();
|
||||||
// Or press Ctrl+Shift+M
|
// Or press Ctrl+Shift+M
|
||||||
```
|
```
|
||||||
|
|
||||||
**Quick health check:**
|
**Quick test of alert system:**
|
||||||
```javascript
|
```javascript
|
||||||
MSPTestRunner.quickHealthCheck();
|
MSPDebug.testAlerts();
|
||||||
```
|
```
|
||||||
|
|
||||||
**Run stress tests:**
|
**Run stress tests:**
|
||||||
```javascript
|
```javascript
|
||||||
// Run specific test
|
// Run specific test
|
||||||
MSPTestRunner.runTest('queue-flooding');
|
MSPDebug.runTests();
|
||||||
|
|
||||||
// Run full test suite
|
// Run complete stress test suite with detailed console output
|
||||||
MSPTestRunner.runFullSuite();
|
MSPDebug.runFullSuite();
|
||||||
|
|
||||||
|
// Run individual test by name
|
||||||
|
MSPDebug.runTest('queue-flooding');
|
||||||
|
|
||||||
|
// Quick health check
|
||||||
|
MSPDebug.quickHealthCheck();
|
||||||
|
|
||||||
|
// Run stress scenario
|
||||||
|
MSPDebug.stressScenario('high-frequency');
|
||||||
```
|
```
|
||||||
|
|
||||||
## Available Commands
|
## Available Commands
|
||||||
|
|
||||||
|
The MSP Debug Tools provide two APIs:
|
||||||
|
- **MSPDebug**: Modern, simplified API (recommended)
|
||||||
|
- **MSPTestRunner**: Legacy API with additional methods
|
||||||
|
|
||||||
|
Both APIs provide the same core functionality. Use `MSPDebug` for new code.
|
||||||
|
|
||||||
### Monitoring Commands
|
### Monitoring Commands
|
||||||
|
|
||||||
| Command | Description |
|
| Command | Description |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `MSPTestRunner.startQuickMonitor()` | Start monitoring with console output |
|
| `MSPDebug.startMonitoring()` | Start monitoring with console output |
|
||||||
| `MSPTestRunner.stopMonitor()` | Stop monitoring |
|
| `MSPDebug.stopMonitoring()` | Stop monitoring |
|
||||||
| `MSPTestRunner.getStatus()` | Get current MSP status |
|
| `MSPDebug.getStatus()` | Get current MSP status |
|
||||||
| `MSPTestRunner.analyzeQueue()` | Analyze current queue contents |
|
| `MSPDebug.monitor.getStatus()` | Get current MSP status (alternative) |
|
||||||
|
| `MSPDebug.analyze()` | Analyze current queue contents |
|
||||||
|
|
||||||
### Testing Commands
|
### Testing Commands
|
||||||
|
|
||||||
| Command | Description |
|
| Command | Description |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `MSPTestRunner.runTest('test-name')` | Run specific stress test |
|
| `MSPDebug.runTests()` | Run stress test suite |
|
||||||
| `MSPTestRunner.runFullSuite()` | Run complete test suite |
|
| `MSPDebug.runFullSuite()` | Run complete stress test suite with detailed output |
|
||||||
| `MSPTestRunner.quickHealthCheck()` | Quick health validation |
|
| `MSPDebug.runTest('test-name')` | Run a specific test by name |
|
||||||
|
| `MSPDebug.quickHealthCheck()` | Run a quick MSP health check |
|
||||||
|
| `MSPDebug.stressScenario('scenario')` | Run specific stress test scenario |
|
||||||
|
| `MSPDebug.testAlerts()` | Test alert system |
|
||||||
|
| `MSPDebug.triggerTestAlerts()` | Manually trigger alerts |
|
||||||
|
|
||||||
### Stress Scenarios
|
### Alert Testing
|
||||||
|
|
||||||
| Command | Description |
|
| Command | Description |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `MSPTestRunner.stressScenario('high-frequency')` | High frequency request test |
|
| `MSPDebug.setTestThresholds()` | Lower thresholds for easier testing |
|
||||||
| `MSPTestRunner.stressScenario('queue-overflow')` | Queue overflow handling test |
|
| `MSPDebug.setNormalThresholds()` | Restore normal thresholds |
|
||||||
| `MSPTestRunner.stressScenario('mixed-load')` | Mixed request types test |
|
| `MSPDebug.testAlerts()` | Complete alert system test |
|
||||||
|
|
||||||
### Visual Tools
|
### Visual Tools
|
||||||
|
|
||||||
| Command | Description |
|
| Command | Description |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `MSPTestRunner.showDashboard()` | Show visual debug dashboard |
|
| `MSPDebug.show()` | Show visual debug dashboard |
|
||||||
| `MSPTestRunner.generateReport()` | Generate and download report |
|
| `MSPDebug.report()` | Generate and download report |
|
||||||
|
|
||||||
## Dashboard Interactions
|
## Dashboard Interactions
|
||||||
|
|
||||||
|
@ -139,15 +159,27 @@ The visual dashboard includes smart interaction handling to ensure a smooth user
|
||||||
|
|
||||||
## Available Tests
|
## Available Tests
|
||||||
|
|
||||||
1. **Queue Flooding** - Tests queue limits with many simultaneous requests
|
### Individual Test Names (for `runTest`)
|
||||||
2. **Rapid Fire Requests** - Tests high-frequency request handling
|
|
||||||
3. **Duplicate Request Handling** - Validates duplicate request management
|
1. **queue-flooding** - Tests queue limits with many simultaneous requests
|
||||||
4. **Timeout Recovery** - Tests timeout and retry mechanisms
|
2. **rapid-fire** - Tests high-frequency request handling
|
||||||
5. **Memory Leak Detection** - Checks for proper cleanup of completed requests
|
3. **duplicates** - Validates duplicate request management
|
||||||
6. **Concurrent Mixed Requests** - Tests various request types simultaneously
|
4. **timeout-recovery** - Tests timeout and retry mechanisms
|
||||||
7. **Queue Overflow Handling** - Tests behavior when queue reaches capacity
|
5. **memory-leaks** - Checks for proper cleanup of completed requests
|
||||||
8. **Connection Disruption** - Simulates connection issues
|
6. **concurrent-mixed** - Tests various request types simultaneously
|
||||||
9. **Performance Under Load** - Tests sustained load performance
|
7. **queue-overflow** - Tests behavior when queue reaches capacity
|
||||||
|
8. **connection-disruption** - Simulates connection issues
|
||||||
|
9. **performance-load** - Tests sustained load performance
|
||||||
|
|
||||||
|
### Stress Scenarios (for `stressScenario`)
|
||||||
|
|
||||||
|
- **high-frequency** - High-frequency requests every 10ms for 5 seconds
|
||||||
|
- **queue-overflow** - Floods queue beyond capacity
|
||||||
|
- **mixed-load** - Various request types and sizes
|
||||||
|
|
||||||
|
### Full Test Suite
|
||||||
|
|
||||||
|
The `runFullSuite()` command runs all individual tests in sequence with detailed console output and generates a comprehensive report.
|
||||||
|
|
||||||
## Monitoring Metrics
|
## Monitoring Metrics
|
||||||
|
|
||||||
|
@ -190,37 +222,50 @@ The visual dashboard provides:
|
||||||
### Development Testing
|
### Development Testing
|
||||||
```javascript
|
```javascript
|
||||||
// Start monitoring during development
|
// Start monitoring during development
|
||||||
MSPTestRunner.startQuickMonitor();
|
MSPDebug.startMonitoring();
|
||||||
|
|
||||||
// Run quick health check after changes
|
// Quick health check
|
||||||
MSPTestRunner.quickHealthCheck();
|
MSPDebug.quickHealthCheck();
|
||||||
|
|
||||||
// Test specific functionality
|
// Test the alert system
|
||||||
MSPTestRunner.runTest('timeout-recovery');
|
MSPDebug.testAlerts();
|
||||||
|
|
||||||
|
// Show visual dashboard
|
||||||
|
MSPDebug.show();
|
||||||
```
|
```
|
||||||
|
|
||||||
### Performance Analysis
|
### Performance Analysis
|
||||||
```javascript
|
```javascript
|
||||||
// Show dashboard for visual monitoring
|
// Show dashboard for visual monitoring
|
||||||
MSPTestRunner.showDashboard();
|
MSPDebug.show();
|
||||||
|
|
||||||
// Run performance stress test
|
// Run complete stress tests with detailed output
|
||||||
MSPTestRunner.stressScenario('high-frequency');
|
MSPDebug.runFullSuite();
|
||||||
|
|
||||||
|
// Test specific scenarios
|
||||||
|
MSPDebug.stressScenario('high-frequency');
|
||||||
|
|
||||||
// Generate detailed report
|
// Generate detailed report
|
||||||
MSPTestRunner.generateReport();
|
MSPDebug.report();
|
||||||
```
|
```
|
||||||
|
|
||||||
### Issue Debugging
|
### Issue Debugging
|
||||||
```javascript
|
```javascript
|
||||||
|
// Get current status
|
||||||
|
MSPDebug.getStatus();
|
||||||
|
|
||||||
// Analyze current queue state
|
// Analyze current queue state
|
||||||
MSPTestRunner.analyzeQueue();
|
MSPDebug.analyze();
|
||||||
|
|
||||||
// Check for memory leaks
|
// Test specific problematic scenario
|
||||||
MSPTestRunner.runTest('memory-leaks');
|
MSPDebug.runTest('memory-leaks');
|
||||||
|
|
||||||
// Run full diagnostic
|
// Check for alerts with low thresholds
|
||||||
MSPTestRunner.runFullSuite();
|
MSPDebug.setTestThresholds();
|
||||||
|
MSPDebug.triggerTestAlerts();
|
||||||
|
|
||||||
|
// Generate diagnostic report
|
||||||
|
MSPDebug.report();
|
||||||
```
|
```
|
||||||
|
|
||||||
## Integration with Existing Code
|
## Integration with Existing Code
|
||||||
|
@ -232,6 +277,41 @@ The debug tools are designed to be non-intrusive:
|
||||||
- No performance impact when not actively monitoring
|
- No performance impact when not actively monitoring
|
||||||
- Original MSP behavior is preserved
|
- Original MSP behavior is preserved
|
||||||
|
|
||||||
|
### Auto-loading
|
||||||
|
The debug tools auto-load when `msp_debug_tools.js` is imported. They detect the presence of the global MSP object and initialize automatically.
|
||||||
|
|
||||||
|
### Keyboard Shortcuts
|
||||||
|
- `Ctrl+Shift+M`: Toggle debug dashboard
|
||||||
|
|
||||||
|
## Implementation Status
|
||||||
|
|
||||||
|
### ✅ Current Features
|
||||||
|
|
||||||
|
#### Alert System
|
||||||
|
- Enhanced debug logging with reduced console noise
|
||||||
|
- Test infrastructure: `triggerTestAlerts()`, `setTestThresholds()`, `setNormalThresholds()`
|
||||||
|
- Visual alert display in dashboard
|
||||||
|
- Smart threshold management for testing
|
||||||
|
|
||||||
|
#### Interactive Dashboard
|
||||||
|
- Smart update pausing during user interactions
|
||||||
|
- Clickable test results with detailed information
|
||||||
|
- Enhanced interaction handling for all UI elements
|
||||||
|
- Visual feedback with updates pause indicator
|
||||||
|
|
||||||
|
#### Complete API
|
||||||
|
- Dual API support: `MSPDebug` (modern) and `MSPTestRunner` (legacy)
|
||||||
|
- All documented commands implemented and verified
|
||||||
|
- Comprehensive testing methods (9 test types + 3 stress scenarios)
|
||||||
|
- Real-time monitoring with alert detection
|
||||||
|
|
||||||
|
### ✅ Verified Working
|
||||||
|
- Alert system triggers correctly when thresholds exceeded
|
||||||
|
- Dashboard displays alerts visually without update interference
|
||||||
|
- Test results provide comprehensive detailed information
|
||||||
|
- All API commands function as documented
|
||||||
|
- Auto-loading works in development environment
|
||||||
|
|
||||||
## File Structure
|
## File Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -70,6 +70,9 @@ export class MSPDebugDashboard {
|
||||||
<!-- Alerts Section -->
|
<!-- Alerts Section -->
|
||||||
<div class="alerts-section">
|
<div class="alerts-section">
|
||||||
<h4>🚨 Alerts</h4>
|
<h4>🚨 Alerts</h4>
|
||||||
|
<div class="alerts-header">
|
||||||
|
<button id="clear-alerts" style="float: right; padding: 2px 6px; font-size: 10px; background: #666; color: white; border: none; border-radius: 2px; cursor: pointer;">Clear Alerts</button>
|
||||||
|
</div>
|
||||||
<div id="alerts-container" class="alerts-container">
|
<div id="alerts-container" class="alerts-container">
|
||||||
<div class="no-alerts">No active alerts</div>
|
<div class="no-alerts">No active alerts</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -88,7 +91,7 @@ export class MSPDebugDashboard {
|
||||||
<!-- Live Chart -->
|
<!-- Live Chart -->
|
||||||
<div class="chart-section">
|
<div class="chart-section">
|
||||||
<h4>📈 Live Metrics</h4>
|
<h4>📈 Live Metrics</h4>
|
||||||
<canvas id="msp-metrics-chart" width="400" height="200"></canvas>
|
<canvas id="msp-metrics-chart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Request Details -->
|
<!-- Request Details -->
|
||||||
|
@ -304,6 +307,11 @@ export class MSPDebugDashboard {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.queue-item-empty {
|
||||||
|
opacity: 0.3;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
.test-results {
|
.test-results {
|
||||||
background: #2a2a2a;
|
background: #2a2a2a;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
@ -344,6 +352,7 @@ export class MSPDebugDashboard {
|
||||||
height: 150px;
|
height: 150px;
|
||||||
background: #2a2a2a;
|
background: #2a2a2a;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.test-result-item {
|
.test-result-item {
|
||||||
|
@ -421,6 +430,8 @@ export class MSPDebugDashboard {
|
||||||
this.runStressTest();
|
this.runStressTest();
|
||||||
} else if (e.target.id === "msp-clear-metrics") {
|
} else if (e.target.id === "msp-clear-metrics") {
|
||||||
this.clearMetrics();
|
this.clearMetrics();
|
||||||
|
} else if (e.target.id === "clear-alerts") {
|
||||||
|
this.clearAlerts();
|
||||||
} else if (e.target.id === "msp-close-dashboard") {
|
} else if (e.target.id === "msp-close-dashboard") {
|
||||||
this.hide();
|
this.hide();
|
||||||
} else if (e.target.id === "analyze-queue") {
|
} else if (e.target.id === "analyze-queue") {
|
||||||
|
@ -444,6 +455,14 @@ export class MSPDebugDashboard {
|
||||||
this.toggle();
|
this.toggle();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle window resize to redraw canvas with correct dimensions
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
if (this.isVisible) {
|
||||||
|
// Delay redraw to ensure layout is updated
|
||||||
|
setTimeout(() => this.drawChart(), 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -606,6 +625,13 @@ export class MSPDebugDashboard {
|
||||||
this.updateDisplay();
|
this.updateDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear alerts only
|
||||||
|
*/
|
||||||
|
clearAlerts() {
|
||||||
|
mspQueueMonitor.clearAlerts();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update display with current status
|
* Update display with current status
|
||||||
*/
|
*/
|
||||||
|
@ -752,23 +778,37 @@ export class MSPDebugDashboard {
|
||||||
const container = document.getElementById("queue-contents");
|
const container = document.getElementById("queue-contents");
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
if (!queueContents || queueContents.length === 0) {
|
// Always show exactly 5 slots to prevent layout shifts
|
||||||
container.innerHTML = '<div style="text-align: center; color: #888; padding: 20px;">Queue is empty</div>';
|
const maxSlots = 5;
|
||||||
return;
|
const items = queueContents || [];
|
||||||
|
const slotsHtml = [];
|
||||||
|
|
||||||
|
// Add actual queue items
|
||||||
|
for (let i = 0; i < maxSlots; i++) {
|
||||||
|
if (i < items.length) {
|
||||||
|
const item = items[i];
|
||||||
|
slotsHtml.push(`
|
||||||
|
<div class="queue-item">
|
||||||
|
<span>Code: ${item.code}</span>
|
||||||
|
<span>Age: ${Math.round(item.age)}ms</span>
|
||||||
|
<span>Attempts: ${item.attempts}</span>
|
||||||
|
<span style="color: ${item.hasTimer ? "#00ff00" : "#ff4444"}">${item.hasTimer ? "✓" : "✗"}</span>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
} else {
|
||||||
|
// Add empty slot placeholder
|
||||||
|
slotsHtml.push(`
|
||||||
|
<div class="queue-item queue-item-empty">
|
||||||
|
<span style="color: #555;">—</span>
|
||||||
|
<span style="color: #555;">—</span>
|
||||||
|
<span style="color: #555;">—</span>
|
||||||
|
<span style="color: #555;">—</span>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = queueContents
|
container.innerHTML = slotsHtml.join("");
|
||||||
.map(
|
|
||||||
(item) => `
|
|
||||||
<div class="queue-item">
|
|
||||||
<span>Code: ${item.code}</span>
|
|
||||||
<span>Age: ${Math.round(item.age)}ms</span>
|
|
||||||
<span>Attempts: ${item.attempts}</span>
|
|
||||||
<span style="color: ${item.hasTimer ? "#00ff00" : "#ff4444"}">${item.hasTimer ? "✓" : "✗"}</span>
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
)
|
|
||||||
.join("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -805,8 +845,28 @@ export class MSPDebugDashboard {
|
||||||
if (!canvas) return;
|
if (!canvas) return;
|
||||||
|
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
const width = canvas.width;
|
|
||||||
const height = canvas.height;
|
// Get the display size (CSS pixels)
|
||||||
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
const displayWidth = rect.width;
|
||||||
|
const displayHeight = rect.height;
|
||||||
|
|
||||||
|
// Get the device pixel ratio, falling back to 1
|
||||||
|
const devicePixelRatio = window.devicePixelRatio || 1;
|
||||||
|
|
||||||
|
// Set the internal canvas size to actual pixels for Hi-DPI displays
|
||||||
|
canvas.width = displayWidth * devicePixelRatio;
|
||||||
|
canvas.height = displayHeight * devicePixelRatio;
|
||||||
|
|
||||||
|
// Scale the canvas back down using CSS
|
||||||
|
canvas.style.width = `${displayWidth }px`;
|
||||||
|
canvas.style.height = `${displayHeight }px`;
|
||||||
|
|
||||||
|
// Scale the drawing context so everything draws at the correct size
|
||||||
|
ctx.scale(devicePixelRatio, devicePixelRatio);
|
||||||
|
|
||||||
|
const width = displayWidth;
|
||||||
|
const height = displayHeight;
|
||||||
|
|
||||||
// Clear canvas
|
// Clear canvas
|
||||||
ctx.fillStyle = "#2a2a2a";
|
ctx.fillStyle = "#2a2a2a";
|
||||||
|
@ -834,7 +894,7 @@ export class MSPDebugDashboard {
|
||||||
|
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
// Draw labels
|
// Draw labels with proper font scaling
|
||||||
ctx.fillStyle = "#ffffff";
|
ctx.fillStyle = "#ffffff";
|
||||||
ctx.font = "10px monospace";
|
ctx.font = "10px monospace";
|
||||||
ctx.fillText("Queue Size", 5, 15);
|
ctx.fillText("Queue Size", 5, 15);
|
||||||
|
@ -1010,10 +1070,17 @@ window.MSPDebug = {
|
||||||
startMonitoring: () => mspQueueMonitor.startMonitoring(),
|
startMonitoring: () => mspQueueMonitor.startMonitoring(),
|
||||||
stopMonitoring: () => mspQueueMonitor.stopMonitoring(),
|
stopMonitoring: () => mspQueueMonitor.stopMonitoring(),
|
||||||
runTests: () => mspStressTest.runStressTestSuite(),
|
runTests: () => mspStressTest.runStressTestSuite(),
|
||||||
|
runFullSuite: () => mspStressTest.runStressTestSuite(),
|
||||||
analyze: () => mspQueueMonitor.analyzeQueue(),
|
analyze: () => mspQueueMonitor.analyzeQueue(),
|
||||||
report: () => mspQueueMonitor.generateReport(),
|
report: () => mspQueueMonitor.generateReport(),
|
||||||
showTestDetails: (index) => mspDebugDashboard.showTestDetails(index),
|
showTestDetails: (index) => mspDebugDashboard.showTestDetails(index),
|
||||||
|
|
||||||
|
// Individual test methods
|
||||||
|
runTest: (testName) => mspStressTest.runSpecificTest(testName),
|
||||||
|
quickHealthCheck: () => window.MSPTestRunner.quickHealthCheck(),
|
||||||
|
stressScenario: (scenario) => window.MSPTestRunner.stressScenario(scenario),
|
||||||
|
getStatus: () => mspQueueMonitor.getStatus(),
|
||||||
|
|
||||||
// Alert testing methods
|
// Alert testing methods
|
||||||
triggerTestAlerts: () => mspQueueMonitor.triggerTestAlerts(),
|
triggerTestAlerts: () => mspQueueMonitor.triggerTestAlerts(),
|
||||||
setTestThresholds: () => mspQueueMonitor.setTestThresholds(),
|
setTestThresholds: () => mspQueueMonitor.setTestThresholds(),
|
||||||
|
|
|
@ -29,7 +29,7 @@ export class MSPQueueMonitor {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.thresholds = {
|
this.thresholds = {
|
||||||
maxQueueSize: 40, // Alert when queue > 80% of MAX_QUEUE_SIZE
|
maxQueueSize: Math.floor((this.msp.MAX_QUEUE_SIZE || 50) * 0.8), // Alert when queue > 80% of MAX_QUEUE_SIZE
|
||||||
maxAvgResponseTime: 2000, // Alert when avg response > 2s
|
maxAvgResponseTime: 2000, // Alert when avg response > 2s
|
||||||
maxTimeoutRate: 0.1, // Alert when timeout rate > 10%
|
maxTimeoutRate: 0.1, // Alert when timeout rate > 10%
|
||||||
memoryLeakThreshold: 100, // Alert when callbacks grow beyond expected
|
memoryLeakThreshold: 100, // Alert when callbacks grow beyond expected
|
||||||
|
@ -83,7 +83,7 @@ export class MSPQueueMonitor {
|
||||||
this.metrics.requestsByCode.set(code, count + 1);
|
this.metrics.requestsByCode.set(code, count + 1);
|
||||||
|
|
||||||
// Check for queue size peaks
|
// Check for queue size peaks
|
||||||
const currentQueueSize = this.msp.callbacks.length;
|
const currentQueueSize = this.msp.callbacks?.length ?? 0;
|
||||||
if (currentQueueSize > this.metrics.queuePeakSize) {
|
if (currentQueueSize > this.metrics.queuePeakSize) {
|
||||||
this.metrics.queuePeakSize = currentQueueSize;
|
this.metrics.queuePeakSize = currentQueueSize;
|
||||||
}
|
}
|
||||||
|
@ -339,7 +339,7 @@ export class MSPQueueMonitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset metrics
|
* Reset metrics only (keep alerts intact)
|
||||||
*/
|
*/
|
||||||
resetMetrics() {
|
resetMetrics() {
|
||||||
this.metrics = {
|
this.metrics = {
|
||||||
|
@ -356,12 +356,30 @@ export class MSPQueueMonitor {
|
||||||
errorsByType: new Map(),
|
errorsByType: new Map(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Note: Alerts are NOT reset here - they should only be cleared when conditions are no longer true
|
||||||
|
// or when explicitly requested via clearAlerts() method
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear alerts (separate from metrics)
|
||||||
|
*/
|
||||||
|
clearAlerts() {
|
||||||
|
console.log("🔄 Clearing all alerts...");
|
||||||
this.alerts = {
|
this.alerts = {
|
||||||
queueFull: false,
|
queueFull: false,
|
||||||
highTimeout: false,
|
highTimeout: false,
|
||||||
slowResponses: false,
|
slowResponses: false,
|
||||||
memoryLeak: false,
|
memoryLeak: false,
|
||||||
};
|
};
|
||||||
|
this._notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset both metrics and alerts (complete reset)
|
||||||
|
*/
|
||||||
|
resetAll() {
|
||||||
|
this.resetMetrics();
|
||||||
|
this.clearAlerts();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -516,7 +534,7 @@ export class MSPQueueMonitor {
|
||||||
setNormalThresholds() {
|
setNormalThresholds() {
|
||||||
console.log("🔧 Resetting to normal thresholds...");
|
console.log("🔧 Resetting to normal thresholds...");
|
||||||
this.thresholds = {
|
this.thresholds = {
|
||||||
maxQueueSize: 40, // Alert when queue > 80% of MAX_QUEUE_SIZE
|
maxQueueSize: Math.floor((this.msp.MAX_QUEUE_SIZE || 50) * 0.8), // Alert when queue > 80% of MAX_QUEUE_SIZE
|
||||||
maxAvgResponseTime: 2000, // Alert when avg response > 2s
|
maxAvgResponseTime: 2000, // Alert when avg response > 2s
|
||||||
maxTimeoutRate: 0.1, // Alert when timeout rate > 10%
|
maxTimeoutRate: 0.1, // Alert when timeout rate > 10%
|
||||||
memoryLeakThreshold: 100, // Alert when callbacks grow beyond expected
|
memoryLeakThreshold: 100, // Alert when callbacks grow beyond expected
|
||||||
|
|
|
@ -60,7 +60,7 @@ export class MSPStressTest {
|
||||||
try {
|
try {
|
||||||
console.log(`\n📋 Running: ${testDef.name}`);
|
console.log(`\n📋 Running: ${testDef.name}`);
|
||||||
this.currentTest = testDef.name;
|
this.currentTest = testDef.name;
|
||||||
this.monitor.resetMetrics();
|
this.monitor.resetAll(); // Reset both metrics and alerts for clean test start
|
||||||
|
|
||||||
const startTime = performance.now();
|
const startTime = performance.now();
|
||||||
const result = await testDef.test();
|
const result = await testDef.test();
|
||||||
|
@ -547,7 +547,7 @@ export class MSPStressTest {
|
||||||
|
|
||||||
console.log(`🧪 Running specific test: ${testName}`);
|
console.log(`🧪 Running specific test: ${testName}`);
|
||||||
this.monitor.startMonitoring(100);
|
this.monitor.startMonitoring(100);
|
||||||
this.monitor.resetMetrics();
|
this.monitor.resetAll(); // Reset both metrics and alerts for clean test start
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await testMethod();
|
const result = await testMethod();
|
||||||
|
|
|
@ -20,13 +20,22 @@ import { mspStressTest } from "./msp_stress_test.js";
|
||||||
import { mspDebugDashboard } from "./msp_debug_dashboard.js";
|
import { mspDebugDashboard } from "./msp_debug_dashboard.js";
|
||||||
|
|
||||||
export const MSPTestRunner = {
|
export const MSPTestRunner = {
|
||||||
|
// Store the listener function so it can be removed later
|
||||||
|
_quickMonitorListener: null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start quick monitoring with console output
|
* Start quick monitoring with console output
|
||||||
*/
|
*/
|
||||||
startQuickMonitor() {
|
startQuickMonitor() {
|
||||||
console.log("🚀 Starting MSP Quick Monitor...");
|
console.log("🚀 Starting MSP Quick Monitor...");
|
||||||
|
|
||||||
mspQueueMonitor.addListener((status) => {
|
// Remove any existing listener first
|
||||||
|
if (this._quickMonitorListener) {
|
||||||
|
mspQueueMonitor.removeListener(this._quickMonitorListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the listener function so it can be referenced for removal
|
||||||
|
this._quickMonitorListener = (status) => {
|
||||||
if (status.alerts && Object.values(status.alerts).some((alert) => alert)) {
|
if (status.alerts && Object.values(status.alerts).some((alert) => alert)) {
|
||||||
console.warn("🚨 MSP Alert:", status.alerts);
|
console.warn("🚨 MSP Alert:", status.alerts);
|
||||||
}
|
}
|
||||||
|
@ -37,8 +46,9 @@ export const MSPTestRunner = {
|
||||||
`📊 MSP Status: Queue=${status.currentQueueSize}/${status.maxQueueSize}, Requests=${status.metrics.totalRequests}, AvgTime=${Math.round(status.metrics.avgResponseTime)}ms`,
|
`📊 MSP Status: Queue=${status.currentQueueSize}/${status.maxQueueSize}, Requests=${status.metrics.totalRequests}, AvgTime=${Math.round(status.metrics.avgResponseTime)}ms`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
mspQueueMonitor.addListener(this._quickMonitorListener);
|
||||||
mspQueueMonitor.startMonitoring(1000);
|
mspQueueMonitor.startMonitoring(1000);
|
||||||
console.log("✅ Quick monitor started. Use MSPTestRunner.stopMonitor() to stop.");
|
console.log("✅ Quick monitor started. Use MSPTestRunner.stopMonitor() to stop.");
|
||||||
|
|
||||||
|
@ -54,6 +64,13 @@ export const MSPTestRunner = {
|
||||||
*/
|
*/
|
||||||
stopMonitor() {
|
stopMonitor() {
|
||||||
mspQueueMonitor.stopMonitoring();
|
mspQueueMonitor.stopMonitoring();
|
||||||
|
|
||||||
|
// Remove the listener to prevent duplicate logs
|
||||||
|
if (this._quickMonitorListener) {
|
||||||
|
mspQueueMonitor.removeListener(this._quickMonitorListener);
|
||||||
|
this._quickMonitorListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
console.log("⏹️ MSP Monitor stopped");
|
console.log("⏹️ MSP Monitor stopped");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
/**
|
|
||||||
* Alert System Test Script
|
|
||||||
* Run this in the browser console to test the MSP debug alert system
|
|
||||||
*/
|
|
||||||
|
|
||||||
console.log("🧪 Starting MSP Alert System Test...");
|
|
||||||
|
|
||||||
// Test function to check alert system
|
|
||||||
async function testAlertSystem() {
|
|
||||||
console.log("1. Checking if MSPDebug is available...");
|
|
||||||
if (typeof window.MSPDebug === "undefined") {
|
|
||||||
console.error("❌ MSPDebug not found! Debug tools may not be loaded.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("✅ MSPDebug is available");
|
|
||||||
|
|
||||||
console.log("2. Checking dashboard...");
|
|
||||||
const dashboard = window.MSPDebug.dashboard;
|
|
||||||
if (!dashboard) {
|
|
||||||
console.error("❌ Dashboard not found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("✅ Dashboard is available");
|
|
||||||
|
|
||||||
console.log("3. Checking monitor...");
|
|
||||||
const monitor = window.MSPDebug.monitor;
|
|
||||||
if (!monitor) {
|
|
||||||
console.error("❌ Monitor not found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("✅ Monitor is available");
|
|
||||||
|
|
||||||
console.log("4. Showing dashboard...");
|
|
||||||
dashboard.show();
|
|
||||||
|
|
||||||
console.log("5. Starting monitoring...");
|
|
||||||
monitor.startMonitoring(500);
|
|
||||||
|
|
||||||
console.log("6. Checking alert container exists...");
|
|
||||||
const alertContainer = document.getElementById("alerts-container");
|
|
||||||
if (!alertContainer) {
|
|
||||||
console.error("❌ Alert container not found in DOM!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("✅ Alert container found:", alertContainer);
|
|
||||||
|
|
||||||
console.log("7. Getting current status...");
|
|
||||||
const status = monitor.getStatus();
|
|
||||||
console.log("Current status:", status);
|
|
||||||
console.log("Current alerts:", status.alerts);
|
|
||||||
|
|
||||||
console.log("8. Testing alert display directly...");
|
|
||||||
dashboard.updateAlerts({
|
|
||||||
queueFull: true,
|
|
||||||
highTimeout: false,
|
|
||||||
slowResponses: true,
|
|
||||||
memoryLeak: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("9. Checking alert container content after manual update...");
|
|
||||||
console.log("Alert container HTML:", alertContainer.innerHTML);
|
|
||||||
|
|
||||||
console.log("10. Triggering test alerts...");
|
|
||||||
const testAlerts = monitor.triggerTestAlerts();
|
|
||||||
console.log("Test alerts triggered:", testAlerts);
|
|
||||||
|
|
||||||
console.log("11. Waiting 2 seconds and checking again...");
|
|
||||||
setTimeout(() => {
|
|
||||||
const newStatus = monitor.getStatus();
|
|
||||||
console.log("Status after test alerts:", newStatus);
|
|
||||||
console.log("Alerts after test:", newStatus.alerts);
|
|
||||||
console.log("Alert container HTML after test:", alertContainer.innerHTML);
|
|
||||||
|
|
||||||
// Test the complete update flow
|
|
||||||
console.log("12. Testing complete update flow...");
|
|
||||||
dashboard.updateDisplay(newStatus);
|
|
||||||
console.log("Alert container HTML after updateDisplay:", alertContainer.innerHTML);
|
|
||||||
|
|
||||||
console.log("🏁 Alert system test complete!");
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the test
|
|
||||||
testAlertSystem();
|
|
||||||
|
|
||||||
// Also provide manual test functions
|
|
||||||
window.testAlertSystem = testAlertSystem;
|
|
||||||
window.checkAlerts = () => {
|
|
||||||
const container = document.getElementById("alerts-container");
|
|
||||||
console.log("Alert container:", container);
|
|
||||||
console.log("Alert container HTML:", container?.innerHTML);
|
|
||||||
const status = window.MSPDebug?.monitor?.getStatus();
|
|
||||||
console.log("Current alerts:", status?.alerts);
|
|
||||||
};
|
|
||||||
|
|
||||||
window.manualTestAlert = () => {
|
|
||||||
console.log("Testing alert display manually...");
|
|
||||||
const dashboard = window.MSPDebug.dashboard;
|
|
||||||
dashboard.updateAlerts({
|
|
||||||
queueFull: true,
|
|
||||||
highTimeout: true,
|
|
||||||
slowResponses: false,
|
|
||||||
memoryLeak: true,
|
|
||||||
});
|
|
||||||
console.log("Manual test alerts set");
|
|
||||||
};
|
|
Loading…
Add table
Add a link
Reference in a new issue