Skip to content

Debugging Guide

Eric Fitzgerald edited this page Apr 8, 2026 · 5 revisions

Debugging Guide

This guide provides systematic procedures for debugging TMI issues including debug logging, log analysis, browser developer tools, and database queries.

Debug Logging

Enabling Debug Logging

TMI supports multiple log levels to control verbosity:

Log Levels:

  • debug - Detailed diagnostic information
  • info - General informational messages (default)
  • warn - Warning messages for potentially harmful situations
  • error - Error messages for serious problems

Enable debug logging:

# Via environment variable
export TMI_LOG_LEVEL=debug
./bin/tmiserver

# Via configuration file (under the logging: section in config-development.yml)
# logging:
#   level: debug

# Via Docker
docker run -e TMI_LOG_LEVEL=debug tmi-server

Log Output Formats

TMI uses Go's slog package for structured logging. The output format is controlled by the TMI_LOG_IS_DEV setting:

Text format (human-readable, development mode):

export TMI_LOG_IS_DEV=true

Example output:

time=2025-01-15T10:30:00Z level=INFO msg="Server starting on :8080"
time=2025-01-15T10:30:01Z level=DEBUG msg="Connected to PostgreSQL" host=localhost port=5432
time=2025-01-15T10:30:01Z level=DEBUG msg="Connected to Redis" host=localhost port=6379

JSON format (structured, production; this is the default when TMI_LOG_IS_DEV is false or unset):

Example output:

{"time":"2025-01-15T10:30:00Z","level":"INFO","msg":"Server starting on :8080"}
{"time":"2025-01-15T10:30:01Z","level":"DEBUG","msg":"Connected to PostgreSQL","host":"localhost","port":5432}

Component-Specific Logging

Enable detailed logging for specific subsystems using the TMI_LOG_* environment variables:

# Set log level to debug for verbose output
export TMI_LOG_LEVEL=debug

# Log API request details
export TMI_LOG_API_REQUESTS=true

# Log API response details
export TMI_LOG_API_RESPONSES=true

# WebSocket message logging
export TMI_LOG_WEBSOCKET_MESSAGES=true

# Redact auth tokens in log output (recommended for shared environments)
export TMI_LOG_REDACT_AUTH_TOKENS=true

# Suppress logs for unauthenticated requests (e.g., health probes)
export TMI_LOG_SUPPRESS_UNAUTH_LOGS=true

Log File Configuration

TMI writes log files to a configurable directory. The log file is always named tmi.log within that directory. The default directory is logs/ (relative to the working directory).

Specify log directory:

# Set the log directory via environment variable
export TMI_LOG_DIR=/var/log/tmi
./bin/tmiserver
# Logs will be written to /var/log/tmi/tmi.log

# Also send logs to console (stdout) in addition to the file
export TMI_LOG_ALSO_LOG_TO_CONSOLE=true

Configuration file (in config-development.yml or similar):

logging:
  level: debug
  is_dev: true
  log_dir: /var/log/tmi
  also_log_to_console: true

Built-in log rotation (via lumberjack; no external logrotate needed):

# Maximum size of a single log file before rotation (in MB, default varies)
export TMI_LOG_MAX_SIZE_MB=100

# Maximum number of old log files to retain
export TMI_LOG_MAX_BACKUPS=10

# Maximum number of days to retain old log files
export TMI_LOG_MAX_AGE_DAYS=30

Or in configuration:

logging:
  log_dir: /var/log/tmi
  max_size_mb: 100
  max_backups: 10
  max_age_days: 30

Web Application Debug Logging

The TMI web application (Angular) uses a LoggerService for standardized client-side logging with component-specific filtering and ISO8601 timestamps.

Logger Service Features

  • ISO8601 timestamp format for all log messages
  • Four log levels: DEBUG, INFO, WARN, ERROR
  • Environment-configurable log level threshold
  • Component-specific debug logging for granular control
  • Automatic redaction of sensitive URL parameters

Using the Logger Service

import { LoggerService, LogLevel } from '../../core/services/logger.service';

@Component({
  // ...
})
export class MyComponent {
  constructor(private logger: LoggerService) {
    // Component-specific debug logging (preferred for DEBUG level)
    logger.debugComponent('MyComponent', 'Detailed debugging information');
    logger.debugComponent('MyComponent', 'State changed', { oldState, newState });

    // General log levels
    logger.info('Informational message');
    logger.warn('Warning message');
    logger.error('Error message');

    // Include additional data with any log level
    logger.error('Failed to load user data', error);
  }
}

