Logging¶
Kinetis’s logging is plain PSR-3 —
Psr\Log\LoggerInterface — not a Kinetis-specific contract. Any PSR-3
logger works: register it once, and everything inside Kinetis that logs
uses it automatically.
Registering your own logger¶
use Kinetis\Container\AppScope;
use Psr\Log\LoggerInterface;
$app = new AppScope();
$app->instance(LoggerInterface::class, $yourLogger);
$app->boot();
Register it before boot(), the same discipline as every other
AppScope binding — see Container.
If you never register one, AppScope::boot() binds
Psr\Log\NullLogger for you automatically. Framework internals resolve
LoggerInterface through the container, so something must always be
bound by the time they run — a consumer who never configures a real
logger sees log output silently discarded, not an exception the first
time something tries to log.
Where Kinetis logs, and why¶
Nowhere by default on a successful request — logging every request regardless of outcome is something you opt into with your own global middleware, not something the framework forces. The three places framework internals log on their own are all genuine anomaly signals, not routine chatter:
ExceptionHandlerMiddleware¶
The outermost global middleware every Kernel wires in unconditionally
(see Middleware). Resolved through the container, so its
LoggerInterface autowires from whatever you registered:
error: Unhandled exception while handling {method} {path}: {message}
method: POST
path: /users
message: ...
exception: <the Throwable itself>
The exception context key follows PSR-3 convention — Monolog and other
real loggers look for exactly that key to render a stack trace.
TransactionGuard::rollbackDangling()¶
Registered as an unconditional RequestScope dispose hook on every
request (see Persistence), so it runs whether or not a request
ever opened a transaction. It logs a warning only when it actually
finds an active transaction to roll back — the overwhelming majority of
calls are a genuine no-op, and logging on every one of them regardless
would turn a real anomaly signal into noise.
McpServer’s top-level exception handler¶
The JSON-RPC transport’s counterpart to ExceptionHandlerMiddleware: an
unexpected Throwable reaching McpServer::handle()’s outer catch
becomes a -32603 Internal error response, logged the same way (see
Model Context Protocol (MCP)). McpServer is constructed directly by you — over stdio via
bin/kinetis mcp:serve, or passed to Kernel’s $mcp parameter — rather
than resolved through the container, so pass your logger explicitly:
use Kinetis\Mcp\McpDispatcher;
use Kinetis\Mcp\McpServer;
$mcp = new McpServer($registry, new McpDispatcher($app), logger: $app->get(Psr\Log\LoggerInterface::class));
bin/kinetis mcp:serve already does this for you, pulling whatever’s
registered on its own AppScope.
See also¶
Container —
AppScope::boot()’s registration-lock discipline in full.Middleware —
ExceptionHandlerMiddleware’s place in the global pipeline.Persistence —
TransactionGuard’s full request-lifecycle role.Model Context Protocol (MCP) — the JSON-RPC error-handling convention
McpServerfollows.