synthetic-monitoring
55
总安装量
55
周安装量
#3906
全站排名
安装命令
npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill synthetic-monitoring
Agent 安装分布
claude-code
45
opencode
40
gemini-cli
38
codex
36
cursor
34
Skill 文档
Synthetic Monitoring
Overview
Set up synthetic monitoring to automatically simulate real user journeys, API workflows, and critical business transactions to detect issues and validate performance.
When to Use
- End-to-end workflow validation
- API flow testing
- User journey simulation
- Transaction monitoring
- Critical path validation
Instructions
1. Synthetic Tests with Playwright
// synthetic-tests.js
const { chromium } = require('playwright');
class SyntheticMonitor {
constructor(config = {}) {
this.baseUrl = config.baseUrl || 'https://app.example.com';
this.timeout = config.timeout || 30000;
}
async testUserFlow() {
const browser = await chromium.launch();
const page = await browser.newPage();
const metrics = { steps: {} };
const startTime = Date.now();
try {
// Step 1: Navigate to login
let stepStart = Date.now();
await page.goto(`${this.baseUrl}/login`, { waitUntil: 'networkidle' });
metrics.steps.navigation = Date.now() - stepStart;
// Step 2: Perform login
stepStart = Date.now();
await page.fill('input[name="email"]', 'test@example.com');
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
await page.waitForNavigation({ waitUntil: 'networkidle' });
metrics.steps.login = Date.now() - stepStart;
// Step 3: Navigate to dashboard
stepStart = Date.now();
await page.goto(`${this.baseUrl}/dashboard`, { waitUntil: 'networkidle' });
metrics.steps.dashboard = Date.now() - stepStart;
// Step 4: Search for products
stepStart = Date.now();
await page.fill('input[placeholder="Search products"]', 'laptop');
await page.waitForSelector('.product-list');
metrics.steps.search = Date.now() - stepStart;
// Step 5: Add to cart
stepStart = Date.now();
const firstProduct = await page.$('.product-item');
if (firstProduct) {
await firstProduct.click();
await page.click('button:has-text("Add to Cart")');
await page.waitForSelector('[data-testid="cart-count"]');
}
metrics.steps.addToCart = Date.now() - stepStart;
metrics.totalTime = Date.now() - startTime;
metrics.status = 'success';
} catch (error) {
metrics.status = 'failed';
metrics.error = error.message;
metrics.totalTime = Date.now() - startTime;
} finally {
await browser.close();
}
return metrics;
}
async testMobileUserFlow() {
const browser = await chromium.launch();
const context = await browser.createBrowserContext({
...chromium.devices['iPhone 12']
});
const page = await context.newPage();
try {
const metrics = { device: 'iPhone 12', steps: {} };
const startTime = Date.now();
let stepStart = Date.now();
await page.goto(this.baseUrl, { waitUntil: 'networkidle' });
metrics.steps.navigation = Date.now() - stepStart;
const viewport = page.viewportSize();
metrics.viewport = viewport;
stepStart = Date.now();
await page.click('.menu-toggle');
await page.waitForSelector('.mobile-menu.open');
metrics.steps.mobileInteraction = Date.now() - stepStart;
metrics.totalTime = Date.now() - startTime;
metrics.status = 'success';
return metrics;
} catch (error) {
return { status: 'failed', error: error.message, device: 'iPhone 12' };
} finally {
await browser.close();
}
}
async testWithPerformanceMetrics() {
const browser = await chromium.launch();
const page = await browser.newPage();
try {
await page.goto(this.baseUrl, { waitUntil: 'networkidle' });
const perfMetrics = JSON.parse(
await page.evaluate(() => JSON.stringify(window.performance.timing))
);
const metrics = {
navigationTiming: {
domInteractive: perfMetrics.domInteractive - perfMetrics.navigationStart,
domComplete: perfMetrics.domComplete - perfMetrics.navigationStart,
loadComplete: perfMetrics.loadEventEnd - perfMetrics.navigationStart
},
status: 'success'
};
return metrics;
} catch (error) {
return { status: 'failed', error: error.message };
} finally {
await browser.close();
}
}
async recordMetrics(testName, metrics) {
try {
await axios.post('http://monitoring-service/synthetic-results', {
testName,
timestamp: new Date(),
metrics,
passed: metrics.status === 'success'
});
} catch (error) {
console.error('Failed to record metrics:', error);
}
}
}
module.exports = SyntheticMonitor;
2. API Synthetic Tests
// api-synthetic-tests.js
const axios = require('axios');
class APISyntheticTests {
constructor(config = {}) {
this.baseUrl = config.baseUrl || 'https://api.example.com';
this.client = axios.create({ baseURL: this.baseUrl });
}
async testAuthenticationFlow() {
const results = { steps: {}, status: 'success' };
try {
const registerStart = Date.now();
const registerRes = await this.client.post('/auth/register', {
email: `test-${Date.now()}@example.com`,
password: 'Test@123456'
});
results.steps.register = Date.now() - registerStart;
if (registerRes.status !== 201) throw new Error('Registration failed');
const loginStart = Date.now();
const loginRes = await this.client.post('/auth/login', {
email: registerRes.data.email,
password: 'Test@123456'
});
results.steps.login = Date.now() - loginStart;
const token = loginRes.data.token;
const authStart = Date.now();
await this.client.get('/api/profile', {
headers: { Authorization: `Bearer ${token}` }
});
results.steps.authenticatedRequest = Date.now() - authStart;
const logoutStart = Date.now();
await this.client.post('/auth/logout', {}, {
headers: { Authorization: `Bearer ${token}` }
});
results.steps.logout = Date.now() - logoutStart;
return results;
} catch (error) {
results.status = 'failed';
results.error = error.message;
return results;
}
}
async testTransactionFlow() {
const results = { steps: {}, status: 'success' };
try {
const orderStart = Date.now();
const orderRes = await this.client.post('/api/orders', {
items: [{ sku: 'ITEM-001', quantity: 2 }]
}, {
headers: { 'X-Idempotency-Key': `order-${Date.now()}` }
});
results.steps.createOrder = Date.now() - orderStart;
const getStart = Date.now();
const getRes = await this.client.get(`/api/orders/${orderRes.data.id}`);
results.steps.getOrder = Date.now() - getStart;
const paymentStart = Date.now();
await this.client.post(`/api/orders/${orderRes.data.id}/payment`, {
method: 'credit_card',
amount: getRes.data.total
});
results.steps.processPayment = Date.now() - paymentStart;
return results;
} catch (error) {
results.status = 'failed';
results.error = error.message;
return results;
}
}
async testUnderLoad(concurrentUsers = 10, duration = 60000) {
const startTime = Date.now();
const results = {
totalRequests: 0,
successfulRequests: 0,
failedRequests: 0,
averageResponseTime: 0,
p95ResponseTime: 0
};
const responseTimes = [];
const makeRequest = async () => {
const reqStart = Date.now();
try {
await this.client.get('/api/health');
results.successfulRequests++;
responseTimes.push(Date.now() - reqStart);
} catch {
results.failedRequests++;
}
results.totalRequests++;
};
const userSimulations = Array(concurrentUsers).fill(null).map(async () => {
while (Date.now() - startTime < duration) {
await makeRequest();
await new Promise(r => setTimeout(r, Math.random() * 1000));
}
});
await Promise.all(userSimulations);
responseTimes.sort((a, b) => a - b);
results.averageResponseTime =
responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length;
results.p95ResponseTime =
responseTimes[Math.floor(responseTimes.length * 0.95)];
return results;
}
}
module.exports = APISyntheticTests;
3. Scheduled Synthetic Monitoring
// scheduled-monitor.js
const cron = require('node-cron');
const SyntheticMonitor = require('./synthetic-tests');
const APISyntheticTests = require('./api-synthetic-tests');
const axios = require('axios');
class ScheduledSyntheticMonitor {
constructor(config = {}) {
this.eMonitor = new SyntheticMonitor(config);
this.apiTests = new APISyntheticTests(config);
this.alertThreshold = config.alertThreshold || 5000;
}
start() {
cron.schedule('*/5 * * * *', () => this.runE2ETests());
cron.schedule('*/2 * * * *', () => this.runAPITests());
cron.schedule('0 * * * *', () => this.runLoadTest());
}
async runE2ETests() {
try {
const metrics = await this.eMonitor.testUserFlow();
await this.recordResults('e2e-user-flow', metrics);
if (metrics.totalTime > this.alertThreshold) {
await this.sendAlert('e2e-user-flow', metrics);
}
} catch (error) {
console.error('E2E test failed:', error);
}
}
async runAPITests() {
try {
const authMetrics = await this.apiTests.testAuthenticationFlow();
const transactionMetrics = await this.apiTests.testTransactionFlow();
await this.recordResults('api-auth-flow', authMetrics);
await this.recordResults('api-transaction-flow', transactionMetrics);
if (authMetrics.status === 'failed' || transactionMetrics.status === 'failed') {
await this.sendAlert('api-tests', { authMetrics, transactionMetrics });
}
} catch (error) {
console.error('API test failed:', error);
}
}
async runLoadTest() {
try {
const results = await this.apiTests.testUnderLoad(10, 30000);
await this.recordResults('load-test', results);
if (results.failedRequests > 0) {
await this.sendAlert('load-test', results);
}
} catch (error) {
console.error('Load test failed:', error);
}
}
async recordResults(testName, metrics) {
try {
await axios.post('http://monitoring-service/synthetic-results', {
testName,
timestamp: new Date(),
metrics
});
console.log(`Recorded: ${testName}`, metrics);
} catch (error) {
console.error('Failed to record results:', error);
}
}
async sendAlert(testName, metrics) {
try {
await axios.post('http://alerting-service/alerts', {
type: 'synthetic_monitoring',
testName,
severity: 'warning',
message: `Synthetic test '${testName}' has issues`,
metrics,
timestamp: new Date()
});
console.log(`Alert sent for ${testName}`);
} catch (error) {
console.error('Failed to send alert:', error);
}
}
}
module.exports = ScheduledSyntheticMonitor;
Best Practices
â DO
- Test critical user journeys
- Simulate real browser conditions
- Monitor from multiple locations
- Track response times
- Alert on test failures
- Rotate test data
- Test mobile and desktop
- Include error scenarios
â DON’T
- Test with production data
- Reuse test accounts
- Skip timeout configurations
- Ignore test maintenance
- Test too frequently
- Hard-code credentials
- Ignore geographic variations
- Test only happy paths
Key Metrics
- Response time
- Success rate
- Availability
- Core Web Vitals
- Error rate