-
Notifications
You must be signed in to change notification settings - Fork 0
Logging
DBAL ships two independent logging facilities, each focused on a different use case.
| Facility | Configured via | When entries are written |
|---|---|---|
| Query log buffer |
queryLogs flag |
Every executed query, success or failure. |
| Critical logger |
log credential |
Only on query failure — receives the failure message. |
The query log is an in-memory ring; the critical logger is a pluggable sink (PSR-3 logger, callable, file path, or duck-typed object).
$db = new Connection(['queryLogs' => true]);
// or at runtime:
$db->setQueryLogs(true);foreach ($db->getQueryLogs() as $entry) {
printf("%6.3fs %s\n", $entry['timer'], $entry['query']);
}Each entry has the shape:
[
'query' => 'SELECT id FROM users WHERE id = :id',
'args' => ['id' => 7],
'timer' => 0.000234, // seconds, 6-decimal precision
]- The buffer lives in process memory and never rotates. Long-running workers should drain it periodically.
- Recording is cheap but not free. Leave it off in production unless you are debugging a hot path.
- The buffer captures bound parameters as PHP values, not the expanded SQL. There is no string-interpolation fallback.
Connection::createLog() is called automatically when a query fails.
The message it receives looks like:
SQLSTATE[HY000]: ... no such table: users
SQL : SELECT * FROM users
If debug is true, a JSON dump of the bound parameters is appended:
SQL : SELECT * FROM users WHERE id = :id
PARAMS : {"id":1}
The log credential is checked at the moment createLog() runs, in
this order:
-
Psr\Log\LoggerInterface—critical($message, $context)is called with the PSR-3{placeholder}template left intact. -
callable— receives the interpolated message string. -
objectwith a publiccritical()method — duck-typed fallback for codebases that ship their own logger but don't pull inpsr/log. -
string— treated as a file path;file_put_contentswithFILE_APPEND. The path may contain time placeholders.
If none of the above apply (or no sink is configured), createLog()
returns false.
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$logger = new Logger('db');
$logger->pushHandler(new StreamHandler('php://stderr'));
$db = new \InitORM\DBAL\Connection\Connection([
'log' => $logger,
// ...
]);This is the recommended setup. Install psr/log (it ships in your
container's logger anyway) and pass the instance through.
For ad-hoc or test logging:
$messages = [];
$db = new Connection([
'log' => static function (string $message) use (&$messages): void {
$messages[] = $message;
},
]);The callable receives a single string — placeholders have already been replaced.
$db = new Connection([
'log' => __DIR__ . '/logs/db-{date}.log',
]);The path template may contain any of these placeholders:
| Token | Replaced with |
|---|---|
{timestamp} |
time() |
{date} |
date('Y-m-d') |
{datetime} |
date('Y-m-d-H-i-s') |
{year} |
date('Y') |
{month} |
date('m') |
{day} |
date('d') |
{hour} |
date('H') |
{minute} |
date('i') |
{second} |
date('s') |
Each call appends one line.
For backwards compatibility with logger classes that predate PSR-3:
class LegacyLogger
{
public function critical(string $message): void { /* ... */ }
}
$db = new Connection(['log' => new LegacyLogger()]);createLog() is part of the public API. You can use it for your own
non-failure events too:
$db->createLog('user {id} signed in', ['id' => 42]);PSR-3 style {placeholder} substitution is honoured. Context values
that are arrays or non-Stringable objects are skipped (their
placeholder remains in the message) — this keeps the call defensive
against accidental serialisation crashes.
| Question | Use |
|---|---|
| "What ran during this request?" | Query log buffer. |
| "How fast was each query?" | Query log buffer (timer). |
| "I want every failure in my app log." | Critical logger (log cred.). |
| "I want a per-day file of every query." | Both, draining the buffer at end. |
- Error Handling for which exceptions trigger the critical logger.
- Connection for the rest of the credentials.
InitORM DBAL · MIT · maintained by Muhammet ŞAFAK · part of the InitORM stack
Getting Started
Core
Cross-Cutting
Reference
Upgrading
Project