Skip to Content
UptimeBeacon 1.0 is released 🎉
Performance Monitoring

Performance Monitoring

Sentinel Guard provides comprehensive performance monitoring capabilities, including database latency tracking for popular databases and caching systems.

Overview

Performance monitoring in Sentinel Guard automatically measures and reports:

  • Service response times
  • Database query latency (Prisma)
  • Cache operation latency (Redis)
  • Performance trends over time
  • Automatic alerts for performance degradation

All performance data is automatically included in heartbeats and displayed in your UptimeBeacon.cloud dashboard.

Database Latency Tracking

Prisma Integration

Monitor PostgreSQL, MySQL, SQLite, and other databases through Prisma ORM.

Setup

import { PrismaClient } from "@prisma/client"; import { SentinelGuard } from "@uptimebeacon/sentinel-guard"; const prisma = new PrismaClient(); const sentinel = new SentinelGuard({ apiKey: process.env.SENTINEL_API_KEY!, baseUrl: process.env.SENTINEL_API_URL!, monitorApiKey: process.env.SENTINEL_MONITOR_API_KEY!, }); // Enable Prisma monitoring sentinel.setPrismaClient(prisma); // Start monitoring sentinel.startMonitoring({ interval: 30000, maxConsecutiveErrors: 5, });

How It Works

When you configure a Prisma client, Sentinel Guard:

  1. Executes a lightweight SELECT 1 query periodically
  2. Measures the query execution time
  3. Includes latency data in heartbeats
  4. Alerts if database performance degrades

Supported Prisma Configurations

// Standard Prisma client const prisma = new PrismaClient(); // Prisma with custom configuration const prisma = new PrismaClient({ datasources: { db: { url: process.env.DATABASE_URL, }, }, }); // Prisma with connection pooling const prisma = new PrismaClient({ datasources: { db: { url: `${process.env.DATABASE_URL}?connection_limit=20&pool_timeout=20`, }, }, }); // All configurations work with Sentinel Guard sentinel.setPrismaClient(prisma);

Redis Integration

Monitor Redis cache performance and connection health.

Setup

import { createClient } from "redis"; import { SentinelGuard } from "@uptimebeacon/sentinel-guard"; const redis = createClient({ url: process.env.REDIS_URL, }); const sentinel = new SentinelGuard({ apiKey: process.env.SENTINEL_API_KEY!, baseUrl: process.env.SENTINEL_API_URL!, monitorApiKey: process.env.SENTINEL_MONITOR_API_KEY!, }); // Connect to Redis await redis.connect(); // Enable Redis monitoring sentinel.setRedisClient(redis); // Start monitoring sentinel.startMonitoring({ interval: 30000, maxConsecutiveErrors: 5, });

How It Works

With Redis monitoring enabled, Sentinel Guard:

  1. Executes PING commands to test connectivity
  2. Measures response times
  3. Monitors connection health
  4. Includes Redis metrics in heartbeats

Supported Redis Configurations

// Standard Redis client const redis = createClient(); // Redis with URL const redis = createClient({ url: "redis://localhost:6379", }); // Redis with authentication const redis = createClient({ url: "redis://username:password@localhost:6379", }); // Redis Cluster const redis = createClient({ url: "redis://localhost:7000", // cluster configuration }); // All configurations work with Sentinel Guard await redis.connect(); sentinel.setRedisClient(redis);

Performance Metrics Structure

PerformanceMetrics Interface

interface PerformanceMetrics { serviceLatency: number; prismaLatency?: number; redisLatency?: number; timestamp: string; }

Metric Details

serviceLatency

  • Type: number
  • Description: Overall service response time in milliseconds
  • Calculated: Time from heartbeat initiation to completion

prismaLatency

  • Type: number (optional)
  • Description: Database query latency in milliseconds
  • Calculated: Time to execute SELECT 1 query

redisLatency

  • Type: number (optional)
  • Description: Redis operation latency in milliseconds
  • Calculated: Time to execute PING command

timestamp

  • Type: string
  • Description: ISO 8601 timestamp of measurement
  • Example: "2024-01-15T10:30:00.000Z"

Complete Integration Example