Component-Specific Debug Logging

The debugComponent() method provides fine-grained control over debug logging by component name.

Benefits:

  • Filter debug logs by specific components during development
  • Reduce console noise by enabling only relevant debug output
  • Better organize debug logs by application area

Configuration in environment files:

// src/environments/environment.ts
export const environment = {
  // ...
  logLevel: 'DEBUG',
  debugComponents: ['AppDiagramService', 'websocket-api', 'DfdCollaborationService'],
};

When debugComponents is defined, only debug logs from those components will be shown. When undefined or empty, all debug logs are shown (if log level permits).

Environment Log Level Configuration

Configure log levels in environment files:

Environment File Log Level Description
Development environment.ts DEBUG Show all logs for debugging
Test environment.test.ts WARN Only warnings and errors
Staging environment.staging.ts WARN Only warnings and errors
Production environment.prod.ts ERROR Only errors

Log Level Hierarchy

From most to least verbose:

  1. DEBUG - Detailed information for debugging purposes
  2. INFO - General informational messages about system operation
  3. WARN - Potential issues that are not yet errors
  4. ERROR - Error conditions that should be addressed

Each level includes all higher-priority levels. Setting the level to WARN will show both WARN and ERROR messages, but not INFO or DEBUG.

Runtime Log Level Changes

You can change the log level at runtime:

import { LogLevel, LoggerService } from '../../core/services/logger.service';

// Temporarily enable verbose logging
logger.setLogLevel(LogLevel.DEBUG);

Available Debug Component Names

Below is the list of component names used throughout the application for debugComponent() logging. Use these names when configuring debugComponents in your environment:

Application Layer (DFD):

  • AppDfdFacade, AppDfdOrchestrator, AppDiagramLoadingService
  • AppDiagramOperationBroadcaster, AppDiagramResyncService, AppDiagramService
  • AppEdgeService, AppExportService, AppGraphOperationManager
  • AppHistoryService, AppNotificationService, AppOperationRejectionHandler
  • AppPersistenceCoordinator, AppRemoteOperationHandler, AppStateService

Executors (DFD):

  • BaseOperationExecutor, BatchOperationExecutor, EdgeOperationExecutor
  • LoadDiagramExecutor, NodeOperationExecutor

Validators (DFD):

  • BaseOperationValidator

Infrastructure Layer (DFD):

  • InfraDfdWebsocketAdapter, InfraEdgeService, InfraLocalStorageAdapter
  • InfraNodeService, InfraRestPersistenceStrategy, InfraX6GraphAdapter
  • InfraX6SelectionAdapter, WebSocketPersistenceStrategy

X6 Adapters (DFD):

  • X6CoreOperations, X6Embedding, X6EventHandlers, X6EventLogger
  • X6Graph, X6Keyboard, X6Tooltip, ZOrderService

Presentation Layer (DFD):

  • DfdComponent, DfdDiagram, DfdEdge, DfdEdgeQuery
  • DfdEventHandlers, DfdExport, DfdPortStateManager, DfdState
  • DfdStateStore, DfdTooltip, DfdVisualEffects, Embedding
  • UiPresenterCoordinator, UiPresenterCursorDisplayService

Core Services:

  • Api, api, DfdCollaborationService, SecurityConfigService
  • ServerConnection, SessionManager, websocket-api

Collaboration:

  • CollaborationComponent, CollaborationDialog, CollaborationSession
  • GraphHistoryCoordinator, WebSocketCollaboration

Threat Modeling:

  • TM, TmEdit, TmEditComponent, ThreatEditorDialog
  • ThreatModelAuthorizationService, ThreatModelReportService
  • ThreatModelResolver, ThreatModelService, ThreatModelValidator
  • SvgCacheService, SvgOptimizationService

Authentication and Authorization:

  • Auth, AuthGuard, HomeGuard, RoleGuard

Utilities:

  • CellDataExtractionService, CellRelationshipValidation, Notification

Other:

  • App, Dashboard, DFD

Example: Debugging Collaboration Issues

To debug collaboration-related issues, configure your environment:

export const environment = {
  // ...
  logLevel: 'DEBUG',
  debugComponents: [
    'DfdCollaborationService',
    'CollaborationSession',
    'WebSocketCollaboration',
    'websocket-api',
    'AppDiagramOperationBroadcaster',
    'AppRemoteOperationHandler',
  ],
};

