Overview
Aeros provides a simple but effective logging system through the Logger class. Logs are written to files with timestamps, making it easy to track application behavior and debug issues.
Basic Usage
Use the logger() helper function to log messages:
// Log to default file (logs/error.log)
logger () -> log ( 'Application started' );
// Log errors
logger () -> log ( 'Database connection failed' );
// Log complex data
logger () -> log ([ 'user_id' => 123 , 'action' => 'login' , 'ip' => '192.168.1.1' ]);
Log Method
logger () -> log (
mixed $msg , // Message or data to log
string $logFile = '' , // Optional custom log file path
bool $createFile = false // Create file if it doesn't exist
): bool
Parameters
The message or data to log. Can be a string, array, object, or any serializable data.
logFile
string
default: "logs/error.log"
Path to the log file. If empty, defaults to {basedir}/logs/error.log.
Whether to create the log file if it doesn’t exist.
All log entries include a timestamp:
[2026-03-03 14:23:15] User login successful: [email protected]
[2026-03-03 14:23:45] Database query failed: Table 'users' doesn't exist
[2026-03-03 14:24:10] a:3:{s:7:"user_id";i:123;s:6:"action";s:5:"login";s:2:"ip";s:13:"192.168.1.1";}
Non-string data is automatically serialized before logging, preserving complex data structures.
Custom Log Files
Organize logs by creating separate log files:
// Application logs
logger () -> log ( 'App initialized' , app () -> basedir . '/logs/app.log' );
// Database logs
logger () -> log ( 'Query executed' , app () -> basedir . '/logs/database.log' );
// API logs
logger () -> log ( 'API request received' , app () -> basedir . '/logs/api.log' );
// Security logs
logger () -> log ( 'Failed login attempt' , app () -> basedir . '/logs/security.log' );
Creating Log Files
By default, logging to a non-existent file will log an error. Use the third parameter to create files:
// Will create the file if it doesn't exist
logger () -> log (
'First log entry' ,
app () -> basedir . '/logs/new-feature.log' ,
true // Create file flag
);
If a log file doesn’t exist and createFile is false, an error is logged to the default error.log file.
Practical Examples
Example 1: Error Logging
function connectToDatabase () {
try {
$db = new PDO ( 'mysql:host=localhost;dbname=myapp' , 'user' , 'pass' );
logger () -> log ( 'Database connection successful' );
return $db ;
} catch ( PDOException $e ) {
logger () -> log ( 'Database connection failed: ' . $e -> getMessage ());
throw $e ;
}
}
Example 2: Request Logging
function logRequest () {
$logData = [
'timestamp' => date ( 'Y-m-d H:i:s' ),
'method' => $_SERVER [ 'REQUEST_METHOD' ],
'uri' => $_SERVER [ 'REQUEST_URI' ],
'ip' => $_SERVER [ 'REMOTE_ADDR' ],
'user_agent' => $_SERVER [ 'HTTP_USER_AGENT' ] ?? 'Unknown' ,
];
logger () -> log (
json_encode ( $logData ),
app () -> basedir . '/logs/requests.log' ,
true
);
}
Example 3: Debug Logging
function processOrder ( $orderData ) {
logger () -> log ( 'Processing order: ' . json_encode ( $orderData ), app () -> basedir . '/logs/orders.log' );
// Validate order
if ( ! validateOrder ( $orderData )) {
logger () -> log ( 'Order validation failed' , app () -> basedir . '/logs/orders.log' );
return false ;
}
// Process payment
$paymentResult = processPayment ( $orderData );
logger () -> log ( 'Payment result: ' . json_encode ( $paymentResult ), app () -> basedir . '/logs/orders.log' );
if ( $paymentResult [ 'success' ]) {
logger () -> log ( 'Order completed successfully' , app () -> basedir . '/logs/orders.log' );
return true ;
}
logger () -> log ( 'Order processing failed' , app () -> basedir . '/logs/orders.log' );
return false ;
}
function logPerformance ( $operation , $startTime ) {
$duration = microtime ( true ) - $startTime ;
logger () -> log (
sprintf (
'Operation: %s | Duration: %.4f seconds' ,
$operation ,
$duration
),
app () -> basedir . '/logs/performance.log' ,
true
);
// Alert if slow
if ( $duration > 1.0 ) {
logger () -> log (
"SLOW OPERATION: { $operation } took { $duration } seconds" ,
app () -> basedir . '/logs/slow-operations.log' ,
true
);
}
}
// Usage
$start = microtime ( true );
$data = fetchDataFromApi ();
logPerformance ( 'fetchDataFromApi' , $start );
Example 5: User Activity Logging
function logUserActivity ( $userId , $action , $details = []) {
$entry = [
'user_id' => $userId ,
'action' => $action ,
'details' => $details ,
'timestamp' => date ( 'Y-m-d H:i:s' ),
'ip' => $_SERVER [ 'REMOTE_ADDR' ] ?? 'Unknown' ,
];
logger () -> log (
json_encode ( $entry ),
app () -> basedir . '/logs/user-activity.log' ,
true
);
}
// Usage examples
logUserActivity ( 123 , 'login' , [ 'method' => 'email' ]);
logUserActivity ( 123 , 'profile_update' , [ 'field' => 'email' ]);
logUserActivity ( 123 , 'logout' );
Structured Logging
Create a structured logging helper:
app/Helpers/StructuredLogger.php
class StructuredLogger
{
public static function logEvent (
string $level ,
string $message ,
array $context = [],
string $logFile = ''
) : bool {
$entry = [
'timestamp' => date ( 'Y-m-d H:i:s' ),
'level' => strtoupper ( $level ),
'message' => $message ,
'context' => $context ,
];
$logFile = $logFile ?: app () -> basedir . '/logs/app.log' ;
return logger () -> log ( json_encode ( $entry ), $logFile , true );
}
public static function debug ( string $message , array $context = []) : bool
{
return self :: logEvent ( 'debug' , $message , $context );
}
public static function info ( string $message , array $context = []) : bool
{
return self :: logEvent ( 'info' , $message , $context );
}
public static function warning ( string $message , array $context = []) : bool
{
return self :: logEvent ( 'warning' , $message , $context );
}
public static function error ( string $message , array $context = []) : bool
{
return self :: logEvent ( 'error' , $message , $context );
}
}
Usage:
StructuredLogger :: info ( 'User logged in' , [ 'user_id' => 123 ]);
StructuredLogger :: error ( 'Payment failed' , [ 'order_id' => 456 , 'error' => 'Insufficient funds' ]);
StructuredLogger :: warning ( 'High memory usage' , [ 'usage' => '85%' ]);
Log Rotation
Implement log rotation to prevent files from growing too large:
app/Crons/LogRotationCron.php
class LogRotationCron extends Cron
{
protected string $id = 'log-rotation' ;
public function run ()
{
app () -> scheduler -> call ( function () {
$this -> work ();
}) -> daily () -> at ( '00:00' );
}
public function work ()
{
$logsDir = app () -> basedir . '/logs' ;
$maxSize = 10 * 1024 * 1024 ; // 10 MB
foreach ( glob ( "{ $logsDir }/*.log" ) as $logFile ) {
if ( filesize ( $logFile ) > $maxSize ) {
$timestamp = date ( 'Y-m-d_H-i-s' );
$archiveName = str_replace ( '.log' , "_{ $timestamp }.log" , $logFile );
// Rename current log
rename ( $logFile , $archiveName );
// Compress old log
exec ( "gzip { $archiveName }" );
// Create new empty log
touch ( $logFile );
logger () -> log ( "Rotated log: { $logFile }" );
}
}
}
}
Log Analysis
Create a simple log viewer:
#!/usr/bin/env php
<? php
require __DIR__ . '/../bootstrap.php' ;
$logFile = $argv [ 1 ] ?? 'error.log' ;
$lines = $argv [ 2 ] ?? 50 ;
$fullPath = app () -> basedir . '/logs/' . $logFile ;
if ( ! file_exists ( $fullPath )) {
echo "Log file not found: { $fullPath } \n " ;
exit ( 1 );
}
echo "Last { $lines } lines of { $logFile }: \n " ;
echo "=" . str_repeat ( "=" , 50 ) . " \n " ;
passthru ( "tail -n { $lines } { $fullPath }" );
Usage:
# View last 50 lines of error.log
php commands/view-logs.php error.log
# View last 100 lines of api.log
php commands/view-logs.php api.log 100
Best Practices
Be Descriptive Write clear, descriptive log messages that include context and relevant data.
Organize Logs Use separate log files for different components (API, database, auth, etc.).
Log Levels Implement severity levels (debug, info, warning, error) for better filtering.
Sensitive Data Never log sensitive information like passwords, credit cards, or API keys.
Performance Be mindful of logging overhead in high-traffic applications.
Rotate Logs Implement log rotation to prevent disk space issues.
Integration with Other Components
With Queue Jobs
class SendEmailJob extends Job
{
public function doWork () : bool
{
logger () -> log ( "Starting email job: { $this -> uuid }" , app () -> basedir . '/logs/jobs.log' );
try {
// Send email
mail ( $this -> email , $this -> subject , $this -> body );
logger () -> log ( "Email sent successfully: { $this -> uuid }" , app () -> basedir . '/logs/jobs.log' );
return true ;
} catch ( \ Exception $e ) {
logger () -> log ( "Email job failed: { $this -> uuid } - { $e -> getMessage ()}" , app () -> basedir . '/logs/jobs.log' );
return false ;
}
}
}
With Cron Jobs
class DatabaseBackupCron extends Cron
{
protected string $id = 'database-backup' ;
public function work ()
{
$logFile = app () -> basedir . '/logs/cron.log' ;
logger () -> log ( "[{ $this -> id }] Starting backup" , $logFile );
try {
// Backup logic
$filename = 'backup_' . date ( 'Y-m-d_H-i-s' ) . '.sql' ;
exec ( "mysqldump -u user -p pass db > /backups/{ $filename }" );
logger () -> log ( "[{ $this -> id }] Backup completed: { $filename }" , $logFile );
} catch ( \ Exception $e ) {
logger () -> log ( "[{ $this -> id }] Backup failed: { $e -> getMessage ()}" , $logFile );
}
}
}
With Events
class UserRegisteredEvent extends Observable
{
public function update ( mixed $eventData ) : bool
{
logger () -> log (
'User registered: ' . $eventData [ 'email' ],
app () -> basedir . '/logs/events.log'
);
// Trigger other actions
queue () -> push ( new SendWelcomeEmailJob ( $eventData ));
return true ;
}
}
Log Directory Structure
Recommended organization:
logs/
├── error.log # Default error log
├── app.log # Application events
├── api.log # API requests/responses
├── database.log # Database queries/errors
├── jobs.log # Queue job execution
├── cron.log # Scheduled task execution
├── events.log # Event emissions
├── security.log # Authentication/authorization
├── performance.log # Performance metrics
└── user-activity.log # User actions
Monitoring Logs
Create an alert system for critical errors:
function logCriticalError ( string $message , array $context = []) : void
{
// Log to file
logger () -> log (
'CRITICAL: ' . $message . ' | ' . json_encode ( $context ),
app () -> basedir . '/logs/critical.log' ,
true
);
// Send alert email
queue () -> push ( new SendAlertJob (
'[email protected] ' ,
'Critical Error Alert' ,
"Critical error occurred: { $message } \n\n Context: " . print_r ( $context , true )
));
}