v0.1.11 configurable logging added, minor refactoring, orgnized docs added

This commit is contained in:
2025-07-10 01:17:06 -04:00
parent bc4ce1d0ae
commit 5936f82970
40 changed files with 5745 additions and 1701 deletions

76
doc/README.md Normal file
View File

@ -0,0 +1,76 @@
# LogWisp Documentation
Welcome to the LogWisp documentation. This guide covers all aspects of installing, configuring, and using LogWisp for multi-stream log monitoring.
## 📚 Documentation Index
### Getting Started
- **[Installation Guide](installation.md)** - How to install LogWisp on various platforms
- **[Quick Start](quickstart.md)** - Get up and running in 5 minutes
- **[Architecture Overview](architecture.md)** - System design and components
### Configuration
- **[Configuration Guide](configuration.md)** - Complete configuration reference
- **[Environment Variables](environment.md)** - Environment variable reference
- **[Command Line Options](cli.md)** - CLI flags and parameters
### Features
- **[Filters Guide](filters.md)** - Pattern-based log filtering
- **[Rate Limiting](ratelimiting.md)** - Request and connection limiting
- **[Router Mode](router.md)** - Path-based multi-stream routing
- **[Authentication](authentication.md)** - Securing your log streams *(planned)*
### Operations
- **[Monitoring & Status](monitoring.md)** - Health checks and statistics
- **[Performance Tuning](performance.md)** - Optimization guidelines
- **[Troubleshooting](troubleshooting.md)** - Common issues and solutions
### Advanced Topics
- **[Security Best Practices](security.md)** - Hardening your deployment
- **[Integration Examples](integrations.md)** - Working with other tools
- **[Development Guide](development.md)** - Contributing to LogWisp
## 🚀 Quick Links
- **[Example Configurations](examples/)** - Ready-to-use config templates
- **[API Reference](api.md)** - SSE/TCP protocol documentation
- **[Changelog](../CHANGELOG.md)** - Version history and updates
## 💡 Common Use Cases
### Single Application Monitoring
Monitor logs from one application with basic filtering:
```toml
[[streams]]
name = "myapp"
[streams.monitor]
targets = [{ path = "/var/log/myapp", pattern = "*.log" }]
[[streams.filters]]
type = "include"
patterns = ["ERROR", "WARN"]
```
### Multi-Service Architecture
Monitor multiple services with different configurations:
```bash
logwisp --router --config /etc/logwisp/services.toml
```
### High-Security Environments
Enable authentication and rate limiting:
```toml
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 10.0
max_connections_per_ip = 3
```
## 🔍 Finding Help
- **GitHub Issues**: [Report bugs or request features](https://github.com/logwisp/logwisp/issues)
- **Discussions**: [Ask questions and share ideas](https://github.com/logwisp/logwisp/discussions)
- **Examples**: Check the [examples directory](examples/) for common scenarios
## 📝 License
BSD-3-Clause

View File

@ -1,422 +0,0 @@
# LogWisp Architecture and Project Structure
## Directory Structure
```
logwisp/
├── Makefile # Build automation with version injection
├── go.mod # Go module definition
├── go.sum # Go module checksums
├── README.md # Project documentation
├── config/
│ ├── logwisp.toml.defaults # Default configuration and guide
│ ├── logwisp.toml.example # Example configuration
│ └── logwisp.toml.minimal # Minimal configuration template
├── doc/
│ └── architecture.md # This file - architecture documentation
└── src/
├── cmd/
│ └── logwisp/
│ └── main.go # Application entry point, CLI handling
└── internal/
├── config/
│ ├── auth.go # Authentication configuration structures
│ ├── config.go # Main configuration structures
│ ├── loader.go # Configuration loading with lixenwraith/config
│ ├── server.go # TCP/HTTP server configurations with rate limiting
│ ├── ssl.go # SSL/TLS configuration structures
│ ├── stream.go # Stream-specific configurations with filters
│ └── validation.go # Configuration validation including filters and rate limits
├── filter/
│ ├── filter.go # Regex-based log filtering implementation
│ └── chain.go # Sequential filter chain management
├── monitor/
│ ├── file_watcher.go # File watching and rotation detection
│ └── monitor.go # Log monitoring interface and implementation
├── ratelimit/
│ ├── ratelimit.go # Token bucket algorithm implementation
│ └── limiter.go # Per-stream rate limiter with IP tracking
├── service/
│ ├── httprouter.go # HTTP router for path-based routing
│ ├── logstream.go # Stream lifecycle management
│ ├── routerserver.go # Router server implementation
│ └── service.go # Multi-stream service orchestration
├── transport/
│ ├── httpstreamer.go # HTTP/SSE streaming with rate limiting
│ ├── noop_logger.go # Silent logger for gnet
│ ├── tcpserver.go # TCP server with rate limiting (gnet)
│ └── tcpstreamer.go # TCP streaming implementation
└── version/
└── version.go # Version information management
```
## Configuration System
### Configuration Hierarchy (Highest to Lowest Priority)
1. **CLI Arguments**: Direct command-line flags
2. **Environment Variables**: `LOGWISP_` prefixed variables
3. **Configuration File**: TOML format configuration
4. **Built-in Defaults**: Hardcoded default values
### Configuration Locations
```bash
# Default configuration file location
~/.config/logwisp.toml
# Override via environment variable
export LOGWISP_CONFIG_FILE=/etc/logwisp/production.toml
# Override config directory
export LOGWISP_CONFIG_DIR=/etc/logwisp
export LOGWISP_CONFIG_FILE=production.toml # Relative to CONFIG_DIR
# Direct CLI override
./logwisp --config /path/to/config.toml
```
### Environment Variable Mapping
Environment variables follow a structured naming pattern:
- Prefix: `LOGWISP_`
- Path separator: `_` (underscore)
- Array index: Numeric suffix (0-based)
Examples:
```bash
# Stream-specific settings
LOGWISP_STREAMS_0_NAME=app
LOGWISP_STREAMS_0_MONITOR_CHECK_INTERVAL_MS=50
LOGWISP_STREAMS_0_HTTPSERVER_PORT=8080
LOGWISP_STREAMS_0_HTTPSERVER_BUFFER_SIZE=2000
LOGWISP_STREAMS_0_HTTPSERVER_HEARTBEAT_ENABLED=true
LOGWISP_STREAMS_0_HTTPSERVER_HEARTBEAT_FORMAT=json
# Filter configuration
LOGWISP_STREAMS_0_FILTERS_0_TYPE=include
LOGWISP_STREAMS_0_FILTERS_0_LOGIC=or
LOGWISP_STREAMS_0_FILTERS_0_PATTERNS='["ERROR","WARN"]'
# Rate limiting configuration
LOGWISP_STREAMS_0_HTTPSERVER_RATE_LIMIT_ENABLED=true
LOGWISP_STREAMS_0_HTTPSERVER_RATE_LIMIT_REQUESTS_PER_SECOND=10.0
LOGWISP_STREAMS_0_HTTPSERVER_RATE_LIMIT_BURST_SIZE=20
LOGWISP_STREAMS_0_HTTPSERVER_RATE_LIMIT_LIMIT_BY=ip
# Multiple streams
LOGWISP_STREAMS_1_NAME=system
LOGWISP_STREAMS_1_MONITOR_CHECK_INTERVAL_MS=1000
LOGWISP_STREAMS_1_TCPSERVER_PORT=9090
```
## Component Architecture
### Core Components
1. **Service (`logstream.Service`)**
- Manages multiple log streams
- Handles lifecycle (creation, shutdown)
- Provides global statistics
- Thread-safe stream registry
2. **LogStream (`logstream.LogStream`)**
- Represents a single log monitoring pipeline
- Contains: Monitor + Filter Chain + Rate Limiter + Servers (TCP/HTTP)
- Independent configuration
- Per-stream statistics with filter and rate limit metrics
3. **Monitor (`monitor.Monitor`)**
- Watches files and directories
- Detects log rotation
- Publishes log entries to subscribers
- Configurable check intervals
4. **Filter (`filter.Filter`)**
- Regex-based log filtering
- Include (whitelist) or Exclude (blacklist) modes
- OR/AND logic for multiple patterns
- Per-filter statistics (processed, matched, dropped)
5. **Filter Chain (`filter.Chain`)**
- Sequential application of multiple filters
- All filters must pass for entry to be streamed
- Aggregate statistics across filter chain
6. **Rate Limiter (`ratelimit.Limiter`)**
- Token bucket algorithm for smooth rate limiting
- Per-IP or global limiting strategies
- Connection tracking and limits
- Automatic cleanup of stale entries
- Non-blocking rejection of excess requests
7. **Streamers**
- **HTTPStreamer**: SSE-based streaming over HTTP
- Rate limit enforcement before request handling
- Connection tracking for per-IP limits
- Configurable 429 responses
- **TCPStreamer**: Raw JSON streaming over TCP
- Silent connection drops when rate limited
- Per-IP connection tracking
- Both support configurable heartbeats
- Non-blocking client management
8. **HTTPRouter (`logstream.HTTPRouter`)**
- Optional component for path-based routing
- Consolidates multiple HTTP streams on shared ports
- Provides global status endpoint
- Longest-prefix path matching
- Dynamic stream registration/deregistration
### Data Flow
```
File System → Monitor → LogEntry Channel → Filter Chain → [Rate Limiter] → Streamer → Network Client
↑ ↓ ↓ ↓
└── Rotation Detection Pattern Match Rate Limit Check
↓ ↓
Pass/Drop Accept/Reject
```
### Filter Architecture
```
Log Entry → Filter Chain → Filter 1 → Filter 2 → ... → Output
↓ ↓
Include? Exclude?
↓ ↓
OR/AND OR/AND
Logic Logic
```
### Rate Limiting Architecture
```
Client Request → Rate Limiter → Token Bucket Check → Allow/Deny
↓ ↓
IP Tracking Refill Rate
Cleanup Timer
```
### Configuration Structure
```toml
[[streams]]
name = "stream-name"
[streams.monitor]
check_interval_ms = 100 # Per-transport check interval
targets = [
{ path = "/path/to/logs", pattern = "*.log", is_file = false },
{ path = "/path/to/file.log", is_file = true }
]
# Filter configuration (optional)
[[streams.filters]]
type = "include" # "include" or "exclude"
logic = "or" # "or" or "and"
patterns = [
"(?i)error", # Case-insensitive error matching
"(?i)warn" # Case-insensitive warning matching
]
[[streams.filters]]
type = "exclude"
patterns = ["DEBUG", "TRACE"]
[streams.httpserver]
enabled = true
port = 8080
buffer_size = 1000
stream_path = "/stream"
status_path = "/status"
[streams.httpserver.heartbeat]
enabled = true
interval_seconds = 30
format = "comment" # or "json"
include_timestamp = true
include_stats = false
[streams.httpserver.rate_limit]
enabled = false # Disabled by default
requests_per_second = 10.0 # Token refill rate
burst_size = 20 # Token bucket capacity
limit_by = "ip" # "ip" or "global"
response_code = 429 # HTTP response code
response_message = "Rate limit exceeded"
max_connections_per_ip = 5 # Concurrent connection limit
max_total_connections = 100 # Global connection limit
[streams.tcpserver]
enabled = true
port = 9090
buffer_size = 5000
[streams.tcpserver.heartbeat]
enabled = true
interval_seconds = 60
include_timestamp = true
include_stats = true
[streams.tcpserver.rate_limit]
enabled = false
requests_per_second = 5.0
burst_size = 10
limit_by = "ip"
```
## Filter Implementation
### Filter Types
1. **Include Filter**: Only logs matching patterns are streamed (whitelist)
2. **Exclude Filter**: Logs matching patterns are dropped (blacklist)
### Pattern Logic
- **OR Logic**: Log matches if ANY pattern matches
- **AND Logic**: Log matches only if ALL patterns match
### Filter Chain
- Multiple filters are applied sequentially
- All filters must pass for a log to be streamed
- Efficient short-circuit evaluation
### Performance Considerations
- Regex patterns compiled once at startup
- Cached for efficient matching
- Statistics tracked without locks in hot path
## Rate Limiting Implementation
### Token Bucket Algorithm
- Each IP (or global limiter) gets a bucket with configurable capacity
- Tokens refill at `requests_per_second` rate
- Each request/connection consumes one token
- Smooth rate limiting without hard cutoffs
### Limiting Strategies
1. **Per-IP**: Each client IP gets its own token bucket
2. **Global**: All clients share a single token bucket
### Connection Limits
- Per-IP connection limits prevent single client resource exhaustion
- Global connection limits protect overall system resources
- Checked before rate limits to prevent connection hanging
### Cleanup
- IP entries older than 5 minutes are automatically removed
- Prevents unbounded memory growth
- Runs every minute in background
## Build System
### Makefile Targets
```bash
make build # Build with version information
make install # Install to /usr/local/bin
make clean # Remove built binary
make test # Run test suite
make release TAG=v1.0.0 # Create and push git tag
```
### Version Management
Version information is injected at compile time:
```bash
# Automatic version detection from git
VERSION := $(shell git describe --tags --always --dirty)
GIT_COMMIT := $(shell git rev-parse --short HEAD)
BUILD_TIME := $(shell date -u '+%Y-%m-%d_%H:%M:%S')
# Manual build with version
go build -ldflags "-X 'logwisp/src/internal/version.Version=v1.0.0'" \
-o logwisp ./src/cmd/logwisp
```
## Operating Modes
### 1. Standalone Mode (Default)
- Each stream runs its own HTTP/TCP servers
- Direct port access per stream
- Simple configuration
- Best for single-stream or distinct-port setups
### 2. Router Mode (`--router`)
- HTTP streams share ports via path-based routing
- Consolidated access through URL paths
- Global status endpoint with aggregated statistics
- Best for multi-stream setups with limited ports
- Streams accessible at `/{stream_name}/{path}`
## Testing
### Test Suites
1. **Router Testing** (`test_router.sh`)
- Path routing verification
- Client isolation between streams
- Statistics aggregation
- Graceful shutdown
- Port conflict handling
2. **Rate Limiting Testing** (`test_ratelimit.sh`)
- Per-IP rate limiting
- Global rate limiting
- Connection limits
- Rate limit recovery
- Statistics accuracy
- Stress testing
3. **Filter Testing** (recommended)
- Pattern matching accuracy
- Include/exclude logic
- OR/AND combination logic
- Performance with complex patterns
- Filter chain behavior
### Running Tests
```bash
# Test router functionality
./test_router.sh
# Test rate limiting
./test_ratelimit.sh
# Run all tests
make test
```
## Performance Considerations
### Filter Overhead
- Regex compilation: One-time cost at startup
- Pattern matching: O(n*m) where n=patterns, m=text length
- Use simple patterns when possible
- Consider pattern order (most likely matches first)
### Rate Limiting Overhead
- Token bucket checks: O(1) time complexity
- Memory: ~100 bytes per tracked IP
- Cleanup: Runs asynchronously every minute
- Minimal impact when disabled
### Optimization Guidelines
- Use specific patterns to reduce regex complexity
- Place most selective filters first in chain
- Use per-IP limiting for fairness
- Use global limiting for resource protection
- Set burst size to 2-3x requests_per_second
- Monitor rate limit statistics for tuning
- Higher check_interval_ms for low-activity logs
## Security Architecture
### Current Security Features
- Read-only file access
- Rate limiting for DDoS protection
- Connection limits for resource protection
- Non-blocking request rejection
- Regex pattern validation at startup

155
doc/cli.md Normal file
View File

@ -0,0 +1,155 @@
# Command Line Interface
LogWisp provides a comprehensive set of command-line options for controlling its behavior without modifying configuration files.
## Synopsis
```bash
logwisp [options]
```
## General Options
### `--config <path>`
Specify the configuration file location.
- **Default**: `~/.config/logwisp.toml`
- **Example**: `logwisp --config /etc/logwisp/production.toml`
### `--router`
Enable HTTP router mode for path-based routing of multiple streams.
- **Default**: `false` (standalone mode)
- **Use case**: Consolidate multiple HTTP streams on shared ports
- **Example**: `logwisp --router`
### `--version`
Display version information and exit.
- **Example**: `logwisp --version`
### `--background`
Run LogWisp as a background process.
- **Default**: `false` (foreground mode)
- **Example**: `logwisp --background`
## Logging Options
These options override the corresponding configuration file settings.
### `--log-output <mode>`
Control where LogWisp writes its own operational logs.
- **Values**: `file`, `stdout`, `stderr`, `both`, `none`
- **Default**: Configured value or `stderr`
- **Example**: `logwisp --log-output both`
#### Output Modes:
- `file`: Write logs only to files
- `stdout`: Write logs only to standard output
- `stderr`: Write logs only to standard error
- `both`: Write logs to both files and console
- `none`: Disable logging (⚠️ SECURITY: Not recommended)
### `--log-level <level>`
Set the minimum log level for LogWisp's operational logs.
- **Values**: `debug`, `info`, `warn`, `error`
- **Default**: Configured value or `info`
- **Example**: `logwisp --log-level debug`
### `--log-file <path>`
Specify the log file path when using file output.
- **Default**: Configured value or `./logs/logwisp.log`
- **Example**: `logwisp --log-output file --log-file /var/log/logwisp/app.log`
### `--log-dir <directory>`
Specify the log directory when using file output.
- **Default**: Configured value or `./logs`
- **Example**: `logwisp --log-output file --log-dir /var/log/logwisp`
### `--log-console <target>`
Control console output destination when using `stdout`, `stderr`, or `both` modes.
- **Values**: `stdout`, `stderr`, `split`
- **Default**: `stderr`
- **Example**: `logwisp --log-output both --log-console split`
#### Console Targets:
- `stdout`: All logs to standard output
- `stderr`: All logs to standard error
- `split`: INFO/DEBUG to stdout, WARN/ERROR to stderr (planned)
## Examples
### Basic Usage
```bash
# Start with default configuration
logwisp
# Use a specific configuration file
logwisp --config /etc/logwisp/production.toml
```
### Development Mode
```bash
# Enable debug logging to console
logwisp --log-output stderr --log-level debug
# Debug with file output
logwisp --log-output both --log-level debug --log-dir ./debug-logs
```
### Production Deployment
```bash
# File logging with info level
logwisp --log-output file --log-dir /var/log/logwisp --log-level info
# Background mode with custom config
logwisp --background --config /etc/logwisp/prod.toml
# Router mode for multiple services
logwisp --router --config /etc/logwisp/services.toml
```
### Troubleshooting
```bash
# Maximum verbosity to stderr
logwisp --log-output stderr --log-level debug
# Check version
logwisp --version
# Test configuration without backgrounding
logwisp --config test.toml --log-level debug
```
## Priority Order
Configuration values are applied in the following priority order (highest to lowest):
1. **Command-line flags** - Explicitly specified options
2. **Environment variables** - `LOGWISP_*` prefixed variables
3. **Configuration file** - TOML configuration
4. **Built-in defaults** - Hardcoded fallback values
## Exit Codes
- `0`: Successful execution
- `1`: General error (configuration, startup failure)
- `2`: Invalid command-line arguments
## Signals
LogWisp responds to the following signals:
- `SIGINT` (Ctrl+C): Graceful shutdown
- `SIGTERM`: Graceful shutdown
- `SIGKILL`: Immediate termination (not recommended)
During graceful shutdown, LogWisp will:
1. Stop accepting new connections
2. Finish streaming to existing clients
3. Flush all buffers
4. Close all file handles
5. Exit cleanly
## See Also
- [Configuration Guide](configuration.md) - Complete configuration reference
- [Environment Variables](environment.md) - Environment variable options
- [Router Mode](router.md) - Path-based routing details

354
doc/configuration.md Normal file
View File

@ -0,0 +1,354 @@
# Configuration Guide
LogWisp uses TOML format for configuration with sensible defaults for all settings.
## Configuration File Location
Default search order:
1. Command line: `--config /path/to/config.toml`
2. Environment: `$LOGWISP_CONFIG_FILE`
3. User config: `~/.config/logwisp.toml`
4. Current directory: `./logwisp.toml`
## Configuration Structure
```toml
# Optional: LogWisp's own logging configuration
[logging]
output = "stderr" # file, stdout, stderr, both, none
level = "info" # debug, info, warn, error
# Required: At least one stream
[[streams]]
name = "default" # Unique identifier
[streams.monitor] # Required: What to monitor
# ... monitor settings ...
[streams.httpserver] # Optional: HTTP/SSE server
# ... HTTP settings ...
[streams.tcpserver] # Optional: TCP server
# ... TCP settings ...
[[streams.filters]] # Optional: Log filtering
# ... filter settings ...
```
## Logging Configuration
Controls LogWisp's operational logging (not the logs being monitored).
```toml
[logging]
output = "stderr" # Where to write LogWisp's logs
level = "info" # Minimum log level
# File output settings (when output includes "file")
[logging.file]
directory = "./logs" # Log directory
name = "logwisp" # Base filename
max_size_mb = 100 # Rotate at this size
max_total_size_mb = 1000 # Total size limit
retention_hours = 168 # Keep for 7 days
# Console output settings
[logging.console]
target = "stderr" # stdout, stderr, split
format = "txt" # txt or json
```
## Stream Configuration
Each `[[streams]]` section defines an independent log monitoring pipeline.
### Monitor Settings
What files or directories to watch:
```toml
[streams.monitor]
check_interval_ms = 100 # How often to check for new entries
# Monitor targets (at least one required)
targets = [
# Watch all .log files in a directory
{ path = "/var/log/myapp", pattern = "*.log", is_file = false },
# Watch a specific file
{ path = "/var/log/app.log", is_file = true },
# Multiple patterns
{ path = "/logs", pattern = "app-*.log", is_file = false },
{ path = "/logs", pattern = "error-*.txt", is_file = false }
]
```
### HTTP Server (SSE)
Server-Sent Events streaming over HTTP:
```toml
[streams.httpserver]
enabled = true
port = 8080
buffer_size = 1000 # Per-client event buffer
stream_path = "/stream" # SSE endpoint
status_path = "/status" # Statistics endpoint
# Keep-alive heartbeat
[streams.httpserver.heartbeat]
enabled = true
interval_seconds = 30
format = "comment" # "comment" or "json"
include_timestamp = true
include_stats = false
# Rate limiting (optional)
[streams.httpserver.rate_limit]
enabled = false
requests_per_second = 10.0
burst_size = 20
limit_by = "ip" # "ip" or "global"
response_code = 429
response_message = "Rate limit exceeded"
max_connections_per_ip = 5
max_total_connections = 100
```
### TCP Server
Raw TCP streaming for high performance:
```toml
[streams.tcpserver]
enabled = true
port = 9090
buffer_size = 5000 # Larger buffer for TCP
# Heartbeat (always JSON format for TCP)
[streams.tcpserver.heartbeat]
enabled = true
interval_seconds = 60
include_timestamp = true
include_stats = false
# Rate limiting
[streams.tcpserver.rate_limit]
enabled = false
requests_per_second = 5.0
burst_size = 10
limit_by = "ip"
```
### Filters
Control which log entries are streamed:
```toml
# Include filter - only matching logs pass
[[streams.filters]]
type = "include"
logic = "or" # "or" = match any, "and" = match all
patterns = [
"ERROR",
"WARN",
"CRITICAL"
]
# Exclude filter - matching logs are dropped
[[streams.filters]]
type = "exclude"
patterns = [
"DEBUG",
"health check"
]
```
## Complete Examples
### Minimal Configuration
```toml
[[streams]]
name = "simple"
[streams.monitor]
targets = [{ path = "./logs", pattern = "*.log" }]
[streams.httpserver]
enabled = true
port = 8080
```
### Production Web Application
```toml
[logging]
output = "file"
level = "info"
[logging.file]
directory = "/var/log/logwisp"
max_size_mb = 500
retention_hours = 336 # 14 days
[[streams]]
name = "webapp"
[streams.monitor]
check_interval_ms = 50
targets = [
{ path = "/var/log/nginx", pattern = "access.log*" },
{ path = "/var/log/nginx", pattern = "error.log*" },
{ path = "/var/log/myapp", pattern = "*.log" }
]
# Only errors and warnings
[[streams.filters]]
type = "include"
logic = "or"
patterns = [
"\\b(ERROR|error|Error)\\b",
"\\b(WARN|WARNING|warn|warning)\\b",
"\\b(CRITICAL|FATAL|critical|fatal)\\b",
"status=[4-5][0-9][0-9]" # HTTP errors
]
# Exclude noise
[[streams.filters]]
type = "exclude"
patterns = [
"/health",
"/metrics",
"ELB-HealthChecker"
]
[streams.httpserver]
enabled = true
port = 8080
buffer_size = 2000
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 25.0
burst_size = 50
max_connections_per_ip = 10
```
### Multi-Service with Router
```toml
# Run with: logwisp --router
# Service 1: API
[[streams]]
name = "api"
[streams.monitor]
targets = [{ path = "/var/log/api", pattern = "*.log" }]
[streams.httpserver]
enabled = true
port = 8080 # All streams can use same port in router mode
# Service 2: Database
[[streams]]
name = "database"
[streams.monitor]
targets = [{ path = "/var/log/postgresql", pattern = "*.log" }]
[[streams.filters]]
type = "include"
patterns = ["ERROR", "FATAL", "deadlock", "timeout"]
[streams.httpserver]
enabled = true
port = 8080
# Service 3: System
[[streams]]
name = "system"
[streams.monitor]
targets = [
{ path = "/var/log/syslog", is_file = true },
{ path = "/var/log/auth.log", is_file = true }
]
[streams.tcpserver]
enabled = true
port = 9090
```
### High-Security Configuration
```toml
[logging]
output = "file"
level = "warn" # Less verbose
[[streams]]
name = "secure"
[streams.monitor]
targets = [{ path = "/var/log/secure", pattern = "*.log" }]
# Only security events
[[streams.filters]]
type = "include"
patterns = [
"auth",
"sudo",
"ssh",
"login",
"failed",
"denied"
]
[streams.httpserver]
enabled = true
port = 8443
# Strict rate limiting
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 2.0
burst_size = 3
limit_by = "ip"
max_connections_per_ip = 1
response_code = 403 # Forbidden instead of 429
# Future: Authentication
# [streams.auth]
# type = "basic"
# [streams.auth.basic_auth]
# users_file = "/etc/logwisp/users.htpasswd"
```
## Configuration Tips
### Performance Tuning
- **check_interval_ms**: Higher values reduce CPU usage
- **buffer_size**: Larger buffers handle bursts better
- **rate_limit**: Essential for public-facing streams
### Filter Patterns
- Use word boundaries: `\\berror\\b` (won't match "errorCode")
- Case-insensitive: `(?i)error`
- Anchors for speed: `^ERROR` faster than `ERROR`
- Test complex patterns before deployment
### Resource Limits
- Each stream uses ~10-50MB RAM (depending on buffers)
- CPU usage scales with check_interval and file activity
- Network bandwidth depends on log volume and client count
## Validation
LogWisp validates configuration on startup:
- Required fields (name, monitor targets)
- Port conflicts between streams
- Pattern syntax for filters
- Path accessibility
## See Also
- [Environment Variables](environment.md) - Override via environment
- [CLI Options](cli.md) - Override via command line
- [Filter Guide](filters.md) - Advanced filtering patterns
- [Examples](examples/) - Ready-to-use configurations

275
doc/environment.md Normal file
View File

@ -0,0 +1,275 @@
# Environment Variables
LogWisp supports comprehensive configuration through environment variables, allowing deployment without configuration files or dynamic overrides in containerized environments.
## Naming Convention
Environment variables follow a structured pattern:
- **Prefix**: `LOGWISP_`
- **Path separator**: `_` (underscore)
- **Array indices**: Numeric suffix (0-based)
- **Case**: UPPERCASE
### Examples:
- Config file setting: `logging.level = "debug"`
- Environment variable: `LOGWISP_LOGGING_LEVEL=debug`
- Array element: `streams[0].name = "app"`
- Environment variable: `LOGWISP_STREAMS_0_NAME=app`
## General Variables
### `LOGWISP_CONFIG_FILE`
Path to the configuration file.
- **Default**: `~/.config/logwisp.toml`
- **Example**: `LOGWISP_CONFIG_FILE=/etc/logwisp/config.toml`
### `LOGWISP_CONFIG_DIR`
Directory containing configuration files.
- **Usage**: Combined with `LOGWISP_CONFIG_FILE` for relative paths
- **Example**:
```bash
export LOGWISP_CONFIG_DIR=/etc/logwisp
export LOGWISP_CONFIG_FILE=production.toml
# Loads: /etc/logwisp/production.toml
```
### `LOGWISP_DISABLE_STATUS_REPORTER`
Disable the periodic status reporter.
- **Values**: `1` (disable), `0` or unset (enable)
- **Default**: `0` (enabled)
- **Example**: `LOGWISP_DISABLE_STATUS_REPORTER=1`
### `LOGWISP_BACKGROUND`
Internal marker for background process detection.
- **Note**: Set automatically by `--background` flag
- **Values**: `1` (background), unset (foreground)
## Logging Variables
### `LOGWISP_LOGGING_OUTPUT`
LogWisp's operational log output mode.
- **Values**: `file`, `stdout`, `stderr`, `both`, `none`
- **Example**: `LOGWISP_LOGGING_OUTPUT=both`
### `LOGWISP_LOGGING_LEVEL`
Minimum log level for operational logs.
- **Values**: `debug`, `info`, `warn`, `error`
- **Example**: `LOGWISP_LOGGING_LEVEL=debug`
### File Logging
```bash
LOGWISP_LOGGING_FILE_DIRECTORY=/var/log/logwisp
LOGWISP_LOGGING_FILE_NAME=logwisp
LOGWISP_LOGGING_FILE_MAX_SIZE_MB=100
LOGWISP_LOGGING_FILE_MAX_TOTAL_SIZE_MB=1000
LOGWISP_LOGGING_FILE_RETENTION_HOURS=168 # 7 days
```
### Console Logging
```bash
LOGWISP_LOGGING_CONSOLE_TARGET=stderr # stdout, stderr, split
LOGWISP_LOGGING_CONSOLE_FORMAT=txt # txt, json
```
## Stream Configuration
Streams are configured using array indices (0-based).
### Basic Stream Settings
```bash
# First stream (index 0)
LOGWISP_STREAMS_0_NAME=app
LOGWISP_STREAMS_0_MONITOR_CHECK_INTERVAL_MS=100
# Second stream (index 1)
LOGWISP_STREAMS_1_NAME=system
LOGWISP_STREAMS_1_MONITOR_CHECK_INTERVAL_MS=1000
```
### Monitor Targets
```bash
# Single file target
LOGWISP_STREAMS_0_MONITOR_TARGETS_0_PATH=/var/log/app.log
LOGWISP_STREAMS_0_MONITOR_TARGETS_0_IS_FILE=true
# Directory with pattern
LOGWISP_STREAMS_0_MONITOR_TARGETS_1_PATH=/var/log/myapp
LOGWISP_STREAMS_0_MONITOR_TARGETS_1_PATTERN="*.log"
LOGWISP_STREAMS_0_MONITOR_TARGETS_1_IS_FILE=false
```
### Filters
```bash
# Include filter
LOGWISP_STREAMS_0_FILTERS_0_TYPE=include
LOGWISP_STREAMS_0_FILTERS_0_LOGIC=or
LOGWISP_STREAMS_0_FILTERS_0_PATTERNS='["ERROR","WARN","CRITICAL"]'
# Exclude filter
LOGWISP_STREAMS_0_FILTERS_1_TYPE=exclude
LOGWISP_STREAMS_0_FILTERS_1_PATTERNS='["DEBUG","TRACE"]'
```
### HTTP Server
```bash
LOGWISP_STREAMS_0_HTTPSERVER_ENABLED=true
LOGWISP_STREAMS_0_HTTPSERVER_PORT=8080
LOGWISP_STREAMS_0_HTTPSERVER_BUFFER_SIZE=1000
LOGWISP_STREAMS_0_HTTPSERVER_STREAM_PATH=/stream
LOGWISP_STREAMS_0_HTTPSERVER_STATUS_PATH=/status
# Heartbeat
LOGWISP_STREAMS_0_HTTPSERVER_HEARTBEAT_ENABLED=true
LOGWISP_STREAMS_0_HTTPSERVER_HEARTBEAT_INTERVAL_SECONDS=30
LOGWISP_STREAMS_0_HTTPSERVER_HEARTBEAT_FORMAT=comment
LOGWISP_STREAMS_0_HTTPSERVER_HEARTBEAT_INCLUDE_TIMESTAMP=true
LOGWISP_STREAMS_0_HTTPSERVER_HEARTBEAT_INCLUDE_STATS=false
# Rate Limiting
LOGWISP_STREAMS_0_HTTPSERVER_RATE_LIMIT_ENABLED=true
LOGWISP_STREAMS_0_HTTPSERVER_RATE_LIMIT_REQUESTS_PER_SECOND=10.0
LOGWISP_STREAMS_0_HTTPSERVER_RATE_LIMIT_BURST_SIZE=20
LOGWISP_STREAMS_0_HTTPSERVER_RATE_LIMIT_LIMIT_BY=ip
LOGWISP_STREAMS_0_HTTPSERVER_RATE_LIMIT_MAX_CONNECTIONS_PER_IP=5
```
### TCP Server
```bash
LOGWISP_STREAMS_0_TCPSERVER_ENABLED=true
LOGWISP_STREAMS_0_TCPSERVER_PORT=9090
LOGWISP_STREAMS_0_TCPSERVER_BUFFER_SIZE=5000
# Rate Limiting
LOGWISP_STREAMS_0_TCPSERVER_RATE_LIMIT_ENABLED=true
LOGWISP_STREAMS_0_TCPSERVER_RATE_LIMIT_REQUESTS_PER_SECOND=5.0
LOGWISP_STREAMS_0_TCPSERVER_RATE_LIMIT_BURST_SIZE=10
```
## Complete Example
Here's a complete example configuring two streams via environment variables:
```bash
#!/bin/bash
# Logging configuration
export LOGWISP_LOGGING_OUTPUT=both
export LOGWISP_LOGGING_LEVEL=info
export LOGWISP_LOGGING_FILE_DIRECTORY=/var/log/logwisp
export LOGWISP_LOGGING_FILE_MAX_SIZE_MB=100
# Stream 0: Application logs
export LOGWISP_STREAMS_0_NAME=app
export LOGWISP_STREAMS_0_MONITOR_CHECK_INTERVAL_MS=50
export LOGWISP_STREAMS_0_MONITOR_TARGETS_0_PATH=/var/log/myapp
export LOGWISP_STREAMS_0_MONITOR_TARGETS_0_PATTERN="*.log"
export LOGWISP_STREAMS_0_MONITOR_TARGETS_0_IS_FILE=false
# Stream 0: Filters
export LOGWISP_STREAMS_0_FILTERS_0_TYPE=include
export LOGWISP_STREAMS_0_FILTERS_0_PATTERNS='["ERROR","WARN"]'
# Stream 0: HTTP server
export LOGWISP_STREAMS_0_HTTPSERVER_ENABLED=true
export LOGWISP_STREAMS_0_HTTPSERVER_PORT=8080
export LOGWISP_STREAMS_0_HTTPSERVER_RATE_LIMIT_ENABLED=true
export LOGWISP_STREAMS_0_HTTPSERVER_RATE_LIMIT_REQUESTS_PER_SECOND=25.0
# Stream 1: System logs
export LOGWISP_STREAMS_1_NAME=system
export LOGWISP_STREAMS_1_MONITOR_CHECK_INTERVAL_MS=1000
export LOGWISP_STREAMS_1_MONITOR_TARGETS_0_PATH=/var/log/syslog
export LOGWISP_STREAMS_1_MONITOR_TARGETS_0_IS_FILE=true
# Stream 1: TCP server
export LOGWISP_STREAMS_1_TCPSERVER_ENABLED=true
export LOGWISP_STREAMS_1_TCPSERVER_PORT=9090
# Start LogWisp
logwisp
```
## Docker/Kubernetes Usage
Environment variables are ideal for containerized deployments:
### Docker
```dockerfile
FROM logwisp:latest
ENV LOGWISP_LOGGING_OUTPUT=stdout
ENV LOGWISP_STREAMS_0_NAME=container
ENV LOGWISP_STREAMS_0_MONITOR_TARGETS_0_PATH=/var/log/app
ENV LOGWISP_STREAMS_0_HTTPSERVER_PORT=8080
```
### Docker Compose
```yaml
version: '3'
services:
logwisp:
image: logwisp:latest
environment:
- LOGWISP_LOGGING_OUTPUT=stdout
- LOGWISP_STREAMS_0_NAME=webapp
- LOGWISP_STREAMS_0_MONITOR_TARGETS_0_PATH=/logs
- LOGWISP_STREAMS_0_HTTPSERVER_PORT=8080
volumes:
- ./logs:/logs:ro
ports:
- "8080:8080"
```
### Kubernetes ConfigMap
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: logwisp-config
data:
LOGWISP_LOGGING_LEVEL: "info"
LOGWISP_STREAMS_0_NAME: "k8s-app"
LOGWISP_STREAMS_0_HTTPSERVER_PORT: "8080"
```
## Precedence Rules
When the same setting is configured multiple ways, this precedence applies:
1. **Command-line flags** (highest priority)
2. **Environment variables**
3. **Configuration file**
4. **Default values** (lowest priority)
Example:
```bash
# Config file has: logging.level = "info"
export LOGWISP_LOGGING_LEVEL=warn
logwisp --log-level debug
# Result: log level will be "debug" (CLI flag wins)
```
## Debugging
To see which environment variables LogWisp recognizes:
```bash
# List all LOGWISP variables
env | grep ^LOGWISP_
# Test configuration parsing
LOGWISP_LOGGING_LEVEL=debug logwisp --version
```
## Security Considerations
- **Sensitive Values**: Avoid putting passwords or tokens in environment variables
- **Process Visibility**: Environment variables may be visible to other processes
- **Container Security**: Use secrets management for sensitive configuration
- **Logging**: Be careful not to log environment variable values
## See Also
- [Configuration Guide](configuration.md) - Complete configuration reference
- [CLI Options](cli.md) - Command-line interface
- [Docker Deployment](integrations.md#docker) - Container-specific guidance

439
doc/filters.md Normal file
View File

@ -0,0 +1,439 @@
# Filter Guide
LogWisp's filtering system allows you to control which log entries are streamed to clients, reducing noise and focusing on what matters.
## How Filters Work
Filters use regular expressions to match log entries. Each filter can either:
- **Include**: Only matching logs pass through (whitelist)
- **Exclude**: Matching logs are dropped (blacklist)
Multiple filters are applied sequentially - a log entry must pass ALL filters to be streamed.
## Filter Configuration
### Basic Structure
```toml
[[streams.filters]]
type = "include" # or "exclude"
logic = "or" # or "and"
patterns = [
"pattern1",
"pattern2"
]
```
### Filter Types
#### Include Filter (Whitelist)
Only logs matching the patterns are streamed:
```toml
[[streams.filters]]
type = "include"
logic = "or"
patterns = [
"ERROR",
"WARN",
"CRITICAL"
]
# Result: Only ERROR, WARN, or CRITICAL logs are streamed
```
#### Exclude Filter (Blacklist)
Logs matching the patterns are dropped:
```toml
[[streams.filters]]
type = "exclude"
patterns = [
"DEBUG",
"TRACE",
"/health"
]
# Result: DEBUG, TRACE, and health check logs are filtered out
```
### Logic Operators
#### OR Logic (Default)
Log matches if ANY pattern matches:
```toml
[[streams.filters]]
type = "include"
logic = "or"
patterns = ["ERROR", "FAIL", "EXCEPTION"]
# Matches: "ERROR: disk full" OR "FAIL: connection timeout" OR "NullPointerException"
```
#### AND Logic
Log matches only if ALL patterns match:
```toml
[[streams.filters]]
type = "include"
logic = "and"
patterns = ["database", "timeout", "ERROR"]
# Matches: "ERROR: database connection timeout"
# Doesn't match: "ERROR: file not found" (missing "database" and "timeout")
```
## Pattern Syntax
LogWisp uses Go's regular expression syntax (RE2):
### Basic Patterns
```toml
patterns = [
"ERROR", # Exact substring match
"(?i)error", # Case-insensitive
"\\berror\\b", # Word boundaries
"^ERROR", # Start of line
"ERROR$", # End of line
"ERR(OR)?", # Optional group
"error|fail|exception" # Alternatives
]
```
### Common Pattern Examples
#### Log Levels
```toml
# Standard log levels
patterns = [
"\\[(ERROR|WARN|INFO|DEBUG)\\]", # [ERROR] format
"(?i)\\b(error|warning|info|debug)\\b", # Word boundaries
"level=(error|warn|info|debug)", # key=value format
"<(Error|Warning|Info|Debug)>" # XML-style
]
# Severity patterns
patterns = [
"(?i)(fatal|critical|severe)",
"(?i)(error|fail|exception)",
"(?i)(warn|warning|caution)",
"panic:", # Go panics
"Traceback", # Python errors
]
```
#### Application Errors
```toml
# Java/JVM
patterns = [
"Exception",
"\\.java:[0-9]+", # Stack trace lines
"at com\\.mycompany\\.", # Company packages
"NullPointerException|ClassNotFoundException"
]
# Python
patterns = [
"Traceback \\(most recent call last\\)",
"File \".+\\.py\", line [0-9]+",
"(ValueError|TypeError|KeyError)"
]
# Go
patterns = [
"panic:",
"goroutine [0-9]+",
"runtime error:"
]
# Node.js
patterns = [
"Error:",
"at .+ \\(.+\\.js:[0-9]+:[0-9]+\\)",
"UnhandledPromiseRejection"
]
```
#### Performance Issues
```toml
patterns = [
"took [0-9]{4,}ms", # Operations over 999ms
"duration>[0-9]{3,}s", # Long durations
"timeout|timed out", # Timeouts
"slow query", # Database
"memory pressure", # Memory issues
"high cpu|cpu usage: [8-9][0-9]%" # CPU issues
]
```
#### Security Patterns
```toml
patterns = [
"(?i)(unauthorized|forbidden|denied)",
"(?i)(auth|authentication) fail",
"invalid (token|session|credentials)",
"SQL injection|XSS|CSRF",
"brute force|rate limit",
"suspicious activity"
]
```
#### HTTP Patterns
```toml
# Error status codes
patterns = [
"status[=:][4-5][0-9]{2}", # status=404, status:500
"HTTP/[0-9.]+ [4-5][0-9]{2}", # HTTP/1.1 404
"\"status\":\\s*[4-5][0-9]{2}" # JSON "status": 500
]
# Specific endpoints
patterns = [
"\"(GET|POST|PUT|DELETE) /api/",
"/api/v[0-9]+/users",
"path=\"/admin"
]
```
## Filter Chains
Multiple filters create a processing chain. Each filter must pass for the log to be streamed.
### Example: Error Monitoring
```toml
# Step 1: Include only errors and warnings
[[streams.filters]]
type = "include"
logic = "or"
patterns = [
"(?i)\\b(error|fail|exception)\\b",
"(?i)\\b(warn|warning)\\b",
"(?i)\\b(critical|fatal|severe)\\b"
]
# Step 2: Exclude known non-issues
[[streams.filters]]
type = "exclude"
patterns = [
"Error: Expected behavior",
"Warning: Deprecated API",
"INFO.*error in message" # INFO logs talking about errors
]
# Step 3: Exclude noisy sources
[[streams.filters]]
type = "exclude"
patterns = [
"/health",
"/metrics",
"ELB-HealthChecker",
"Googlebot"
]
```
### Example: API Monitoring
```toml
# Include only API calls
[[streams.filters]]
type = "include"
patterns = [
"/api/",
"/v[0-9]+/"
]
# Exclude successful requests
[[streams.filters]]
type = "exclude"
patterns = [
"\" 200 ", # HTTP 200 OK
"\" 201 ", # HTTP 201 Created
"\" 204 ", # HTTP 204 No Content
"\" 304 " # HTTP 304 Not Modified
]
# Exclude OPTIONS requests (CORS)
[[streams.filters]]
type = "exclude"
patterns = [
"OPTIONS "
]
```
### Example: Security Audit
```toml
# Include security-relevant events
[[streams.filters]]
type = "include"
logic = "or"
patterns = [
"(?i)auth",
"(?i)login|logout",
"(?i)sudo|root",
"(?i)ssh|sftp|ftp",
"(?i)firewall|iptables",
"COMMAND=", # sudo commands
"USER=", # user actions
"SELINUX"
]
# Must also contain failure/success indicators
[[streams.filters]]
type = "include"
logic = "or"
patterns = [
"(?i)(fail|denied|error)",
"(?i)(success|accepted|granted)",
"(?i)(invalid|unauthorized)"
]
```
## Performance Considerations
### Pattern Complexity
Simple patterns are fast (~1μs per check):
```toml
patterns = ["ERROR", "WARN", "FATAL"]
```
Complex patterns are slower (~10-100μs per check):
```toml
patterns = [
"^\\[\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\]\\s+\\[(ERROR|WARN)\\]\\s+\\[([^\\]]+)\\]\\s+(.+)$"
]
```
### Optimization Tips
1. **Use anchors when possible**:
```toml
"^ERROR" # Faster than "ERROR"
```
2. **Avoid nested quantifiers**:
```toml
# BAD: Can cause exponential backtracking
"((a+)+)+"
# GOOD: Linear time
"a+"
```
3. **Use non-capturing groups**:
```toml
"(?:error|warn)" # Instead of "(error|warn)"
```
4. **Order patterns by frequency**:
```toml
# Most common first
patterns = ["ERROR", "WARN", "INFO", "DEBUG"]
```
5. **Prefer character classes**:
```toml
"[0-9]" # Instead of "\\d"
"[a-zA-Z]" # Instead of "\\w"
```
## Testing Filters
### Test Configuration
Create a test configuration with sample logs:
```toml
[[streams]]
name = "test"
[streams.monitor]
targets = [{ path = "./test-logs", pattern = "*.log" }]
[[streams.filters]]
type = "include"
patterns = ["YOUR_PATTERN_HERE"]
[streams.httpserver]
enabled = true
port = 8888
```
### Generate Test Logs
```bash
# Create test log entries
echo "[ERROR] Database connection failed" >> test-logs/app.log
echo "[INFO] User logged in" >> test-logs/app.log
echo "[WARN] High memory usage: 85%" >> test-logs/app.log
# Run LogWisp with debug logging
logwisp --config test.toml --log-level debug
# Check what passes through
curl -N http://localhost:8888/stream
```
### Debug Filter Behavior
Enable debug logging to see filter decisions:
```bash
logwisp --log-level debug --log-output stderr
```
Look for messages like:
```
Entry filtered out component=filter_chain filter_index=0 filter_type=include
Entry passed all filters component=filter_chain
```
## Common Pitfalls
### Case Sensitivity
By default, patterns are case-sensitive:
```toml
# Won't match "error" or "Error"
patterns = ["ERROR"]
# Use case-insensitive flag
patterns = ["(?i)error"]
```
### Partial Matches
Patterns match substrings by default:
```toml
# Matches "ERROR", "ERRORS", "TERROR"
patterns = ["ERROR"]
# Use word boundaries for exact words
patterns = ["\\bERROR\\b"]
```
### Special Characters
Remember to escape regex special characters:
```toml
# Won't work as expected
patterns = ["[ERROR]"]
# Correct: escape brackets
patterns = ["\\[ERROR\\]"]
```
### Performance Impact
Too many complex patterns can impact performance:
```toml
# Consider splitting into multiple streams instead
[[streams.filters]]
patterns = [
# 50+ complex patterns...
]
```
## Best Practices
1. **Start Simple**: Begin with basic patterns and refine as needed
2. **Test Thoroughly**: Use test logs to verify filter behavior
3. **Monitor Performance**: Check filter statistics in `/status`
4. **Document Patterns**: Comment complex patterns for maintenance
5. **Use Multiple Streams**: Instead of complex filters, consider separate streams
6. **Regular Review**: Periodically review and optimize filter rules
## See Also
- [Configuration Guide](configuration.md) - Complete configuration reference
- [Performance Tuning](performance.md) - Optimization guidelines
- [Examples](examples/) - Real-world filter configurations

591
doc/installation.md Normal file
View File

@ -0,0 +1,591 @@
# Installation Guide
This guide covers installing LogWisp on various platforms and deployment scenarios.
## Requirements
### System Requirements
- **OS**: Linux, macOS, FreeBSD, Windows (with WSL)
- **Architecture**: amd64, arm64
- **Memory**: 64MB minimum, 256MB recommended
- **Disk**: 10MB for binary, plus log storage
- **Go**: 1.23+ (for building from source)
### Runtime Dependencies
LogWisp is a single static binary with no runtime dependencies. It only requires:
- Read access to monitored log files
- Network access for serving streams
- Write access for operational logs (optional)
## Installation Methods
### Pre-built Binaries
Download the latest release:
```bash
# Linux (amd64)
wget https://github.com/yourusername/logwisp/releases/latest/download/logwisp-linux-amd64
chmod +x logwisp-linux-amd64
sudo mv logwisp-linux-amd64 /usr/local/bin/logwisp
# macOS (Intel)
wget https://github.com/yourusername/logwisp/releases/latest/download/logwisp-darwin-amd64
chmod +x logwisp-darwin-amd64
sudo mv logwisp-darwin-amd64 /usr/local/bin/logwisp
# macOS (Apple Silicon)
wget https://github.com/yourusername/logwisp/releases/latest/download/logwisp-darwin-arm64
chmod +x logwisp-darwin-arm64
sudo mv logwisp-darwin-arm64 /usr/local/bin/logwisp
```
Verify installation:
```bash
logwisp --version
```
### From Source
Build from source code:
```bash
# Clone repository
git clone https://github.com/yourusername/logwisp.git
cd logwisp
# Build
make build
# Install
sudo make install
# Or install to custom location
make install PREFIX=/opt/logwisp
```
### Using Go Install
Install directly with Go:
```bash
go install github.com/yourusername/logwisp/src/cmd/logwisp@latest
```
Note: This installs to `$GOPATH/bin` (usually `~/go/bin`)
### Docker
Official Docker image:
```bash
# Pull image
docker pull yourusername/logwisp:latest
# Run with volume mount
docker run -d \
--name logwisp \
-p 8080:8080 \
-v /var/log:/logs:ro \
-v $PWD/config.toml:/config/logwisp.toml:ro \
yourusername/logwisp:latest \
--config /config/logwisp.toml
```
Build your own image:
```dockerfile
FROM golang:1.23-alpine AS builder
WORKDIR /build
COPY . .
RUN go build -o logwisp ./src/cmd/logwisp
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /build/logwisp /usr/local/bin/
ENTRYPOINT ["logwisp"]
```
## Platform-Specific Instructions
### Linux
#### Debian/Ubuntu
Create package (planned):
```bash
# Future feature
sudo apt install logwisp
```
Manual installation:
```bash
# Download binary
wget https://github.com/yourusername/logwisp/releases/latest/download/logwisp-linux-amd64 -O logwisp
chmod +x logwisp
sudo mv logwisp /usr/local/bin/
# Create config directory
sudo mkdir -p /etc/logwisp
sudo cp config/logwisp.toml.example /etc/logwisp/logwisp.toml
# Create systemd service
sudo tee /etc/systemd/system/logwisp.service << EOF
[Unit]
Description=LogWisp Log Monitoring Service
After=network.target
[Service]
Type=simple
User=logwisp
Group=logwisp
ExecStart=/usr/local/bin/logwisp --config /etc/logwisp/logwisp.toml
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=logwisp
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadOnlyPaths=/var/log
ReadWritePaths=/var/log/logwisp
[Install]
WantedBy=multi-user.target
EOF
# Create user
sudo useradd -r -s /bin/false logwisp
# Create log directory
sudo mkdir -p /var/log/logwisp
sudo chown logwisp:logwisp /var/log/logwisp
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable logwisp
sudo systemctl start logwisp
```
#### Red Hat/CentOS/Fedora
```bash
# Similar to Debian, but use:
sudo yum install wget # or dnf on newer versions
# SELinux context (if enabled)
sudo semanage fcontext -a -t bin_t /usr/local/bin/logwisp
sudo restorecon -v /usr/local/bin/logwisp
```
#### Arch Linux
AUR package (community maintained):
```bash
# Future feature
yay -S logwisp
```
### macOS
#### Homebrew
Formula (planned):
```bash
# Future feature
brew install logwisp
```
#### Manual Installation
```bash
# Download and install
curl -L https://github.com/yourusername/logwisp/releases/latest/download/logwisp-darwin-$(uname -m) -o logwisp
chmod +x logwisp
sudo mv logwisp /usr/local/bin/
# Create LaunchDaemon
sudo tee /Library/LaunchDaemons/com.logwisp.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.logwisp</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/logwisp</string>
<string>--config</string>
<string>/usr/local/etc/logwisp/logwisp.toml</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/usr/local/var/log/logwisp.log</string>
<key>StandardErrorPath</key>
<string>/usr/local/var/log/logwisp.error.log</string>
</dict>
</plist>
EOF
# Load service
sudo launchctl load /Library/LaunchDaemons/com.logwisp.plist
```
### FreeBSD
#### Ports
```bash
# Future feature
cd /usr/ports/sysutils/logwisp
make install clean
```
#### Manual Installation
```bash
# Download
fetch https://github.com/yourusername/logwisp/releases/latest/download/logwisp-freebsd-amd64
chmod +x logwisp-freebsd-amd64
mv logwisp-freebsd-amd64 /usr/local/bin/logwisp
# RC script
cat > /usr/local/etc/rc.d/logwisp << 'EOF'
#!/bin/sh
# PROVIDE: logwisp
# REQUIRE: DAEMON
# KEYWORD: shutdown
. /etc/rc.subr
name="logwisp"
rcvar="${name}_enable"
command="/usr/local/bin/logwisp"
command_args="--config /usr/local/etc/logwisp/logwisp.toml"
pidfile="/var/run/${name}.pid"
load_rc_config $name
: ${logwisp_enable:="NO"}
run_rc_command "$1"
EOF
chmod +x /usr/local/etc/rc.d/logwisp
# Enable
sysrc logwisp_enable="YES"
service logwisp start
```
### Windows
#### Windows Subsystem for Linux (WSL)
```bash
# Inside WSL, follow Linux instructions
wget https://github.com/yourusername/logwisp/releases/latest/download/logwisp-linux-amd64
chmod +x logwisp-linux-amd64
./logwisp-linux-amd64
```
#### Native Windows (planned)
Future support for native Windows service.
## Container Deployment
### Docker Compose
```yaml
version: '3.8'
services:
logwisp:
image: yourusername/logwisp:latest
container_name: logwisp
restart: unless-stopped
ports:
- "8080:8080"
- "9090:9090" # If using TCP
volumes:
- /var/log:/logs:ro
- ./logwisp.toml:/config/logwisp.toml:ro
command: ["--config", "/config/logwisp.toml"]
environment:
- LOGWISP_LOGGING_LEVEL=info
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/status"]
interval: 30s
timeout: 3s
retries: 3
```
### Kubernetes
Deployment manifest:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: logwisp
labels:
app: logwisp
spec:
replicas: 1
selector:
matchLabels:
app: logwisp
template:
metadata:
labels:
app: logwisp
spec:
containers:
- name: logwisp
image: yourusername/logwisp:latest
args:
- --config
- /config/logwisp.toml
ports:
- containerPort: 8080
name: http
- containerPort: 9090
name: tcp
volumeMounts:
- name: logs
mountPath: /logs
readOnly: true
- name: config
mountPath: /config
livenessProbe:
httpGet:
path: /status
port: 8080
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /status
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
volumes:
- name: logs
hostPath:
path: /var/log
- name: config
configMap:
name: logwisp-config
---
apiVersion: v1
kind: Service
metadata:
name: logwisp
spec:
selector:
app: logwisp
ports:
- name: http
port: 8080
targetPort: 8080
- name: tcp
port: 9090
targetPort: 9090
---
apiVersion: v1
kind: ConfigMap
metadata:
name: logwisp-config
data:
logwisp.toml: |
[[streams]]
name = "k8s"
[streams.monitor]
targets = [{ path = "/logs", pattern = "*.log" }]
[streams.httpserver]
enabled = true
port = 8080
```
## Post-Installation
### Verify Installation
1. Check version:
```bash
logwisp --version
```
2. Test configuration:
```bash
logwisp --config /etc/logwisp/logwisp.toml --log-level debug
```
3. Check service status:
```bash
# systemd
sudo systemctl status logwisp
# macOS
sudo launchctl list | grep logwisp
# FreeBSD
service logwisp status
```
4. Test streaming:
```bash
curl -N http://localhost:8080/stream
```
### Security Hardening
1. **Create dedicated user**:
```bash
sudo useradd -r -s /bin/false -d /var/lib/logwisp logwisp
```
2. **Set file permissions**:
```bash
sudo chown root:root /usr/local/bin/logwisp
sudo chmod 755 /usr/local/bin/logwisp
sudo chown -R logwisp:logwisp /etc/logwisp
sudo chmod 640 /etc/logwisp/logwisp.toml
```
3. **Configure firewall**:
```bash
# UFW
sudo ufw allow 8080/tcp comment "LogWisp HTTP"
# firewalld
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
```
4. **Enable SELinux/AppArmor** (if applicable)
### Initial Configuration
1. Copy example configuration:
```bash
sudo cp /usr/local/share/logwisp/examples/logwisp.toml.example /etc/logwisp/logwisp.toml
```
2. Edit configuration:
```bash
sudo nano /etc/logwisp/logwisp.toml
```
3. Set up log monitoring:
```toml
[[streams]]
name = "myapp"
[streams.monitor]
targets = [
{ path = "/var/log/myapp", pattern = "*.log" }
]
```
4. Restart service:
```bash
sudo systemctl restart logwisp
```
## Uninstallation
### Linux
```bash
# Stop service
sudo systemctl stop logwisp
sudo systemctl disable logwisp
# Remove files
sudo rm /usr/local/bin/logwisp
sudo rm /etc/systemd/system/logwisp.service
sudo rm -rf /etc/logwisp
sudo rm -rf /var/log/logwisp
# Remove user
sudo userdel logwisp
```
### macOS
```bash
# Stop service
sudo launchctl unload /Library/LaunchDaemons/com.logwisp.plist
# Remove files
sudo rm /usr/local/bin/logwisp
sudo rm /Library/LaunchDaemons/com.logwisp.plist
sudo rm -rf /usr/local/etc/logwisp
```
### Docker
```bash
docker stop logwisp
docker rm logwisp
docker rmi yourusername/logwisp:latest
```
## Troubleshooting Installation
### Permission Denied
If you get permission errors:
```bash
# Check file ownership
ls -la /usr/local/bin/logwisp
# Fix permissions
sudo chmod +x /usr/local/bin/logwisp
# Check log directory
sudo mkdir -p /var/log/logwisp
sudo chown logwisp:logwisp /var/log/logwisp
```
### Service Won't Start
Check logs:
```bash
# systemd
sudo journalctl -u logwisp -f
# Manual run
sudo -u logwisp /usr/local/bin/logwisp --config /etc/logwisp/logwisp.toml
```
### Port Already in Use
Find conflicting process:
```bash
sudo lsof -i :8080
# or
sudo netstat -tlnp | grep 8080
```
## See Also
- [Quick Start](quickstart.md) - Get running quickly
- [Configuration Guide](configuration.md) - Configure LogWisp
- [Troubleshooting](troubleshooting.md) - Common issues
- [Security Best Practices](security.md) - Hardening guide

511
doc/monitoring.md Normal file
View File

@ -0,0 +1,511 @@
# Monitoring & Status Guide
LogWisp provides comprehensive monitoring capabilities through status endpoints, operational logs, and metrics.
## Status Endpoints
### Stream Status
Each stream exposes its own status endpoint:
```bash
# Standalone mode
curl http://localhost:8080/status
# Router mode
curl http://localhost:8080/streamname/status
```
Example response:
```json
{
"service": "LogWisp",
"version": "1.0.0",
"server": {
"type": "http",
"port": 8080,
"active_clients": 5,
"buffer_size": 1000,
"uptime_seconds": 3600,
"mode": {
"standalone": true,
"router": false
}
},
"monitor": {
"active_watchers": 3,
"total_entries": 152341,
"dropped_entries": 12,
"start_time": "2024-01-20T10:00:00Z",
"last_entry_time": "2024-01-20T11:00:00Z"
},
"filters": {
"filter_count": 2,
"total_processed": 152341,
"total_passed": 48234,
"filters": [
{
"type": "include",
"logic": "or",
"pattern_count": 3,
"total_processed": 152341,
"total_matched": 48234,
"total_dropped": 0
}
]
},
"features": {
"heartbeat": {
"enabled": true,
"interval": 30,
"format": "comment"
},
"rate_limit": {
"enabled": true,
"total_requests": 8234,
"blocked_requests": 89,
"active_ips": 12,
"total_connections": 5
}
}
}
```
### Global Status (Router Mode)
In router mode, a global status endpoint provides aggregated information:
```bash
curl http://localhost:8080/status
```
## Key Metrics
### Monitor Metrics
Track file watching performance:
| Metric | Description | Healthy Range |
|--------|-------------|---------------|
| `active_watchers` | Number of files being watched | 1-1000 |
| `total_entries` | Total log entries processed | Increasing |
| `dropped_entries` | Entries dropped due to buffer full | < 1% of total |
| `entries_per_second` | Current processing rate | Varies |
### Connection Metrics
Monitor client connections:
| Metric | Description | Warning Signs |
|--------|-------------|---------------|
| `active_clients` | Current SSE connections | Near limit |
| `tcp_connections` | Current TCP connections | Near limit |
| `total_connections` | All active connections | > 80% of max |
### Filter Metrics
Understand filtering effectiveness:
| Metric | Description | Optimization |
|--------|-------------|--------------|
| `total_processed` | Entries checked | - |
| `total_passed` | Entries that passed | Very low = too restrictive |
| `total_dropped` | Entries filtered out | Very high = review patterns |
### Rate Limit Metrics
Track rate limiting impact:
| Metric | Description | Action Needed |
|--------|-------------|---------------|
| `blocked_requests` | Rejected requests | High = increase limits |
| `active_ips` | Unique clients | High = scale out |
| `blocked_percentage` | Rejection rate | > 10% = review |
## Operational Logging
### Log Levels
Configure LogWisp's operational logging:
```toml
[logging]
output = "both" # file and stderr
level = "info" # info for production
```
Log levels and their use:
- **DEBUG**: Detailed internal operations
- **INFO**: Normal operations, connections
- **WARN**: Recoverable issues
- **ERROR**: Errors requiring attention
### Important Log Messages
#### Startup Messages
```
LogWisp starting version=1.0.0 config_file=/etc/logwisp.toml
Stream registered with router stream=app
TCP endpoint configured transport=system port=9090
HTTP endpoints configured transport=app stream_url=http://localhost:8080/stream
```
#### Connection Events
```
HTTP client connected remote_addr=192.168.1.100:54231 active_clients=6
HTTP client disconnected remote_addr=192.168.1.100:54231 active_clients=5
TCP connection opened remote_addr=192.168.1.100:54232 active_connections=3
```
#### Error Conditions
```
Failed to open file for checking path=/var/log/app.log error=permission denied
Scanner error while reading file path=/var/log/huge.log error=token too long
Request rate limited ip=192.168.1.100
Connection limit exceeded ip=192.168.1.100 connections=5 limit=5
```
#### Performance Warnings
```
Dropped log entry - subscriber buffer full
Dropped entry for slow client remote_addr=192.168.1.100
Check interval too small: 5ms (min: 10ms)
```
## Health Checks
### Basic Health Check
Simple up/down check:
```bash
#!/bin/bash
# health_check.sh
STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/status)
if [ "$STATUS" -eq 200 ]; then
echo "LogWisp is healthy"
exit 0
else
echo "LogWisp is unhealthy (status: $STATUS)"
exit 1
fi
```
### Advanced Health Check
Check specific conditions:
```bash
#!/bin/bash
# advanced_health_check.sh
RESPONSE=$(curl -s http://localhost:8080/status)
# Check if processing logs
ENTRIES=$(echo "$RESPONSE" | jq -r '.monitor.total_entries')
if [ "$ENTRIES" -eq 0 ]; then
echo "WARNING: No log entries processed"
exit 1
fi
# Check dropped entries
DROPPED=$(echo "$RESPONSE" | jq -r '.monitor.dropped_entries')
TOTAL=$(echo "$RESPONSE" | jq -r '.monitor.total_entries')
DROP_PERCENT=$(( DROPPED * 100 / TOTAL ))
if [ "$DROP_PERCENT" -gt 5 ]; then
echo "WARNING: High drop rate: ${DROP_PERCENT}%"
exit 1
fi
# Check connections
CONNECTIONS=$(echo "$RESPONSE" | jq -r '.server.active_clients')
echo "OK: Processing logs, $CONNECTIONS active clients"
exit 0
```
### Container Health Check
Docker/Kubernetes configuration:
```dockerfile
# Dockerfile
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost:8080/status || exit 1
```
```yaml
# Kubernetes
livenessProbe:
httpGet:
path: /status
port: 8080
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /status
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
```
## Monitoring Integration
### Prometheus Metrics
Export metrics in Prometheus format:
```bash
#!/bin/bash
# prometheus_exporter.sh
while true; do
STATUS=$(curl -s http://localhost:8080/status)
# Extract metrics
CLIENTS=$(echo "$STATUS" | jq -r '.server.active_clients')
ENTRIES=$(echo "$STATUS" | jq -r '.monitor.total_entries')
DROPPED=$(echo "$STATUS" | jq -r '.monitor.dropped_entries')
# Output Prometheus format
cat << EOF
# HELP logwisp_active_clients Number of active streaming clients
# TYPE logwisp_active_clients gauge
logwisp_active_clients $CLIENTS
# HELP logwisp_total_entries Total log entries processed
# TYPE logwisp_total_entries counter
logwisp_total_entries $ENTRIES
# HELP logwisp_dropped_entries Total log entries dropped
# TYPE logwisp_dropped_entries counter
logwisp_dropped_entries $DROPPED
EOF
sleep 60
done
```
### Grafana Dashboard
Key panels for Grafana:
1. **Active Connections**
- Query: `logwisp_active_clients`
- Visualization: Graph
- Alert: > 80% of max
2. **Log Processing Rate**
- Query: `rate(logwisp_total_entries[5m])`
- Visualization: Graph
- Alert: < 1 entry/min
3. **Drop Rate**
- Query: `rate(logwisp_dropped_entries[5m]) / rate(logwisp_total_entries[5m])`
- Visualization: Gauge
- Alert: > 5%
4. **Rate Limit Rejections**
- Query: `rate(logwisp_blocked_requests[5m])`
- Visualization: Graph
- Alert: > 10/min
### Datadog Integration
Send custom metrics:
```bash
#!/bin/bash
# datadog_metrics.sh
while true; do
STATUS=$(curl -s http://localhost:8080/status)
# Send metrics to Datadog
echo "$STATUS" | jq -r '
"logwisp.connections:\(.server.active_clients)|g",
"logwisp.entries:\(.monitor.total_entries)|c",
"logwisp.dropped:\(.monitor.dropped_entries)|c"
' | while read metric; do
echo "$metric" | nc -u -w1 localhost 8125
done
sleep 60
done
```
## Performance Monitoring
### CPU Usage
Monitor CPU usage by component:
```bash
# Check process CPU
top -p $(pgrep logwisp) -b -n 1
# Profile CPU usage
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
```
Common CPU consumers:
- File watching (reduce check_interval_ms)
- Regex filtering (simplify patterns)
- JSON encoding (reduce clients)
### Memory Usage
Track memory consumption:
```bash
# Check process memory
ps aux | grep logwisp
# Detailed memory stats
cat /proc/$(pgrep logwisp)/status | grep -E "Vm(RSS|Size)"
```
Memory optimization:
- Reduce buffer sizes
- Limit connections
- Simplify filters
### Network Bandwidth
Monitor streaming bandwidth:
```bash
# Network statistics
netstat -i
iftop -i eth0 -f "port 8080"
# Connection count
ss -tan | grep :8080 | wc -l
```
## Alerting
### Basic Alerts
Essential alerts to configure:
| Alert | Condition | Severity |
|-------|-----------|----------|
| Service Down | Status endpoint fails | Critical |
| High Drop Rate | > 10% entries dropped | Warning |
| No Log Activity | 0 entries/min for 5 min | Warning |
| Connection Limit | > 90% of max connections | Warning |
| Rate Limit High | > 20% requests blocked | Warning |
### Alert Script
Example monitoring script:
```bash
#!/bin/bash
# monitor_alerts.sh
check_alert() {
local name=$1
local condition=$2
local message=$3
if eval "$condition"; then
echo "ALERT: $name - $message"
# Send to alerting system
# curl -X POST https://alerts.example.com/...
fi
}
while true; do
STATUS=$(curl -s http://localhost:8080/status)
if [ -z "$STATUS" ]; then
check_alert "SERVICE_DOWN" "true" "LogWisp not responding"
sleep 60
continue
fi
# Extract metrics
DROPPED=$(echo "$STATUS" | jq -r '.monitor.dropped_entries')
TOTAL=$(echo "$STATUS" | jq -r '.monitor.total_entries')
CLIENTS=$(echo "$STATUS" | jq -r '.server.active_clients')
# Check conditions
check_alert "HIGH_DROP_RATE" \
"[ $((DROPPED * 100 / TOTAL)) -gt 10 ]" \
"Drop rate above 10%"
check_alert "HIGH_CONNECTIONS" \
"[ $CLIENTS -gt 90 ]" \
"Near connection limit: $CLIENTS/100"
sleep 60
done
```
## Troubleshooting with Monitoring
### No Logs Appearing
Check monitor stats:
```bash
curl -s http://localhost:8080/status | jq '.monitor'
```
Look for:
- `active_watchers` = 0 (no files found)
- `total_entries` not increasing (files not updating)
### High CPU Usage
Enable debug logging:
```bash
logwisp --log-level debug --log-output stderr
```
Watch for:
- Frequent "checkFile" messages (reduce check_interval)
- Many filter operations (optimize patterns)
### Memory Growth
Monitor over time:
```bash
while true; do
ps aux | grep logwisp | grep -v grep
curl -s http://localhost:8080/status | jq '.server.active_clients'
sleep 10
done
```
### Connection Issues
Check connection stats:
```bash
# Current connections
curl -s http://localhost:8080/status | jq '.server'
# Rate limit stats
curl -s http://localhost:8080/status | jq '.features.rate_limit'
```
## Best Practices
1. **Regular Monitoring**: Check status endpoints every 30-60 seconds
2. **Set Alerts**: Configure alerts for critical conditions
3. **Log Rotation**: Rotate LogWisp's own logs to prevent disk fill
4. **Baseline Metrics**: Establish normal ranges for your environment
5. **Capacity Planning**: Monitor trends for scaling decisions
6. **Test Monitoring**: Verify alerts work before issues occur
## See Also
- [Performance Tuning](performance.md) - Optimization guide
- [Troubleshooting](troubleshooting.md) - Common issues
- [Configuration Guide](configuration.md) - Monitoring configuration
- [Integration Examples](integrations.md) - Monitoring system integration

209
doc/quickstart.md Normal file
View File

@ -0,0 +1,209 @@
# Quick Start Guide
Get LogWisp up and running in 5 minutes!
## Installation
### From Source
```bash
# Clone the repository
git clone https://github.com/yourusername/logwisp.git
cd logwisp
# Build and install
make install
# Or just build
make build
./logwisp --version
```
### Using Go Install
```bash
go install github.com/yourusername/logwisp/src/cmd/logwisp@latest
```
## Basic Usage
### 1. Monitor Current Directory
Start LogWisp with defaults (monitors `*.log` files in current directory):
```bash
logwisp
```
### 2. Stream Logs
In another terminal, connect to the log stream:
```bash
# Using curl (SSE stream)
curl -N http://localhost:8080/stream
# Check status
curl http://localhost:8080/status | jq .
```
### 3. Create Some Logs
Generate test logs to see streaming in action:
```bash
# In a third terminal
echo "[ERROR] Something went wrong!" >> test.log
echo "[INFO] Application started" >> test.log
echo "[WARN] Low memory warning" >> test.log
```
## Common Scenarios
### Monitor Specific Directory
Create a configuration file `~/.config/logwisp.toml`:
```toml
[[streams]]
name = "myapp"
[streams.monitor]
targets = [
{ path = "/var/log/myapp", pattern = "*.log", is_file = false }
]
[streams.httpserver]
enabled = true
port = 8080
```
Run LogWisp:
```bash
logwisp
```
### Filter Only Errors and Warnings
Add filters to your configuration:
```toml
[[streams]]
name = "errors"
[streams.monitor]
targets = [
{ path = "./", pattern = "*.log" }
]
[[streams.filters]]
type = "include"
patterns = ["ERROR", "WARN", "CRITICAL", "FATAL"]
[streams.httpserver]
enabled = true
port = 8080
```
### Multiple Log Sources
Monitor different applications on different ports:
```toml
# Stream 1: Web application
[[streams]]
name = "webapp"
[streams.monitor]
targets = [{ path = "/var/log/nginx", pattern = "*.log" }]
[streams.httpserver]
enabled = true
port = 8080
# Stream 2: Database
[[streams]]
name = "database"
[streams.monitor]
targets = [{ path = "/var/log/postgresql", pattern = "*.log" }]
[streams.httpserver]
enabled = true
port = 8081
```
### TCP Streaming
For high-performance streaming, use TCP:
```toml
[[streams]]
name = "highperf"
[streams.monitor]
targets = [{ path = "/var/log/app", pattern = "*.log" }]
[streams.tcpserver]
enabled = true
port = 9090
buffer_size = 5000
```
Connect with netcat:
```bash
nc localhost 9090
```
### Router Mode
Consolidate multiple streams on one port using router mode:
```bash
# With the multi-stream config above
logwisp --router
# Access streams at:
# http://localhost:8080/webapp/stream
# http://localhost:8080/database/stream
# http://localhost:8080/status (global status)
```
## Quick Tips
### Enable Debug Logging
```bash
logwisp --log-level debug --log-output stderr
```
### Run in Background
```bash
logwisp --background --config /etc/logwisp/prod.toml
```
### Rate Limiting
Protect your streams from abuse:
```toml
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 10.0
burst_size = 20
max_connections_per_ip = 5
```
### JSON Output Format
For structured logging:
```toml
[logging.console]
format = "json"
```
## What's Next?
- Read the [Configuration Guide](configuration.md) for all options
- Learn about [Filters](filters.md) for advanced pattern matching
- Explore [Rate Limiting](ratelimiting.md) for production deployments
- Check out [Example Configurations](examples/) for more scenarios
## Getting Help
- Run `logwisp --help` for CLI options
- Check `http://localhost:8080/status` for runtime statistics
- Enable debug logging for troubleshooting
- Visit our [GitHub repository](https://github.com/yourusername/logwisp) for issues and discussions

526
doc/ratelimiting.md Normal file
View File

@ -0,0 +1,526 @@
# Rate Limiting Guide
LogWisp provides configurable rate limiting to protect against abuse, prevent resource exhaustion, and ensure fair access to log streams.
## How Rate Limiting Works
LogWisp uses a **token bucket algorithm** for smooth, burst-tolerant rate limiting:
1. Each client (or globally) gets a bucket with a fixed capacity
2. Tokens are added to the bucket at a configured rate
3. Each request consumes one token
4. If no tokens are available, the request is rejected
5. The bucket can accumulate tokens up to its capacity for bursts
## Configuration
### Basic Configuration
```toml
[streams.httpserver.rate_limit]
enabled = true # Enable rate limiting
requests_per_second = 10.0 # Token refill rate
burst_size = 20 # Maximum tokens (bucket capacity)
limit_by = "ip" # "ip" or "global"
```
### Complete Options
```toml
[streams.httpserver.rate_limit]
# Core settings
enabled = true # Enable/disable rate limiting
requests_per_second = 10.0 # Token generation rate (float)
burst_size = 20 # Token bucket capacity
# Limiting strategy
limit_by = "ip" # "ip" or "global"
# Connection limits
max_connections_per_ip = 5 # Max concurrent connections per IP
max_total_connections = 100 # Max total concurrent connections
# Response configuration
response_code = 429 # HTTP status code when limited
response_message = "Rate limit exceeded" # Error message
# Same options available for TCP
[streams.tcpserver.rate_limit]
enabled = true
requests_per_second = 5.0
burst_size = 10
limit_by = "ip"
```
## Limiting Strategies
### Per-IP Limiting (Default)
Each client IP address gets its own token bucket:
```toml
[streams.httpserver.rate_limit]
enabled = true
limit_by = "ip"
requests_per_second = 10.0
burst_size = 20
```
**Use cases:**
- Fair access for multiple users
- Prevent single client from monopolizing resources
- Public-facing endpoints
**Example behavior:**
- Client A: Can make 10 req/sec
- Client B: Also can make 10 req/sec
- Total: Up to 10 × number of clients
### Global Limiting
All clients share a single token bucket:
```toml
[streams.httpserver.rate_limit]
enabled = true
limit_by = "global"
requests_per_second = 50.0
burst_size = 100
```
**Use cases:**
- Protect backend resources
- Control total system load
- Internal services with known clients
**Example behavior:**
- All clients combined: 50 req/sec max
- One aggressive client can consume all tokens
## Connection Limits
In addition to request rate limiting, you can limit concurrent connections:
### Per-IP Connection Limit
```toml
[streams.httpserver.rate_limit]
max_connections_per_ip = 5 # Each IP can have max 5 connections
```
**Behavior:**
- Prevents connection exhaustion attacks
- Limits resource usage per client
- Checked before rate limits
### Total Connection Limit
```toml
[streams.httpserver.rate_limit]
max_total_connections = 100 # Max 100 connections total
```
**Behavior:**
- Protects server resources
- Prevents memory exhaustion
- Global limit across all IPs
## Response Behavior
### HTTP Responses
When rate limited, HTTP clients receive:
```json
{
"error": "Rate limit exceeded",
"retry_after": "60"
}
```
With these headers:
- Status code: 429 (default) or configured value
- Content-Type: application/json
Configure custom responses:
```toml
[streams.httpserver.rate_limit]
response_code = 503 # Service Unavailable
response_message = "Server overloaded, please retry later"
```
### TCP Behavior
TCP connections are **silently dropped** when rate limited:
- No error message sent
- Connection immediately closed
- Prevents information leakage
## Configuration Examples
### Light Protection
For internal or trusted environments:
```toml
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 50.0
burst_size = 100
limit_by = "ip"
```
### Moderate Protection
For semi-public endpoints:
```toml
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 10.0
burst_size = 30
limit_by = "ip"
max_connections_per_ip = 5
max_total_connections = 200
```
### Strict Protection
For public or sensitive endpoints:
```toml
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 2.0
burst_size = 5
limit_by = "ip"
max_connections_per_ip = 2
max_total_connections = 50
response_code = 503
response_message = "Service temporarily unavailable"
```
### Debug/Development
Disable for testing:
```toml
[streams.httpserver.rate_limit]
enabled = false
```
## Use Case Scenarios
### Public Log Viewer
Prevent abuse while allowing legitimate use:
```toml
[[streams]]
name = "public-logs"
[streams.httpserver]
enabled = true
port = 8080
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 5.0 # 5 new connections per second
burst_size = 10 # Allow short bursts
limit_by = "ip"
max_connections_per_ip = 3 # Max 3 streams per user
max_total_connections = 100
```
### Internal Monitoring
Protect against accidental overload:
```toml
[[streams]]
name = "internal-metrics"
[streams.httpserver]
enabled = true
port = 8081
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 100.0 # High limit for internal use
burst_size = 200
limit_by = "global" # Total system limit
max_total_connections = 500
```
### High-Security Audit Logs
Very restrictive access:
```toml
[[streams]]
name = "audit"
[streams.httpserver]
enabled = true
port = 8443
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 0.5 # 1 request every 2 seconds
burst_size = 2
limit_by = "ip"
max_connections_per_ip = 1 # Single connection only
max_total_connections = 10
response_code = 403 # Forbidden (hide rate limit)
response_message = "Access denied"
```
### Multi-Tenant Service
Different limits per stream:
```toml
# Free tier
[[streams]]
name = "logs-free"
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 1.0
burst_size = 5
max_connections_per_ip = 1
# Premium tier
[[streams]]
name = "logs-premium"
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 50.0
burst_size = 100
max_connections_per_ip = 10
```
## Monitoring Rate Limits
### Status Endpoint
Check rate limit statistics:
```bash
curl http://localhost:8080/status | jq '.server.features.rate_limit'
```
Response includes:
```json
{
"enabled": true,
"total_requests": 15234,
"blocked_requests": 89,
"active_ips": 12,
"total_connections": 8,
"config": {
"requests_per_second": 10,
"burst_size": 20,
"limit_by": "ip"
}
}
```
### Debug Logging
Enable debug logs to see rate limit decisions:
```bash
logwisp --log-level debug
```
Look for messages:
```
Request rate limited ip=192.168.1.100
Connection limit exceeded ip=192.168.1.100 connections=5 limit=5
Created new IP limiter ip=192.168.1.100 total_ips=3
```
## Testing Rate Limits
### Test Script
```bash
#!/bin/bash
# Test rate limiting behavior
URL="http://localhost:8080/stream"
PARALLEL=10
DURATION=10
echo "Testing rate limits..."
echo "URL: $URL"
echo "Parallel connections: $PARALLEL"
echo "Duration: ${DURATION}s"
echo
# Function to connect and count lines
test_connection() {
local id=$1
local count=0
local start=$(date +%s)
while (( $(date +%s) - start < DURATION )); do
if curl -s -N --max-time 1 "$URL" >/dev/null 2>&1; then
((count++))
echo "[$id] Connected successfully (total: $count)"
else
echo "[$id] Rate limited!"
fi
sleep 0.1
done
}
# Run parallel connections
for i in $(seq 1 $PARALLEL); do
test_connection $i &
done
wait
echo "Test complete"
```
### Load Testing
Using Apache Bench (ab):
```bash
# Test burst handling
ab -n 100 -c 20 http://localhost:8080/status
# Test sustained load
ab -n 1000 -c 5 -r http://localhost:8080/status
```
Using curl:
```bash
# Test connection limit
for i in {1..10}; do
curl -N http://localhost:8080/stream &
done
```
## Tuning Guidelines
### Setting requests_per_second
Consider:
- Expected legitimate traffic
- Server capacity
- Client retry behavior
**Formula**: `requests_per_second = expected_clients × requests_per_client`
### Setting burst_size
General rule: `burst_size = 2-3 × requests_per_second`
Examples:
- `10 req/s → burst_size = 20-30`
- `1 req/s → burst_size = 3-5`
- `100 req/s → burst_size = 200-300`
### Connection Limits
Based on available memory:
- Each HTTP connection: ~1-2MB
- Each TCP connection: ~0.5-1MB
**Formula**: `max_connections = available_memory / memory_per_connection`
## Common Issues
### "All requests blocked"
Check if:
- Rate limits too strict
- Burst size too small
- Using global limiting with many clients
### "Memory growth"
Possible causes:
- No connection limits set
- Slow clients holding connections
- Too high burst_size
Solutions:
```toml
max_connections_per_ip = 5
max_total_connections = 100
```
### "Legitimate users blocked"
Consider:
- Increasing burst_size for short spikes
- Using per-IP instead of global limiting
- Different streams for different user tiers
## Security Considerations
### Information Disclosure
Rate limit responses can reveal information:
```toml
# Default - informative
response_code = 429
response_message = "Rate limit exceeded"
# Security-focused - generic
response_code = 503
response_message = "Service unavailable"
# High security - misleading
response_code = 403
response_message = "Forbidden"
```
### DDoS Protection
Rate limiting helps but isn't complete DDoS protection:
- Use with firewall rules
- Consider CDN/proxy rate limiting
- Monitor for distributed attacks
### Resource Exhaustion
Protect against:
- Connection exhaustion
- Memory exhaustion
- CPU exhaustion
```toml
# Comprehensive protection
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 10.0
burst_size = 20
max_connections_per_ip = 5
max_total_connections = 100
limit_by = "ip"
```
## Best Practices
1. **Start Conservative**: Begin with strict limits and relax as needed
2. **Monitor Statistics**: Use `/status` endpoint to track behavior
3. **Test Thoroughly**: Verify limits work as expected under load
4. **Document Limits**: Make rate limits clear to users
5. **Provide Retry Info**: Help clients implement proper retry logic
6. **Different Tiers**: Consider different limits for different user types
7. **Regular Review**: Adjust limits based on usage patterns
## See Also
- [Configuration Guide](configuration.md) - Complete configuration reference
- [Security Best Practices](security.md) - Security hardening
- [Performance Tuning](performance.md) - Optimization guidelines
- [Troubleshooting](troubleshooting.md) - Common issues

520
doc/router.md Normal file
View File

@ -0,0 +1,520 @@
# 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

537
doc/troubleshooting.md Normal file
View File

@ -0,0 +1,537 @@
# Troubleshooting Guide
This guide helps diagnose and resolve common issues with LogWisp.
## Diagnostic Tools
### Enable Debug Logging
The first step in troubleshooting is enabling debug logs:
```bash
# Via command line
logwisp --log-level debug --log-output stderr
# Via environment
export LOGWISP_LOGGING_LEVEL=debug
logwisp
# Via config
[logging]
level = "debug"
output = "stderr"
```
### Check Status Endpoint
Verify LogWisp is running and processing:
```bash
# Basic check
curl http://localhost:8080/status
# Pretty print
curl -s http://localhost:8080/status | jq .
# Check specific metrics
curl -s http://localhost:8080/status | jq '.monitor'
```
### Test Log Streaming
Verify streams are working:
```bash
# Test SSE stream (should show heartbeats if enabled)
curl -N http://localhost:8080/stream
# Test with timeout
timeout 5 curl -N http://localhost:8080/stream
# Test TCP stream
nc localhost 9090
```
## Common Issues
### No Logs Appearing
**Symptoms:**
- Stream connects but no log entries appear
- Status shows `total_entries: 0`
**Diagnosis:**
1. Check monitor configuration:
```bash
curl -s http://localhost:8080/status | jq '.monitor'
```
2. Verify file paths exist:
```bash
# Check your configured paths
ls -la /var/log/myapp/
```
3. Check file permissions:
```bash
# LogWisp user must have read access
sudo -u logwisp ls /var/log/myapp/
```
4. Verify files match pattern:
```bash
# If pattern is "*.log"
ls /var/log/myapp/*.log
```
5. Check if files are being updated:
```bash
# Should show recent timestamps
ls -la /var/log/myapp/*.log
tail -f /var/log/myapp/app.log
```
**Solutions:**
- Fix file permissions:
```bash
sudo chmod 644 /var/log/myapp/*.log
sudo usermod -a -G adm logwisp # Add to log group
```
- Correct path configuration:
```toml
targets = [
{ path = "/correct/path/to/logs", pattern = "*.log" }
]
```
- Use absolute paths:
```toml
# Bad: Relative path
targets = [{ path = "./logs", pattern = "*.log" }]
# Good: Absolute path
targets = [{ path = "/var/log/app", pattern = "*.log" }]
```
### High CPU Usage
**Symptoms:**
- LogWisp process using excessive CPU
- System slowdown
**Diagnosis:**
1. Check process CPU:
```bash
top -p $(pgrep logwisp)
```
2. Review check intervals:
```bash
grep check_interval /etc/logwisp/logwisp.toml
```
3. Count active watchers:
```bash
curl -s http://localhost:8080/status | jq '.monitor.active_watchers'
```
4. Check filter complexity:
```bash
curl -s http://localhost:8080/status | jq '.filters'
```
**Solutions:**
- Increase check interval:
```toml
[streams.monitor]
check_interval_ms = 1000 # Was 50ms
```
- Reduce watched files:
```toml
# Instead of watching entire directory
targets = [
{ path = "/var/log/specific-app.log", is_file = true }
]
```
- Simplify filter patterns:
```toml
# Complex regex (slow)
patterns = ["^\\[\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\]\\s+\\[(ERROR|WARN)\\]"]
# Simple patterns (fast)
patterns = ["ERROR", "WARN"]
```
### Memory Growth
**Symptoms:**
- Increasing memory usage over time
- Eventually runs out of memory
**Diagnosis:**
1. Monitor memory usage:
```bash
watch -n 10 'ps aux | grep logwisp'
```
2. Check connection count:
```bash
curl -s http://localhost:8080/status | jq '.server.active_clients'
```
3. Check for dropped entries:
```bash
curl -s http://localhost:8080/status | jq '.monitor.dropped_entries'
```
**Solutions:**
- Limit connections:
```toml
[streams.httpserver.rate_limit]
enabled = true
max_connections_per_ip = 5
max_total_connections = 100
```
- Reduce buffer sizes:
```toml
[streams.httpserver]
buffer_size = 500 # Was 5000
```
- Enable rate limiting:
```toml
[streams.httpserver.rate_limit]
enabled = true
requests_per_second = 10.0
```
### Connection Refused
**Symptoms:**
- Cannot connect to LogWisp
- `curl: (7) Failed to connect`
**Diagnosis:**
1. Check if LogWisp is running:
```bash
ps aux | grep logwisp
systemctl status logwisp
```
2. Verify listening ports:
```bash
sudo netstat -tlnp | grep logwisp
# or
sudo ss -tlnp | grep logwisp
```
3. Check firewall:
```bash
sudo iptables -L -n | grep 8080
sudo ufw status
```
**Solutions:**
- Start the service:
```bash
sudo systemctl start logwisp
```
- Fix port configuration:
```toml
[streams.httpserver]
enabled = true # Must be true
port = 8080 # Correct port
```
- Open firewall:
```bash
sudo ufw allow 8080/tcp
```
### Rate Limit Errors
**Symptoms:**
- HTTP 429 responses
- "Rate limit exceeded" errors
**Diagnosis:**
1. Check rate limit stats:
```bash
curl -s http://localhost:8080/status | jq '.features.rate_limit'
```
2. Test rate limits:
```bash
# Rapid requests
for i in {1..20}; do curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/status; done
```
**Solutions:**
- Increase rate limits:
```toml
[streams.httpserver.rate_limit]
requests_per_second = 50.0 # Was 10.0
burst_size = 100 # Was 20
```
- Use per-IP limiting:
```toml
limit_by = "ip" # Instead of "global"
```
- Disable for internal use:
```toml
enabled = false
```
### Filter Not Working
**Symptoms:**
- Unwanted logs still appearing
- Wanted logs being filtered out
**Diagnosis:**
1. Check filter configuration:
```bash
curl -s http://localhost:8080/status | jq '.filters'
```
2. Test patterns:
```bash
# Test regex pattern
echo "ERROR: test message" | grep -E "your-pattern"
```
3. Enable debug logging to see filter decisions:
```bash
logwisp --log-level debug 2>&1 | grep filter
```
**Solutions:**
- Fix pattern syntax:
```toml
# Word boundaries
patterns = ["\\bERROR\\b"] # Not "ERROR" which matches "TERROR"
# Case insensitive
patterns = ["(?i)error"]
```
- Check filter order:
```toml
# Include filters run first
[[streams.filters]]
type = "include"
patterns = ["ERROR", "WARN"]
# Then exclude filters
[[streams.filters]]
type = "exclude"
patterns = ["IGNORE_THIS"]
```
- Use correct logic:
```toml
logic = "or" # Match ANY pattern
# not
logic = "and" # Match ALL patterns
```
### Logs Dropping
**Symptoms:**
- `dropped_entries` counter increasing
- Missing log entries in stream
**Diagnosis:**
1. Check drop statistics:
```bash
curl -s http://localhost:8080/status | jq '{
dropped: .monitor.dropped_entries,
total: .monitor.total_entries,
percent: (.monitor.dropped_entries / .monitor.total_entries * 100)
}'
```
2. Monitor drop rate:
```bash
watch -n 5 'curl -s http://localhost:8080/status | jq .monitor.dropped_entries'
```
**Solutions:**
- Increase buffer sizes:
```toml
[streams.httpserver]
buffer_size = 5000 # Was 1000
```
- Add flow control:
```toml
[streams.monitor]
check_interval_ms = 500 # Slow down reading
```
- Reduce clients:
```toml
[streams.httpserver.rate_limit]
max_total_connections = 50
```
## Performance Issues
### Slow Response Times
**Diagnosis:**
```bash
# Measure response time
time curl -s http://localhost:8080/status > /dev/null
# Check system load
uptime
top
```
**Solutions:**
- Reduce concurrent operations
- Increase system resources
- Use TCP instead of HTTP for high volume
### Network Bandwidth
**Diagnosis:**
```bash
# Monitor network usage
iftop -i eth0 -f "port 8080"
# Check connection count
ss -tan | grep :8080 | wc -l
```
**Solutions:**
- Enable compression (future feature)
- Filter more aggressively
- Use TCP for local connections
## Debug Commands
### System Information
```bash
# LogWisp version
logwisp --version
# System resources
free -h
df -h
ulimit -a
# Network state
ss -tlnp
netstat -anp | grep logwisp
```
### Process Inspection
```bash
# Process details
ps aux | grep logwisp
# Open files
lsof -p $(pgrep logwisp)
# System calls (Linux)
strace -p $(pgrep logwisp) -e trace=open,read,write
# File system activity
inotifywait -m /var/log/myapp/
```
### Configuration Validation
```bash
# Test configuration
logwisp --config test.toml --log-level debug --log-output stderr
# Check file syntax
cat /etc/logwisp/logwisp.toml | grep -E "^\s*\["
# Validate TOML
python3 -m pip install toml
python3 -c "import toml; toml.load('/etc/logwisp/logwisp.toml'); print('Valid')"
```
## Getting Help
### Collect Diagnostic Information
Create a diagnostic bundle:
```bash
#!/bin/bash
# diagnostic.sh
DIAG_DIR="logwisp-diag-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$DIAG_DIR"
# Version
logwisp --version > "$DIAG_DIR/version.txt" 2>&1
# Configuration (sanitized)
grep -v "password\|secret\|token" /etc/logwisp/logwisp.toml > "$DIAG_DIR/config.toml"
# Status
curl -s http://localhost:8080/status > "$DIAG_DIR/status.json"
# System info
uname -a > "$DIAG_DIR/system.txt"
free -h >> "$DIAG_DIR/system.txt"
df -h >> "$DIAG_DIR/system.txt"
# Process info
ps aux | grep logwisp > "$DIAG_DIR/process.txt"
lsof -p $(pgrep logwisp) > "$DIAG_DIR/files.txt" 2>&1
# Recent logs
journalctl -u logwisp -n 1000 > "$DIAG_DIR/logs.txt" 2>&1
# Create archive
tar -czf "$DIAG_DIR.tar.gz" "$DIAG_DIR"
rm -rf "$DIAG_DIR"
echo "Diagnostic bundle created: $DIAG_DIR.tar.gz"
```
### Report Issues
When reporting issues, include:
1. LogWisp version
2. Configuration (sanitized)
3. Error messages
4. Steps to reproduce
5. Diagnostic bundle
## See Also
- [Monitoring Guide](monitoring.md) - Status and metrics
- [Performance Tuning](performance.md) - Optimization
- [Configuration Guide](configuration.md) - Settings reference
- [FAQ](faq.md) - Frequently asked questions