This configuration shows only debug logs related to collaboration, filtering out noise from other components.

Log Analysis

Reading TMI Logs

TMI uses Go's slog package for structured JSON logging with consistent fields:

Key fields:

  • time - Timestamp (RFC3339 format)
  • level - Log level (DEBUG, INFO, WARN, ERROR)
  • msg - Human-readable message
  • request_id - Request trace ID (added by context logger middleware)
  • client_ip - Client IP address (added by context logger middleware)
  • user_id - User identifier (added by context logger middleware when authenticated)
  • method - HTTP method (on request completion logs)
  • path - Request path (on request completion logs)
  • status_code - HTTP response status code (on request completion logs)
  • duration - Request/operation duration (Go duration format, e.g., "1.234ms")
  • source - Source file and line number (development mode only)

Example log entries:

{"time":"2025-01-15T10:30:00Z","level":"INFO","msg":"Request completed successfully","method":"GET","path":"/api/v1/threat-models","status_code":200,"duration":"45.2ms","request_id":"abc-123","user_id":"user@example.com"}
{"time":"2025-01-15T10:30:01Z","level":"ERROR","msg":"Query failed","error":"connection refused","request_id":"def-456"}
{"time":"2025-01-15T10:30:02Z","level":"DEBUG","msg":"Client connected","user_id":"xyz-789"}

Filtering and Searching Logs

Search for errors:

# All errors
grep '"level":"ERROR"' logs/tmi.log

# Errors with text format
grep 'ERROR' logs/tmi.log

# Errors in last hour
grep '"level":"ERROR"' logs/tmi.log | grep "$(date -u +%Y-%m-%dT%H)"

Search by message content:

# Database-related logs
grep -i '"msg":".*database\|.*postgres\|.*redis' logs/tmi.log

# Authentication-related logs
grep -i '"msg":".*auth\|.*token\|.*login\|.*OAuth' logs/tmi.log

# WebSocket-related logs
grep -i '"msg":".*[Ww]eb[Ss]ocket\|.*WS ' logs/tmi.log

Search by user:

# All activity for specific user
grep '"user_id":"abc-123"' logs/tmi.log

# Failed operations for user
grep '"user_id":"abc-123"' logs/tmi.log | grep '"level":"ERROR"'

Search by request:

# Follow request through system
grep '"request_id":"req-xyz-789"' logs/tmi.log

# All GET requests
grep '"method":"GET"' logs/tmi.log

# Slow requests (duration is a Go duration string like "45.2ms" or "1.5s")
grep '"duration":"[0-9]*\.[0-9]*s"' logs/tmi.log  # Requests taking seconds

Log Analysis Tools

jq for JSON logs:

# Pretty print JSON logs
cat logs/tmi.log | jq .

# Extract error messages
cat logs/tmi.log | jq 'select(.level=="ERROR") | .msg'

# Count errors by message
cat logs/tmi.log | jq 'select(.level=="ERROR") | .msg' | sort | uniq -c

# Find requests with durations in seconds (slow requests)
cat logs/tmi.log | jq 'select(.duration != null and (.duration | test("[0-9]+\\.?[0-9]*s$"))) | {path, duration}'

grep patterns:

# Authentication failures
grep -i "authentication failed\|unauthorized\|invalid token" logs/tmi.log

# Database errors
grep -i "database error\|connection refused\|query failed" logs/tmi.log

# WebSocket issues
grep -i "websocket.*error\|connection.*closed\|upgrade failed" logs/tmi.log

# Performance issues (requests taking multiple seconds)
grep '"duration":"[5-9][0-9]*\.[0-9]*s\|[0-9][0-9]\+\.[0-9]*s' logs/tmi.log

Common patterns:

# Top 10 API endpoints by count
grep '"method":"' logs/tmi.log | jq -r '.path' | sort | uniq -c | sort -rn | head -10

# Error rate per hour
grep '"level":"ERROR"' logs/tmi.log | jq -r '.time' | cut -d: -f1-2 | uniq -c

# List request durations by endpoint (duration is a Go duration string, not numeric)
grep '"duration":' logs/tmi.log | jq '{path, duration}' | jq -s 'group_by(.path) | map({path: .[0].path, count: length, durations: map(.duration)})'

Browser Developer Tools

Console Debugging

