wilycode / logger-file
Lightweight PSR-3 file logger with channels, level filtering, structured context and atomic appends.
Requires
- php: ^8.4
- psr/log: ^3.0
Requires (Dev)
- phpunit/phpunit: ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-12 21:31:40 UTC
README
A lightweight PSR-3 file logger for PHP 8.4+. Write structured, append-only log entries with configurable severity, named channels, message interpolation and JSON context. No framework required.
WilyCode PHP Ecosystem
Part of WilyCode — independent, reusable PHP components with their own repositories, releases and Composer installation.
Features
- Implements
Psr\Log\LoggerInterface(psr/log:^3.0). - Supports the eight PSR-3 severity methods and
log(). - Filters records using a minimum
Levelenum;Level::Nonedisables logging. - Writes timestamped, tab-separated entries with channel, interpolated message, JSON context and exception details.
- Appends using
FILE_APPEND | LOCK_EX; creates missing parent directories. - Replaces tabs and line breaks in visible fields to prevent extra log columns or lines.
- Optionally mirrors entries to PHP output (disabled by default).
Requirements
- PHP 8.4+.
psr/log3.x (installed automatically by Composer).
Installation
composer require wilycode/logger-file
Quick start
<?php require __DIR__ . '/vendor/autoload.php'; use WilyCode\Logger\FileLogger; use WilyCode\Logger\Level; $logger = new FileLogger( logFile: __DIR__ . '/var/log/app.log', channel: 'app', minLevel: Level::Info, ); $logger->info('Article {id} saved', ['id' => 15]); $logger->warning('Retrying request {attempt}', ['attempt' => 2]); $logger->debug('Ignored at the Info threshold');
The parent directory is created if needed. Each record is appended to the specified log file. Keep log files outside your publicly accessible web directory.
Output format
Each record has six tab-separated fields (the timestamp is followed by five more fields):
2026-10-12 18:42:13.123456 [INFO] [app] Article 15 saved {"id":15} {}
The displayed spacing above represents tabs. The fields are:
- Timestamp (
Y-m-d H:i:s.u, using the PHP process timezone). - Uppercase level in brackets.
- Channel in brackets.
- Interpolated message.
- Context serialized as JSON, excluding a recognized
exceptionentry. - Exception serialized as JSON, or
{}if none was supplied.
User-controlled tabs and line breaks are replaced with spaces in the channel and other fields to keep each event on one line. This is a tab-separated log format, not JSON Lines.
Severity levels
Use any of the eight PSR-3 helper methods (debug(), info(), notice(), warning(), error(), critical(), alert() and emergency()) or call log() with a string or the Level enum:
$logger->log('warning', 'Request took {duration} ms', ['duration' => 120]); $logger->log(Level::Error, 'Request failed'); $logger->setLogLevel(Level::Error); $logger->getLogLevel(); // Level::Error $logger->setLogLevel(Level::None); // Disable all writes.
Level::fromName('warning') also recognizes the aliases warn and off (Level::None). An unknown level throws InvalidArgumentException.
Channels and optional output
$logger->setChannel('payments'); $logger->getChannel(); // 'payments' $logger->setOutput(true); // Also emit each written line to PHP output. $logger->isOutputEnabled(); // true
The optional output uses echo, so it may appear in terminal output or in an HTTP response. Leave it disabled for web applications unless explicitly required.
Context, placeholders and exceptions
PSR-3 placeholders in braces are replaced with matching context values. The original context is also included in the JSON field.
$logger->info('Order {order} processed', [ 'order' => 42, 'paid' => true, ]); try { throw new RuntimeException('Connection refused'); } catch (RuntimeException $exception) { $logger->error('Payment processing failed', [ 'order' => 42, 'exception' => $exception, ]); }
A Throwable passed under the exception key is stored separately from the remaining context, including its message, code, file, line and trace. Do not log passwords, access tokens, session IDs or other secrets; exceptions may expose file paths and application details.
JSON serialization is best-effort. Unencodable values produce a __json_error__ marker rather than a JSON encoding exception.
Filesystem errors
File writing uses an exclusive lock and raises RuntimeException if the directory cannot be created or the complete line cannot be appended. Ensure your PHP process has appropriate directory permissions. The logger does not silently swallow filesystem failures.
The logger does not include log rotation, retention, remote logging or automatic sensitive-data redaction. Use an external rotation mechanism when needed.
Development
composer install
composer validate --strict
composer test
The test suite runs in GitHub Actions on pushes and pull requests. Development files and tests stay in Git but are excluded from distribution archives.
Contributing
Contributions are welcome. See CONTRIBUTING.md and GitHub Issues.
License
MIT © 2026 Simon Piter. See LICENSE.