Skip to content

Commit 3af3610

Browse files
committed
feat: add additional logging for database errors
Signed-off-by: Robin Appelman <robin@icewind.nl>
1 parent 06fb25b commit 3af3610

3 files changed

Lines changed: 73 additions & 6 deletions

File tree

lib/private/DB/Connection.php

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ class Connection extends \Doctrine\DBAL\Connection {
7979
/** @var DbDataCollector|null */
8080
protected $dbDataCollector = null;
8181

82+
private ?array $transactionBacktrace = null;
83+
8284
protected bool $logRequestId;
8385
protected string $requestId;
8486

@@ -263,7 +265,12 @@ public function executeQuery(string $sql, array $params = [], $types = [], Query
263265
$sql = $this->finishQuery($sql);
264266
$this->queriesExecuted++;
265267
$this->logQueryToFile($sql);
266-
return parent::executeQuery($sql, $params, $types, $qcp);
268+
try {
269+
return parent::executeQuery($sql, $params, $types, $qcp);
270+
} catch (\Exception $e) {
271+
$this->logDatabaseException($e);
272+
throw $e;
273+
}
267274
}
268275

269276
/**
@@ -273,7 +280,12 @@ public function executeUpdate(string $sql, array $params = [], array $types = []
273280
$sql = $this->finishQuery($sql);
274281
$this->queriesExecuted++;
275282
$this->logQueryToFile($sql);
276-
return parent::executeUpdate($sql, $params, $types);
283+
try {
284+
return parent::executeUpdate($sql, $params, $types);
285+
} catch (\Exception $e) {
286+
$this->logDatabaseException($e);
287+
throw $e;
288+
}
277289
}
278290

279291
/**
@@ -294,7 +306,12 @@ public function executeStatement($sql, array $params = [], array $types = []): i
294306
$sql = $this->finishQuery($sql);
295307
$this->queriesExecuted++;
296308
$this->logQueryToFile($sql);
297-
return (int)parent::executeStatement($sql, $params, $types);
309+
try {
310+
return (int)parent::executeStatement($sql, $params, $types);
311+
} catch (\Exception $e) {
312+
$this->logDatabaseException($e);
313+
throw $e;
314+
}
298315
}
299316

300317
protected function logQueryToFile(string $sql): void {
@@ -356,11 +373,21 @@ public function realLastInsertId($seqName = null) {
356373
* @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
357374
*/
358375
public function insertIfNotExist($table, $input, array $compare = null) {
359-
return $this->adapter->insertIfNotExist($table, $input, $compare);
376+
try {
377+
return $this->adapter->insertIfNotExist($table, $input, $compare);
378+
} catch (\Exception $e) {
379+
$this->logDatabaseException($e);
380+
throw $e;
381+
}
360382
}
361383

362384
public function insertIgnoreConflict(string $table, array $values) : int {
363-
return $this->adapter->insertIgnoreConflict($table, $values);
385+
try {
386+
return $this->adapter->insertIgnoreConflict($table, $values);
387+
} catch (\Exception $e) {
388+
$this->logDatabaseException($e);
389+
throw $e;
390+
}
364391
}
365392

366393
private function getType($value) {
@@ -616,4 +643,35 @@ private function getMigrator() {
616643
return new Migrator($this, $config, $dispatcher);
617644
}
618645
}
646+
647+
public function beginTransaction() {
648+
if (!$this->inTransaction()) {
649+
$this->transactionBacktrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
650+
}
651+
return parent::beginTransaction();
652+
}
653+
654+
public function commit() {
655+
$result = parent::commit();
656+
if ($this->getTransactionNestingLevel() === 0) {
657+
$this->transactionBacktrace = null;
658+
}
659+
return $result;
660+
}
661+
662+
public function rollBack() {
663+
$result = parent::rollBack();
664+
if ($this->getTransactionNestingLevel() === 0) {
665+
$this->transactionBacktrace = null;
666+
}
667+
return $result;
668+
}
669+
670+
public function logDatabaseException(\Exception $exception): void {
671+
if ($exception instanceof Exception\UniqueConstraintViolationException) {
672+
$this->logger->info($exception->getMessage(), ['exception' => $exception, 'transaction' => $this->transactionBacktrace]);
673+
} else {
674+
$this->logger->error($exception->getMessage(), ['exception' => $exception, 'transaction' => $this->transactionBacktrace]);
675+
}
676+
}
619677
}

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
}

lib/private/DB/QueryBuilder/QueryBuilder.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,12 @@ public function execute() {
277277
]);
278278
}
279279

280-
$result = $this->queryBuilder->execute();
280+
try {
281+
$result = $this->queryBuilder->execute();
282+
} catch (\Exception $e) {
283+
$this->connection->logDatabaseException($e);
284+
throw $e;
285+
}
281286
if (is_int($result)) {
282287
return $result;
283288
}

0 commit comments

Comments
 (0)