Open Developer Tools:

  • Chrome/Edge: F12 or Ctrl+Shift+I (Windows/Linux), Cmd+Option+I (Mac)
  • Firefox: F12 or Ctrl+Shift+I (Windows/Linux), Cmd+Option+I (Mac)
  • Safari: Cmd+Option+I (Mac) - Enable "Show Develop menu" in Preferences first

Key areas to check:

  1. Console Tab:

    • JavaScript errors
    • Failed API calls
    • WebSocket connection issues
    • Application warnings
  2. Network Tab:

    • API request/response details
    • HTTP status codes
    • Request/response headers
    • WebSocket handshake
  3. Application Tab:

    • Cookies (HttpOnly session cookies; tokens are not in localStorage)
    • Local storage (OAuth state parameters)
    • Session storage (PKCE verifier)
    • Cache status

Debugging API Calls

Network tab inspection:

  1. Open Network tab in Developer Tools
  2. Refresh page or trigger API call
  3. Find request in list
  4. Click to view details:
    • Headers: Request/response headers, status code
    • Preview: Formatted response data
    • Response: Raw response data
    • Timing: Request timing breakdown

Common issues:

401 Unauthorized:

TMI uses HttpOnly cookies for session management, so tokens are not accessible to JavaScript through localStorage or sessionStorage. To debug 401 errors:

// Check the Network tab for the failing request:
// 1. Look at Request Headers for the Cookie header
// 2. Check Response Headers for Set-Cookie directives
// 3. In the Application tab > Cookies, verify cookie presence and expiration

// Check if a session is active by calling the userinfo endpoint
fetch('/oauth2/userinfo', { credentials: 'include' })
  .then(r => { console.log('Status:', r.status); return r.json(); })
  .then(data => console.log('User info:', data))
  .catch(e => console.error('Not authenticated:', e));

CORS errors:

Access to fetch at 'https://api.example.com' from origin 'https://app.example.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present.

Check server CORS configuration:

# Verify CORS headers
curl -H "Origin: https://app.example.com" \
     -H "Access-Control-Request-Method: GET" \
     -H "Access-Control-Request-Headers: Authorization" \
     -X OPTIONS \
     -v \
     https://api.example.com/api/v1/threat-models

Network errors:

// Check for network connectivity (the root endpoint / returns health and version info)
fetch('https://api.example.com/')
  .then(r => console.log('Server reachable:', r.status))
  .catch(e => console.error('Network error:', e));

Debugging WebSocket Connections

Network tab WebSocket inspection:

  1. Open Network tab
  2. Filter by "WS" or "WebSocket"
  3. Click WebSocket connection
  4. View Messages tab:
    • Outgoing messages (sent)
    • Incoming messages (received)
    • Message timestamps

Console WebSocket debugging:

// Monitor WebSocket events
const socket = new WebSocket('wss://api.example.com/ws');

socket.onopen = (e) => console.log('WebSocket connected:', e);
socket.onerror = (e) => console.error('WebSocket error:', e);
socket.onclose = (e) => console.log('WebSocket closed:', e.code, e.reason);
socket.onmessage = (e) => console.log('WebSocket message:', JSON.parse(e.data));

Common WebSocket issues:

