aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/DB
diff options
context:
space:
mode:
authorStephan Orbaugh <62374139+sorbaugh@users.noreply.github.com>2024-07-25 09:09:57 +0200
committerGitHub <noreply@github.com>2024-07-25 09:09:57 +0200
commit65941811b326a35bf828879fa0330029d9c75c05 (patch)
treeb977e7d0a4a35823909e5050731bdba2dca9d77f /lib/private/DB
parentd843d671d5dc3ae4023e80ae5e923f7f7b9cf946 (diff)
parent7fbb98187780ecf19a415366f9089c9b88f41362 (diff)
downloadnextcloud-server-65941811b326a35bf828879fa0330029d9c75c05.tar.gz
nextcloud-server-65941811b326a35bf828879fa0330029d9c75c05.zip
Merge pull request #44788 from nextcloud/db-error-logging
feat: add additional logging for database errors
Diffstat (limited to 'lib/private/DB')
-rw-r--r--lib/private/DB/Connection.php51
-rw-r--r--lib/private/DB/ConnectionAdapter.php4
-rw-r--r--lib/private/DB/QueryBuilder/QueryBuilder.php1
3 files changed, 52 insertions, 4 deletions
diff --git a/lib/private/DB/Connection.php b/lib/private/DB/Connection.php
index e584690f95d..3cdd5fd06c0 100644
--- a/lib/private/DB/Connection.php
+++ b/lib/private/DB/Connection.php
@@ -69,6 +69,9 @@ class Connection extends PrimaryReadReplicaConnection {
/** @var array<string, int> */
protected $tableDirtyWrites = [];
+ protected bool $logDbException = false;
+ private ?array $transactionBacktrace = null;
+
protected bool $logRequestId;
protected string $requestId;
@@ -101,6 +104,7 @@ class Connection extends PrimaryReadReplicaConnection {
$this->logger = Server::get(LoggerInterface::class);
$this->logRequestId = $this->systemConfig->getValue('db.log_request_id', false);
+ $this->logDbException = $this->systemConfig->getValue('db.log_exceptions', false);
$this->requestId = Server::get(IRequestId::class)->getId();
/** @var \OCP\Profiler\IProfiler */
@@ -304,7 +308,12 @@ class Connection extends PrimaryReadReplicaConnection {
$sql = $this->finishQuery($sql);
$this->queriesExecuted++;
$this->logQueryToFile($sql);
- return parent::executeQuery($sql, $params, $types, $qcp);
+ try {
+ return parent::executeQuery($sql, $params, $types, $qcp);
+ } catch (\Exception $e) {
+ $this->logDatabaseException($e);
+ throw $e;
+ }
}
/**
@@ -346,7 +355,12 @@ class Connection extends PrimaryReadReplicaConnection {
$sql = $this->finishQuery($sql);
$this->queriesExecuted++;
$this->logQueryToFile($sql);
- return (int)parent::executeStatement($sql, $params, $types);
+ try {
+ return (int)parent::executeStatement($sql, $params, $types);
+ } catch (\Exception $e) {
+ $this->logDatabaseException($e);
+ throw $e;
+ }
}
protected function logQueryToFile(string $sql): void {
@@ -419,11 +433,21 @@ class Connection extends PrimaryReadReplicaConnection {
* @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
*/
public function insertIfNotExist($table, $input, ?array $compare = null) {
- return $this->adapter->insertIfNotExist($table, $input, $compare);
+ try {
+ return $this->adapter->insertIfNotExist($table, $input, $compare);
+ } catch (\Exception $e) {
+ $this->logDatabaseException($e);
+ throw $e;
+ }
}
public function insertIgnoreConflict(string $table, array $values) : int {
- return $this->adapter->insertIgnoreConflict($table, $values);
+ try {
+ return $this->adapter->insertIgnoreConflict($table, $values);
+ } catch (\Exception $e) {
+ $this->logDatabaseException($e);
+ throw $e;
+ }
}
private function getType($value) {
@@ -682,6 +706,7 @@ class Connection extends PrimaryReadReplicaConnection {
public function beginTransaction() {
if (!$this->inTransaction()) {
+ $this->transactionBacktrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
$this->transactionActiveSince = microtime(true);
}
return parent::beginTransaction();
@@ -691,6 +716,7 @@ class Connection extends PrimaryReadReplicaConnection {
$result = parent::commit();
if ($this->getTransactionNestingLevel() === 0) {
$timeTook = microtime(true) - $this->transactionActiveSince;
+ $this->transactionBacktrace = null;
$this->transactionActiveSince = null;
if ($timeTook > 1) {
$this->logger->debug('Transaction took ' . $timeTook . 's', ['exception' => new \Exception('Transaction took ' . $timeTook . 's')]);
@@ -703,6 +729,7 @@ class Connection extends PrimaryReadReplicaConnection {
$result = parent::rollBack();
if ($this->getTransactionNestingLevel() === 0) {
$timeTook = microtime(true) - $this->transactionActiveSince;
+ $this->transactionBacktrace = null;
$this->transactionActiveSince = null;
if ($timeTook > 1) {
$this->logger->debug('Transaction rollback took longer than 1s: ' . $timeTook, ['exception' => new \Exception('Long running transaction rollback')]);
@@ -759,4 +786,20 @@ class Connection extends PrimaryReadReplicaConnection {
/** @var ServerInfoAwareConnection $this->_conn */
return $this->_conn->getServerVersion();
}
+
+ /**
+ * Log a database exception if enabled
+ *
+ * @param \Exception $exception
+ * @return void
+ */
+ public function logDatabaseException(\Exception $exception): void {
+ if ($this->logDbException) {
+ if ($exception instanceof Exception\UniqueConstraintViolationException) {
+ $this->logger->info($exception->getMessage(), ['exception' => $exception, 'transaction' => $this->transactionBacktrace]);
+ } else {
+ $this->logger->error($exception->getMessage(), ['exception' => $exception, 'transaction' => $this->transactionBacktrace]);
+ }
+ }
+ }
}
diff --git a/lib/private/DB/ConnectionAdapter.php b/lib/private/DB/ConnectionAdapter.php
index b7225169e4c..88083711195 100644
--- a/lib/private/DB/ConnectionAdapter.php
+++ b/lib/private/DB/ConnectionAdapter.php
@@ -240,4 +240,8 @@ class ConnectionAdapter implements IDBConnection {
public function getServerVersion(): string {
return $this->inner->getServerVersion();
}
+
+ public function logDatabaseException(\Exception $exception) {
+ $this->inner->logDatabaseException($exception);
+ }
}
diff --git a/lib/private/DB/QueryBuilder/QueryBuilder.php b/lib/private/DB/QueryBuilder/QueryBuilder.php
index 0ea223cd89c..4c4786f02b6 100644
--- a/lib/private/DB/QueryBuilder/QueryBuilder.php
+++ b/lib/private/DB/QueryBuilder/QueryBuilder.php
@@ -253,6 +253,7 @@ class QueryBuilder implements IQueryBuilder {
// `IQueryBuilder->execute` never wrapped the exception, but `executeQuery` and `executeStatement` do
/** @var \Doctrine\DBAL\Exception $previous */
$previous = $e->getPrevious();
+
throw $previous;
}
}