Skip to content

Commit

Permalink
DbLoggerInterface
Browse files Browse the repository at this point in the history
  • Loading branch information
darkdef committed Jan 2, 2024
1 parent 199070f commit d8f6ca4
Show file tree
Hide file tree
Showing 13 changed files with 367 additions and 62 deletions.
21 changes: 7 additions & 14 deletions src/Driver/Pdo/AbstractPdoCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@
use PDO;
use PDOException;
use PDOStatement;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\LogLevel;
use Throwable;
use Yiisoft\Db\Command\AbstractCommand;
use Yiisoft\Db\Command\Param;
use Yiisoft\Db\Command\ParamInterface;
use Yiisoft\Db\Exception\ConvertException;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidParamException;
use Yiisoft\Db\Logger\Context\QueryContext;
use Yiisoft\Db\Logger\DbLoggerAwareInterface;
use Yiisoft\Db\Logger\DbLoggerAwareTrait;
use Yiisoft\Db\Logger\DbLoggerEvent;
use Yiisoft\Db\Profiler\Context\CommandContext;
use Yiisoft\Db\Profiler\ProfilerAwareInterface;
use Yiisoft\Db\Profiler\ProfilerAwareTrait;
Expand All @@ -32,9 +33,9 @@
*
* It also provides methods for binding parameter values and retrieving query results.
*/
abstract class AbstractPdoCommand extends AbstractCommand implements PdoCommandInterface, LoggerAwareInterface, ProfilerAwareInterface
abstract class AbstractPdoCommand extends AbstractCommand implements PdoCommandInterface, DbLoggerAwareInterface, ProfilerAwareInterface
{
use LoggerAwareTrait;
use DbLoggerAwareTrait;
use ProfilerAwareTrait;

/**
Expand Down Expand Up @@ -255,21 +256,13 @@ protected function internalGetQueryResult(int $queryMode): mixed
return $result;
}

/**
* Logs the current database query if query logging is on and returns the profiling token if profiling is on.
*/
protected function logQuery(string $rawSql, string $category): void
{
$this->logger?->log(LogLevel::INFO, $rawSql, [$category]);
}

protected function queryInternal(int $queryMode): mixed
{
$logCategory = self::class . '::' . $this->getQueryMode($queryMode);

if ($this->logger !== null) {
$rawSql = $this->getRawSql();
$this->logQuery($rawSql, $logCategory);
$this->logger->log(DbLoggerEvent::QUERY, new QueryContext(__METHOD__, $rawSql, $logCategory));
}

$queryContext = new CommandContext(__METHOD__, $logCategory, $this->getSql(), $this->getParams());
Expand Down
37 changes: 20 additions & 17 deletions src/Driver/Pdo/AbstractPdoConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@

use PDO;
use PDOException;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\LogLevel;
use Throwable;
use Yiisoft\Db\Cache\SchemaCache;
use Yiisoft\Db\Connection\AbstractConnection;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidCallException;
use Yiisoft\Db\Exception\InvalidConfigException;
use Yiisoft\Db\Profiler\Context\ConnectionContext;
use Yiisoft\Db\Logger\Context\ConnectionContext as LoggerContext;
use Yiisoft\Db\Logger\Context\TransactionContext as LoggerTransactionContext;
use Yiisoft\Db\Logger\DbLoggerAwareInterface;
use Yiisoft\Db\Logger\DbLoggerAwareTrait;
use Yiisoft\Db\Logger\DbLoggerEvent;
use Yiisoft\Db\Profiler\Context\ConnectionContext as ProfilerContext;
use Yiisoft\Db\Profiler\ProfilerAwareInterface;
use Yiisoft\Db\Profiler\ProfilerAwareTrait;
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
Expand All @@ -36,9 +38,9 @@
*
* It implements the ConnectionInterface, which defines the interface for interacting with a database connection.
*/
abstract class AbstractPdoConnection extends AbstractConnection implements PdoConnectionInterface, LoggerAwareInterface, ProfilerAwareInterface
abstract class AbstractPdoConnection extends AbstractConnection implements PdoConnectionInterface, DbLoggerAwareInterface, ProfilerAwareInterface
{
use LoggerAwareTrait;
use DbLoggerAwareTrait;
use ProfilerAwareTrait;

protected PDO|null $pdo = null;
Expand Down Expand Up @@ -80,7 +82,7 @@ public function __sleep(): array
public function beginTransaction(string $isolationLevel = null): TransactionInterface
{
$transaction = parent::beginTransaction($isolationLevel);
if ($this->logger !== null && $transaction instanceof LoggerAwareInterface) {
if ($this->logger !== null && $transaction instanceof DbLoggerAwareInterface) {
$transaction->setLogger($this->logger);
}

Expand All @@ -98,16 +100,17 @@ public function open(): void
}

$token = 'Opening DB connection: ' . $this->driver->getDsn();
$connectionContext = new ConnectionContext(__METHOD__);
$profilerContext = new ProfilerContext(__METHOD__);
$loggerContext = new LoggerContext(__METHOD__, $this->getDriver()->getDsn());

try {
$this->logger?->log(LogLevel::INFO, $token);
$this->profiler?->begin($token, $connectionContext);
$this->logger?->log(DbLoggerEvent::CONNECTION_BEGIN, $loggerContext);
$this->profiler?->begin($token, $profilerContext);
$this->initConnection();
$this->profiler?->end($token, $connectionContext);
$this->profiler?->end($token, $profilerContext);
} catch (PDOException $e) {
$this->profiler?->end($token, $connectionContext->setException($e));
$this->logger?->log(LogLevel::ERROR, $token);
$this->profiler?->end($token, $profilerContext->setException($e));
$this->logger?->log(DbLoggerEvent::CONNECTION_ERROR, $loggerContext->setException($e));

throw new Exception($e->getMessage(), (array) $e->errorInfo, $e);
}
Expand All @@ -117,9 +120,9 @@ public function close(): void
{
if ($this->pdo !== null) {
$this->logger?->log(
LogLevel::DEBUG,
'Closing DB connection: ' . $this->driver->getDsn() . ' ' . __METHOD__,
);
DbLoggerEvent::CONNECTION_BEGIN,
new LoggerContext(__METHOD__, $this->getDriver()->getDsn()),
);

$this->pdo = null;
$this->transaction = null;
Expand Down Expand Up @@ -225,7 +228,7 @@ protected function rollbackTransactionOnLevel(TransactionInterface $transaction,
try {
$transaction->rollBack();
} catch (Throwable $e) {
$this->logger?->log(LogLevel::ERROR, (string) $e, [__METHOD__]);
$this->logger?->log(DbLoggerEvent::TRANSACTION_ROLLBACK_ON_LEVEL, (new LoggerTransactionContext(__METHOD__, $level))->setException($e));
/** hide this exception to be able to continue throwing original exception outside */
}
}
Expand Down
50 changes: 19 additions & 31 deletions src/Driver/Pdo/AbstractPdoTransaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

namespace Yiisoft\Db\Driver\Pdo;

use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\LogLevel;
use Throwable;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidConfigException;
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Logger\Context\TransactionContext;
use Yiisoft\Db\Logger\DbLoggerAwareInterface;
use Yiisoft\Db\Logger\DbLoggerAwareTrait;
use Yiisoft\Db\Logger\DbLoggerEvent;
use Yiisoft\Db\Transaction\TransactionInterface;

/**
Expand All @@ -35,9 +36,9 @@
* }
* ```
*/
abstract class AbstractPdoTransaction implements TransactionInterface, LoggerAwareInterface
abstract class AbstractPdoTransaction implements TransactionInterface, DbLoggerAwareInterface
{
use LoggerAwareTrait;
use DbLoggerAwareTrait;

/**
* @var int The nesting level of the transaction.
Expand All @@ -52,16 +53,13 @@ public function begin(string $isolationLevel = null): void
{
$this->db->open();

$loggerContext = new TransactionContext(__METHOD__, $this->level, $isolationLevel);
if ($this->level === 0) {
if ($isolationLevel !== null) {
$this->setTransactionIsolationLevel($isolationLevel);
}

$this->logger?->log(
LogLevel::DEBUG,
'Begin transaction' . ($isolationLevel ? ' with isolation level ' . $isolationLevel : '')
. ' ' . __METHOD__
);
$this->logger?->log(DbLoggerEvent::TRANSACTION_BEGIN_TRANS, $loggerContext);

$this->db->getPDO()?->beginTransaction();
$this->level = 1;
Expand All @@ -70,14 +68,11 @@ public function begin(string $isolationLevel = null): void
}

if ($this->db->isSavepointEnabled()) {
$this->logger?->log(LogLevel::DEBUG, 'Set savepoint ' . $this->level . ' ' . __METHOD__);
$this->logger?->log(DbLoggerEvent::TRANSACTION_BEGIN_SAVEPOINT, $loggerContext);

$this->createSavepoint('LEVEL' . $this->level);
} else {
$this->logger?->log(
LogLevel::DEBUG,
'Transaction not started: nested transaction not supported ' . __METHOD__
);
$this->logger?->log(DbLoggerEvent::TRANSACTION_BEGIN_NESTED_ERROR, $loggerContext);

throw new NotSupportedException('Transaction not started: nested transaction not supported.');
}
Expand All @@ -93,21 +88,19 @@ public function commit(): void

$this->level--;

$loggerContext = new TransactionContext(__METHOD__, $this->level);
if ($this->level === 0) {
$this->logger?->log(LogLevel::DEBUG, 'Commit transaction ' . __METHOD__);
$this->logger?->log(DbLoggerEvent::TRANSACTION_COMMIT, $loggerContext);
$this->db->getPDO()?->commit();

return;
}

if ($this->db->isSavepointEnabled()) {
$this->logger?->log(LogLevel::DEBUG, 'Release savepoint ' . $this->level . ' ' . __METHOD__);
$this->logger?->log(DbLoggerEvent::TRANSACTION_RELEASE_SAVEPOINT, $loggerContext);
$this->releaseSavepoint('LEVEL' . $this->level);
} else {
$this->logger?->log(
LogLevel::INFO,
'Transaction not committed: nested transaction not supported ' . __METHOD__
);
$this->logger?->log(DbLoggerEvent::TRANSACTION_COMMIT_NESTED_ERROR, $loggerContext);
}
}

Expand All @@ -134,21 +127,19 @@ public function rollBack(): void

$this->level--;

$loggerContext = new TransactionContext(__METHOD__, $this->level);
if ($this->level === 0) {
$this->logger?->log(LogLevel::INFO, 'Roll back transaction ' . __METHOD__);
$this->logger?->log(DbLoggerEvent::TRANSACTION_ROLLBACK, $loggerContext);
$this->db->getPDO()?->rollBack();

return;
}

if ($this->db->isSavepointEnabled()) {
$this->logger?->log(LogLevel::DEBUG, 'Roll back to savepoint ' . $this->level . ' ' . __METHOD__);
$this->logger?->log(DbLoggerEvent::TRANSACTION_ROLLBACK_SAVEPOINT, $loggerContext);
$this->rollBackSavepoint('LEVEL' . $this->level);
} else {
$this->logger?->log(
LogLevel::INFO,
'Transaction not rolled back: nested transaction not supported ' . __METHOD__
);
$this->logger?->log(DbLoggerEvent::TRANSACTION_ROLLBACK_NESTED_ERROR, $loggerContext);
}
}

Expand All @@ -158,10 +149,7 @@ public function setIsolationLevel(string $level): void
throw new Exception('Failed to set isolation level: transaction was inactive.');
}

$this->logger?->log(
LogLevel::DEBUG,
'Setting transaction isolation level to ' . $this->level . ' ' . __METHOD__
);
$this->logger?->log(DbLoggerEvent::TRANSACTION_SET_ISOLATION_LEVEL, new TransactionContext(__METHOD__, $this->level, $level));

Check warning on line 152 in src/Driver/Pdo/AbstractPdoTransaction.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/Pdo/AbstractPdoTransaction.php#L152

Added line #L152 was not covered by tests
$this->setTransactionIsolationLevel($level);
}

Expand Down
33 changes: 33 additions & 0 deletions src/Logger/Context/AbstractContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Db\Logger\Context;

use Throwable;
use Yiisoft\Db\Logger\ContextInterface;

abstract class AbstractContext implements ContextInterface
{
private Throwable|null $exception = null;

public function __construct(private string $methodName)
{
}

public function getMethodName(): string
{
return $this->methodName;
}

public function setException(Throwable $e): static
{
$this->exception = $e;
return $this;
}

public function getException(): Throwable|null
{
return $this->exception;
}
}
18 changes: 18 additions & 0 deletions src/Logger/Context/ConnectionContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Db\Logger\Context;

final class ConnectionContext extends AbstractContext
{
public function __construct(string $methodName, private string $dsn)
{
parent::__construct($methodName);
}

public function getDsn(): string
{
return $this->dsn;
}
}
23 changes: 23 additions & 0 deletions src/Logger/Context/QueryContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Db\Logger\Context;

final class QueryContext extends AbstractContext
{
public function __construct(string $methodName, private string $rawSql, private string $category)
{
parent::__construct($methodName);
}

public function getRawSql(): string
{
return $this->rawSql;
}

public function getCategory(): string
{
return $this->category;
}
}
23 changes: 23 additions & 0 deletions src/Logger/Context/TransactionContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Db\Logger\Context;

final class TransactionContext extends AbstractContext
{
public function __construct(string $methodName, private int $level, private string|null $isolationLevel = null)
{
parent::__construct($methodName);
}

public function getLevel(): int
{
return $this->level;
}

public function getIsolationLevel(): string|null
{
return $this->isolationLevel;
}
}
18 changes: 18 additions & 0 deletions src/Logger/ContextInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Db\Logger;

use Throwable;

/**
* Logger context.
*/
interface ContextInterface
{
public function getMethodName(): string;

public function getException(): Throwable|null;
public function setException(Throwable $e): static;
}
Loading

0 comments on commit d8f6ca4

Please sign in to comment.