Logs
This guide explains how to view and manage PCH-SIG logs.
Log types
| Log | Source | Content |
|---|---|---|
| Backend Symfony | PHP-FPM | PHP errors, API requests, authentication |
| Nginx Frontend | Nginx | HTTP access, server errors |
| Nginx Backend | Nginx | API requests, proxying |
| PostgreSQL | PostgreSQL | SQL queries, DB errors |
| Redis | Redis | Cache operations |
| Docker | Containers | Startup, shutdown, errors |
View Docker logs
Container logs
# Backend logs
docker logs pch_backend
# Last 100 lines
docker logs pch_backend --tail 100
# Follow logs in real-time
docker logs pch_backend -f
# Logs with timestamps
docker logs pch_backend --timestamps
All containers logs
# Via docker compose
cd deploy
docker compose logs
# Follow in real-time
docker compose logs -f
# Specific container
docker compose logs -f backend
Backend Symfony Logs
Location
Symfony logs are in /app/var/log/ of the container:
# List log files
docker exec pch_backend ls -la /app/var/log/
# Typical content
# dev.log - Development environment
# prod.log - Production environment
View logs
# Last lines of prod log
docker exec pch_backend tail -100 /app/var/log/prod.log
# Follow in real-time
docker exec pch_backend tail -f /app/var/log/prod.log
# Search for errors
docker exec pch_backend grep -i "error" /app/var/log/prod.log
Log levels
| Level | Description |
|---|---|
| DEBUG | Detailed debug information |
| INFO | Informational events |
| NOTICE | Normal but significant events |
| WARNING | Warnings |
| ERROR | Runtime errors |
| CRITICAL | Critical errors |
| ALERT | Immediate action required |
| EMERGENCY | System unusable |
Monolog configuration
File: backend/config/packages/monolog.yaml
monolog:
handlers:
main:
type: rotating_file
path: '%kernel.logs_dir%/%kernel.environment%.log'
level: info
max_files: 10
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine"]
Nginx Logs
Frontend
# Access logs
docker exec pch_frontend cat /var/log/nginx/access.log
# Error logs
docker exec pch_frontend cat /var/log/nginx/error.log
# Follow in real-time
docker exec pch_frontend tail -f /var/log/nginx/access.log
Backend API
# API access logs
docker exec pch_nginx_backend cat /var/log/nginx/access.log
# Error logs
docker exec pch_nginx_backend tail -f /var/log/nginx/error.log
Nginx log format
192.168.1.100 - - [15/Jan/2024:10:30:45 +0000] "GET /api/menages HTTP/1.1" 200 1234 "-" "Mozilla/5.0..."
| Field | Description |
|---|---|
| IP | Client address |
| Date | Date and time |
| Method | GET, POST, etc. |
| URI | Requested URL |
| Status | HTTP code (200, 404, 500...) |
| Size | Response size |
| User-Agent | Client browser |
PostgreSQL Logs
View logs
# PostgreSQL logs
docker logs pch_postgres
# Last lines
docker logs pch_postgres --tail 50
Enable query logging
In postgresql.conf:
log_statement = 'all' # none, ddl, mod, all
log_min_duration_statement = 0 # Log all queries
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d '
Analyze slow queries
# Queries over 1 second
docker logs pch_postgres 2>&1 | grep "duration:"
Redis Logs
# Redis logs
docker logs pch_redis
# Server info
docker exec pch_redis redis-cli -a redis_secure_2025 INFO
Centralization with Loki
PCH-SIG uses Loki to centralize logs.
Architecture
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Containers │────▶│ Promtail │────▶│ Loki │
│ Docker │ │ (collector) │ │ (storage) │
└─────────────────┘ └─────────────────┘ └────────┬────────┘
│
▼
┌─────────────────┐
│ Grafana │
│ (visualization) │
└─────────────────┘
Access logs in Grafana
- Open Grafana: http://localhost:3001
- Go to Explore
- Select Loki datasource
- Use LogQL to search
LogQL queries
# Backend logs
{container="pch_backend"}
# Errors only
{container="pch_backend"} |= "error"
# Specific user logs
{container="pch_backend"} |= "admin@pch-sig.sn"
# Last hour logs with errors
{container="pch_backend"} |= "error" | json | level="ERROR"
Log rotation
Docker
By default, Docker limits log size. Configuration in docker-compose.yml:
services:
backend:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
Symfony
Rotation is managed by Monolog (rotating_file handler):
main:
type: rotating_file
max_files: 10 # Keep last 10 files
Manual cleanup
# Clear container logs
docker exec pch_backend truncate -s 0 /app/var/log/prod.log
# Delete old logs
docker exec pch_backend find /app/var/log -name "*.log.*" -mtime +7 -delete
Log search
Basic grep
# Search for error
docker logs pch_backend 2>&1 | grep -i "error"
# Search for user
docker logs pch_backend 2>&1 | grep "admin@pch-sig.sn"
# Search for period
docker logs pch_backend 2>&1 | grep "2024-01-15"
With context
# 3 lines before and after
docker logs pch_backend 2>&1 | grep -B 3 -A 3 "Exception"
Count occurrences
# Number of errors by type
docker logs pch_backend 2>&1 | grep -o "Exception.*$" | sort | uniq -c | sort -rn
Log alerts
Monitoring script
# check-logs.ps1
$ErrorPatterns = @("ERROR", "CRITICAL", "Exception", "Fatal")
$Logs = docker logs pch_backend --since 1h 2>&1
foreach ($Pattern in $ErrorPatterns) {
$Matches = $Logs | Select-String -Pattern $Pattern
if ($Matches) {
Write-Host "ALERT: $($Matches.Count) occurrences of '$Pattern'" -ForegroundColor Red
$Matches | Select-Object -First 5
}
}
With Grafana
- Create a dashboard with logs
- Add an alert on error count
- Configure notifications (email, Slack, etc.)
Best practices
Structured logging
Use JSON for logs:
$this->logger->info('Household created', [
'menage_id' => $menage->getId(),
'user' => $user->getEmail(),
'ip' => $request->getClientIp()
]);
Do not log
- Passwords (even hashed)
- Authentication tokens
- Full identity document numbers
- Banking data
Retention
- Error logs: 90 days minimum
- Access logs: 30 days
- Debug logs: 7 days