Skip to content

Commit 1223c02

Browse files
icewind1991backportbot[bot]
authored andcommitted
feat: add additional logging for database errors
including the stack trace of the current database transaction Signed-off-by: Robin Appelman <robin@icewind.nl> [skip ci]
1 parent 4ec3ccd commit 1223c02

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

lib/private/DB/Connection.php

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ class Connection extends PrimaryReadReplicaConnection {
9292
/** @var array<string, int> */
9393
protected $tableDirtyWrites = [];
9494

95+
protected bool $logDbException = false;
96+
private ?array $transactionBacktrace = null;
97+
9598
protected bool $logRequestId;
9699
protected string $requestId;
97100

@@ -124,6 +127,7 @@ public function __construct(
124127
$this->logger = \OC::$server->get(LoggerInterface::class);
125128

126129
$this->logRequestId = $this->systemConfig->getValue('db.log_request_id', false);
130+
$this->logDbException = $this->systemConfig->getValue('db.log_exceptions', false);
127131
$this->requestId = Server::get(IRequestId::class)->getId();
128132

129133
/** @var \OCP\Profiler\IProfiler */
@@ -325,7 +329,12 @@ public function executeQuery(string $sql, array $params = [], $types = [], ?Quer
325329
$sql = $this->finishQuery($sql);
326330
$this->queriesExecuted++;
327331
$this->logQueryToFile($sql);
328-
return parent::executeQuery($sql, $params, $types, $qcp);
332+
try {
333+
return parent::executeQuery($sql, $params, $types, $qcp);
334+
} catch (\Exception $e) {
335+
$this->logDatabaseException($e);
336+
throw $e;
337+
}
329338
}
330339

331340
/**
@@ -370,7 +379,12 @@ public function executeStatement($sql, array $params = [], array $types = []): i
370379
$sql = $this->finishQuery($sql);
371380
$this->queriesExecuted++;
372381
$this->logQueryToFile($sql);
373-
return (int)parent::executeStatement($sql, $params, $types);
382+
try {
383+
return (int)parent::executeStatement($sql, $params, $types);
384+
} catch (\Exception $e) {
385+
$this->logDatabaseException($e);
386+
throw $e;
387+
}
374388
}
375389

376390
protected function logQueryToFile(string $sql): void {
@@ -437,11 +451,21 @@ public function realLastInsertId($seqName = null) {
437451
* @deprecated 15.0.0 - use unique index and "try { $db->insert() } catch (UniqueConstraintViolationException $e) {}" instead, because it is more reliable and does not have the risk for deadlocks - see https://github.com/nextcloud/server/pull/12371
438452
*/
439453
public function insertIfNotExist($table, $input, ?array $compare = null) {
440-
return $this->adapter->insertIfNotExist($table, $input, $compare);
454+
try {
455+
return $this->adapter->insertIfNotExist($table, $input, $compare);
456+
} catch (\Exception $e) {
457+
$this->logDatabaseException($e);
458+
throw $e;
459+
}
441460
}
442461

443462
public function insertIgnoreConflict(string $table, array $values) : int {
444-
return $this->adapter->insertIgnoreConflict($table, $values);
463+
try {
464+
return $this->adapter->insertIgnoreConflict($table, $values);
465+
} catch (\Exception $e) {
466+
$this->logDatabaseException($e);
467+
throw $e;
468+
}
445469
}
446470

447471
private function getType($value) {
@@ -700,6 +724,7 @@ private function getMigrator() {
700724

701725
public function beginTransaction() {
702726
if (!$this->inTransaction()) {
727+
$this->transactionBacktrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
703728
$this->transactionActiveSince = microtime(true);
704729
}
705730
return parent::beginTransaction();
@@ -709,6 +734,7 @@ public function commit() {
709734
$result = parent::commit();
710735
if ($this->getTransactionNestingLevel() === 0) {
711736
$timeTook = microtime(true) - $this->transactionActiveSince;
737+
$this->transactionBacktrace = null;
712738
$this->transactionActiveSince = null;
713739
if ($timeTook > 1) {
714740
$this->logger->debug('Transaction took ' . $timeTook . 's', ['exception' => new \Exception('Transaction took ' . $timeTook . 's')]);
@@ -721,6 +747,7 @@ public function rollBack() {
721747
$result = parent::rollBack();
722748
if ($this->getTransactionNestingLevel() === 0) {
723749
$timeTook = microtime(true) - $this->transactionActiveSince;
750+
$this->transactionBacktrace = null;
724751
$this->transactionActiveSince = null;
725752
if ($timeTook > 1) {
726753
$this->logger->debug('Transaction rollback took longer than 1s: ' . $timeTook, ['exception' => new \Exception('Long running transaction rollback')]);

lib/private/DB/ConnectionAdapter.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,4 +261,8 @@ public function getDatabaseProvider(): string {
261261
throw new \Exception('Database ' . $platform::class . ' not supported');
262262
}
263263
}
264+
265+
public function logDatabaseException(\Exception $exception) {
266+
$this->inner->logDatabaseException($exception);
267+
}
264268
}

0 commit comments

Comments
 (0)