Skip to content

Commit

Permalink
Add structured trace for all DB drivers
Browse files Browse the repository at this point in the history
  • Loading branch information
paulbalandan committed Jan 2, 2025
1 parent d393960 commit 319a3ec
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 9 deletions.
7 changes: 6 additions & 1 deletion system/Database/MySQLi/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,12 @@ protected function execute(string $sql)
try {
return $this->connID->query($this->prepQuery($sql), $this->resultMode);
} catch (mysqli_sql_exception $e) {
log_message('error', (string) $e);
log_message('error', "{message}\nin {exFile} on line {exLine}.\n{trace}", [
'message' => $e->getMessage(),
'exFile' => clean_path($e->getFile()),
'exLine' => $e->getLine(),
'trace' => render_backtrace($e->getTrace()),
]);

if ($this->DBDebug) {
throw new DatabaseException($e->getMessage(), $e->getCode(), $e);
Expand Down
9 changes: 8 additions & 1 deletion system/Database/OCI8/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,14 @@ protected function execute(string $sql)

return $result;
} catch (ErrorException $e) {
log_message('error', (string) $e);
$trace = array_slice($e->getTrace(), 2); // remove call to error handler

log_message('error', "{message}\nin {exFile} on line {exLine}.\n{trace}", [
'message' => $e->getMessage(),
'exFile' => clean_path($e->getFile()),
'exLine' => $e->getLine(),
'trace' => render_backtrace($trace),
]);

if ($this->DBDebug) {
throw new DatabaseException($e->getMessage(), $e->getCode(), $e);
Expand Down
9 changes: 8 additions & 1 deletion system/Database/Postgre/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,14 @@ protected function execute(string $sql)
try {
return pg_query($this->connID, $sql);
} catch (ErrorException $e) {
log_message('error', (string) $e);
$trace = array_slice($e->getTrace(), 2); // remove the call to error handler

log_message('error', "{message}\nin {exFile} on line {exLine}.\n{trace}", [
'message' => $e->getMessage(),
'exFile' => clean_path($e->getFile()),
'exLine' => $e->getLine(),
'trace' => render_backtrace($trace),
]);

if ($this->DBDebug) {
throw new DatabaseException($e->getMessage(), $e->getCode(), $e);
Expand Down
17 changes: 12 additions & 5 deletions system/Database/SQLSRV/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -488,14 +488,21 @@ public function setDatabase(?string $databaseName = null)
*/
protected function execute(string $sql)
{
$stmt = ($this->scrollable === false || $this->isWriteType($sql)) ?
sqlsrv_query($this->connID, $sql) :
sqlsrv_query($this->connID, $sql, [], ['Scrollable' => $this->scrollable]);
$stmt = ($this->scrollable === false || $this->isWriteType($sql))
? sqlsrv_query($this->connID, $sql)
: sqlsrv_query($this->connID, $sql, [], ['Scrollable' => $this->scrollable]);

if ($stmt === false) {
$error = $this->error();

log_message('error', $error['message']);
$trace = debug_backtrace();
$first = array_shift($trace);

log_message('error', "{message}\nin {exFile} on line {exLine}.\n{trace}", [
'message' => $error['message'],
'exFile' => clean_path($first['file']),
'exLine' => $first['line'],
'trace' => render_backtrace($trace),
]);

if ($this->DBDebug) {
throw new DatabaseException($error['message']);
Expand Down
7 changes: 6 additions & 1 deletion system/Database/SQLite3/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,12 @@ protected function execute(string $sql)
? $this->connID->exec($sql)
: $this->connID->query($sql);
} catch (Exception $e) {
log_message('error', (string) $e);
log_message('error', "{message}\nin {exFile} on line {exLine}.\n{trace}", [
'message' => $e->getMessage(),
'exFile' => clean_path($e->getFile()),
'exLine' => $e->getLine(),
'trace' => render_backtrace($e->getTrace()),
]);

if ($this->DBDebug) {
throw new DatabaseException($e->getMessage(), $e->getCode(), $e);
Expand Down
58 changes: 58 additions & 0 deletions tests/system/Database/Live/ExecuteLogMessageFormatTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\Database\Live;

use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\TestLogger;
use Config\Database;
use PHPUnit\Framework\Attributes\Group;

/**
* @internal
*/
#[Group('DatabaseLive')]
final class ExecuteLogMessageFormatTest extends CIUnitTestCase
{
public function testLogMessageWhenExecuteFailsShowFullStructuredBacktrace(): void
{
$db = Database::connect();
$this->setPrivateProperty($db, 'DBDebug', false);

$sql = 'SELECT * FROM some_table WHERE id = ? AND status = ? AND author = ?';
$db->query($sql, [3, 'live', 'Rick']);

$message = match ($db->DBDriver) {

Check failure on line 35 in tests/system/Database/Live/ExecuteLogMessageFormatTest.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Match expression does not handle remaining value: string
'MySQLi' => 'Table \'test.some_table\' doesn\'t exist',
'Postgre' => 'pg_query(): Query failed: ERROR: relation "some_table" does not exist',
'SQLite3' => 'Unable to prepare statement: no such table: some_table',
'OCI8' => 'oci_execute(): ORA-00942: table or view does not exist',
'SQLSRV' => '[Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Invalid object name \'some_table\'.',
};
$messageFromLogs = explode("\n", $this->getPrivateProperty(TestLogger::class, 'op_logs')[0]['message']);

$this->assertSame($message, array_shift($messageFromLogs));

if ($db->DBDriver === 'Postgre') {
$messageFromLogs = array_slice($messageFromLogs, 2);
} elseif ($db->DBDriver === 'OCI8') {
$messageFromLogs = array_slice($messageFromLogs, 1);
}

$this->assertMatchesRegularExpression('/^in \S+ on line \d+\.$/', array_shift($messageFromLogs));

foreach ($messageFromLogs as $line) {
$this->assertMatchesRegularExpression('/\s?\d*\s\S+\(\d+\)\:\s.+/', $line);
}
}
}

0 comments on commit 319a3ec

Please sign in to comment.