📊 Logging & Monitoring¶
GRAB includes a comprehensive structured logging system that provides detailed insights into your API's behavior, performance, and errors. This guide covers everything you need to know about logging configuration, monitoring, and production deployment.
🎯 Overview¶
GRAB uses structured JSON logging with the following features:
- ✅ Structured JSON Format - Easy to parse and analyze
- ✅ Request Tracking - Unique request IDs for tracing
- ✅ Performance Metrics - Response times and sizes
- ✅ Smart Log Levels - Automatic level adjustment based on status codes
- ✅ Environment-Aware - Skip paths automatically configured per environment
- ✅ Configurable - Log levels via YAML config or environment variables
📋 Log Format¶
Every HTTP request generates a structured JSON log entry:
{
"time": "2025-10-07T20:58:09.182401421Z",
"level": "INFO",
"msg": "HTTP Request",
"request_id": "245bf1f3-0c9b-4242-8770-bbf3735ce303",
"method": "POST",
"path": "/api/v1/auth/login",
"status": 200,
"duration": 87074653,
"duration_ms": "87ms",
"client_ip": "192.168.97.1",
"user_agent": "PostmanRuntime/7.26.8",
"response_size": 287
}
📄 Example Log File: See examples/server.log for a complete example with multiple log entries showing different scenarios (success, warnings, errors).
Log Fields Explained¶
Field | Description | Example |
---|---|---|
time | Timestamp in RFC3339 format | 2025-10-07T20:58:09.182401421Z |
level | Log level (INFO/WARN/ERROR) | INFO |
msg | Log message | HTTP Request |
request_id | Unique request identifier | 245bf1f3-0c9b-4242-8770-bbf3735ce303 |
method | HTTP method | POST , GET , PUT , DELETE |
path | Request path with query params | /api/v1/auth/login?debug=true |
status | HTTP status code | 200 , 404 , 500 |
duration | Request duration in nanoseconds | 87074653 |
duration_ms | Human-readable duration | 87ms |
client_ip | Client IP address | 192.168.97.1 |
user_agent | Client user agent | PostmanRuntime/7.26.8 |
response_size | Response body size in bytes | 287 |
🎚️ Log Levels¶
GRAB automatically adjusts log levels based on HTTP status codes:
Status Code | Log Level | Description |
---|---|---|
200-399 | INFO | Successful requests |
400-499 | WARN | Client errors (bad requests, unauthorized, etc.) |
500-599 | ERROR | Server errors (internal errors, database issues, etc.) |
Configurable Log Levels¶
You can also set a minimum log level to filter out less important messages:
Level | Description | Use Case |
---|---|---|
debug | Most verbose, includes all messages | Development debugging |
info | Standard logging (default) | Development and staging |
warn | Warnings and errors only | Production (recommended) |
error | Errors only | High-traffic production |
⚙️ Configuration¶
YAML Configuration¶
Edit configs/config.yaml
:
Environment Variables¶
Override YAML configuration with environment variables:
Docker Configuration¶
In docker-compose.yml
:
In docker-compose.prod.yml
:
🚫 Skip Paths (Environment-Based)¶
Skip paths are automatically determined based on environment to reduce log noise:
Environment | Skip Paths | Reason |
---|---|---|
production | /health , /metrics , /debug , /pprof | Reduce noise from monitoring endpoints |
development | /health | Keep health checks quiet |
test | /health | Clean test output |
default | /health | Safe default |
📍 Where to Find Logs¶
🐳 Docker Development¶
View live logs:
# View all container logs
docker-compose logs -f
# View only app logs
docker-compose logs -f app
# View logs with timestamps
docker-compose logs -f -t app
Save logs to file:
# Save logs to file
docker-compose logs app > server.log
# Append logs to file
docker-compose logs app >> server.log
# Save logs with timestamps
docker-compose logs -t app > server.log
Redirect stdout to file:
# Method 1: Redirect docker-compose output
docker-compose up > server.log 2>&1
# Method 2: Use docker logs with redirection
docker-compose up -d
docker-compose logs -f app > server.log &
# Method 3: Direct container log redirection
docker logs -f go_api_app > server.log
🏗️ Go Build & Run¶
Direct execution:
# Logs go to stdout (terminal)
go run cmd/server/main.go
# Redirect to file
go run cmd/server/main.go > server.log 2>&1
# Run in background with logging
nohup go run cmd/server/main.go > server.log 2>&1 &
Built binary:
# Build the binary
go build -o bin/server cmd/server/main.go
# Run with logging
./bin/server > server.log 2>&1
# Run in background
nohup ./bin/server > server.log 2>&1 &
📁 Log File Locations¶
Method | Default Location | Custom Location |
---|---|---|
Docker stdout | Container logs | docker-compose logs > custom.log |
Go run redirect | ./server.log | go run cmd/server/main.go > custom.log |
Binary redirect | ./server.log | ./bin/server > custom.log |
Background process | ./nohup.out | nohup ./bin/server > custom.log |
🏭 Production Logging¶
Log Aggregation Setup¶
For production, you'll want to set up log aggregation. Here are popular options:
1. ELK Stack (Elasticsearch, Logstash, Kibana)¶
# docker-compose.prod.yml
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# ... rest of config
2. Fluentd + Elasticsearch¶
# docker-compose.prod.yml
services:
app:
logging:
driver: "fluentd"
options:
fluentd-address: "localhost:24224"
tag: "api.logs"
3. Prometheus + Grafana¶
# docker-compose.prod.yml
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Production Configuration¶
Recommended production settings:
Log Rotation¶
Docker log rotation:
# docker-compose.prod.yml
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m" # Max 10MB per file
max-file: "5" # Keep 5 files (50MB total)
System log rotation:
# Install logrotate
sudo apt-get install logrotate
# Create logrotate config
sudo tee /etc/logrotate.d/go-api << EOF
/path/to/server.log {
daily
missingok
rotate 7
compress
delaycompress
notifempty
create 644 root root
postrotate
# Restart your service if needed
systemctl reload go-api
endscript
}
EOF
🔍 Log Analysis Examples¶
Basic Analysis with jq
¶
# Count requests by status code
cat server.log | jq -r '.status' | sort | uniq -c
# Find slow requests (>100ms)
cat server.log | jq 'select(.duration_ms | tonumber > 100)'
# Find errors
cat server.log | jq 'select(.level == "ERROR")'
# Count requests by endpoint
cat server.log | jq -r '.path' | sort | uniq -c
# Find requests from specific IP
cat server.log | jq 'select(.client_ip == "192.168.1.100")'
Advanced Analysis¶
# Average response time by endpoint
cat server.log | jq -r 'select(.status < 400) | "\(.path) \(.duration_ms)"' | \
awk '{sum[$1]+=$2; count[$1]++} END {for (i in sum) print i, sum[i]/count[i]}'
# Top 10 slowest requests
cat server.log | jq -r 'select(.status < 400) | "\(.duration_ms) \(.path) \(.method)"' | \
sort -nr | head -10
# Error rate by endpoint
cat server.log | jq -r '.path' | sort | uniq -c | \
awk '{print $2, $1}' | sort -k2 -nr
🛠️ Troubleshooting¶
Common Issues¶
1. No logs appearing:
# Check if service is running
docker-compose ps
# Check container logs
docker-compose logs app
# Verify log level
echo $LOG_LEVEL
2. Too many logs:
3. Log file not created:
# Check permissions
ls -la server.log
# Check disk space
df -h
# Verify redirection
go run cmd/server/main.go > server.log 2>&1 &
Debug Mode¶
Enable debug logging:
# Development
export LOG_LEVEL=debug
export ENV=development
go run cmd/server/main.go
# Docker
LOG_LEVEL=debug docker-compose up
📊 Monitoring Integration¶
Health Check Endpoint¶
The /health
endpoint is automatically excluded from logging but provides basic health information:
Response:
Metrics Collection¶
For production monitoring, consider adding:
- Prometheus metrics for request rates, response times, error rates
- Health check endpoints for load balancer health
- Custom metrics for business logic monitoring
🎯 Best Practices¶
Development¶
- Use
debug
level for detailed debugging - Monitor logs in real-time with
docker-compose logs -f
- Use structured queries with
jq
for analysis
Production¶
- Use
warn
level to reduce noise - Set up log aggregation (ELK, Fluentd, etc.)
- Implement log rotation to prevent disk space issues
- Monitor error rates and response times
- Set up alerts for high error rates or slow responses
Security¶
- Never log sensitive data (passwords, tokens, PII)
- Use request IDs for tracing without exposing user data
- Consider log sanitization for compliance requirements
🚀 Quick Commands Reference¶
# View live logs (Docker)
docker-compose logs -f app
# Save logs to file (Docker)
docker-compose logs app > server.log
# View logs (Go run)
go run cmd/server/main.go
# Save logs to file (Go run)
go run cmd/server/main.go > server.log 2>&1
# Analyze logs with jq
cat server.log | jq 'select(.level == "ERROR")'
# Count requests by status
cat server.log | jq -r '.status' | sort | uniq -c
# Find slow requests
cat server.log | jq 'select(.duration_ms | tonumber > 100)'