rex_logger
Keywords: Logging, PSR-3, Exception-Handling, Debug, Error-Logging, System-Log, var/log/system.log
Übersicht
rex_logger implementiert PSR-3 Logger-Interface. Schreibt Exceptions, Fehler und Debug-Infos in var/log/system.log. Unterscheidet Log-Levels (emergency, alert, critical, error, warning, notice, info, debug). Shortcuts für Exceptions und PHP-Errors.
Methoden
| Methode | Parameter | Rückgabe | Beschreibung |
|---|---|---|---|
factory() |
- | rex_logger |
Gibt Logger-Instanz zurück |
log($level, $message, $context) |
string, string, array |
void |
PSR-3 Standard-Log mit Context-Interpolation |
logException($exception) |
Throwable |
void |
Loggt Exception mit Stacktrace |
logError($errno, $errstr, $errfile, $errline) |
int, string, string, int |
void |
Loggt PHP-Error (E_WARNING, E_NOTICE etc.) |
emergency($message, $context) |
string, array |
void |
System ist nicht nutzbar |
alert($message, $context) |
string, array |
void |
Sofortiges Handeln erforderlich |
critical($message, $context) |
string, array |
void |
Kritische Bedingungen |
error($message, $context) |
string, array |
void |
Fehler ohne Systemausfall |
warning($message, $context) |
string, array |
void |
Warnung |
notice($message, $context) |
string, array |
void |
Hinweis |
info($message, $context) |
string, array |
void |
Informationen |
debug($message, $context) |
string, array |
void |
Debug-Informationen |
Praxisbeispiele
Exception loggen
try {
$addon = rex_addon::get('nonexistent');
} catch (rex_exception $e) {
rex_logger::logException($e);
echo rex_view::error('Addon nicht gefunden');
}
// Wird in var/log/system.log geschrieben:
// [YYYY-MM-DD HH:MM:SS] CRITICAL: rex_exception: Addon "nonexistent" nicht gefunden
// Stack trace: ...
Addon Install/Uninstall Fehler
// install.php
try {
rex_sql_table::get('rex_myaddon_table')
->ensureColumn(new rex_sql_column('id', 'int(11)'))
->ensure();
} catch (Exception $e) {
rex_logger::logException($e);
return false; // Install fehlgeschlagen
}
PHP-Error explizit loggen
// Deprecated-Funktion nutzen, Error loggen
if (function_exists('old_function')) {
rex_logger::logError(
E_USER_DEPRECATED,
'old_function() is deprecated, use new_function()',
__FILE__,
__LINE__
);
}
PSR-3 Log-Levels
$logger = rex_logger::factory();
// Emergency - System down
$logger->emergency('Database server offline');
// Alert - Sofortige Aktion nötig
$logger->alert('Disk space < 5%');
// Critical - Kritisch aber System läuft
$logger->critical('Payment gateway timeout');
// Error - Fehler in Addon
$logger->error('Failed to send email to user');
// Warning - Warnung
$logger->warning('Deprecated API endpoint called');
// Notice - Hinweis
$logger->notice('User login from new IP');
// Info - Information
$logger->info('Cronjob completed successfully');
// Debug - Entwickler-Infos
$logger->debug('Cache hit for key: article_123');
Context-Interpolation
$logger = rex_logger::factory();
// {placeholders} werden durch $context ersetzt
$logger->error('User {user_id} failed login attempt #{attempt}', [
'user_id' => 42,
'attempt' => 3,
]);
// Log: User 42 failed login attempt #3
API-Call Fehler loggen
function fetchExternalData($url) {
try {
$response = file_get_contents($url);
if ($response === false) {
throw new RuntimeException('HTTP request failed');
}
return json_decode($response);
} catch (Exception $e) {
rex_logger::logException($e);
return null;
}
}
Datei-Upload Fehler
$upload = rex_file::upload($_FILES['file'], $targetPath);
if (!$upload['success']) {
rex_logger::factory()->error('File upload failed: {msg}', [
'msg' => $upload['message'],
'file' => $_FILES['file']['name'],
]);
echo rex_view::error($upload['message']);
}
Cronjob mit Logging
class MyCronjob extends rex_cronjob {
public function execute() {
try {
$processed = $this->processItems();
rex_logger::factory()->info('Cronjob processed {count} items', [
'count' => $processed,
]);
return true;
} catch (Exception $e) {
rex_logger::logException($e);
$this->setMessage($e->getMessage());
return false;
}
}
}
Pwned Password Check (yform_field)
try {
$response = file_get_contents("https://api.pwnedpasswords.com/...");
} catch (Exception $e) {
rex_logger::logError(
E_WARNING,
'Failed to connect to pwnedpasswords.com',
__FILE__,
__LINE__
);
}
Bulk-Rework Fehlerbehandlung (uploader)
foreach ($files as $file) {
try {
$this->processFile($file);
} catch (Exception $e) {
rex_logger::logException($e);
continue; // Nächste Datei verarbeiten
}
}
Statistics Addon - IP2Geo Fehler
try {
$geo = $this->fetchGeoData($ip);
} catch (Exception $e) {
rex_logger::logException($e);
return ['country' => 'Unknown', 'city' => 'Unknown'];
}
Media Manager - Responsive Fehler
if (!file_exists($sourcePath)) {
rex_logger::factory()->error('Source image not found: {path}', [
'path' => $sourcePath,
'media' => $mediaFile,
]);
return false;
}
MForm Handler Exception
try {
$value = $this->parseValue($_POST['field']);
} catch (InvalidArgumentException $e) {
rex_logger::logException($e);
$this->addError('Invalid field value');
}
Project Manager Server Connection
try {
$client = new GuzzleHttp\Client();
$response = $client->post($url, ['json' => $data]);
} catch (GuzzleHttp\Exception\RequestException $e) {
rex_logger::logException($e);
echo rex_view::error('Server nicht erreichbar');
}
Debugging mit Context-Array
$logger = rex_logger::factory();
$logger->debug('Article save attempt', [
'article_id' => $article->getId(),
'user' => rex::getUser()->getLogin(),
'changes' => $article->getModifiedFields(),
'timestamp' => date('Y-m-d H:i:s'),
]);
Addon Boot Fehler
// boot.php
try {
if (!class_exists('SomeRequiredClass')) {
throw new rex_exception('Required dependency missing');
}
$addon->includeFile('lib/autoload.php');
} catch (Exception $e) {
rex_logger::logException($e);
}
Log-File auslesen
// var/log/system.log Inhalt lesen
$logFile = rex_path::log('system.log');
$lines = file($logFile, FILE_IGNORE_NEW_LINES);
// Letzte 50 Zeilen ausgeben
$recent = array_slice($lines, -50);
echo '<pre>' . implode("\n", $recent) . '</pre>';
Custom Error Handler
set_error_handler(function($errno, $errstr, $errfile, $errline) {
rex_logger::logError($errno, $errstr, $errfile, $errline);
return true; // Error handled
});
// Trigger error
trigger_error('Custom warning', E_USER_WARNING);
Log-Rotation via Cronjob
class LogRotateCronjob extends rex_cronjob {
public function execute() {
$logPath = rex_path::log('system.log');
if (filesize($logPath) > 10 * 1024 * 1024) { // > 10MB
$backupPath = rex_path::log('system_' . date('Y-m-d') . '.log');
rename($logPath, $backupPath);
rex_logger::factory()->info('Log rotated to {file}', [
'file' => basename($backupPath),
]);
}
return true;
}
}
Conditional Logging (Debug-Mode)
if (rex::isDebugMode()) {
rex_logger::factory()->debug('Query executed: {sql}', [
'sql' => $sql->getQuery(),
'time' => $sql->getQueryTime() . 'ms',
]);
}
Try-Catch in Extension Point
rex_extension::register('PACKAGES_INCLUDED', function() {
try {
$config = rex_file::getCache('my_config.json');
$parsed = json_decode($config, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException('Invalid JSON in config');
}
return $parsed;
} catch (Exception $e) {
rex_logger::logException($e);
return [];
}
});
Batch-Processing mit Fehler-Tracking
$errors = 0;
$success = 0;
foreach ($items as $item) {
try {
$this->processItem($item);
$success++;
} catch (Exception $e) {
rex_logger::factory()->error('Item processing failed: {id}', [
'id' => $item->getId(),
'error' => $e->getMessage(),
]);
$errors++;
}
}
rex_logger::factory()->info('Batch complete: {success} success, {errors} errors', [
'success' => $success,
'errors' => $errors,
]);
Performance-Logging
$start = microtime(true);
// Lange Operation
$result = $this->heavyComputation();
$duration = microtime(true) - $start;
if ($duration > 1.0) {
rex_logger::factory()->warning('Slow operation detected: {duration}s', [
'duration' => round($duration, 2),
'operation' => 'heavyComputation',
]);
}