Browse Source

feat: add additional logging for database errors

Signed-off-by: Robin Appelman <robin@icewind.nl>
db-error-logging-28
Robin Appelman 2 months ago
parent
commit
72ef313a70
No account linked to committer's email address

+ 63
- 5
lib/private/DB/Connection.php View File

/** @var DbDataCollector|null */ /** @var DbDataCollector|null */
protected $dbDataCollector = null; protected $dbDataCollector = null;


private ?array $transactionBacktrace = null;

/** /**
* Initializes a new instance of the Connection class. * Initializes a new instance of the Connection class.
* *
$sql = $this->adapter->fixupStatement($sql); $sql = $this->adapter->fixupStatement($sql);
$this->queriesExecuted++; $this->queriesExecuted++;
$this->logQueryToFile($sql); $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;
}
} }


/** /**
$sql = $this->adapter->fixupStatement($sql); $sql = $this->adapter->fixupStatement($sql);
$this->queriesExecuted++; $this->queriesExecuted++;
$this->logQueryToFile($sql); $this->logQueryToFile($sql);
return parent::executeUpdate($sql, $params, $types);
try {
return parent::executeUpdate($sql, $params, $types);
} catch (\Exception $e) {
$this->logDatabaseException($e);
throw $e;
}
} }


/** /**
$sql = $this->adapter->fixupStatement($sql); $sql = $this->adapter->fixupStatement($sql);
$this->queriesExecuted++; $this->queriesExecuted++;
$this->logQueryToFile($sql); $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 { protected function logQueryToFile(string $sql): void {
* @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 * @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) { 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 { 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) { private function getType($value) {
return new Migrator($this, $config, $dispatcher); return new Migrator($this, $config, $dispatcher);
} }
} }

public function beginTransaction() {
if (!$this->inTransaction()) {
$this->transactionBacktrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}
return parent::beginTransaction();
}

public function commit() {
$result = parent::commit();
if ($this->getTransactionNestingLevel() === 0) {
$this->transactionBacktrace = null;
}
return $result;
}

public function rollBack() {
$result = parent::rollBack();
if ($this->getTransactionNestingLevel() === 0) {
$this->transactionBacktrace = null;
}
return $result;
}

public function logDatabaseException(\Exception $exception): void {
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]);
}
}
} }

+ 4
- 0
lib/private/DB/ConnectionAdapter.php View File

throw new \Exception('Database ' . $platform::class . ' not supported'); throw new \Exception('Database ' . $platform::class . ' not supported');
} }
} }

public function logDatabaseException(\Exception $exception) {
$this->inner->logDatabaseException($exception);
}
} }

+ 6
- 1
lib/private/DB/QueryBuilder/QueryBuilder.php View File

]); ]);
} }


$result = $this->queryBuilder->execute();
try {
$result = $this->queryBuilder->execute();
} catch (\Exception $e) {
$this->connection->logDatabaseException($e);
throw $e;
}
if (is_int($result)) { if (is_int($result)) {
return $result; return $result;
} }

Loading…
Cancel
Save