import { PrismaClient } from "@prisma/client"; import { createClient } from "redis"; import { SentinelGuard } from "@uptimebeacon/sentinel-guard"; class ApplicationMonitor { private prisma: PrismaClient; private redis: ReturnType<typeof createClient>; private sentinel: SentinelGuard; constructor() { this.prisma = new PrismaClient(); this.redis = createClient({ url: process.env.REDIS_URL, }); this.sentinel = new SentinelGuard({ apiKey: process.env.SENTINEL_API_KEY!, baseUrl: process.env.SENTINEL_API_URL!, monitorApiKey: process.env.SENTINEL_MONITOR_API_KEY!, }); } async initialize() { // Connect to databases await this.redis.connect(); console.log("Database connections established"); // Configure performance monitoring this.sentinel.setPrismaClient(this.prisma); this.sentinel.setRedisClient(this.redis); // Start monitoring this.sentinel.startMonitoring({ interval: 30000, maxConsecutiveErrors: 5, }); console.log("Performance monitoring started"); } async getPerformanceReport() { // Send a heartbeat to get current performance metrics const response = await this.sentinel.sendHeartbeat({ status: "ONLINE", metadata: { operation: "performance_check", timestamp: new Date().toISOString(), }, }); return response; } async cleanup() { await this.prisma.$disconnect(); await this.redis.disconnect(); this.sentinel.stopMonitoring(); } } // Usage const monitor = new ApplicationMonitor(); await monitor.initialize(); // Get performance report const report = await monitor.getPerformanceReport(); console.log("Performance report:", report);

Advanced Performance Monitoring

Custom Performance Tracking

import { SentinelGuard } from "@uptimebeacon/sentinel-guard"; class CustomPerformanceMonitor { private sentinel: SentinelGuard; private metrics: Map<string, number[]> = new Map(); constructor() { this.sentinel = new SentinelGuard({ apiKey: process.env.SENTINEL_API_KEY!, baseUrl: process.env.SENTINEL_API_URL!, monitorApiKey: process.env.SENTINEL_MONITOR_API_KEY!, }); } async trackOperation<T>( operationName: string, operation: () => Promise<T>, ): Promise<T> { const startTime = Date.now(); try { const result = await operation(); const duration = Date.now() - startTime; // Store metrics this.addMetric(operationName, duration); // Send heartbeat with performance data await this.sentinel.sendHeartbeat({ status: "ONLINE", metadata: { operation: operationName, duration, averageLatency: this.getAverageLatency(operationName), performanceGrade: this.getPerformanceGrade(duration), }, }); return result; } catch (error) { const duration = Date.now() - startTime; await this.sentinel.sendHeartbeat({ status: "ERROR", metadata: { operation: operationName, duration, error: error.message, }, }); throw error; } } private addMetric(operation: string, duration: number) { if (!this.metrics.has(operation)) { this.metrics.set(operation, []); } const metrics = this.metrics.get(operation)!; metrics.push(duration); // Keep only last 100 measurements if (metrics.length > 100) { metrics.shift(); } } private getAverageLatency(operation: string): number { const metrics = this.metrics.get(operation) || []; if (metrics.length === 0) return 0; return metrics.reduce((sum, val) => sum + val, 0) / metrics.length; } private getPerformanceGrade(duration: number): string { if (duration < 100) return "excellent"; if (duration < 500) return "good"; if (duration < 1000) return "fair"; if (duration < 2000) return "poor"; return "critical"; } } // Usage const monitor = new CustomPerformanceMonitor(); // Track database operations await monitor.trackOperation("user_query", async () => { return await prisma.user.findMany({ take: 10 }); }); // Track API calls await monitor.trackOperation("external_api", async () => { return await fetch("https://api.example.com/data"); });

Performance Alerting

import { SentinelGuard } from "@uptimebeacon/sentinel-guard"; class PerformanceAlerting { private sentinel: SentinelGuard; private thresholds = { database: 200, // 200ms cache: 50, // 50ms service: 1000, // 1s }; constructor() { this.sentinel = new SentinelGuard({ apiKey: process.env.SENTINEL_API_KEY!, baseUrl: process.env.SENTINEL_API_URL!, monitorApiKey: process.env.SENTINEL_MONITOR_API_KEY!, }); } async checkPerformance() { const startTime = Date.now(); try { // Check database performance const dbStart = Date.now(); await this.checkDatabaseHealth(); const dbLatency = Date.now() - dbStart; // Check cache performance const cacheStart = Date.now(); await this.checkCacheHealth(); const cacheLatency = Date.now() - cacheStart; const totalLatency = Date.now() - startTime; // Determine status based on thresholds const status = this.determineStatus( dbLatency, cacheLatency, totalLatency, ); await this.sentinel.sendHeartbeat({ status, metadata: { databaseLatency: dbLatency, cacheLatency: cacheLatency, totalLatency: totalLatency, thresholds: this.thresholds, performanceIssues: this.getPerformanceIssues( dbLatency, cacheLatency, ), }, }); } catch (error) { await this.sentinel.sendHeartbeat({ status: "ERROR", metadata: { error: error.message, performanceCheck: "failed", }, }); } } private determineStatus( dbLatency: number, cacheLatency: number, serviceLatency: number, ): "ONLINE" | "HIGH_LATENCY" | "ERROR" { if ( dbLatency > this.thresholds.database * 2 || cacheLatency > this.thresholds.cache * 2 || serviceLatency > this.thresholds.service * 2 ) { return "ERROR"; } if ( dbLatency > this.thresholds.database || cacheLatency > this.thresholds.cache || serviceLatency > this.thresholds.service ) { return "HIGH_LATENCY"; } return "ONLINE"; } private getPerformanceIssues( dbLatency: number, cacheLatency: number, ): string[] { const issues: string[] = []; if (dbLatency > this.thresholds.database) { issues.push("database_slow"); } if (cacheLatency > this.thresholds.cache) { issues.push("cache_slow"); } return issues; } private async checkDatabaseHealth() { // Database health check logic await new Promise((resolve) => setTimeout(resolve, 10)); } private async checkCacheHealth() { // Cache health check logic await new Promise((resolve) => setTimeout(resolve, 5)); } } // Schedule performance checks const alerting = new PerformanceAlerting(); setInterval(() => alerting.checkPerformance(), 60000); // Every minute

Best Practices

Performance Monitoring

  1. Set Appropriate Thresholds

    // Production thresholds const thresholds = { database: 200, // 200ms for database queries cache: 50, // 50ms for cache operations service: 1000, // 1s for service responses }; // Development thresholds (more lenient) const devThresholds = { database: 500, cache: 100, service: 2000, };
  2. Monitor Database Connection Pool

    const prisma = new PrismaClient({ datasources: { db: { url: `${process.env.DATABASE_URL}?connection_limit=20&pool_timeout=20`, }, }, }); // Monitor connection pool health setInterval(async () => { const poolStats = await prisma.$executeRaw` SELECT count(*) as active_connections FROM pg_stat_activity WHERE state = 'active' `; await sentinel.sendHeartbeat({ status: "ONLINE", metadata: { connectionPool: poolStats, maxConnections: 20, }, }); }, 300000); // Every 5 minutes
  3. Track Performance Trends

    class PerformanceTrends { private metrics: Array<{ timestamp: Date; latency: number }> = []; addMetric(latency: number) { this.metrics.push({ timestamp: new Date(), latency, }); // Keep only last 1000 measurements if (this.metrics.length > 1000) { this.metrics.shift(); } } getTrend(): "improving" | "stable" | "degrading" { if (this.metrics.length < 10) return "stable"; const recent = this.metrics.slice(-10); const older = this.metrics.slice(-20, -10); const recentAvg = recent.reduce((sum, m) => sum + m.latency, 0) / recent.length; const olderAvg = older.reduce((sum, m) => sum + m.latency, 0) / older.length; if (recentAvg < olderAvg * 0.9) return "improving"; if (recentAvg > olderAvg * 1.1) return "degrading"; return "stable"; } }

Resource Management

  1. Efficient Database Queries

    // Monitor query performance async function monitoredQuery<T>( operation: string, query: () => Promise<T>, ): Promise<T> { const start = Date.now(); try { const result = await query(); const duration = Date.now() - start; if (duration > 1000) { await sentinel.sendHeartbeat({ status: "HIGH_LATENCY", metadata: { operation, duration, warning: "slow_query", }, }); } return result; } catch (error) { await sentinel.sendHeartbeat({ status: "ERROR", metadata: { operation, error: error.message, }, }); throw error; } }
  2. Connection Management

    // Proper cleanup process.on("SIGINT", async () => { console.log("Shutting down gracefully..."); // Stop monitoring first sentinel.stopMonitoring(); // Close database connections await prisma.$disconnect(); await redis.disconnect(); // Final cleanup sentinel.destroy(); process.exit(0); });

Troubleshooting

Common Issues

High Database Latency

  • Check database server load
  • Optimize queries with indexes
  • Review connection pool configuration
  • Monitor database locks

Redis Connection Issues

  • Verify Redis server is running
  • Check network connectivity
  • Review Redis configuration
  • Monitor Redis memory usage

Missing Performance Data

  • Ensure clients are properly connected
  • Verify client compatibility
  • Check for authentication issues
  • Review error logs

Performance Debugging

// Debug performance issues class PerformanceDebugger { private sentinel: SentinelGuard; constructor() { this.sentinel = new SentinelGuard({ apiKey: process.env.SENTINEL_API_KEY!, baseUrl: process.env.SENTINEL_API_URL!, monitorApiKey: process.env.SENTINEL_MONITOR_API_KEY!, }); } async diagnosePerformance() { const diagnostics = { timestamp: new Date().toISOString(), nodeVersion: process.version, memoryUsage: process.memoryUsage(), cpuUsage: process.cpuUsage(), uptime: process.uptime(), }; await this.sentinel.sendHeartbeat({ status: "ONLINE", metadata: { diagnostics, performanceDebug: true, }, }); } }