# Router Mode Guide Router mode allows multiple LogWisp streams to share HTTP ports through path-based routing, simplifying deployment and access control. ## Overview In standard mode, each stream requires its own port: - Stream 1: `http://localhost:8080/stream` - Stream 2: `http://localhost:8081/stream` - Stream 3: `http://localhost:8082/stream` In router mode, streams share ports via paths: - Stream 1: `http://localhost:8080/app/stream` - Stream 2: `http://localhost:8080/database/stream` - Stream 3: `http://localhost:8080/system/stream` - Global status: `http://localhost:8080/status` ## Enabling Router Mode Start LogWisp with the `--router` flag: ```bash logwisp --router --config /etc/logwisp/multi-stream.toml ``` ## Configuration ### Basic Router Configuration ```toml # All streams can use the same port in router mode [[streams]] name = "app" [streams.monitor] targets = [{ path = "/var/log/app", pattern = "*.log" }] [streams.httpserver] enabled = true port = 8080 # Same port OK [[streams]] name = "database" [streams.monitor] targets = [{ path = "/var/log/postgresql", pattern = "*.log" }] [streams.httpserver] enabled = true port = 8080 # Shared port [[streams]] name = "nginx" [streams.monitor] targets = [{ path = "/var/log/nginx", pattern = "*.log" }] [streams.httpserver] enabled = true port = 8080 # Shared port ``` ### Path Structure In router mode, paths are automatically prefixed with the stream name: | Stream Name | Configuration Path | Router Mode Path | |------------|-------------------|------------------| | `app` | `/stream` | `/app/stream` | | `app` | `/status` | `/app/status` | | `database` | `/stream` | `/database/stream` | | `database` | `/status` | `/database/status` | ### Custom Paths You can customize the paths in each stream: ```toml [[streams]] name = "api" [streams.httpserver] stream_path = "/logs" # Becomes /api/logs status_path = "/health" # Becomes /api/health ``` ## URL Endpoints ### Stream Endpoints Access individual streams: ```bash # SSE stream for 'app' logs curl -N http://localhost:8080/app/stream # Status for 'database' stream curl http://localhost:8080/database/status # Custom path example curl -N http://localhost:8080/api/logs ``` ### Global Status Router mode provides a global status endpoint: ```bash curl http://localhost:8080/status | jq . ``` Returns aggregated information: ```json { "service": "LogWisp Router", "version": "1.0.0", "port": 8080, "total_streams": 3, "streams": { "app": { /* stream stats */ }, "database": { /* stream stats */ }, "nginx": { /* stream stats */ } }, "router": { "uptime_seconds": 3600, "total_requests": 15234, "routed_requests": 15220, "failed_requests": 14 } } ``` ## Port Sharing ### How It Works 1. Router server listens on configured ports 2. Examines request path to determine target stream 3. Routes request to appropriate stream handler 4. Stream handles request as if standalone ### Port Assignment Rules In router mode: - Multiple streams can use the same port - Router detects and consolidates shared ports - Each unique port gets one router server - TCP servers remain independent (no routing) Example with multiple ports: ```toml # Streams 1-3 share port 8080 [[streams]] name = "app" [streams.httpserver] port = 8080 [[streams]] name = "db" [streams.httpserver] port = 8080 [[streams]] name = "web" [streams.httpserver] port = 8080 # Stream 4 uses different port [[streams]] name = "admin" [streams.httpserver] port = 9090 # Result: 2 router servers (8080 and 9090) ``` ## Use Cases ### Microservices Architecture Route logs from different services: ```toml [[streams]] name = "frontend" [streams.monitor] targets = [{ path = "/var/log/frontend", pattern = "*.log" }] [streams.httpserver] enabled = true port = 8080 [[streams]] name = "backend" [streams.monitor] targets = [{ path = "/var/log/backend", pattern = "*.log" }] [streams.httpserver] enabled = true port = 8080 [[streams]] name = "worker" [streams.monitor] targets = [{ path = "/var/log/worker", pattern = "*.log" }] [streams.httpserver] enabled = true port = 8080 ``` Access via: - Frontend logs: `http://localhost:8080/frontend/stream` - Backend logs: `http://localhost:8080/backend/stream` - Worker logs: `http://localhost:8080/worker/stream` ### Environment-Based Routing Different log levels per environment: ```toml [[streams]] name = "prod" [streams.monitor] targets = [{ path = "/logs/prod", pattern = "*.log" }] [[streams.filters]] type = "include" patterns = ["ERROR", "WARN"] [streams.httpserver] port = 8080 [[streams]] name = "staging" [streams.monitor] targets = [{ path = "/logs/staging", pattern = "*.log" }] [[streams.filters]] type = "include" patterns = ["ERROR", "WARN", "INFO"] [streams.httpserver] port = 8080 [[streams]] name = "dev" [streams.monitor] targets = [{ path = "/logs/dev", pattern = "*.log" }] # No filters - all logs [streams.httpserver] port = 8080 ``` ### Department Access Separate streams for different teams: ```toml [[streams]] name = "engineering" [streams.monitor] targets = [{ path = "/logs/apps", pattern = "*.log" }] [streams.httpserver] port = 8080 [streams.httpserver.rate_limit] enabled = true requests_per_second = 50.0 [[streams]] name = "security" [streams.monitor] targets = [{ path = "/logs/audit", pattern = "*.log" }] [streams.httpserver] port = 8080 [streams.httpserver.rate_limit] enabled = true requests_per_second = 5.0 max_connections_per_ip = 1 [[streams]] name = "support" [streams.monitor] targets = [{ path = "/logs/customer", pattern = "*.log" }] [[streams.filters]] type = "exclude" patterns = ["password", "token", "secret"] [streams.httpserver] port = 8080 ``` ## Advanced Features ### Mixed Mode Deployment Combine router and standalone modes: ```toml # Public streams via router [[streams]] name = "public-api" [streams.httpserver] enabled = true port = 8080 # Router mode [[streams]] name = "public-web" [streams.httpserver] enabled = true port = 8080 # Router mode # Internal stream standalone [[streams]] name = "internal" [streams.httpserver] enabled = true port = 9999 # Different port, standalone # High-performance TCP [[streams]] name = "metrics" [streams.tcpserver] enabled = true port = 9090 # TCP not affected by router ``` ### Load Balancer Integration Router mode works well with load balancers: ```nginx # Nginx configuration upstream logwisp { server logwisp1:8080; server logwisp2:8080; server logwisp3:8080; } location /logs/ { proxy_pass http://logwisp/; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_buffering off; } ``` Access becomes: - `https://example.com/logs/app/stream` - `https://example.com/logs/database/stream` - `https://example.com/logs/status` ### Path-Based Access Control Use reverse proxy for authentication: ```nginx # Require auth for security logs location /logs/security/ { auth_basic "Security Logs"; auth_basic_user_file /etc/nginx/security.htpasswd; proxy_pass http://localhost:8080/security/; } # Public access for status location /logs/app/ { proxy_pass http://localhost:8080/app/; } ``` ## Limitations ### Router Mode Limitations 1. **HTTP Only**: Router mode only works for HTTP/SSE streams 2. **No TCP Routing**: TCP streams remain on separate ports 3. **Path Conflicts**: Stream names must be unique 4. **Same Config**: All streams on a port share SSL/auth settings ### When Not to Use Router Mode - High-performance scenarios (use TCP) - Streams need different SSL certificates - Complex authentication per stream - Network isolation requirements ## Troubleshooting ### "Path not found" Check available routes: ```bash curl http://localhost:8080/invalid-path ``` Response shows available routes: ```json { "error": "Not Found", "requested_path": "/invalid-path", "available_routes": [ "/status (global status)", "/app/stream (stream: app)", "/app/status (status: app)", "/database/stream (stream: database)", "/database/status (status: database)" ] } ``` ### "Port conflict" If you see port conflicts: 1. Ensure `--router` flag is used 2. Check all streams have `httpserver.enabled = true` 3. Verify no other services use the port ### Debug Routing Enable debug logging: ```bash logwisp --router --log-level debug ``` Look for routing decisions: ``` Router request method=GET path=/app/stream remote_addr=127.0.0.1:54321 Routing request to stream stream=app original_path=/app/stream remaining_path=/stream ``` ### Performance Impact Router mode adds minimal overhead: - ~100-200ns per request for path matching - Negligible memory overhead - No impact on streaming performance ## Best Practices ### Naming Conventions Use clear, consistent stream names: ```toml # Good: Clear purpose name = "frontend-prod" name = "backend-staging" name = "worker-payments" # Bad: Ambiguous name = "logs1" name = "stream2" name = "test" ``` ### Path Organization Group related streams: ``` /prod/frontend/stream /prod/backend/stream /staging/frontend/stream /staging/backend/stream ``` ### Documentation Document your routing structure: ```toml # Stream for production API logs # Access: https://logs.example.com/api-prod/stream [[streams]] name = "api-prod" ``` ### Monitoring Use global status for overview: ```bash # Monitor all streams watch -n 5 'curl -s localhost:8080/status | jq .streams' # Check specific stream curl -s localhost:8080/status | jq '.streams.app' ``` ## Migration Guide ### From Standalone to Router 1. **Update configuration** - ensure consistent ports: ```toml # Change from different ports [streams.httpserver] port = 8080 # Was 8081, 8082, etc. ``` 2. **Start with router flag**: ```bash logwisp --router --config existing.toml ``` 3. **Update client URLs**: ```bash # Old: http://localhost:8081/stream # New: http://localhost:8080/streamname/stream ``` 4. **Update monitoring**: ```bash # Global status now available curl http://localhost:8080/status ``` ### Gradual Migration Run both modes during transition: ```bash # Week 1: Run standalone (current) logwisp --config prod.toml # Week 2: Run both logwisp --config prod.toml & # Standalone logwisp --router --config prod-router.toml & # Router # Week 3: Router only logwisp --router --config prod.toml ``` ## See Also - [Configuration Guide](configuration.md) - Stream configuration - [HTTP Streaming](api.md#http-sse) - SSE protocol details - [Load Balancing](integrations.md#load-balancers) - Integration patterns - [Security Best Practices](security.md) - Securing router deployments