initial
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Reservair\Logger;
|
||||
|
||||
class Logger {
|
||||
private const FILE = 'reservair.log';
|
||||
|
||||
public static function info(string $message): void {
|
||||
self::write($message, 'info');
|
||||
}
|
||||
|
||||
public static function warning(string $message): void {
|
||||
self::write($message, 'warning');
|
||||
}
|
||||
|
||||
/** Accepts a Throwable so it can replace error_log($e) call sites directly. */
|
||||
public static function error(string|\Throwable $message): void {
|
||||
self::write($message instanceof \Throwable ? (string) $message : $message, 'error');
|
||||
}
|
||||
|
||||
public static function get_path(): string {
|
||||
return self::dir() . '/' . self::FILE;
|
||||
}
|
||||
|
||||
/** @return array<array{time: string, level: string, message: string}> Most-recent entry first. */
|
||||
public static function get_entries(): array {
|
||||
$path = self::get_path();
|
||||
if (!file_exists($path)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$entries = [];
|
||||
foreach (file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
|
||||
$entry = json_decode($line, true);
|
||||
if ($entry !== null) {
|
||||
$entries[] = $entry;
|
||||
}
|
||||
}
|
||||
|
||||
return array_reverse($entries);
|
||||
}
|
||||
|
||||
public static function clear(): void {
|
||||
$path = self::get_path();
|
||||
if (file_exists($path)) {
|
||||
file_put_contents($path, '', LOCK_EX);
|
||||
}
|
||||
}
|
||||
|
||||
private static function write(string $message, string $level): void {
|
||||
self::ensure_dir();
|
||||
$line = json_encode([
|
||||
'time' => (new \DateTime('now', wp_timezone()))->format('Y-m-d H:i:s'),
|
||||
'level' => $level,
|
||||
'message' => $message,
|
||||
]);
|
||||
file_put_contents(self::get_path(), $line . PHP_EOL, FILE_APPEND | LOCK_EX);
|
||||
}
|
||||
|
||||
private static function dir(): string {
|
||||
static $dir = null;
|
||||
if ($dir === null) {
|
||||
$dir = wp_upload_dir()['basedir'] . '/reservair';
|
||||
}
|
||||
return $dir;
|
||||
}
|
||||
|
||||
private static function ensure_dir(): void {
|
||||
$dir = self::dir();
|
||||
if (!is_dir($dir)) {
|
||||
wp_mkdir_p($dir);
|
||||
// Block direct browser access to the log file.
|
||||
file_put_contents($dir . '/.htaccess', "Deny from all\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
# Logger Module
|
||||
|
||||
A file-based logger that writes structured entries to a JSONL file in the WordPress uploads directory. Designed as a drop-in replacement for `error_log()` that produces entries you can read, table-display, and download from the admin UI.
|
||||
|
||||
**Namespace:** `Reservair\Logger`
|
||||
**Log file:** `wp-content/uploads/reservair/reservair.log`
|
||||
|
||||
## Usage
|
||||
|
||||
```php
|
||||
use Reservair\Logger\Logger;
|
||||
|
||||
Logger::info('Timetable reservation created.');
|
||||
Logger::warning('Maintainer email not set for timetable #' . $id);
|
||||
Logger::error('Insert failed: ' . $message);
|
||||
|
||||
// Accepts Throwable directly — replaces error_log($e) call sites directly
|
||||
Logger::error($exception);
|
||||
```
|
||||
|
||||
## Admin UI integration
|
||||
|
||||
```php
|
||||
use Reservair\Logger\Logger;
|
||||
|
||||
// Table — get_entries() returns newest-first; each entry has time/level/message keys
|
||||
foreach (Logger::get_entries() as $entry) {
|
||||
// $entry['time'] e.g. "2026-05-30 14:22:01"
|
||||
// $entry['level'] "info" | "warning" | "error"
|
||||
// $entry['message'] the log text
|
||||
}
|
||||
|
||||
// Download button — serve this path as a file download
|
||||
$path = Logger::get_path();
|
||||
|
||||
// Clear the log
|
||||
Logger::clear();
|
||||
```
|
||||
|
||||
## Log file format
|
||||
|
||||
Each line is a JSON object (JSONL). Safe to tail, grep, or import into any log viewer.
|
||||
|
||||
```json
|
||||
{"time":"2026-05-30 14:22:01","level":"info","message":"Reservation #12 created."}
|
||||
{"time":"2026-05-30 14:22:03","level":"error","message":"Insert failed: Duplicate entry"}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Written to `wp-content/uploads/reservair/` rather than the plugin directory so the file survives plugin updates.
|
||||
- The directory is created on first write with an `.htaccess` that blocks direct browser access (`Deny from all`).
|
||||
- `LOCK_EX` is used on every write to prevent interleaved entries under concurrent requests.
|
||||
- `wp_upload_dir()` result is cached statically to avoid repeated database lookups per request.
|
||||
Reference in New Issue
Block a user