Logging and Troubleshooting¶
This page covers Pathary's logging system and common troubleshooting scenarios.
Logging Architecture¶
Pathary uses Monolog for structured logging with multiple output handlers.
Log Handlers¶
File: src/Factory.php
public static function createLogger(ContainerInterface $container, Config $config) : LoggerInterface
{
$logger = new Logger('movary');
// Always log to stdout (for Docker)
$logger->pushHandler(self::createLoggerStreamHandlerStdout($container, $config));
// Optionally log to file
$enableFileLogging = $config->getAsBool('LOG_ENABLE_FILE_LOGGING', self::DEFAULT_ENABLE_FILE_LOGGING);
if ($enableFileLogging === true) {
$logger->pushHandler(self::createLoggerStreamHandlerFile($container, $config));
}
return $logger;
}
Output destinations:
| Handler | Destination | Default |
|---------|-------------|---------|
| Stdout | php://stdout | Always enabled |
| File | storage/logs/app.log | Enabled by default |
Log Configuration¶
Environment Variables¶
# Log level: debug, info, notice, warning, error, critical, alert, emergency
LOG_LEVEL=warning
# Include stack traces in logs (useful for debugging)
LOG_ENABLE_STACKTRACE=0
# Write logs to file (in addition to stdout)
LOG_ENABLE_FILE_LOGGING=1
Log Levels¶
| Level | Use Case |
|---|---|
debug |
Detailed debugging (very verbose) |
info |
Informational messages |
notice |
Normal but significant events |
warning |
Warning conditions (default) |
error |
Error conditions |
critical |
Critical conditions |
alert |
Action must be taken immediately |
emergency |
System is unusable |
Log Format¶
File: src/Factory.php
public static function createLineFormatter(ContainerInterface $container, Config $config) : LineFormatter
{
$enableStackTrace = $config->getAsBool('LOG_ENABLE_STACKTRACE', self::DEFAULT_LOG_ENABLE_STACKTRACE);
$formatter = new LineFormatter(null, null, true, true);
$formatter->includeStacktraces($enableStackTrace);
return $formatter;
}
Log format example:
Log Locations¶
Container Paths¶
| Path | Content |
|---|---|
/app/storage/logs/app.log |
Application log file |
| Docker stdout | Container log stream |
Volume Mount¶
Logs are persisted in the pathary-storage volume under logs/.
Viewing Logs¶
Docker Container Logs (stdout)¶
# View all logs
docker logs pathary
# Follow logs in real-time
docker logs -f pathary
# Show last 100 lines
docker logs --tail 100 pathary
# Show logs since timestamp
docker logs --since "2025-12-14T10:00:00" pathary
Application Log File¶
# View log file (inside container)
docker exec pathary cat /app/storage/logs/app.log
# Tail log file in real-time
docker exec pathary tail -f /app/storage/logs/app.log
# Search logs for errors
docker exec pathary grep -i error /app/storage/logs/app.log
# View last 50 lines
docker exec pathary tail -n 50 /app/storage/logs/app.log
Docker Compose¶
# View logs for all services
docker compose logs
# Follow logs
docker compose logs -f
# View specific service
docker compose logs pathary
Error Handling¶
Global Exception Handler¶
File: public/index.php
try {
// Route handling...
} catch (Throwable $t) {
$container->get(LoggerInterface::class)->emergency($t->getMessage(), ['exception' => $t]);
if (str_starts_with($uri, '/api') === false) {
$response = $container->get(ErrorController::class)->renderInternalServerError();
}
}
All uncaught exceptions are: 1. Logged at EMERGENCY level with full exception context 2. Displayed as a 500 error page (web) or empty response (API)
Error Pages¶
File: src/HttpController/Web/ErrorController.php
| Status | Template | Controller Method |
|---|---|---|
| 404 | templates/page/404.html.twig |
renderNotFound() |
| 500 | templates/page/500.html.twig |
renderInternalServerError() |
Common 500 Error Causes¶
1. Database Connection Failed¶
Symptoms: 500 error on all pages
Log message:
Solutions:
# Check database container is running
docker ps | grep mysql
# Check database connection settings
docker exec pathary env | grep DATABASE
# Test MySQL connection
docker exec pathary-mysql mysql -u <database_user> -p -e "SELECT 1"
2. Migration Failed¶
Symptoms: 500 error after update
Log message:
Solutions:
# Check migration status
docker exec pathary php bin/console.php database:migration:status
# Re-run migrations
docker exec pathary php bin/console.php database:migration:migrate
# Check for SQL errors in logs
docker logs pathary | grep -i migration
3. Missing TMDB API Key¶
Symptoms: 500 error on search or movie pages
Log message:
Solutions:
# Verify environment variable
docker exec pathary env | grep TMDB
# Check .env file
cat .env | grep TMDB_API_KEY
4. Permission Errors¶
Symptoms: 500 error on file operations
Log message:
Solutions:
# Fix storage permissions
docker exec pathary chown -R www-data:www-data /app/storage
docker exec pathary chmod -R 755 /app/storage
5. Memory Exhausted¶
Symptoms: 500 error on large operations
Log message:
Solutions:
Debugging Techniques¶
Enable Debug Logging¶
Then restart the container:
Check PHP Errors¶
# View PHP-FPM error log
docker exec pathary cat /var/log/php-fpm-error.log
# Check Nginx error log
docker exec pathary cat /var/log/nginx/error.log
Interactive Shell¶
# Get shell access to container
docker exec -it pathary /bin/sh
# Run PHP commands
docker exec -it pathary php -a
Test Database Query¶
# MySQL
docker exec pathary-mysql mysql -u <database_user> -p <database_name> -e "SELECT COUNT(*) FROM movie"
# SQLite
docker exec pathary sqlite3 /app/storage/movary.sqlite "SELECT COUNT(*) FROM movie"
Troubleshooting Checklist¶
Container Won't Start¶
- Check logs:
docker logs pathary - Verify environment variables in
.env - Check volume permissions
- Ensure port 80 is available
Blank White Page¶
- Check
LOG_LEVEL=debugis set - View logs:
docker logs pathary - Check PHP-FPM is running:
docker exec pathary ps aux | grep php - Verify Nginx is running:
docker exec pathary ps aux | grep nginx
Authentication Issues¶
- Clear browser cookies
- Check
user_auth_tokentable - Verify session cookie configuration
- Check for HTTPS/HTTP mismatch with
APPLICATION_URL
Image Not Loading¶
- Check TMDB API key is valid
- Verify image caching setting:
TMDB_ENABLE_IMAGE_CACHING - Check storage permissions on
/app/storage/images
Slow Performance¶
- Enable MySQL (SQLite is slower for large datasets)
- Check for N+1 queries in logs
- Monitor container resources:
docker stats pathary
Health Check¶
Basic Health Test¶
# Check if web server responds
curl -f http://localhost:8080/ || echo "FAILED"
# Check container health
docker inspect pathary --format='{{.State.Health.Status}}'
Docker Compose Health Check¶
services:
pathary:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
Log Rotation¶
Application logs can grow large. Implement rotation:
Logrotate Configuration¶
# /etc/logrotate.d/pathary
/app/storage/logs/*.log {
daily
rotate 7
compress
missingok
notifempty
copytruncate
}
Manual Cleanup¶
# Truncate log file
docker exec pathary truncate -s 0 /app/storage/logs/app.log
# Remove old logs
docker exec pathary find /app/storage/logs -name "*.log" -mtime +7 -delete
Related Pages¶
- Production Deployment - Production setup
- Quickstart Guide - Initial configuration
- Database - Database troubleshooting
- Migrations - Migration issues