mirror of
https://github.com/nextcloud/server.git
synced 2026-04-29 18:11:41 -04:00
Merge pull request #44788 from nextcloud/db-error-logging
feat: add additional logging for database errors
This commit is contained in:
commit
65941811b3
3 changed files with 52 additions and 4 deletions
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue