Skip to main content

Overview

Effective monitoring is essential for maintaining a production gambling application. This guide covers logging, error tracking, performance monitoring, and database observability to ensure your Cajas deployment runs smoothly.

Logging Strategy

Vercel Function Logs

Vercel automatically captures logs from all serverless functions and API routes:
// Use structured logging for better searchability
export async function POST(request: Request) {
  const startTime = Date.now();
  
  try {
    const { caseId } = await request.json();
    
    console.log(JSON.stringify({
      level: 'info',
      event: 'case_open_started',
      caseId,
      timestamp: new Date().toISOString()
    }));
    
    // ... process case opening ...
    
    const duration = Date.now() - startTime;
    console.log(JSON.stringify({
      level: 'info',
      event: 'case_open_completed',
      caseId,
      duration,
      timestamp: new Date().toISOString()
    }));
    
  } catch (error) {
    console.error(JSON.stringify({
      level: 'error',
      event: 'case_open_failed',
      error: error.message,
      stack: error.stack,
      timestamp: new Date().toISOString()
    }));
  }
}

Accessing Vercel Logs

  1. Open your project on Vercel Dashboard
  2. Navigate to Logs tab
  3. Filter by:
    • Time range
    • Function name
    • Log level (info, warn, error)
    • Status code
  4. Click on individual requests for detailed traces

Log Retention

Vercel Log Retention:
  • Hobby: 1 hour
  • Pro: 1 day
  • Enterprise: Custom retention
For longer retention, integrate with external logging services.

Error Tracking

Sentry Integration

Integrate Sentry for comprehensive error tracking:
1

Install Sentry

npm install @sentry/nextjs
2

Configure Sentry

sentry.client.config.ts
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  
  // Set tracesSampleRate to 1.0 to capture 100%
  tracesSampleRate: 1.0,
  
  // Capture Replay for session analysis
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,
  
  // Filter sensitive data
  beforeSend(event, hint) {
    // Remove sensitive user data
    if (event.user) {
      delete event.user.email;
      delete event.user.ip_address;
    }
    return event;
  },
  
  // Environment detection
  environment: process.env.VERCEL_ENV || 'development',
});
sentry.server.config.ts
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 1.0,
  environment: process.env.VERCEL_ENV || 'development',
});
3

Add to API Routes

app/api/cases/open/route.ts
import * as Sentry from '@sentry/nextjs';

export async function POST(request: Request) {
  try {
    // ... case opening logic ...
  } catch (error) {
    Sentry.captureException(error, {
      tags: {
        api_route: 'case_open',
        case_id: caseId
      },
      user: {
        id: user.id,
        username: user.username
      },
      extra: {
        casePrice: box.price,
        userBalance: userBalance
      }
    });
    
    throw error;
  }
}
4

Configure Vercel Integration

Add Sentry environment variables:
vercel env add NEXT_PUBLIC_SENTRY_DSN production
vercel env add SENTRY_DSN production
vercel env add SENTRY_AUTH_TOKEN production

Error Boundaries

Implement React error boundaries for client-side errors:
components/error-boundary.tsx
'use client';

import * as Sentry from '@sentry/nextjs';
import { useEffect } from 'react';

export default function ErrorBoundary({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  useEffect(() => {
    // Log to Sentry
    Sentry.captureException(error);
  }, [error]);

  return (
    <div className="flex flex-col items-center justify-center min-h-screen">
      <h2 className="text-2xl font-bold mb-4">Something went wrong!</h2>
      <p className="text-gray-600 mb-4">{error.message}</p>
      <button
        onClick={reset}
        className="px-4 py-2 bg-primary text-white rounded"
      >
        Try again
      </button>
    </div>
  );
}

Performance Monitoring

Vercel Analytics

Enable Vercel Analytics for real user monitoring:
1

Enable Analytics

  1. Go to your project on Vercel
  2. Navigate to Analytics tab
  3. Click Enable Analytics
2

Add to Application

app/layout.tsx
import { Analytics } from '@vercel/analytics/react';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Analytics />
      </body>
    </html>
  );
}
3

Track Custom Events

import { track } from '@vercel/analytics';

// Track case opening
track('case_opened', {
  caseId: box.id,
  caseName: box.name,
  price: box.price,
  itemWon: winner.name,
  itemValue: winner.price
});

// Track user actions
track('deposit', { amount: depositAmount });
track('withdrawal', { amount: withdrawAmount });

Web Vitals Monitoring

Monitor Core Web Vitals for performance insights:
app/layout.tsx
import { SpeedInsights } from '@vercel/speed-insights/next';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <SpeedInsights />
      </body>
    </html>
  );
}
Core Web Vitals Tracked:
  • LCP (Largest Contentful Paint): Loading performance
  • FID (First Input Delay): Interactivity
  • CLS (Cumulative Layout Shift): Visual stability
  • TTFB (Time to First Byte): Server response time

API Performance

Monitor API route performance:
app/api/cases/open/route.ts
export async function POST(request: Request) {
  const startTime = performance.now();
  
  try {
    // ... case opening logic ...
    
    const duration = performance.now() - startTime;
    
    // Log slow requests
    if (duration > 1000) {
      console.warn('Slow API request', {
        route: '/api/cases/open',
        duration,
        caseId
      });
    }
    
    // Add timing header
    return NextResponse.json(data, {
      headers: {
        'Server-Timing': `total;dur=${duration}`
      }
    });
    
  } catch (error) {
    const duration = performance.now() - startTime;
    console.error('API error', { duration, error });
    throw error;
  }
}

Database Monitoring

Supabase Logs

Access database query logs in Supabase:
  1. Open your Supabase project
  2. Navigate to Logs section
  3. View:
    • Postgres Logs: Query execution
    • API Logs: REST/GraphQL requests
    • Auth Logs: Authentication events
    • Realtime Logs: WebSocket connections

Query Optimization

Optimize database queries for performance:
-- Index for user lookups
CREATE INDEX idx_users_username ON users(username);

-- Index for case items
CREATE INDEX idx_case_items_case_id ON case_items(case_id);

-- Index for user inventory
CREATE INDEX idx_user_items_user_id ON user_items(user_id);
CREATE INDEX idx_user_items_status ON user_items(status);

-- Composite index for transactions
CREATE INDEX idx_transactions_user_date 
  ON transactions(user_id, created_at DESC);
Analyze query performance:
EXPLAIN ANALYZE
SELECT ci.*, i.*
FROM case_items ci
JOIN items i ON ci.item_id = i.id
WHERE ci.case_id = 'abc-123';

-- Look for:
-- - Sequential scans (add indexes)
-- - High execution time
-- - Nested loops (consider joins)
Reduce round trips with batch operations:
// Instead of multiple inserts
for (const item of items) {
  await supabase.from('user_items').insert(item);
}

// Use single batch insert
await supabase.from('user_items').insert(items);

Database Metrics

Monitor key database metrics:

Connection Pool

Healthy Range: 10-50 connectionsAlerts:
  • 80% capacity: Scale up
  • Connection timeouts: Add pooling

Query Performance

Target: < 100ms averageAlerts:
  • 500ms: Investigate slow queries
  • 1000ms: Immediate optimization needed

Storage Usage

Monitor: Table sizes and growthMaintenance:
  • Archive old transactions
  • Vacuum tables regularly

RLS Performance

Check: Policy execution timeOptimize:
  • Simplify complex policies
  • Add indexes on policy columns

Alerting

Vercel Alerts

Configure alerts for production issues:
1

Deployment Alerts

  1. Go to SettingsNotifications
  2. Enable:
    • Deployment started
    • Deployment failed
    • Deployment ready
2

Error Alerts

Configure error rate thresholds:
  • Error rate > 1%
  • 5xx responses > 0.1%
  • Function timeout > 5%
3

Integration Channels

Send alerts to:
  • Email
  • Slack
  • Discord
  • Webhooks

Sentry Alerts

Set up Sentry alerts for critical errors:
.sentryclirc
alerts:
  - type: error_rate
    threshold: 10  # errors per minute
    window: 5      # minutes
    actions:
      - email
      - slack
  
  - type: new_issue
    filters:
      level: error
    actions:
      - slack
  
  - type: regression
    filters:
      is_unresolved: true
    actions:
      - email
      - slack

Custom Health Checks

Implement custom health monitoring:
app/api/health/route.ts
export async function GET() {
  const checks = await Promise.allSettled([
    checkDatabase(),
    checkSupabase(),
    checkExternalAPIs()
  ]);
  
  const status = checks.every(c => c.status === 'fulfilled') 
    ? 'healthy' 
    : 'unhealthy';
  
  return NextResponse.json({
    status,
    timestamp: new Date().toISOString(),
    checks: {
      database: checks[0].status === 'fulfilled',
      supabase: checks[1].status === 'fulfilled',
      external_apis: checks[2].status === 'fulfilled'
    }
  }, {
    status: status === 'healthy' ? 200 : 503
  });
}

async function checkDatabase() {
  const supabase = await createClient();
  const { error } = await supabase.from('cases').select('count').single();
  if (error) throw error;
}

async function checkSupabase() {
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest/v1/`,
    {
      headers: {
        apikey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      }
    }
  );
  if (!response.ok) throw new Error('Supabase unreachable');
}
Monitor the /api/health endpoint with an external service like UptimeRobot or Pingdom.

Dashboard Setup

Vercel Analytics Dashboard

Key metrics to monitor:

Traffic

  • Total requests
  • Unique visitors
  • Page views
  • Geographic distribution

Performance

  • Average response time
  • 95th percentile latency
  • Core Web Vitals
  • Function execution time

Errors

  • Error rate
  • 4xx responses
  • 5xx responses
  • Failed functions

Business Metrics

  • Cases opened
  • Revenue
  • User signups
  • Conversion rate

Custom Dashboard

Build a custom monitoring dashboard:
app/admin/monitoring/page.tsx
'use client';

import { useEffect, useState } from 'react';

export default function MonitoringDashboard() {
  const [metrics, setMetrics] = useState(null);
  
  useEffect(() => {
    const fetchMetrics = async () => {
      const response = await fetch('/api/admin/metrics');
      const data = await response.json();
      setMetrics(data);
    };
    
    fetchMetrics();
    const interval = setInterval(fetchMetrics, 30000); // 30s
    
    return () => clearInterval(interval);
  }, []);
  
  return (
    <div className="p-8">
      <h1 className="text-3xl font-bold mb-8">System Monitoring</h1>
      
      <div className="grid grid-cols-4 gap-4">
        <MetricCard
          title="Active Users"
          value={metrics?.activeUsers}
          change={metrics?.activeUsersChange}
        />
        <MetricCard
          title="Error Rate"
          value={`${metrics?.errorRate}%`}
          alert={metrics?.errorRate > 1}
        />
        <MetricCard
          title="Avg Response"
          value={`${metrics?.avgResponse}ms`}
          alert={metrics?.avgResponse > 500}
        />
        <MetricCard
          title="DB Connections"
          value={metrics?.dbConnections}
          alert={metrics?.dbConnections > 80}
        />
      </div>
    </div>
  );
}

Monitoring Checklist

1

Logging

  • Structured logging implemented
  • Log levels configured correctly
  • Sensitive data filtered from logs
  • Log retention policy defined
2

Error Tracking

  • Sentry integrated
  • Error boundaries implemented
  • Source maps uploaded
  • Alert rules configured
3

Performance

  • Vercel Analytics enabled
  • Speed Insights integrated
  • Custom events tracked
  • Performance budgets set
4

Database

  • Query logs enabled
  • Slow query alerts set
  • Indexes optimized
  • Connection pooling configured
5

Alerting

  • Critical alerts configured
  • On-call rotation established
  • Runbooks documented
  • Escalation paths defined

Best Practices

  • Use structured logging (JSON)
  • Include request IDs for tracing
  • Log at appropriate levels (info, warn, error)
  • Avoid logging sensitive data (passwords, tokens)
  • Include context (user ID, resource IDs)
  • Track Core Web Vitals
  • Monitor conversion funnels
  • Identify slow pages
  • Measure feature adoption
  • Collect user feedback
  • Avoid alert fatigue (be selective)
  • Set actionable thresholds
  • Include context in alerts
  • Test alert channels regularly
  • Document response procedures
  • Weekly metrics review
  • Monthly performance audit
  • Quarterly capacity planning
  • Annual security review
Well-Monitored System: With comprehensive monitoring in place, you can detect issues before they impact users, optimize performance continuously, and make data-driven decisions.

Resources

Vercel Observability

Official Vercel monitoring docs

Sentry Docs

Next.js Sentry integration

Supabase Logs

Database monitoring guide

Security Monitoring

Security best practices

Build docs developers (and LLMs) love