generated from spatie/package-skeleton-laravel
-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
351 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?php | ||
|
||
namespace Naoray\LaravelGithubMonolog\Contracts; | ||
|
||
use Monolog\LogRecord; | ||
|
||
interface SignatureGenerator | ||
{ | ||
/** | ||
* Generate a unique signature for the log record | ||
*/ | ||
public function generate(LogRecord $record): string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?php | ||
|
||
namespace Naoray\LaravelGithubMonolog; | ||
|
||
use Monolog\LogRecord; | ||
use Naoray\LaravelGithubMonolog\Contracts\SignatureGenerator; | ||
use Throwable; | ||
|
||
class DefaultSignatureGenerator implements SignatureGenerator | ||
{ | ||
/** | ||
* Generate a unique signature for the log record | ||
*/ | ||
public function generate(LogRecord $record): string | ||
{ | ||
$exception = $record->context['exception'] ?? null; | ||
|
||
if (!$exception instanceof Throwable) { | ||
return $this->generateFromMessage($record); | ||
} | ||
|
||
return $this->generateFromException($exception); | ||
} | ||
|
||
/** | ||
* Generate a signature from a message and context | ||
*/ | ||
private function generateFromMessage(LogRecord $record): string | ||
{ | ||
return md5($record->message . json_encode($record->context)); | ||
} | ||
|
||
/** | ||
* Generate a signature from an exception | ||
*/ | ||
private function generateFromException(Throwable $exception): string | ||
{ | ||
$trace = $exception->getTrace(); | ||
$firstFrame = !empty($trace) ? $trace[0] : null; | ||
|
||
return md5(implode(':', [ | ||
$exception::class, | ||
$exception->getFile(), | ||
$exception->getLine(), | ||
$firstFrame ? ($firstFrame['file'] ?? '') . ':' . ($firstFrame['line'] ?? '') : '', | ||
])); | ||
} | ||
} |
2 changes: 1 addition & 1 deletion
2
src/GithubIssueFormatted.php → src/Formatters/GithubIssueFormatted.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<?php | ||
|
||
namespace Naoray\LaravelGithubMonolog\Handlers; | ||
|
||
use Monolog\Handler\DeduplicationHandler; | ||
use Monolog\Handler\HandlerInterface; | ||
use Monolog\Level; | ||
use Monolog\LogRecord; | ||
use Naoray\LaravelGithubMonolog\Contracts\SignatureGenerator; | ||
use Naoray\LaravelGithubMonolog\DefaultSignatureGenerator; | ||
|
||
class SignatureDeduplicationHandler extends DeduplicationHandler | ||
{ | ||
private SignatureGenerator $signatureGenerator; | ||
|
||
public function __construct( | ||
HandlerInterface $handler, | ||
?string $deduplicationStore = null, | ||
int|string|Level $deduplicationLevel = Level::Error, | ||
int $time = 60, | ||
bool $bubble = true, | ||
?SignatureGenerator $signatureGenerator = null, | ||
) { | ||
parent::__construct($handler, $deduplicationStore, $deduplicationLevel, $time, $bubble); | ||
$this->signatureGenerator = $signatureGenerator ?? new DefaultSignatureGenerator(); | ||
} | ||
|
||
/** | ||
* Override isDuplicate to use our signature-based deduplication | ||
*/ | ||
protected function isDuplicate(array $store, LogRecord $record): bool | ||
{ | ||
$timestampValidity = $record->datetime->getTimestamp() - $this->time; | ||
$signature = $this->signatureGenerator->generate($record); | ||
|
||
foreach ($store as $entry) { | ||
[$timestamp, $storedSignature] = explode(':', $entry, 2); | ||
|
||
if ($storedSignature === $signature && $timestamp > $timestampValidity) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* Override store entry format to use our signature | ||
*/ | ||
protected function buildDeduplicationStoreEntry(LogRecord $record): string | ||
{ | ||
return $record->datetime->getTimestamp() . ':' . $this->signatureGenerator->generate($record); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?php | ||
|
||
use Monolog\Level; | ||
use Monolog\LogRecord; | ||
use Naoray\LaravelGithubMonolog\DefaultSignatureGenerator; | ||
|
||
beforeEach(function () { | ||
$this->generator = new DefaultSignatureGenerator(); | ||
}); | ||
|
||
test('generates signature from message', function () { | ||
$record = new LogRecord( | ||
datetime: new \DateTimeImmutable(), | ||
channel: 'test', | ||
level: Level::Error, | ||
message: 'Test message', | ||
context: ['foo' => 'bar'], | ||
extra: [], | ||
); | ||
|
||
$signature1 = $this->generator->generate($record); | ||
expect($signature1)->toBeString(); | ||
|
||
// Same message and context should generate same signature | ||
$record2 = new LogRecord( | ||
datetime: new \DateTimeImmutable(), | ||
channel: 'different-channel', | ||
level: Level::Warning, | ||
message: 'Test message', | ||
context: ['foo' => 'bar'], | ||
extra: ['something' => 'else'], | ||
); | ||
$signature2 = $this->generator->generate($record2); | ||
expect($signature2)->toBe($signature1); | ||
|
||
// Different message should generate different signature | ||
$record3 = new LogRecord( | ||
datetime: new \DateTimeImmutable(), | ||
channel: 'test', | ||
level: Level::Error, | ||
message: 'Different message', | ||
context: ['foo' => 'bar'], | ||
extra: [], | ||
); | ||
$signature3 = $this->generator->generate($record3); | ||
expect($signature3)->not->toBe($signature1); | ||
}); | ||
|
||
test('generates signature from exception', function () { | ||
$exception = new \Exception('Test exception'); | ||
$record = new LogRecord( | ||
datetime: new \DateTimeImmutable(), | ||
channel: 'test', | ||
level: Level::Error, | ||
message: 'Test message', | ||
context: ['exception' => $exception], | ||
extra: [], | ||
); | ||
|
||
$signature1 = $this->generator->generate($record); | ||
expect($signature1)->toBeString(); | ||
|
||
// Same exception should generate same signature | ||
$record2 = new LogRecord( | ||
datetime: new \DateTimeImmutable(), | ||
channel: 'different-channel', | ||
level: Level::Warning, | ||
message: 'Different message', | ||
context: ['exception' => $exception], | ||
extra: ['something' => 'else'], | ||
); | ||
$signature2 = $this->generator->generate($record2); | ||
expect($signature2)->toBe($signature1); | ||
|
||
// Different exception should generate different signature | ||
$differentException = new \Exception('Different exception'); | ||
$record3 = new LogRecord( | ||
datetime: new \DateTimeImmutable(), | ||
channel: 'test', | ||
level: Level::Error, | ||
message: 'Test message', | ||
context: ['exception' => $differentException], | ||
extra: [], | ||
); | ||
$signature3 = $this->generator->generate($record3); | ||
expect($signature3)->not->toBe($signature1); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.