Merge pull request 'Reorganization' (#34) from feature/skip-deprecated into develop
Reviewed-on: #34
This commit is contained in:
@ -11,8 +11,20 @@ use PDOStatement;
|
|||||||
class MySQL extends AbstractProcessingHandler
|
class MySQL extends AbstractProcessingHandler
|
||||||
{
|
{
|
||||||
private bool $initialized = false;
|
private bool $initialized = false;
|
||||||
private PDOStatement $statement;
|
private array $tables = [
|
||||||
private PDOStatement $statementDeprecated;
|
'default' => 'monolog',
|
||||||
|
'deprecated' => 'monolog_deprecated'
|
||||||
|
];
|
||||||
|
private array $statements = [
|
||||||
|
'default' => null,
|
||||||
|
'deprecated' => null
|
||||||
|
];
|
||||||
|
private array $baseQueries = [
|
||||||
|
'check' => "SHOW TABLES LIKE '%s'",
|
||||||
|
'create' => "CREATE TABLE IF NOT EXISTS %s (channel VARCHAR(255), level VARCHAR(100), message LONGTEXT, time DATETIME, context LONGTEXT, extra LONGTEXT)",
|
||||||
|
'insert' => "INSERT INTO %s (channel, level, message, time, context, extra) VALUES (:channel, :level, :message, :time, :context, :extra)",
|
||||||
|
'delete' => "DELETE FROM %s WHERE time < DATE_SUB(CURDATE(), INTERVAL %d DAY)"
|
||||||
|
];
|
||||||
|
|
||||||
public function __construct(protected Connection $connection, protected int $retainDays = 90,
|
public function __construct(protected Connection $connection, protected int $retainDays = 90,
|
||||||
int|string|Level $level = Level::Debug, bool $bubble = true)
|
int|string|Level $level = Level::Debug, bool $bubble = true)
|
||||||
@ -22,18 +34,14 @@ class MySQL extends AbstractProcessingHandler
|
|||||||
public function write(LogRecord $record): void
|
public function write(LogRecord $record): void
|
||||||
{
|
{
|
||||||
if (!$this->initialized) {
|
if (!$this->initialized) {
|
||||||
if (!$this->checkTableExists()) {
|
if (!$this->checkTablesExist()) {
|
||||||
$this->createTable();
|
$this->createTables();
|
||||||
}
|
|
||||||
if (!$this->checkTableDeprecatedExists()) {
|
|
||||||
$this->createTableDeprecated();
|
|
||||||
}
|
}
|
||||||
$this->cleanup();
|
$this->cleanup();
|
||||||
$this->cleanupDeprecated();
|
|
||||||
$this->initialized();
|
$this->initialized();
|
||||||
}
|
}
|
||||||
if (str_contains(strtolower($record->message), 'deprecated:')) {
|
if (str_contains(strtolower($record->message), 'deprecated:')) {
|
||||||
$this->statementDeprecated->execute([
|
$this->statements['deprecated']->execute([
|
||||||
'channel' => $record->channel,
|
'channel' => $record->channel,
|
||||||
'level' => $record->level->getName(),
|
'level' => $record->level->getName(),
|
||||||
'message' => $record->formatted,
|
'message' => $record->formatted,
|
||||||
@ -43,7 +51,7 @@ class MySQL extends AbstractProcessingHandler
|
|||||||
]);
|
]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->statement->execute([
|
$this->statements['default']->execute([
|
||||||
'channel' => $record->channel,
|
'channel' => $record->channel,
|
||||||
'level' => $record->level->getName(),
|
'level' => $record->level->getName(),
|
||||||
'message' => $record->formatted,
|
'message' => $record->formatted,
|
||||||
@ -55,21 +63,19 @@ class MySQL extends AbstractProcessingHandler
|
|||||||
|
|
||||||
private function initialized(): void
|
private function initialized(): void
|
||||||
{
|
{
|
||||||
$query = <<<QUERY
|
foreach ($this->tables as $type => $table) {
|
||||||
INSERT INTO monolog (channel, level, message, time, context, extra)
|
$query = sprintf($this->baseQueries['insert'], $table);
|
||||||
VALUES (:channel, :level, :message, :time, :context, :extra)
|
$this->statements[$type] = $this->connection->getPDO()->prepare($query);
|
||||||
QUERY;
|
}
|
||||||
$this->statement = $this->connection->getPDO()->prepare($query);
|
|
||||||
$query = <<<QUERY
|
|
||||||
INSERT INTO monolog_deprecated (channel, level, message, time, context, extra)
|
|
||||||
VALUES (:channel, :level, :message, :time, :context, :extra)
|
|
||||||
QUERY;
|
|
||||||
$this->statementDeprecated = $this->connection->getPDO()->prepare($query);
|
|
||||||
$this->initialized = true;
|
$this->initialized = true;
|
||||||
}
|
}
|
||||||
private function checkTableExists(): bool
|
private function checkTablesExist(): bool
|
||||||
{
|
{
|
||||||
$query = "SHOW TABLES LIKE 'monolog'";
|
return array_all($this->tables, fn($table) => $this->checkTableExists($table));
|
||||||
|
}
|
||||||
|
private function checkTableExists(string $table): bool
|
||||||
|
{
|
||||||
|
$query = sprintf($this->baseQueries['check'], $table);
|
||||||
try {
|
try {
|
||||||
$result = $this->connection->query($query);
|
$result = $this->connection->query($query);
|
||||||
} catch (PDOException) {
|
} catch (PDOException) {
|
||||||
@ -77,51 +83,34 @@ QUERY;
|
|||||||
}
|
}
|
||||||
return $result->rowCount() > 0;
|
return $result->rowCount() > 0;
|
||||||
}
|
}
|
||||||
private function checkTableDeprecatedExists(): bool
|
private function createTables(): void
|
||||||
{
|
{
|
||||||
$query = "SHOW TABLES LIKE 'monolog_deprecated'";
|
foreach ($this->tables as $table) {
|
||||||
|
if (!$this->checkTableExists($table)) {
|
||||||
|
$this->createTable($table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private function createTable(string $table): void
|
||||||
|
{
|
||||||
|
$query = sprintf($this->baseQueries['create'], $table);
|
||||||
try {
|
try {
|
||||||
$result = $this->connection->query($query);
|
$result = $this->connection->getPDO()->exec($query);
|
||||||
} catch (PDOException) {
|
if ($result === false) {
|
||||||
return false;
|
throw new PDOException('Failed to create table: ' . $table);
|
||||||
}
|
}
|
||||||
return $result->rowCount() > 0;
|
} catch (PDOException) {}
|
||||||
}
|
|
||||||
private function createTable(): void
|
|
||||||
{
|
|
||||||
$query = <<<QUERY
|
|
||||||
CREATE TABLE IF NOT EXISTS monolog (
|
|
||||||
channel VARCHAR(255),
|
|
||||||
level VARCHAR(100),
|
|
||||||
message LONGTEXT,
|
|
||||||
time DATETIME,
|
|
||||||
context LONGTEXT,
|
|
||||||
extra LONGTEXT
|
|
||||||
)
|
|
||||||
QUERY;
|
|
||||||
$this->connection->getPDO()->exec($query);
|
|
||||||
}
|
|
||||||
private function createTableDeprecated(): void
|
|
||||||
{
|
|
||||||
$query = <<<QUERY
|
|
||||||
CREATE TABLE IF NOT EXISTS monolog_deprecated (
|
|
||||||
channel VARCHAR(255),
|
|
||||||
level VARCHAR(100),
|
|
||||||
message LONGTEXT,
|
|
||||||
time DATETIME,
|
|
||||||
context LONGTEXT,
|
|
||||||
extra LONGTEXT
|
|
||||||
)
|
|
||||||
QUERY;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
private function cleanup(): void
|
private function cleanup(): void
|
||||||
{
|
{
|
||||||
$query = "DELETE FROM monolog WHERE time < DATE_SUB(CURDATE(), INTERVAL {$this->retainDays} DAY)";
|
foreach ($this->tables as $table) {
|
||||||
$this->connection->query($query);
|
$query = sprintf($this->baseQueries['delete'], $table, $this->retainDays);
|
||||||
|
try {
|
||||||
|
$result = $this->connection->getPDO()->query($query);
|
||||||
|
if ($result === false) {
|
||||||
|
throw new PDOException('Failed to delete from table: ' . $table);
|
||||||
|
}
|
||||||
|
} catch (PDOException) {}
|
||||||
}
|
}
|
||||||
private function cleanupDeprecated(): void
|
|
||||||
{
|
|
||||||
$query = "DELETE FROM monolog_deprecated WHERE time < DATE_SUB(CURDATE(), INTERVAL {$this->retainDays} DAY)";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
59
app/tests/unit/common/Implement/Log/Handler/MySQLTest.php
Normal file
59
app/tests/unit/common/Implement/Log/Handler/MySQLTest.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
namespace Tests\Unit\Common\Implement\Log\Handler;
|
||||||
|
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use PDO;
|
||||||
|
use PDOStatement;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Monolog;
|
||||||
|
use Faker\Factory;
|
||||||
|
use Incoviba\Common\Implement\Log\Handler\MySQL;
|
||||||
|
use Incoviba\Common\Define;
|
||||||
|
|
||||||
|
class MySQLTest extends TestCase
|
||||||
|
{
|
||||||
|
protected Define\Connection $connection;
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$pdo = $this->getMockBuilder(PDO::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$pdo->method('prepare')->willReturn($this->getMockBuilder(PDOStatement::class)->getMock());
|
||||||
|
$this->connection = $this->getMockBuilder(Define\Connection::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$this->connection->method('getPDO')->willReturn($pdo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWrite(): void
|
||||||
|
{
|
||||||
|
$faker = Factory::create();
|
||||||
|
$context = [];
|
||||||
|
$extra = [];
|
||||||
|
for ($i = 0; $i < 5; $i++) {
|
||||||
|
$context[$faker->word] = $faker->word;
|
||||||
|
$extra[$faker->word] = $faker->word;
|
||||||
|
}
|
||||||
|
$recordArray = [
|
||||||
|
'message' => 'Test message',
|
||||||
|
'context' => $context,
|
||||||
|
'level' => 100,
|
||||||
|
'level_name' => 'DEBUG',
|
||||||
|
'channel' => $faker->word,
|
||||||
|
'datetime' => DateTimeImmutable::createFromMutable($faker->dateTime()),
|
||||||
|
'extra' => $extra,
|
||||||
|
];
|
||||||
|
$record = new Monolog\LogRecord(
|
||||||
|
$recordArray['datetime'],
|
||||||
|
$recordArray['channel'],
|
||||||
|
Monolog\Level::fromName($recordArray['level_name']),
|
||||||
|
$recordArray['message'],
|
||||||
|
$recordArray['context'],
|
||||||
|
$recordArray['extra']);
|
||||||
|
|
||||||
|
$handler = new MySQL($this->connection);
|
||||||
|
$handler->write($record);
|
||||||
|
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user