roadrunner-php/app-logger
Send log messages to RoadRunner with this PHP 8.1+ package. Create a Logger over an RPC connection and call debug, info, warning, error, or log to route messages to RoadRunner’s logger or stderr. Simple YAML config.
Install the package via Composer (use ^1.3.1 — see the dependency note below):
composer require roadrunner/app-logger:^1.3.1
Upgrading? The package was previously published as
roadrunner-php/app-logger. Remove the old requirement and add the new one (composer remove roadrunner-php/app-logger && composer require roadrunner/app-logger:^1.3.1). Also confirm the class namespace invendor/roadrunner/app-logger/src— the rename may have moved classes fromSpiral\RoadRunnerAppLogger\…to a new namespace.Minimum 1.3.1, not 1.3.0. 1.3.0 still declared a dependency on the legacy
spiral/roadrunnerpackage; 1.3.1 corrects this toroadrunner/roadrunner. If your lockfile resolved 1.3.0, runcomposer update roadrunner/app-logger -Wand confirm withcomposer why roadrunner/roadrunner(and thatspiral/roadrunneris gone).
Requirements: PHP 8.2+ and RoadRunner v3. If you are still on RoadRunner v2 or PHP 8.1, stay on the 1.2.x line.
Then, in your application entry point (e.g., app.php), initialize the logger using the provided factory:
// Namespace of the worker class depends on which runtime package you have installed:
// roadrunner/worker (new) → RoadRunner\Worker
// spiral/roadrunner-worker (legacy) → Spiral\RoadRunner\Worker
use Spiral\RoadRunner\Worker;
use RoadRunner\AppLogger\LoggerFactory; // verify namespace after the rename
$worker = Worker::create();
$logger = (new LoggerFactory($worker))->create();
// Optionally inject environment-aware context (e.g., request ID)
$logger = $logger->withContext(['request_id' => uniqid('req_', true)]);
Your first use case will likely be logging an inbound request’s outcome:
$logger->info('Request processed', [
'method' => 'GET',
'uri' => '/health',
'status' => 200,
'duration_ms' => 12.3,
]);
The README was refreshed in the 1.3.0 release (header + installation section), so start there before digging into examples/ — the minimal API surface means most patterns follow directly from the constructor and withContext() pattern. 1.3.1 is a pure dependency fix and adds no new API.
Per-Request Logging Scope: In middleware (e.g., PSR-15 or custom), clone the logger with request-specific context:
$logger = $baseLogger->withContext([
'request_id' => $request->getAttribute('request_id') ?? BinGuid::uuid4(),
'user_id' => $request->getAttribute('user_id'),
]);
This avoids cross-request log pollution in persistent workers.
Structured Logging with PSR-3: Since it implements Psr\Log\LoggerInterface, integrate with existing PSR-3–compatible consumers (e.g., Monolog handlers) if needed, but prefer native output:
$logger->info('User logged in', ['ip' => $ip, 'agent' => $userAgent]);
Request Lifecycle Hooks: Emit logs at key phases (dispatch → controller → response):
$logger->debug('Dispatching controller', ['controller' => $controllerClass, 'action' => $action]);
$logger->debug('Response generated', ['status' => $response->getStatusCode()]);
Integration with RoadRunner v3 Workers: Pass the worker to LoggerFactory so it inherits RoadRunner’s worker ID and PID—critical for debugging in multi-worker deployments. Note the v3 upgrade may alter worker construction signatures; check Worker::create() arguments against your .rr.yaml. With 1.3.1 the runtime package pulled in is roadrunner/roadrunner, so align the rest of your RoadRunner stack (roadrunner/worker, roadrunner-cli) on the new names too, otherwise you end up with both dependency trees installed.
No Dependency Injection Needed: Inject the logger into services as a lazy singleton—its context is immutable, and withContext() returns a new instance.
Pin Your Versions During Migration: If you can’t move to PHP 8.2 / RoadRunner v3 immediately, constrain to ^1.2 to avoid pulling 1.3.x with an incompatible runtime. On 8.2/RR3, constrain to ^1.3.1 so nothing re-resolves to the 1.3.0 dependency set.
Package Rename (1.3.0): The Composer name changed to roadrunner/app-logger, and class namespaces likely moved with it. Grep your codebase and composer.json for roadrunner-php/app-logger and Spiral\RoadRunnerAppLogger before upgrading. Autoload failures after composer update are almost always this.
Dependency Swap (1.3.1): roadrunner/roadrunner replaced spiral/roadrunner in the requirement list. Symptoms of staying on 1.3.0: a "new" RoadRunner v3 app that still pulls in legacy spiral/roadrunner, duplicate/conflicting Spiral\RoadRunner\Worker definitions, or Composer refusing to install alongside roadrunner/roadrunner. After upgrading, run composer why spiral/roadrunner — you want no output. If a transitive dependency is holding it, use composer update --with-dependencies on the RoadRunner packages together rather than bumping the logger alone.
PHP 8.2 and RoadRunner v3 Are Hard Requirements: 1.3.x drops older support. Verify php -v and rr --version (RoadRunner 3) before upgrading in production; CI matrices on 8.1 will break. Neither 1.3.0 nor 1.3.1 relaxes this.
Test Tooling Changed Internally, Not for You: Tests migrated to Testo — this affects contributors, not consumers. But if you were relying on Spiral\RoadRunner\Testing\Worker::createMock() in your own tests, re-check it still exists under the v3 testing helpers; otherwise write a thin WorkerInterface fake.
Immutable Context: withContext() returns a new logger instance; forgetting to reassign (e.g., $logger = $logger->withContext(...)) leads to stale context. Always reassign.
Worker Lifecycle ≠ Request Lifecycle: Because workers persist, avoid logging mutable global state. Use per-request cloning explicitly.
No Default Handlers: This package doesn’t attach any log handlers. You control output. To log to stderr (RoadRunner’s default), call error_log() via a custom handler, or rely on RoadRunner’s built-in log collection (ensure roadrunner serve or .rr.yaml has logs.mode = 'debug').
Context Overwrites, Not Merges: New keys in withContext() overwrite existing keys—not merge deeply. Use associative arrays carefully if extending context.
Performance: The logger is lightweight, but avoid creating new loggers inside tight loops. Cache and clone only per-request.
Testing: Mock LoggerInterface in unit tests. For integration tests, use LoggerFactory with a mock worker matching the v3 WorkerInterface. If you swap worker packages as part of 1.3.1, re-verify that your test double implements the interface from the package your app actually resolves.
Missing Request ID? RoadRunner doesn’t auto-inject one—define a middleware to generate/store an X-Request-Id header value in the context for end-to-end traceability.
How can I help you explore Laravel packages today?