synthetic-monitoring
About
This skill enables developers to implement synthetic monitoring and automated testing to simulate user behavior and detect issues proactively. It's designed for creating end-to-end test scenarios, monitoring API flows, and validating user workflows. Key capabilities include simulating real user journeys, testing critical business transactions, and validating performance across applications.
Documentation
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"]', '[email protected]');
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
Quick Install
/plugin add https://github.com/aj-geddes/useful-ai-prompts/tree/main/synthetic-monitoringCopy and paste this command in Claude Code to install this skill
GitHub 仓库
Related Skills
sglang
MetaSGLang is a high-performance LLM serving framework that specializes in fast, structured generation for JSON, regex, and agentic workflows using its RadixAttention prefix caching. It delivers significantly faster inference, especially for tasks with repeated prefixes, making it ideal for complex, structured outputs and multi-turn conversations. Choose SGLang over alternatives like vLLM when you need constrained decoding or are building applications with extensive prefix sharing.
evaluating-llms-harness
TestingThis Claude Skill runs the lm-evaluation-harness to benchmark LLMs across 60+ standardized academic tasks like MMLU and GSM8K. It's designed for developers to compare model quality, track training progress, or report academic results. The tool supports various backends including HuggingFace and vLLM models.
langchain
MetaLangChain is a framework for building LLM applications using agents, chains, and RAG pipelines. It supports multiple LLM providers, offers 500+ integrations, and includes features like tool calling and memory management. Use it for rapid prototyping and deploying production systems like chatbots, autonomous agents, and question-answering services.
Algorithmic Art Generation
MetaThis skill helps developers create algorithmic art using p5.js, focusing on generative art, computational aesthetics, and interactive visualizations. It automatically activates for topics like "generative art" or "p5.js visualization" and guides you through creating unique algorithms with features like seeded randomness, flow fields, and particle systems. Use it when you need to build reproducible, code-driven artistic patterns.