Connection refused:

  • Check WebSocket URL (ws:// vs wss://)
  • Verify server is running
  • Check firewall/proxy settings

Connection closes immediately:

  • Check authentication (JWT token)
  • Verify CORS headers
  • Check server logs for errors

Messages not received:

  • Verify subscription is active
  • Check Redis connectivity on server
  • Monitor Network tab Messages

JavaScript Debugging

Set breakpoints:

  1. Open Sources tab
  2. Find JavaScript file
  3. Click line number to set breakpoint
  4. Trigger action to hit breakpoint
  5. Inspect variables, step through code

Console debugging:

// Log API responses
fetch('/api/v1/threat-models')
  .then(r => r.json())
  .then(data => {
    console.log('API response:', data);
    debugger; // Pause execution here
  });

// Log WebSocket messages
socket.onmessage = (e) => {
  const data = JSON.parse(e.data);
  console.table(data); // Display as table
  console.dir(data);   // Display as object
};

// Trace function calls
console.trace('Function call stack');

Database Queries

Connecting to Database

psql command line:

# Connect to database (default user is 'tmi' per docker-compose.prod.yml)
psql -h localhost -U tmi -d tmi

# Or use the TMI_DATABASE_URL directly
psql "$TMI_DATABASE_URL"

# Or use environment variables
export PGHOST=localhost
export PGUSER=tmi
export PGDATABASE=tmi
psql

From Docker:

# Connect to PostgreSQL container (production container name from docker-compose.prod.yml)
docker exec -it tmi-postgres-prod psql -U tmi -d tmi

Useful Diagnostic Queries

Check active connections:

-- List all connections
SELECT pid, usename, application_name, client_addr, state, query
FROM pg_stat_activity
WHERE datname = 'tmi'
ORDER BY state, query_start DESC;

-- Count connections by state
SELECT state, COUNT(*)
FROM pg_stat_activity
WHERE datname = 'tmi'
GROUP BY state;

Check database size:

-- Database size
SELECT pg_size_pretty(pg_database_size('tmi')) AS database_size;

-- Table sizes
SELECT schemaname, tablename,
       pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC
LIMIT 20;

-- Largest indexes
SELECT schemaname, tablename, indexname,
       pg_size_pretty(pg_relation_size(indexrelid)) AS size
FROM pg_indexes
JOIN pg_class ON pg_class.relname = indexname
WHERE schemaname = 'public'
ORDER BY pg_relation_size(indexrelid) DESC
LIMIT 10;

Check slow queries:

-- Currently running slow queries
SELECT pid, now() - query_start AS duration, state, query
FROM pg_stat_activity
WHERE state = 'active'
  AND now() - query_start > interval '5 seconds'
ORDER BY duration DESC;

-- Kill a long-running query (use carefully!)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE pid = <process_id>;

Check table statistics:

-- Row counts
SELECT schemaname, tablename, n_live_tup AS row_count
FROM pg_stat_user_tables
WHERE schemaname = 'public'
ORDER BY n_live_tup DESC;

-- Table activity (inserts, updates, deletes)
SELECT schemaname, relname,
       seq_scan, seq_tup_read,
       idx_scan, idx_tup_fetch,
       n_tup_ins, n_tup_upd, n_tup_del
FROM pg_stat_user_tables
WHERE schemaname = 'public'
ORDER BY n_tup_ins + n_tup_upd + n_tup_del DESC;

Check indexes:

-- List all indexes
SELECT schemaname, tablename, indexname, indexdef
FROM pg_indexes
WHERE schemaname = 'public'
ORDER BY tablename, indexname;

-- Find unused indexes
SELECT schemaname, tablename, indexname, idx_scan
FROM pg_stat_user_indexes
WHERE schemaname = 'public'
  AND idx_scan = 0
  AND indexrelname NOT LIKE 'pg_toast%'
ORDER BY pg_relation_size(indexrelid) DESC;

-- Find missing indexes (high seq_scan, no idx_scan)
SELECT schemaname, tablename, seq_scan, idx_scan,
       seq_scan - idx_scan AS too_much_seq,
       CASE WHEN seq_scan - idx_scan > 0
            THEN 'Missing Index?'
            ELSE 'OK'
       END AS advice
FROM pg_stat_user_tables
WHERE schemaname = 'public'
  AND seq_scan - idx_scan > 0
ORDER BY too_much_seq DESC;

Application-specific queries:

-- Count threat models by user
SELECT owner, COUNT(*) as threat_model_count
FROM threat_models
GROUP BY owner
ORDER BY threat_model_count DESC
LIMIT 10;

-- Recent threat model activity
SELECT id, name, owner, created_at, modified_at
FROM threat_models
ORDER BY modified_at DESC
LIMIT 20;

-- Users with most authorization grants
SELECT subject, COUNT(*) as grant_count
FROM authorization
GROUP BY subject
ORDER BY grant_count DESC
LIMIT 10;

-- Webhook subscription status
SELECT status, COUNT(*) as count
FROM webhook_subscriptions
GROUP BY status;

-- Failed webhook deliveries (delivery records are stored in Redis, not Postgres)
-- Use the admin API endpoint GET /admin/webhooks/deliveries to query delivery status

Query Performance Analysis

EXPLAIN ANALYZE:

-- Analyze query performance
EXPLAIN ANALYZE
SELECT tm.*, u.email
FROM threat_models tm
JOIN users u ON u.id = tm.owner
WHERE tm.created_at > NOW() - INTERVAL '7 days'
ORDER BY tm.created_at DESC;

-- Look for:
-- - Seq Scan (consider adding index)
-- - High execution time
-- - High row counts

Enable query logging:

-- Log slow queries (PostgreSQL config)
ALTER DATABASE tmi SET log_min_duration_statement = 1000; -- Log queries >1s

-- Log all queries (development only)
ALTER DATABASE tmi SET log_statement = 'all';

Redis Debugging

Connecting to Redis

# Connect via redis-cli
redis-cli

# Connect to specific host/port
redis-cli -h localhost -p 6379

# Connect with password
redis-cli -a yourpassword

# From Docker (production container name from docker-compose.prod.yml)
docker exec -it tmi-redis-prod redis-cli

Useful Redis Commands

Check Redis status:

# Server info
redis-cli INFO

# Memory usage
redis-cli INFO memory

# Connected clients
redis-cli CLIENT LIST

# Server statistics
redis-cli INFO stats

Inspect keys:

# Count keys
redis-cli DBSIZE

# List keys (use carefully in production!)
redis-cli KEYS "*"

# Scan keys safely (paginated)
redis-cli SCAN 0 MATCH "session:*" COUNT 100

# Get key value
redis-cli GET "session:abc123"

# Get key type and TTL
redis-cli TYPE "session:abc123"
redis-cli TTL "session:abc123"

WebSocket debugging:

# List WebSocket sessions
redis-cli KEYS "websocket:*"

# Check WebSocket connection
redis-cli GET "websocket:connection:xyz789"

# Monitor real-time commands
redis-cli MONITOR

Webhook debugging:

# Check event stream
redis-cli XINFO STREAM tmi:events

# View recent events
redis-cli XRANGE tmi:events - + COUNT 10

# Check webhook consumer group
redis-cli XINFO GROUPS tmi:events

# Check pending webhook deliveries
redis-cli XPENDING tmi:events webhook-consumers

Cache debugging:

# Check cache hit rate
redis-cli INFO stats | grep hit_rate

# Find large keys
redis-cli --bigkeys

# Sample keys
redis-cli --sample

Debugging Workflows

Debugging Authentication Issues

  1. Check logs:

    grep -i '"msg":".*auth\|.*token\|.*OAuth' logs/tmi.log | tail -20
  2. Verify OAuth configuration:

    # List available OAuth providers
    curl http://localhost:8080/oauth2/providers
    
    # Initiate OAuth authorization for a specific provider (e.g., github)
    curl -v http://localhost:8080/oauth2/authorize?idp=github
  3. Check session status:

    // In browser console: tokens are in HttpOnly cookies, not accessible to JS
    // Instead, verify session by calling the userinfo endpoint
    fetch('/oauth2/userinfo', { credentials: 'include' })
      .then(r => r.json())
      .then(data => console.log('Session:', data))
      .catch(e => console.error('No active session:', e));
  4. Test API with token:

    curl -H "Authorization: Bearer $TOKEN" \
         http://localhost:8080/api/v1/threat-models

Debugging WebSocket Issues

  1. Check server logs:

    grep -i '"msg":".*[Ww]eb[Ss]ocket' logs/tmi.log
  2. Verify Redis connectivity:

    redis-cli PING
    redis-cli KEYS "websocket:*"
  3. Monitor WebSocket in browser:

    • Open Network tab, filter by WS
    • Check connection status and messages
  4. Test WebSocket connection:

    websocat wss://api.example.com/ws
  5. Use WebSocket Test Harness: See WebSocket-Test-Harness for a comprehensive Go-based testing tool that supports OAuth authentication, host/participant modes, and detailed message logging.

Debugging Performance Issues

  1. Check server logs for slow requests:

    grep '"duration":"[0-9]*\.[0-9]*s"' logs/tmi.log
  2. Profile application:

    # CPU profile
    curl http://localhost:8080/debug/pprof/profile?seconds=30 > cpu.prof
    go tool pprof cpu.prof
    
    # Memory profile
    curl http://localhost:8080/debug/pprof/heap > mem.prof
    go tool pprof mem.prof
  3. Check database performance:

    -- Find slow queries
    SELECT query, calls, total_time, mean_time
    FROM pg_stat_statements
    ORDER BY mean_time DESC
    LIMIT 10;
  4. Check Redis performance:

    # Monitor commands
    redis-cli MONITOR
    
    # Check slow log
    redis-cli SLOWLOG GET 10

Related Pages

Clone this wiki locally